O(3) transformations¶
The metatomic.torch.o3 module rotates and inverts
System and TensorMap
objects, for example to generate randomly rotated copies of a structure for data
augmentation.
Conventions¶
To transform a TensorBlock, transform_block()
and transform_tensor() need to know, for each component axis, whether it
carries a Cartesian or a spherical tensor. This is inferred from the axis name:
Cartesian axes are named
xyz, orxyz_1,xyz_2, … for blocks with several Cartesian axes (e.g. rank-2 Cartesian tensors). These are rotated directly with the (3, 3) transformation matrix \(R\) passed toO3Transformation, following the usual column-vector convention \(v' = R v\) (equivalently, since values are stored as rows,values_transformed = values @ R.T).Spherical axes are named
o3_mu, oro3_mu_1,o3_mu_2, … They are rotated with the real Wigner-D matrix for the angular momentumo3_lambda(respectivelyo3_lambda_1,o3_lambda_2, …) found in the block’s key. Real, rather than complex, spherical harmonics are used throughout, matching the convention used elsewhere in metatomic and metatensor for spherical targets.
Wigner-D matrices¶
Complex Wigner-D matrices are computed by the wigners package, using the convention
with ZYZ Euler angles \((\alpha, \beta, \gamma)\) extracted from the proper part of \(R\), i.e. from \(R\) itself when \(\det R = 1\), or from \(-R\) when \(\det R = -1\), such that this proper part equals \(R_z(\alpha) R_y(\beta) R_z(\gamma)\).
These are then converted to real Wigner-D matrices through the unitary change of basis \(T\) mapping complex spherical harmonics \(Y_{\ell}^{m}\) to real ones:
so that the real Wigner-D matrix is \(D^{\ell}_{\text{real}} = T^{*} D^{\ell} T^{T}\).
Spherical components follow the same column-vector convention as Cartesian ones,
\(f' = D^{\ell}_{\text{real}} f\) (equivalently, since values are stored as
rows, values_transformed = values @ D.T).
For an improper rotation (a rotation composed with an inversion), Cartesian axes are
flipped as part of the transformation matrix itself, while spherical axes pick up an
extra parity factor \((-1)^{\ell} \sigma\), where \(\ell\) is o3_lambda
and \(\sigma\) is the block’s o3_sigma (its behavior under inversion, +1 or
-1), also read from the key.
A TensorBlock in general contains values associated with
several systems. This information is contained in the "system" samples dimension;
each row is rotated with the transformation of the system it belongs to. Gradient blocks
are routed the same way, via their parent block’s "system" column. When only one
system is being transformed, the "system" column is optional and, if present, is
ignored: every row is rotated with the (single) given transformation.
Reference¶
- class metatomic.torch.o3.O3Transformation(matrix: Tensor, max_angular_momentum: int)[source]¶
A single O(3) transformation, represented by a (3, 3) rotation or improper-rotation matrix.
The constructor stores a copy of
matrix.- Parameters:
- transform_spherical(values: Tensor, ell: int, sigma: int) Tensor[source]¶
Apply the transformation to spherical values.
- Parameters:
- Returns:
(…, 2*ell+1) tensor of transformed spherical values
- Return type:
- wigner_D_matrix(ell: int) Tensor[source]¶
Return the proper-part Wigner-D matrix for
ell.For an improper transformation,
transform_spherical()applies the inversion-parity factor separately.
- metatomic.torch.o3.random_transformations(n: int, max_angular_momentum: int = 0, *, device: device, dtype: dtype, include_inversions: bool = False, generator: Generator | None = None) list[O3Transformation][source]¶
Sample
ntransformations uniformly from SO(3), or from O(3) when inversions are included.Rotations are sampled from the Haar measure on SO(3) via random unit quaternions. When
include_inversionsisTrue, each matrix is independently negated with probability 0.5, giving a uniform distribution over the full O(3) group.- Parameters:
n (int) – non-negative number of transformations to generate
max_angular_momentum (int) – non-negative maximum angular momentum for Wigner-D matrices
device (device) – target device for the output tensors
dtype (dtype) – target dtype for the output tensors; must be
torch.float32ortorch.float64include_inversions (bool) – if
True, sample from O(3) instead of SO(3)generator (Generator | None) – optional
torch.Generatorfor reproducible sampling; whenNonethe global RNG is used
- Returns:
list of
nO3Transformationobjects- Return type:
- metatomic.torch.o3.transform_system(system: System, transformation: O3Transformation) System[source]¶
Apply an O(3) transformation to a single System.
Positions, cell vectors, neighbor-list displacements, and custom data following Conventions are transformed. Atomic types and periodic-boundary flags are preserved.
- Parameters:
system (System) – input system
transformation (O3Transformation) – O(3) transformation to apply, matching
system.positionsin dtype and device
- Returns:
new System with transformed geometry
- Return type:
- metatomic.torch.o3.transform_tensor(tensor: TensorMap, systems: list[System], transformations: list[O3Transformation], system_ids: list[int] | Tensor | None = None) TensorMap[source]¶
Apply per-system O(3) transformations to a TensorMap and its gradients.
Scalar, Cartesian, and spherical data are identified by their component-axis names, following Conventions; one
TensorMapmay contain all three kinds of data. At most ten component axes are supported in one value or gradient block.With multiple systems, the
"system"sample label assigns each value sample to a transformation: samples labelledsystem_ids[i]usetransformations[i]. A block may contain samples for only some of the systems, but every"system"label present in the block must appear insystem_ids. A gradient sample uses the same transformation as the parent value sample referenced by its"sample"label. With one system, the"system"label is optional and ignored.- Parameters:
tensor (TensorMap) – TensorMap to transform
systems (list[System]) – systems corresponding positionally to
transformationstransformations (list[O3Transformation]) – one O(3) transformation per system, matching the tensor values in dtype and device when present
system_ids (list[int] | Tensor | None) – one distinct integer
"system"sample label per system; entryiis paired withtransformations[i]. A tensor argument must be one-dimensional and use the same device as the tensor values. Defaults torange(len(systems))
- Returns:
transformed TensorMap with the same keys and global information; when
systemsis empty, the tensor is unchanged- Return type:
- metatomic.torch.o3.transform_block(key: LabelsEntry, block: TensorBlock, systems: list[System], transformations: list[O3Transformation], system_ids: list[int] | Tensor | None = None) TensorBlock[source]¶
Apply per-system O(3) transformations to a block and its gradients.
With one system, the
"system"sample label is optional and ignored, as intransform_tensor().- Parameters:
key (LabelsEntry) – parent block key, supplying the O(3) labels required by spherical component axes
block (TensorBlock) – block to transform
systems (list[System]) – systems corresponding positionally to
transformationstransformations (list[O3Transformation]) – one O(3) transformation per system, matching
block.valuesin dtype and devicesystem_ids (list[int] | Tensor | None) – one distinct integer
"system"sample label per system; entryiis paired withtransformations[i]. A tensor argument must be one-dimensional and use the same device asblock.values. Defaults torange(len(systems))
- Returns:
block with transformed values and gradients and unchanged labels; when
systemsis empty, the block is unchanged- Return type: