Source code for nekmeshpy.pointmesh.pointmesh
"""0-D mesh container: the ``(N,3)`` point array the whole ladder is built on."""
from __future__ import annotations
import numpy as np
from .._typing import PointArray
from ..tags import Tags
[docs]
class PointMesh:
"""The ladder's bottom rung: an ``(N,3)`` point array and the tags on those points.
A point has no interior, no orientation and no connectivity -- its "incidence" is
the identity, so element ``i`` *is* point ``i``. That leaves only the two fields
every rung has: the coordinates, and an :class:`Tags
<nekmeshpy.tags.Tags>` naming whichever of them are named.
It exists so the rule that holds between every other pair of rungs -- **a mesh's
side tags are its rung-below's element tags** -- holds at the bottom too, rather
than the line rung carrying a table of its own shape. Almost nothing constructs one
directly: :class:`LineMesh <nekmeshpy.linemesh.LineMesh>` promotes a bare ``(N,3)``
array into an untagged one, which is what a factory building fresh geometry wants.
Reach for it when you need the tags to survive -- a transform rebuilding a mesh
around moved coordinates, or a point group named before there is a line to hang it
on. There are deliberately no factories and no shape model here: a point cloud is
not something this toolkit meshes, only something the rungs above index into.
"""
[docs]
def __init__(
self,
points: PointArray,
element_tags: Tags | None = None,
) -> None:
"""Construct from ``points`` ``(N,3)`` (must be 3-D) and an optional
:class:`Tags <nekmeshpy.tags.Tags>` over point ids."""
self.points: PointArray = np.asarray(points, dtype=float)
if self.points.ndim != 2 or self.points.shape[1] != 3:
raise ValueError(
"PointMesh: points must be (N,3) 3-D coordinates; got %s -- add a z "
"column (all geometry lives in 3-D)" % (self.points.shape,))
self.element_tags = Tags.empty(self.points.shape[0]) if element_tags is None else element_tags
if self.element_tags.size != self.points.shape[0]:
raise ValueError(
"PointMesh: element_tags must be over the %d points, got a Tags over %d"
% (self.points.shape[0], self.element_tags.size))
def __repr__(self) -> str:
from ..linemesh.linemesh import _repr_tags
try:
return ("<PointMesh %d points, element_tags=%s>"
% (self.points.shape[0], _repr_tags(self.element_group_tags)))
except Exception: # a repr must never break a debug session
return "<PointMesh (unprintable)>"
# -- sizes -----------------------------------------------------------
@property
def n_points(self) -> int:
"""Number of points."""
return self.points.shape[0]
@property
def n_elements(self) -> int:
"""Number of elements -- the same number, since a point *is* an element."""
return self.points.shape[0]
@property
def element_group_tags(self) -> list[str]:
"""Sorted unique non-empty per-point tags present on the mesh."""
return self.element_tags.unique()