Graph & Connectivity#
Derived connectivity tables, graph traversal, and binary morphology on a mesh.
Everything here is pure: each function reads a Mesh2d and returns new arrays or a new
Connectivity, never writing a derived table back onto the mesh it was handed. The edge tables are
derived from the faces; when a file declares its own edge_node_connectivity those edges keep their
positions (edge-located variables index into them) and any face-implied edge the file omits is
appended after them, so a partial edge list still yields a complete face topology.
sparse_adjacency is the shared primitive: connected_components, reverse_cuthill_mckee and the
binary morphology all read it.
One morphology pass is simultaneous — the neighbour test is taken from the mask as it stands at the
start of the pass, and the border_value imputation joins that same update — so one iteration moves
exactly one ring, matching scipy.ndimage.
pyramids.netcdf.ugrid.graph
#
Mesh graph and connectivity operations for UGRID 2D meshes.
A collection of pure functions that each take a :class:~pyramids.netcdf.ugrid.mesh.Mesh2d
(and/or plain numpy arrays) and return plain results — numpy arrays, :class:Connectivity
wrappers, scipy sparse matrices, shapely geometries, or a rebuilt Mesh2d for the one
topology-transforming helper. None of them mutate their input.
The module groups the graph-flavoured mesh operations behind a single import:
- Connectivity builders that pyramids does not derive today:
node_node_connectivity,node_face_connectivity,node_edge_connectivity,edge_node_connectivity,edge_face_connectivity,face_edge_connectivityandedge_edge_connectivity. sparse_adjacency— a scipy sparse adjacency matrix over faces or nodes, the shared primitive the graph algorithms below build on.- Facet remapping (
to_node/to_edge/to_face) that averages a per-element field onto another mesh facet via connectivity. - Graph algorithms:
connected_components,reverse_cuthill_mckee(+permute_faces),binary_dilation/binary_erosion,voronoi/circumcentersand the boundary helpersexterior_edges/exterior_faces/bounding_polygon.
scipy (scipy.sparse, scipy.sparse.csgraph, scipy.spatial) and shapely are hard
dependencies of the UGRID subsystem, so they are imported at module top.
node_face_connectivity(mesh)
#
Faces incident to each node (inverse of face_node_connectivity).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
Ragged |
Source code in src/pyramids/netcdf/ugrid/graph.py
edge_node_connectivity(mesh)
#
The two nodes of each edge, derived from the faces when absent.
A row the file declared but never defined -- one padded with the fill value, or a repeat of
an edge already listed -- comes back as a (-1, -1) placeholder. It keeps its
position, so an edge-located variable stays aligned with the table, but it describes no
edge: :func:_real_edges is the mask of the rows that do, and
:func:edge_face_connectivity / :func:edge_edge_connectivity answer an all-fill row at
the same positions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
|
Connectivity
|
file's edge list declared an edge it did not define. |
Source code in src/pyramids/netcdf/ugrid/graph.py
node_edge_connectivity(mesh)
#
Edges incident to each node (inverse of edge_node_connectivity).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
Ragged |
Source code in src/pyramids/netcdf/ugrid/graph.py
node_node_connectivity(mesh)
#
Neighbouring nodes of each node, derived from the mesh edges.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
Ragged |
Source code in src/pyramids/netcdf/ugrid/graph.py
edge_face_connectivity(mesh)
#
The (up to two) faces on either side of each edge.
Edges on the mesh boundary carry a -1 fill on their missing side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
|
Source code in src/pyramids/netcdf/ugrid/graph.py
face_edge_connectivity(mesh)
#
The boundary edges of each face.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
Ragged |
Source code in src/pyramids/netcdf/ugrid/graph.py
edge_edge_connectivity(mesh)
#
Edges that share a node with each edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Connectivity |
Connectivity
|
Ragged |
Source code in src/pyramids/netcdf/ugrid/graph.py
sparse_adjacency(mesh, kind='face')
#
Build a symmetric scipy sparse adjacency matrix for the mesh.
For kind="face" two faces are adjacent when they share an edge (an edge whose
edge_face_connectivity has two valid faces). For kind="node" two nodes are
adjacent when an edge joins them. The result is the shared primitive consumed by
:func:connected_components, :func:reverse_cuthill_mckee and the binary morphology.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
kind
|
str
|
|
'face'
|
Returns:
| Type | Description |
|---|---|
Any
|
scipy.sparse.csr_matrix: The symmetric |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/netcdf/ugrid/graph.py
to_node(mesh, values, source='face')
#
Remap a per-face or per-edge field onto the nodes by averaging.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
values
|
NDArray
|
Source field, element axis last. |
required |
source
|
str
|
|
'face'
|
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: The node-located field. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/netcdf/ugrid/graph.py
to_face(mesh, values, source='node')
#
Remap a per-node or per-edge field onto the faces by averaging.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
values
|
NDArray
|
Source field, element axis last. |
required |
source
|
str
|
|
'node'
|
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: The face-located field. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/netcdf/ugrid/graph.py
to_edge(mesh, values, source='node')
#
Remap a per-node or per-face field onto the edges by averaging.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
values
|
NDArray
|
Source field, element axis last. |
required |
source
|
str
|
|
'node'
|
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: The edge-located field. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/pyramids/netcdf/ugrid/graph.py
connected_components(mesh)
#
Label each face by the connected component it belongs to.
Two faces are in the same component when a path of shared edges joins them — the mesh analogue of a raster cluster labelling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: Per-face component label of length |
Source code in src/pyramids/netcdf/ugrid/graph.py
reverse_cuthill_mckee(mesh)
#
Return a face permutation that reduces the face-adjacency bandwidth.
Computes the reverse Cuthill-McKee ordering of the face adjacency. Apply it to the mesh
with :func:permute_faces and to every face-located variable with arr[..., perm].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: A permutation of |
Source code in src/pyramids/netcdf/ugrid/graph.py
permute_faces(mesh, perm)
#
Rebuild a mesh with its faces reordered by perm.
Node coordinates and numbering are unchanged — only the face rows (and any face centre
coordinates) are reordered — so the result is congruent to the input. New face k is
old face perm[k]; the input mesh is not mutated, and no array is shared with it.
The three face-indexed tables -- face_edge_connectivity, face_face_connectivity
and edge_face_connectivity -- are dropped rather than permuted, since their
contents index the old face numbering. Derive them again from the result if you need
them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to reorder. |
required |
perm
|
NDArray
|
A permutation of |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Mesh2d |
Mesh2d
|
The reordered mesh. |
Source code in src/pyramids/netcdf/ugrid/graph.py
binary_dilation(mesh, mask, iterations=1, border_value=False, fixed=None)
#
Grow a True region of a boolean face mask across shared edges.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
mask
|
NDArray
|
Input boolean face mask (not mutated). |
required |
iterations
|
int
|
Number of rings to grow. |
1
|
border_value
|
bool
|
Value imputed to the mesh exterior (grows inward from the boundary
when |
False
|
fixed
|
NDArray | None
|
Optional boolean faces held at their input value. |
None
|
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: The dilated boolean face mask. |
Source code in src/pyramids/netcdf/ugrid/graph.py
binary_erosion(mesh, mask, iterations=1, border_value=False, fixed=None)
#
Shrink a True region of a boolean face mask across shared edges.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
mask
|
NDArray
|
Input boolean face mask (not mutated). |
required |
iterations
|
int
|
Number of rings to shrink. |
1
|
border_value
|
bool
|
Value imputed to the mesh exterior (erodes from the boundary when
|
False
|
fixed
|
NDArray | None
|
Optional boolean faces held at their input value. |
None
|
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: The eroded boolean face mask. |
Source code in src/pyramids/netcdf/ugrid/graph.py
circumcenters(mesh)
#
Per-face circumcenter coordinates for a triangular mesh.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read (every face must be a triangle). |
required |
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the mesh is not purely triangular. |
Source code in src/pyramids/netcdf/ugrid/graph.py
voronoi(mesh)
#
Voronoi tessellation of the mesh nodes (the mesh dual).
Uses :class:scipy.spatial.Voronoi over the node coordinates. For a triangular mesh that
is Delaunay the Voronoi vertices coincide with the face :func:circumcenters, and interior
nodes receive bounded dual cells while boundary nodes receive unbounded (-1) regions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
scipy.spatial.Voronoi: The Voronoi object; |
Source code in src/pyramids/netcdf/ugrid/graph.py
exterior_edges(mesh)
#
Indices of the edges on the mesh boundary.
A boundary edge is one whose edge_face_connectivity has a fill on one side (only one
adjacent face).
A dangling edge -- one the file lists that no face implies -- has a fill on both sides, so it is reported here too. That is deliberate: such an edge bounds no face, which makes it part of the mesh's boundary in the only sense this function can measure. A placeholder row (a padded edge the file declared but never defined, or a repeat of an edge already listed) also has two fills, and that one is not reported, because it describes no edge at all.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: Boundary edge indices (into the mesh's edge ordering). |
Source code in src/pyramids/netcdf/ugrid/graph.py
exterior_faces(mesh)
#
Indices of the faces that touch the mesh boundary.
A boundary face is one attached to at least one exterior edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Type | Description |
|---|---|
NDArray
|
np.ndarray: Sorted unique boundary face indices. |
Source code in src/pyramids/netcdf/ugrid/graph.py
bounding_polygon(mesh)
#
Dissolved outline of the mesh as a shapely (Multi)Polygon, holes preserved.
Unions the face polygons so shared interior edges dissolve away; the result's exterior ring is the mesh outline and any mesh hole appears as an interior ring. Its area equals the mesh footprint. The returned geometry carries no CRS — the caller attaches one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh
|
Mesh2d
|
The mesh to read. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
shapely.Polygon | shapely.MultiPolygon: The dissolved outline. |