Skip to content

Meshes and geometric refinement

Geometric partitions, skeletal topology and conforming refinement.

All API families

Geometric integration operations

pymhm.meshes.geometry

Oriented geometry operations for polygons and star-shaped polyhedral cells.

clip_polygon(polygon: ArrayLike, axis: int, level: float, lower: bool) -> FloatArray

Intersect an ordered convex planar polygon with a closed Cartesian half-plane.

polygon contains finite real vertices with shape (n,2), without a repeated closing vertex. axis is 0 or 1. lower=True retains coordinate >= level; lower=False retains coordinate <= level. Output vertices follow the input's clockwise or counterclockwise orientation. An empty intersection has shape (0,2); point/segment intersections and repeated boundary vertices are retained for the caller's measure checks.

Computation uses binary64 and strict comparisons of represented coordinates. An intersection's clipped coordinate is set exactly to level. No geometric tolerance, vertex merging or grid snapping is inferred; applications requiring those conventions declare them before clipping. Convexity and cyclic ordering are caller hypotheses.

Source code in src/pymhm/meshes/geometry.py
def clip_polygon(polygon: ArrayLike, axis: int, level: float, lower: bool) -> FloatArray:
    """Intersect an ordered convex planar polygon with a closed Cartesian half-plane.

    ``polygon`` contains finite real vertices with shape (n,2), without a
    repeated closing vertex. ``axis`` is 0 or 1. ``lower=True`` retains
    coordinate >= level; ``lower=False`` retains coordinate <= level. Output
    vertices follow the input's clockwise or counterclockwise orientation.
    An empty intersection has shape (0,2); point/segment intersections and
    repeated boundary vertices are retained for the caller's measure checks.

    Computation uses binary64 and strict comparisons of represented
    coordinates. An intersection's clipped coordinate is set exactly to
    ``level``. No geometric tolerance, vertex merging or grid snapping is
    inferred; applications requiring those conventions declare them before
    clipping. Convexity and cyclic ordering are caller hypotheses.
    """
    polygon = real_array(polygon, "polygon vertices")
    axis = positive_int(axis, "axis", 0)
    if polygon.ndim != 2 or polygon.shape[1] != 2:
        raise ValueError("polygon vertices must have shape (n,2)")
    if axis > 1:
        raise ValueError("axis must be 0 or 1")
    boundary = real_array(level, "clipping level")
    if boundary.ndim != 0:
        raise ValueError("clipping level must be a scalar")
    level = float(boundary)
    if not isinstance(lower, (bool, np.bool_)):
        raise ValueError("lower must be a boolean half-plane selector")
    if not len(polygon):
        return polygon
    vertices = []
    previous = polygon[-1]
    previous_inside = previous[axis] >= level if lower else previous[axis] <= level
    for current in polygon:
        current_inside = current[axis] >= level if lower else current[axis] <= level
        if current_inside != previous_inside:
            fraction = (level - previous[axis]) / (current[axis] - previous[axis])
            intersection = previous + fraction * (current - previous)
            intersection[axis] = level
            vertices.append(intersection)
        if current_inside:
            vertices.append(current)
        previous, previous_inside = current, current_inside
    return np.asarray(vertices, dtype=float).reshape(-1, 2)

oriented_cell_faces(points: FloatArray, faces: list[IntArray], cells: list[IntArray]) -> tuple[IntArray, ...]

Orient each connected closed cell boundary through opposing directed edge incidences.

The global orientation is selected by its signed surface-volume integral; neither a convex hull nor an assumed interior centroid is used. The caller subsequently checks that the surface is embedded by its positive cone mesh.

