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.AbstractManifoldMeshType
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.

source
ManifoldMeshes._build_edge_endpoint_mapMethod
_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)
source
ManifoldMeshes.boundary_edgesMethod
boundary_edges(g, marker) -> Vector{Int}

Edge IDs on the boundary with the given marker. Returns empty for closed manifolds (e.g., full sphere).

source
ManifoldMeshes.boundary_nodesMethod
boundary_nodes(g, marker) -> Vector{Int}

Node IDs on the boundary with the given marker. Returns empty for closed manifolds (e.g., full sphere).

source
ManifoldMeshes.cell_cellsMethod
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).

source
ManifoldMeshes.cell_edgesMethod
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).

source
ManifoldMeshes.cell_nodesMethod
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).

source
ManifoldMeshes.cell_polygonsMethod
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).

source
ManifoldMeshes.edge_midpointMethod
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.

source
ManifoldMeshes.edge_outward_normalMethod
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_point is the midpoint on the manifold (tangent space origin)
  • normal is the unit normal vector in the tangent space at base_point

For degenerate edges (zero length), returns a zero normal.

source
ManifoldMeshes.edge_segmentsMethod
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.

source
ManifoldMeshes.node_cellsMethod
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.

source
ManifoldMeshes.node_pointsMethod
node_points(g::AbstractManifoldMesh) -> Vector{Point3f}

Return all node positions as Point3f values, indexed by node ID.

source
ManifoldMeshes.slerpMethod
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.

source