Transformations and Projections#
Geometric Transformations#
Linear and affine transformations on mesh geometry. Each function returns a new
Mesh with transformed point coordinates and
appropriately invalidated caches. (Any cached quantities, such as normals and
areas, are automatically recomputed on next access.)
All transformations are also available as methods on
Mesh.
import numpy as np
from physicsnemo.mesh.primitives.surfaces import sphere_icosahedral
mesh = sphere_icosahedral.load(subdivisions=2)
# Via Mesh methods
translated = mesh.translate([1.0, 0.0, 0.0])
rotated = mesh.rotate(axis=[0, 0, 1], angle=np.pi / 4)
scaled = mesh.scale(2.0)
scaled_aniso = mesh.scale([2.0, 1.0, 0.5])
# Arbitrary linear transform
import torch
matrix = torch.eye(3) * 2
transformed = mesh.transform(matrix)
Geometric transformations for simplicial meshes.
This module implements linear and affine transformations with intelligent cache handling. By default, all caches are invalidated; transformations explicitly opt-in to preserve/transform specific cache fields.
Cached fields handled: - areas: point_data and cell_data - normals: point_data and cell_data - centroids: cell_data only
- physicsnemo.mesh.transformations.geometric.rotate(
- mesh: Mesh,
- angle: float,
- axis: Float[Tensor, 'n_spatial_dims'] | Sequence[float] | Literal['x', 'y', 'z'] | None = None,
- center: Float[Tensor, 'n_spatial_dims'] | Sequence[float] | None = None,
- transform_point_data: bool | TensorDict = False,
- transform_cell_data: bool | TensorDict = False,
- transform_global_data: bool | TensorDict = False,
Rotate the mesh about an axis by a specified angle.
- Parameters:
mesh (Mesh) – Input mesh to rotate.
angle (float) – Rotation angle in radians (counterclockwise, right-hand rule).
axis (Float[torch.Tensor, " n_spatial_dims"] or Sequence[float] or {"x", "y", "z"} or None) – Rotation axis vector.
Nonefor 2D, shape \((3,)\) for 3D. String literals"x","y","z"are converted to unit vectors(1,0,0),(0,1,0),(0,0,1)respectively.center (Float[torch.Tensor, " n_spatial_dims"] or Sequence[float] or None) – Center point for rotation. If
None, rotates about the origin.transform_point_data (bool or TensorDict) – Controls transformation of
point_datafields. Seetransform()for full semantics.transform_cell_data (bool or TensorDict) – Same semantics as
transform_point_data, forcell_data.transform_global_data (bool or TensorDict) – Same semantics as
transform_point_data, forglobal_data.
- Returns:
New Mesh with rotated geometry.
- Return type:
Notes
Cache Handling:
areas: Unchanged (rotation preserves volumes)
centroids: Rotated
normals: Rotated
- physicsnemo.mesh.transformations.geometric.rotation_matrix(
- angle: float,
- axis: Float[Tensor, 'n_spatial_dims'] | Sequence[float] | Literal['x', 'y', 'z'] | None,
- n_spatial_dims: int,
- device: device,
- dtype: dtype,
Build a rotation matrix from angle and axis.
- Parameters:
angle (float) – Rotation angle in radians (counterclockwise, right-hand rule).
axis (Float[torch.Tensor, " n_spatial_dims"] or Sequence[float] or {"x", "y", "z"} or None) – Rotation axis.
Nonefor 2D, tensor/sequence/string for 3D.n_spatial_dims (int) – Number of spatial dimensions.
device (torch.device) – Target device for the output matrix.
dtype (torch.dtype) – Target dtype for the output matrix.
- Returns:
Rotation matrix, shape \((S, S)\).
- Return type:
Float[torch.Tensor, “n_spatial_dims n_spatial_dims”]
- physicsnemo.mesh.transformations.geometric.scale(
- mesh: Mesh,
- factor: float | Float[Tensor, 'n_spatial_dims'] | Sequence[float],
- center: Float[Tensor, 'n_spatial_dims'] | Sequence[float] | None = None,
- transform_point_data: bool | TensorDict = False,
- transform_cell_data: bool | TensorDict = False,
- transform_global_data: bool | TensorDict = False,
- assume_invertible: bool | None = None,
Scale the mesh by specified factor(s).
- Parameters:
mesh (Mesh) – Input mesh to scale.
factor (float or Float[torch.Tensor, " n_spatial_dims"] or Sequence[float]) – Scale factor(s). Scalar for uniform, vector for non-uniform.
center (Float[torch.Tensor, " n_spatial_dims"] or Sequence[float] or None) – Center point for scaling. If
None, scales about the origin.transform_point_data (bool or TensorDict) – Controls transformation of
point_datafields. Seetransform()for full semantics.transform_cell_data (bool or TensorDict) – Same semantics as
transform_point_data, forcell_data.transform_global_data (bool or TensorDict) – Same semantics as
transform_point_data, forglobal_data.assume_invertible (bool or None) –
Controls cache propagation:
True: Assume all factors are non-zero, propagate caches (compile-safe)
False: Assume some factor is zero, skip cache propagation (compile-safe)
None: Check determinant at runtime (may cause graph breaks under torch.compile)
- Returns:
New Mesh with scaled geometry.
- Return type:
Notes
Cache Handling:
- areas: Scaled correctly. For non-isotropic transforms of codimension-1
embedded manifolds, per-element scaling is computed using normals.
centroids: Scaled
normals: Transformed by inverse-transpose (direction adjusted, magnitude normalized)
- physicsnemo.mesh.transformations.geometric.scale_matrix(
- factor: float | Float[Tensor, 'n_spatial_dims'] | Sequence[float],
- n_spatial_dims: int,
- device: device,
- dtype: dtype,
Build a diagonal scale matrix from a factor specification.
- Parameters:
factor (float or Float[torch.Tensor, " n_spatial_dims"] or Sequence[float]) – Scale factor(s). Scalar for uniform, vector for non-uniform.
n_spatial_dims (int) – Number of spatial dimensions.
device (torch.device) – Target device for the output matrix.
dtype (torch.dtype) – Target dtype for the output matrix.
- Returns:
Diagonal scale matrix, shape \((S, S)\).
- Return type:
Float[torch.Tensor, “n_spatial_dims n_spatial_dims”]
- Raises:
ValueError – If
factoris a vector whose length does not matchn_spatial_dims.
- physicsnemo.mesh.transformations.geometric.transform(
- mesh: Mesh,
- matrix: Float[Tensor, 'new_n_spatial_dims n_spatial_dims'],
- transform_point_data: bool | TensorDict = False,
- transform_cell_data: bool | TensorDict = False,
- transform_global_data: bool | TensorDict = False,
- assume_invertible: bool | None = None,
Apply a linear transformation to the mesh.
- Parameters:
mesh (Mesh) – Input mesh to transform.
matrix (Float[torch.Tensor, "new_n_spatial_dims n_spatial_dims"]) – Transformation matrix, shape \((S', S)\).
transform_point_data (bool or TensorDict) – Controls transformation of
point_datafields.Truetransforms all compatible fields;Falsetransforms none; aTensorDict(ordict) with scalar bool leaves selectively transforms only the named fields.transform_cell_data (bool or TensorDict) – Same semantics as
transform_point_data, forcell_data.transform_global_data (bool or TensorDict) – Same semantics as
transform_point_data, forglobal_data.assume_invertible (bool or None) –
Controls cache propagation for square matrices:
True: Assume matrix is invertible, propagate caches (compile-safe)
False: Assume matrix is singular, skip cache propagation (compile-safe)
None: Check determinant at runtime (may cause graph breaks under torch.compile)
- Returns:
New Mesh with transformed geometry and appropriately updated caches.
- Return type:
Notes
Cache Handling:
areas: For square invertible matrices:
Full-dimensional meshes: scaled by
|det|Codimension-1 manifolds: per-element scaling using
|det| * ||M^{-T} n||Higher codimension: invalidated
centroids: Always transformed
normals: For square invertible matrices, transformed by inverse-transpose
- physicsnemo.mesh.transformations.geometric.translate(
- mesh: Mesh,
- offset: Float[Tensor, 'n_spatial_dims'] | Sequence[float],
Apply a translation to the mesh.
Translation only affects point positions and centroids. Vector/tensor fields are unchanged by translation (they represent directions, not positions).
- Parameters:
mesh (Mesh) – Input mesh to translate.
offset (Float[torch.Tensor, " n_spatial_dims"] or Sequence[float]) – Translation vector, shape \((S,)\).
- Returns:
New Mesh with translated geometry.
- Return type:
Notes
Cache Handling:
areas: Unchanged
centroids: Translated
normals: Unchanged
Projections#
Spatial dimension manipulation – changing the embedding dimension of a mesh without altering its manifold dimension.
embed()– add spatial dimensions (non-destructive; for example, 2D mesh to 3D by appending zero coordinates)extrude()– sweep a manifold to create a mesh one dimension higher (for example, a triangle mesh extruded to a prism mesh)project()– reduce spatial dimensions (lossy; drops coordinate axes)
Projection operations for mesh extrusion, embedding, and spatial dimension manipulation.
This module provides functionality for: - Embedding meshes in higher-dimensional spaces (non-destructive) - Projecting meshes to lower-dimensional spaces (lossy) - Extruding manifolds to higher dimensions