Source code in src/pymhm/meshes/geometry.py
def oriented_cell_faces(
    points: FloatArray, faces: list[IntArray], cells: list[IntArray]
) -> tuple[IntArray, ...]:
    """Orient each connected closed cell boundary through opposing directed edge incidences.

    The global orientation is selected by its signed surface-volume integral;
    neither a convex hull nor an assumed interior centroid is used. The caller
    subsequently checks that the surface is embedded by its positive cone mesh.
    """
    result = []
    for ids in cells:
        edges: dict[tuple[int, int], list[tuple[int, int]]] = {}
        for side, face in enumerate(ids):
            polygon = faces[face]
            for a, b in zip(polygon, np.roll(polygon, -1), strict=True):
                key = (min(int(a), int(b)), max(int(a), int(b)))
                edges.setdefault(key, []).append((side, 1 if a < b else -1))
        adjacency: list[list[tuple[int, int]]] = [[] for _ in ids]
        for incident in edges.values():
            if len(incident) != 2:
                raise ValueError("polyhedral boundary must be a closed two-manifold")
            (a, da), (b, db) = incident
            adjacency[a].append((b, -da * db))
            adjacency[b].append((a, -da * db))
        signs = np.zeros(len(ids), dtype=np.int64)
        signs[0] = 1
        pending = [0]
        while pending:
            side = pending.pop()
            for neighbor, relation in adjacency[side]:
                wanted = signs[side] * relation
                if signs[neighbor] == 0:
                    signs[neighbor] = wanted
                    pending.append(neighbor)
                elif signs[neighbor] != wanted:
                    raise ValueError("polyhedral boundary must be orientable")
        if np.any(signs == 0):
            raise ValueError(
                "polyhedral boundary must be connected, without separate cavity shells"
            )
        vertices = points[np.unique(np.concatenate([faces[face] for face in ids]))]
        origin = vertices.mean(axis=0)
        scale = float(np.ptp(vertices, axis=0).max())
        if scale == 0:
            raise ValueError("polyhedral cell has zero or unresolved volume")
        volume, absolute_products = 0.0, 0.0
        for face, sign in zip(ids, signs, strict=True):
            polygon = (points[faces[face]] - origin) / scale
            for j in range(1, len(polygon) - 1):
                a, b, c = polygon[[0, j, j + 1]]
                volume += sign * float(np.dot(a, np.cross(b, c))) / 6
                absolute_products += (
                    float(
                        abs(a)
                        @ (abs(b[[1, 2, 0]] * c[[2, 0, 1]]) + abs(b[[2, 0, 1]] * c[[1, 2, 0]]))
                    )
                    / 6
                )
        if abs(volume) <= 256 * np.finfo(float).eps * absolute_products:
            raise ValueError("polyhedral cell has zero or unresolved signed volume")
        result.append(signs if volume > 0 else -signs)
    return tuple(result)

kernel_center(vertices: FloatArray, origins: FloatArray, outward: FloatArray) -> tuple[FloatArray, float, bool]

Find a strictly interior ball in the intersection of all inward face half-spaces.

Convex cells retain the arithmetic vertex center. Nonconvex cells maximize the ball radius by a four-variable linear program in cell-scaled coordinates. Canonically ordered inequalities make degenerate optimal-center selection independent of face-list order. The returned radius is verified against every original face, independently of the optimizer's feasibility tolerance. An empty or unresolved kernel is rejected rather than filled by a convex hull.

