Source code for panel_bie.geometry

"""Geometry protocol and utilities."""

from __future__ import annotations

from typing import Protocol, runtime_checkable

import numpy as np
from numpy.typing import NDArray


[docs] @runtime_checkable class Geometry(Protocol): """Protocol for boundary geometry discretizations. Any object providing these attributes is compatible with panel-bie solvers. The `superellipse.PanelDiscretization` class implements this protocol. """ @property def points(self) -> NDArray[np.floating]: """Boundary nodes, shape (N, 2).""" ... @property def normals(self) -> NDArray[np.floating]: """Outward unit normals, shape (N, 2).""" ... @property def weights(self) -> NDArray[np.floating]: """Quadrature weights (ds measure), shape (N,).""" ... @property def curvature(self) -> NDArray[np.floating]: """Signed curvature at each node, shape (N,).""" ...
[docs] def validate_geometry(geom: Geometry) -> None: """Validate geometry object has correct shapes and properties.""" n = geom.points.shape[0] if geom.points.shape != (n, 2): raise ValueError(f"points must be (N, 2), got {geom.points.shape}") if geom.normals.shape != (n, 2): raise ValueError(f"normals must be (N, 2), got {geom.normals.shape}") if geom.weights.shape != (n,): raise ValueError(f"weights must be (N,), got {geom.weights.shape}") if geom.curvature.shape != (n,): raise ValueError(f"curvature must be (N,), got {geom.curvature.shape}") # Check normals are unit vectors norms = np.linalg.norm(geom.normals, axis=1) if not np.allclose(norms, 1.0, atol=1e-10): raise ValueError("normals must be unit vectors") # Check weights are positive if not np.all(geom.weights > 0): raise ValueError("weights must be positive")