ManifoldMeshes
Mesh infrastructure for scientific computing on manifolds. Currently provides latitude-longitude grids on the unit sphere (S²).
Installation
using Pkg
Pkg.add("https://github.com/VANvonZHANG/ManifoldMeshes.jl")Quick Start
using ManifoldMeshes
# Create a 5×10 latitude-longitude grid on the unit sphere
grid = LatLonGrid(lat_edges=range(-90, 90; length=6), lon_edges=range(0, 360; length=11))
# Global information
num_cells(grid) # 50
num_nodes(grid) # 66
num_edges(grid) # 120
# Cell geometry
cell_volume(grid, 1)
cell_centroid(grid, 1)
# Topological connectivity
cell_nodes(grid, 1)
cell_cells(grid, 1)Design Philosophy
Let geometry belong to manifolds, topology belong to meshes.
- All continuous mathematics (geodesics, distances, projections) is delegated to Manifolds.jl
- This library defines discrete connectivity (cells, nodes, edges) and computes geometric measures
- Cell boundaries are geodesic arcs (great circles), not coordinate lines
API Reference
ManifoldMeshes.AbstractManifoldMeshManifoldMeshes._build_edge_endpoint_mapManifoldMeshes.boundary_edgesManifoldMeshes.boundary_nodesManifoldMeshes.cell_cellsManifoldMeshes.cell_centroidManifoldMeshes.cell_edgesManifoldMeshes.cell_nodesManifoldMeshes.cell_polygonsManifoldMeshes.cell_volumeManifoldMeshes.edge_lengthManifoldMeshes.edge_midpointManifoldMeshes.edge_outward_normalManifoldMeshes.edge_segmentsManifoldMeshes.manifoldManifoldMeshes.node_cellsManifoldMeshes.node_coordinatesManifoldMeshes.node_pointsManifoldMeshes.num_cellsManifoldMeshes.num_edgesManifoldMeshes.num_nodesManifoldMeshes.slerp
ManifoldMeshes.AbstractManifoldMesh — Type
AbstractManifoldMesh{M <: AbstractManifold}Abstract supertype for all mesh types on a manifold M.
Every concrete subtype must implement the full mesh interface: grid properties (manifold, num_cells, num_nodes, num_edges), geometry queries (node_coordinates, cell_volume, cell_centroid), topology queries (cell_nodes, cell_cells, node_cells, cell_edges), edge information (edge_length, edge_midpoint, edge_outward_normal), and boundary markers (boundary_nodes, boundary_edges).
Cell, node, and edge IDs are 1-indexed integers.
ManifoldMeshes._build_edge_endpoint_map — Method
_build_edge_endpoint_map(g::AbstractManifoldMesh) -> Dict{Int, Tuple{Int,Int}}Reconstruct edge-to-endpoint-node mapping from the public cell interface. For each cell, edges are ordered (south, north, west, east) and nodes are ordered (SW, SE, NE, NW), giving:
- south edge: SW -> SE (nodes 1-2)
- north edge: NW -> NE (nodes 4-3)
- west edge: SW -> NW (nodes 1-4)
- east edge: SE -> NE (nodes 2-3)
ManifoldMeshes.boundary_edges — Method
boundary_edges(g, marker) -> Vector{Int}Edge IDs on the boundary with the given marker. Returns empty for closed manifolds (e.g., full sphere).
ManifoldMeshes.boundary_nodes — Method
boundary_nodes(g, marker) -> Vector{Int}Node IDs on the boundary with the given marker. Returns empty for closed manifolds (e.g., full sphere).
ManifoldMeshes.cell_cells — Method
cell_cells(g, cell_id) -> NTuple{K, Int}Cell IDs of cells sharing a face with cell_id. Uses 0 as sentinel for missing neighbors (e.g., at domain boundaries). For quadrilateral cells, returns (south, north, west, east).
ManifoldMeshes.cell_centroid — Method
cell_centroid(g, cell_id) -> SVector{D, Float64}Centroid of cell cell_id on the manifold, pre-computed at construction.
ManifoldMeshes.cell_edges — Method
cell_edges(g, cell_id) -> NTuple{K, Int}Edge IDs of the edges bounding cell cell_id. For quadrilateral cells, returns (south, north, west, east).
ManifoldMeshes.cell_nodes — Method
cell_nodes(g, cell_id) -> NTuple{K, Int}Node IDs at the corners of cell cell_id. Tuple length depends on cell type. For quadrilateral cells, returns (SW, SE, NE, NW).
ManifoldMeshes.cell_polygons — Method
cell_polygons(g::AbstractManifoldMesh; n_arc_points::Int=20) -> Vector{Vector{Point3f}}Return closed cell boundaries as discretized great-circle polygons. Each polygon is a vector of Point3f where the first point equals the last. Edges are ordered: south, east, north (reversed), west (reversed).
ManifoldMeshes.cell_volume — Method
cell_volume(g, cell_id) -> Float64Volume (area on 2D manifolds) of cell cell_id, pre-computed at construction.
ManifoldMeshes.edge_length — Method
edge_length(g, edge_id) -> Float64Geodesic arc length of edge edge_id on the manifold.
ManifoldMeshes.edge_midpoint — Method
edge_midpoint(g, edge_id) -> SVector{D, Float64}Geodesic midpoint of edge edge_id on the manifold. For degenerate (zero-length) edges, returns one of the endpoints.
ManifoldMeshes.edge_outward_normal — Method
edge_outward_normal(g, edge_id, cell_id) -> NamedTuple{(:base_point, :normal)}Outward-pointing unit normal at the midpoint of edge_id, relative to cell_id.
Returns (base_point, normal) where:
base_pointis the midpoint on the manifold (tangent space origin)normalis the unit normal vector in the tangent space atbase_point
For degenerate edges (zero length), returns a zero normal.
ManifoldMeshes.edge_segments — Method
edge_segments(g::AbstractManifoldMesh; n_arc_points::Int=20) -> Vector{Vector{Point3f}}Return discretized great-circle arcs for each edge, as a vector of Point3f arrays. Degenerate edges (coincident endpoints) return a single-point segment.
ManifoldMeshes.manifold — Method
manifold(g) -> AbstractManifoldReturns the underlying manifold on which the mesh is defined.
ManifoldMeshes.node_cells — Method
node_cells(g, node_id) -> Vector{Int}Cell IDs of all cells adjacent to node_id.
Note: Allocates a Vector{Int} per call. Not recommended for tight FVM loops. Future unstructured meshes should consider a CSR layout for allocation-free access.
ManifoldMeshes.node_coordinates — Method
node_coordinates(g, node_id) -> SVector{D, Float64}Cartesian coordinates of node node_id in the embedding space.
ManifoldMeshes.node_points — Method
node_points(g::AbstractManifoldMesh) -> Vector{Point3f}Return all node positions as Point3f values, indexed by node ID.
ManifoldMeshes.num_cells — Method
num_cells(g) -> IntTotal number of cells in the mesh.
ManifoldMeshes.num_edges — Method
num_edges(g) -> IntTotal number of edges in the mesh.
ManifoldMeshes.num_nodes — Method
num_nodes(g) -> IntTotal number of nodes (vertices) in the mesh.
ManifoldMeshes.slerp — Method
slerp(p1::SVector{3,Float64}, p2::SVector{3,Float64}, n::Int) -> Vector{Point3f}Spherical linear interpolation between p1 and p2, producing n evenly spaced points on the great circle arc. For coincident endpoints (θ < 1e-10), returns a single-point vector. For antipodal endpoints (θ ≈ π), falls back to a stable intermediate great circle plane.