Source code in src/pymhm/meshes/geometry.py
def kernel_center(
    vertices: FloatArray, origins: FloatArray, outward: FloatArray
) -> tuple[FloatArray, float, bool]:
    """Find a strictly interior ball in the intersection of all inward face half-spaces.

    Convex cells retain the arithmetic vertex center. Nonconvex cells maximize
    the ball radius by a four-variable linear program in cell-scaled coordinates.
    Canonically ordered inequalities make degenerate optimal-center selection
    independent of face-list order.
    The returned radius is verified against every original face, independently
    of the optimizer's feasibility tolerance. An empty or unresolved kernel is
    rejected rather than filled by a convex hull.
    """
    center = vertices.mean(axis=0)
    scale = float(np.ptp(vertices, axis=0).max())
    tolerance = 512 * np.finfo(float).eps * scale
    distances = np.einsum("fvi,fi->fv", vertices[None] - origins[:, None], outward)
    convex = bool(np.all(distances <= tolerance))
    if not convex:
        bound = np.einsum("fi,fi->f", origins - center, outward) / scale
        ordering = np.lexsort((bound, outward[:, 2], outward[:, 1], outward[:, 0]))
        problem = linprog(
            [0.0, 0.0, 0.0, -1.0],
            A_ub=np.column_stack((outward, np.ones(len(outward))))[ordering],
            b_ub=bound[ordering],
            bounds=[(None, None)] * 3 + [(0.0, None)],
            method="highs",
        )
        if not problem.success:
            raise ValueError("polyhedral cell requires a nonempty star-shaped kernel")
        center = center + scale * problem.x[:3]
    radius = float(np.min(np.einsum("fi,fi->f", origins - center, outward)))
    if not np.isfinite(radius) or radius <= tolerance:
        raise ValueError("polyhedral cell requires a resolvable strictly interior kernel ball")
    return center, radius, convex

validate_disjoint_cones(points: FloatArray, cells: IntArray) -> None

Reject interior overlap of tetrahedral cones using the convex separating-axis theorem.

Face normals and pairwise edge cross products are a complete axis set for two tetrahedra. Coordinates are translated/scaled before projection; touching faces, edges and the common kernel center do not constitute overlap.

Source code in src/pymhm/meshes/geometry.py
def validate_disjoint_cones(points: FloatArray, cells: IntArray) -> None:
    """Reject interior overlap of tetrahedral cones using the convex separating-axis theorem.

    Face normals and pairwise edge cross products are a complete axis set for
    two tetrahedra. Coordinates are translated/scaled before projection; touching
    faces, edges and the common kernel center do not constitute overlap.
    """
    scale = float(np.ptp(points, axis=0).max())
    scaled = (points - points.mean(axis=0)) / scale
    tetrahedra = scaled[cells]
    tolerance = 1024 * np.finfo(float).eps
    edge_ids = np.asarray(list(combinations(range(4), 2)))
    face_ids = np.asarray(list(combinations(range(4), 3)))
    for first, second in combinations(tetrahedra, 2):
        if np.any(
            np.minimum(first.max(axis=0), second.max(axis=0))
            - np.maximum(first.min(axis=0), second.min(axis=0))
            <= tolerance
        ):
            continue
        edges_a = first[edge_ids[:, 1]] - first[edge_ids[:, 0]]
        edges_b = second[edge_ids[:, 1]] - second[edge_ids[:, 0]]
        axes = np.vstack(
            (
                np.cross(
                    first[face_ids[:, 1]] - first[face_ids[:, 0]],
                    first[face_ids[:, 2]] - first[face_ids[:, 0]],
                ),
                np.cross(
                    second[face_ids[:, 1]] - second[face_ids[:, 0]],
                    second[face_ids[:, 2]] - second[face_ids[:, 0]],
                ),
                np.cross(edges_a[:, None], edges_b[None]).reshape(-1, 3),
            )
        )
        lengths = np.linalg.norm(axes, axis=1)
        axes = axes[lengths > tolerance] / lengths[lengths > tolerance, None]
        a, b = first @ axes.T, second @ axes.T
        overlaps = np.minimum(a.max(axis=0), b.max(axis=0)) - np.maximum(
            a.min(axis=0), b.min(axis=0)
        )
        if np.all(overlaps > tolerance):
            raise ValueError("polyhedral boundary produces overlapping tetrahedral interiors")

triangle_in_face(corners: FloatArray, triangles: FloatArray, normal: FloatArray) -> bool

Test a fine boundary triangle against the original face's canonical triangulation.

Conforming local refinements lie within a single canonical triangle even when the original polygon is nonconvex. This preserves individual coplanar faces and does not accept a triangle spanning a reentrant notch.

Source code in src/pymhm/meshes/geometry.py
def triangle_in_face(corners: FloatArray, triangles: FloatArray, normal: FloatArray) -> bool:
    """Test a fine boundary triangle against the original face's canonical triangulation.

    Conforming local refinements lie within a single canonical triangle even
    when the original polygon is nonconvex. This preserves individual coplanar
    faces and does not accept a triangle spanning a reentrant notch.
    """
    for triangle in triangles:
        edges = np.roll(triangle, -1, axis=0) - triangle
        scale = float(np.ptp(triangle, axis=0).max())
        tolerance = 512 * np.finfo(float).eps * scale
        if np.max(abs((corners - triangle[0]) @ normal)) > tolerance:
            continue
        half_planes = np.cross(edges[:, None], corners[None] - triangle[:, None]) @ normal
        if np.all(half_planes >= -tolerance * np.linalg.norm(edges, axis=1)[:, None]):
            return True
    return False

Oriented triangular geometry and signed cell-to-face incidence.

TriangleMesh dataclass

Conforming, nondegenerate planar triangles with consistent face normals.

Points have shape (n, 2) and cells (m, 3). Clockwise input cells are reoriented. Every face normal points out of its first adjacent cell; boundary normals therefore point out of the domain. Geometry arrays are copied.

boundary_faces: IntArray property

Return indices of faces with exactly one adjacent cell.

normals: FloatArray property

Return unit normals in the globally fixed face orientations.

lengths: FloatArray property

Return face lengths.

areas: FloatArray property

Return positive triangle areas.

__post_init__() -> None

Validate geometry and construct the signed cell-to-face incidence.

unit_square(nx: int = 1, ny: int | None = None) -> TriangleMesh classmethod

Split a Cartesian unit-square grid along each southwest diagonal.

submesh(cell: int, subdivisions: int) -> TriangleMesh

Uniformly subdivide one macrotriangle into subdivisions**2 cells.

Affine crisscross partitions inside triangular macroelements.

crisscross_submesh(mesh: TriangleMesh, cell: int, subdivisions: int, *, diagonal_side: int | None = None) -> TriangleMesh

Partition one macrotriangle into 2subdivisions*2 triangles.

The chosen macro side is the diagonal of an affine Cartesian square. Its opposite vertex and two endpoints define the reference right triangle. Interior little squares have both diagonals; squares intersected by the macro diagonal retain two triangles. The diagonal therefore has 2*r fine edges, and each other macro side has r. By default the longest physical macro side is chosen, with the first side resolving equal lengths.

This is the geometry depicted in Barros (2022), Figure 4, when the macro triangles are halves of Cartesian squares. On general triangles it is its explicitly specified affine image. The parameter is a subdivision count, not the maximum physical diameter of the macrotriangle.

Conforming polygonal macro meshes with independent triangular local meshes.

Macro cells are simple straight-sided polygons, including nonconvex cells. Ear triangulation is refined using topological barycentric keys, so internal edges share nodes without coordinate rounding. The global trace remains on the original polygon faces and is never replaced by the triangulation edges.

PolygonMesh dataclass

Planar polygon macrocells with oriented edges and arbitrary vertex counts.

cells lists cyclic vertex indices for each macrocell. Coordinates must use common vertex IDs at shared faces; cells are reoriented counterclockwise. Consecutive collinear boundary vertices are permitted and remain separate macrofaces. Each polygon must be simple, without holes. Adjacent macrofaces must match geometrically; hanging vertices must be inserted on both cells. local_triangulation='boundary' supplies distinct adjacent triangles for distinct polygon faces. It uses an interior centroid fan when visible from every edge, otherwise centroid fans within the ear triangulation. The default 'ears' gives the triangulation with no additional interior vertices.

areas: FloatArray property

Return positive polygon areas from oriented boundary integrals.

lengths: FloatArray property

Return physical lengths of macrofaces, independent of local triangulations.

normals: FloatArray property

Return unit normals pointing out of each face's first adjacent macrocell.

boundary_faces: IntArray property

Return macrofaces with a single adjacent polygon.

__post_init__() -> None

Validate polygon topology and construct signed macroface incidence.

submesh(cell: int, subdivisions: int) -> TriangleMesh

Refine the ear triangulation conformingly with exact topological node keys.

Star-shaped polyhedral macrocells with original polygonal faces and tetrahedral interiors.

PolyhedralMesh

Conforming star-shaped cells bounded by planar simple polygonal faces.

faces contains cyclic vertex indices and cells contains face indices. Each face has at most two adjacent cells. Canonical normals point outward from the first owner. Each closed cell must have a strictly interior kernel ball, whose verified radius is recorded in kernel_radii. Nonconvex cells and faces are permitted; curved faces, separate cavity shells and empty kernels are rejected. Original polygonal faces remain single entities when their interiors are triangulated. Family-wise shape regularity additionally requires a uniform lower bound on kernel radius divided by cell diameter.

__init__(points: Any, faces: Any, cells: Any) -> None

Validate geometry, orientation, closed cell boundaries and positive measures.

cubes(subdivisions: int = 1) -> PolyhedralMesh classmethod

Create n cubical cells per coordinate, retaining quadrilateral macrofaces.

extrude(mesh: PolygonMesh, layers: int = 1, *, interval: tuple[float, float] = (0.0, 1.0)) -> PolyhedralMesh classmethod

Extrude a conforming star-shaped polygon mesh into planar-faced prismatic cells.

submesh(cell: int, refinement: int = 1) -> TetraMesh

Cone canonical face triangulations to the interior center and refine conformingly.

Neighboring cells share the same face triangulation. Dyadic red refinement merges nodes by exact integer barycentric topology, not coordinate rounding.

Affine tetrahedral geometry, oriented topology and conforming red subdivision.

TetraMesh

Oriented straight-sided tetrahedra with signed triangular face incidence.

Faces have a single normal directed outward from their first adjacent cell. cell_faces[:, i] is opposite vertex i. Arrays are copied and frozen; duplicate, degenerate and locally nonmanifold cells are rejected.

__init__(points: Any, cells: Any) -> None

Validate finite three-dimensional coordinates and integer connectivity.

unit_cube(subdivisions: int = 1) -> TetraMesh classmethod

Triangulate each Cartesian cube into six conforming Freudenthal tetrahedra.

submesh(cell: int, refinement: int = 2) -> TetraMesh

Return affine conforming red refinement of one macrocell, with r cubed cells.

tetra_barycentric_gradients(mesh: TetraMesh) -> FloatArray

Return affine gradients of lambda_0,...,lambda_3 on each tetrahedron.

Axes are (cell, barycentric_coordinate, physical_coordinate). The inverse vertex Jacobian gives the last three rows; the first row is their negative sum. These geometric maps contain no finite-element tabulation.

Conforming red-green refinement of triangular macro meshes.

TriangleRefinement dataclass

Refined geometry and exact topological ancestry.

parent_cells maps new cells to old cells. parent_faces maps new faces contained in old faces to their old index, and is -1 otherwise.

validate_submesh(coarse: TriangleMesh | PolygonMesh, cell: int, fine: TriangleMesh) -> None

Check a conforming triangular partition covers exactly one macro polygon.

Vertices lie in the macro triangle, areas agree, and every fine boundary edge is contained in one macro edge. The last condition rejects holes and hanging nodes represented as unmatched interior boundaries. Membership accounts for absolute coordinate roundoff transported through the inverse macro map; domain-area conservation uses a separate determinant perturbation bound.

refine_triangles(mesh: TriangleMesh, marked: Any) -> TriangleRefinement

Red-refine selected cells and complete a conforming red-green partition.

marked is a boolean array with one entry per cell. Red refinement bisects all three edges into four children. Closure promotes any cell with two bisected edges to red refinement; remaining single-edge cells are split into two green children. Shared midpoints are created once, without geometric searches or hanging nodes. Repeated green refinement is supported, but no mesh-independent minimum-angle bound is asserted for arbitrary marking.

transfer_skeleton(original: SkeletonSpace, refinement: TriangleRefinement, *, new_face: FaceSpace) -> SkeletonSpace

Restrict old face partitions to children and initialize new interior faces.

Restriction respects both global face orientations. Existing breakpoints and degrees are retained on their physical support, including continuous spaces. The new-face specification defines approximation only on newly created edges.

Conforming triangular refinement by longest-edge propagation paths.

refine_longest_edge(mesh: TriangleMesh, marked: Any) -> TriangleRefinement

Bisect marked triangles along longest edges with conforming propagation.

Follow longest edges through adjacent triangles until reaching a boundary edge or an edge longest in both incident triangles. Bisect that terminal edge and repeat until each originally marked triangle has been replaced. Only longest-edge bisections occur; no hanging nodes or green templates are introduced. Equal lengths use a consistent global endpoint ordering.

This is two-dimensional Rivara propagation: in exact arithmetic successive longest-edge bisections preserve a lower angle bound of half the original minimum angle. Floating-point geometry remains subject to TriangleMesh validation. The returned cell and face ancestors refer to the input mesh, including faces subdivided more than once during propagation.

Conforming tetrahedral edge-star bisection with exact topological ancestry.

TetraRefinement dataclass

Refined tetrahedra and their original cell/face parents (-1 for new faces).

refine_tetrahedra(mesh: TetraMesh, marked: Any) -> TetraRefinement

Bisect the longest edge of each marked tetrahedron and its entire edge star.

All cells incident on a selected edge share one midpoint and are split together. Original face incidence supplies exact ancestry without coordinate rounding. The result is conforming and volume preserving. This local policy does not assert the finite-similarity-class theorem of a newest-vertex scheme; campaigns should monitor shape quality independently.

Uniform rectangular topology, geometry and exact local subdivision numbering.

CartesianMacroMesh dataclass

Uniform rectangular mesh with counterclockwise cells and oriented faces.

bounds=(xmin,xmax,ymin,ymax) and nx,ny describe the physical domain. The first adjacent cell defines each face normal. A missing ny uses nx. Arrays are immutable; cell and point numbering run fastest in x. The geometric face interface is compatible with SkeletonSpace.

spacing: FloatArray property

Return the physical widths of one rectangular cell.

areas: FloatArray property

Return one positive physical area per cell.

lengths: FloatArray property

Return the physical lengths of the oriented mesh faces.

normals: FloatArray property

Return unit normals pointing out of each face's first adjacent cell.

boundary_faces: IntArray property

Return faces with a single neighboring rectangle.

__post_init__() -> None

Validate the rectangle and build its signed cell-face incidence.

submesh(cell: int, subdivisions: int | tuple[int, int]) -> CartesianMacroMesh

Refine one rectangle independently in its two coordinate directions.

cartesian_refinement(value: int | tuple[int, int]) -> tuple[int, int]

Normalize a scalar or rectangular pair of local subdivision counts.

Trilinear hexahedral geometry, oriented tensor faces and exact subdivisions.

Reference corners are lexicographic in (x,y,z). Geometric validity uses the same sampled positive-Jacobian convention as the physical map evaluations.

HexMesh dataclass

Conforming trilinear hexahedra, with lexicographic (x,y,z) reference corners.

Geometric positivity is checked at corners and a 3×3×3 Gauss rule and again at every requested evaluation point. This is a sampled validity check, not a global proof of injectivity for arbitrary warped input cells.

__post_init__() -> None

Build oriented shared quadrilateral facets and check basic mesh validity.

geometry(points: FloatArray) -> tuple[FloatArray, FloatArray, FloatArray]

Evaluate physical coordinates, Jacobians and determinants in every cell.

submesh(cell: int, refinement: int) -> tuple[HexMesh, FloatArray]

Subdivide one reference cube and retain the parent coordinates of all fine vertices.

refined(subdivisions: int | tuple[int, int, int]) -> HexMesh

Refine every macro map with topological vertex merging and unchanged geometry.

Vertices are identified by their exact rational trilinear weights on original mesh nodes, so neighboring faces share points without geometric rounding, nearest-neighbor searches or an implicit tolerance. Separate axis counts are accepted when their face resolutions agree across every oriented shared face; nonconforming subdivisions are rejected.

unit_cube(subdivisions: int = 1) -> HexMesh classmethod

Create a uniform grid with exact rational geometric corner weights.

Mesh vertices use topological interpolation rather than floating-point finite-element tabulation, preserving the prescribed exterior planes.

annular_prism(radii: FloatArray, height: float, sectors: int = 8) -> HexMesh classmethod

Extrude a polygonal annulus, with explicitly supplied graded radial coordinates.

This geometry has planar polygonal walls and trilinear nonaffine cells; it does not replace them by exact cylindrical surfaces. Height is centered at z=0, and each radius contains sectors equally spaced vertices.

cube_quadrature(order: QuadratureOrder, dimension: int = 3) -> tuple[FloatArray, FloatArray]

Return tensor Gauss points/weights, with optional separate orders per axis.

hexahedral_mapping(vertices: FloatArray, points: FloatArray, *, paired: bool = False) -> tuple[FloatArray, FloatArray, FloatArray]

Evaluate batched trilinear maps from the unit cube to physical hexahedra.

vertices has shape (cells, 8, 3) with corners in lexicographic (x, y, z) order; points has shape (quadrature_points, 3). Coordinates outside [0, 1]^3 evaluate the same trilinear extension, which permits inverse-map iterations. Return physical points (cells, points, 3), Jacobians (cells, points, 3, 3) and determinants (cells, points). Jacobian rows are physical coordinates and columns are reference coordinates. Determinants must be positive at every supplied point; this sampled check does not certify invertibility throughout a curved cell. With paired=True, evaluate point i only in cell i. Their counts must agree; return shapes (points, 3), (points, 3, 3) and (points,) without forming the Cartesian product of cells and points.

Affine tetrahedral and prismatic meshes with canonical physical face moments.

AffineMixedMesh

Conforming affine tetrahedra or prisms with one canonical normal per face.

Prism corners are the triangle (0,1,2), followed by its translate (3,4,5). Nonaffine wedges are rejected: the pressure/divergence polynomial identity and this geometry contract both require a constant nonsingular Jacobian. Tetrahedral vertex orientation is normalized without changing geometry.

__init__(points: Any, cells: Any, kind: CellKind = 'tetrahedron') -> None

Validate geometry, construct face incidence and retain exact affine maps.

geometry(points: FloatArray) -> FloatArray

Map common reference coordinates into every physical cell.

face_coordinates(face: int, physical: FloatArray) -> FloatArray

Return canonical affine coordinates on the specified triangular or rectangular face.

submesh(cell: int, refinement: int) -> AffineMixedMesh

Uniformly refine one macrocell, preserving its affine boundary faces.

refined(refinement: int) -> AffineMixedMesh

Refine all cells, merging shared nodes by exact rational vertex weights.

unit_cube(subdivisions: int = 1, kind: CellKind = 'tetrahedron') -> AffineMixedMesh classmethod

Partition the unit cube into six tetrahedra or two prisms per Cartesian box.

from_extruded_hexahedra(points: Any, cells: Any, kind: CellKind = 'prism') -> AffineMixedMesh classmethod

Split extruded hexahedra without changing their physical boundary.

Eight corners follow lexicographic (x,y,z) order, as in HexMesh. Each planar base quadrilateral is divided along its 00--11 diagonal. Prisms are optionally split into three tetrahedra using globally ordered base vertices, so shared vertical-face diagonals remain conforming. Only genuine translational extrusions satisfy the affine geometry contract.

reference_submesh(kind: CellKind, refinement: int) -> tuple[FloatArray, IntArray] cached

Return a conforming r-cubed reference refinement and its cell connectivity.

hdiv3d_face_offsets(mesh: AffineMixedMesh, family: HDiv3DFamily) -> IntArray

Return global face offsets for the family's declared normal order.

hdiv3d_dofs(mesh: AffineMixedMesh, family: HDiv3DFamily) -> IntArray

Map canonical normal moments and private interior moments to global vector indices.

hdiv3d_transform(mesh: AffineMixedMesh, family: HDiv3DFamily, *, coefficients: FloatArray | None = None) -> FloatArray

Construct polynomial moment transformations for face orientation and permutation.

An explicitly supplied archived basis is used for replay and bypasses the mesh's cache of transformations for the current reference basis.

hdiv3d_basis(mesh: AffineMixedMesh, family: HDiv3DFamily, points: FloatArray, *, transform: FloatArray | None = None, coefficients: FloatArray | None = None) -> tuple[FloatArray, FloatArray, FloatArray]

Apply moment orientation and contravariant Piola to the reference family.

coefficients replays an archived reference matrix in both basis evaluation and face transformations. If transform is also supplied, it must have been constructed with that same matrix.

Source modules

Coordinate perturbation bounds shared by physical mesh validators.

area_coordinate_uncertainty(mesh: TriangleMesh, displacement: FloatArray) -> float

Bound area changes under a componentwise coordinate perturbation envelope.

For edges a,b and coordinate perturbations bounded by d, each edge perturbation is bounded by 2d. Expanding their determinant supplies the linear and quadratic terms. Eight roundoff units account for represented physical coordinates; the absolute-product term bounds arithmetic evaluation and summation. This area bound is distinct from a point-membership test.

coordinate_difference(points: FloatArray, origin: FloatArray) -> tuple[FloatArray, FloatArray]

Subtract represented coordinates and bound input quantization and arithmetic.

This bound is expressed in physical units, independently of whether the difference represents a coordinate, a cell width or a material spacing. Inputs are finite float64 arrays with broadcastable shapes.

cartesian_coordinates(points: FloatArray, origin: FloatArray, spacing: FloatArray) -> tuple[FloatArray, FloatArray]

Transform represented physical points and bound their grid-coordinate error.

The envelope accounts for half-ulp input quantization, the subtraction and division, and half-ulp uncertainty in each grid spacing. For z=(x-o)/h the coordinate and scale contributions are propagated separately; no distance-to-origin relative tolerance is applied to physical mesh areas. Inputs are finite float64 arrays with positive, broadcastable spacing. Callers retain their arithmetic-operation envelope in addition to this bound. Two representations may differ by the sum of their envelopes. Their comparison neighborhoods must not overlap adjacent integer grid lines; unresolved coordinate data are rejected rather than merged.

Physical conformity checks for explicit tetrahedral submeshes and face partitions.

validate_face_partition(values: Any) -> tuple[FloatArray, FloatArray]

Validate a conforming triangulation of one reference triangular macroface.

Each vertex has three barycentric coordinates in the original macroface ordering. Subtriangle ordering is retained, including reversed vertex order. The returned positive weights are physical area fractions. Area equality alone is insufficient: every unmatched edge must lie on the original face boundary, which excludes holes and hanging interior edges.

validate_tetra_submesh(coarse: TetraMesh, cell: int, fine: TetraMesh) -> None

Require a conforming tetrahedral partition of exactly one macro tetrahedron.

Check containment, physical volume and the complete exterior-face envelope. Combined with TetraMesh's oriented two-sided incidence, the exterior condition rejects holes and unmatched hanging internal faces. Coordinate roundoff is transported through the inverse macro map; volume uses a determinant perturbation bound rather than an absolute unit-scale floor.