httk.atomistic.symmetry.canonical

A one-liner canonical form for noisy input: tolerant recognition composed with exact lifting.

canonical_asu() bridges the two layers. Before tolerant recognition, the exact unit-cell geometry is normalized as P1, giving spglib one deterministic basis, origin, and site order for every exact re-expression of the same measured structure. The tolerant layer (recognize_asu(), backed by spglib) then snaps that stable input onto a space group within a Cartesian tolerance. Because a measured structure can sit just inside or just outside a tolerance boundary, recognition is swept over a few symprec multiples from loosest to tightest, and the first member that fits within the base tolerance wins. The exact layer finally fixes that winner’s representation deterministically: by default (lift=False) it returns the canonical representative within the recognized group; lift=True additionally runs canonicalize() to hunt higher pseudosymmetry.

This module is deliberately outside lift.py: lift imports recognition (for its tolerance helpers) and stays spglib-free, while this composer imports both.

Functions

canonical_asu(structure, *[, tolerance, factors, ...])

Return the canonical ASUStructure of a measured structure's symmetry.

Module Contents

httk.atomistic.symmetry.canonical.canonical_asu(structure, *, tolerance=None, factors=(Fraction(1, 5), 1, 5), lift=False, preserve_chirality=True)[source]

Return the canonical ASUStructure of a measured structure’s symmetry.

This is the noisy-input counterpart to canonicalize(): it first normalizes the exact measured geometry in P1, recognizes its symmetry with spglib, and then canonicalizes the recognized result exactly. P1 preconditioning prevents spglib’s tolerance-boundary result from depending on an equivalent input shear, origin shift, or site ordering.

An ASUStructure input is expanded to its unit cell first and the symmetry is re-recognized from the actual coordinates – always from the geometry, never the declared label. Re-recognition can raise a declared symmetry (a hand-written low-symmetry cell whose coordinates in fact support more) and can also lower it (a declared symmetry the coordinates do not support at the derived tolerance).

Recognition is swept over the base * factor symprecs from loosest to tightest. A member is accepted only when its recognized model reproduces every input site within the base tolerance (never the swept one), by an injective same-species match, and matches the per-species site counts. The first accepted member wins – by the same operation-count monotonicity the loosest fitting member is the highest-symmetry one – so recognition (and the expensive stage) runs once in the common case, and a looser member still rescues a tolerance-boundary flip a tighter one fails.

lift selects the expensive stage applied to that winner:

  • lift=False (default): it is mapped to the deterministic canonical representative within its recognized group – the exact terminal representation (setting, origin, orbit representatives, basis orientation all fixed), returned without searching upward. The result is the canonical form of the recognized symmetry; no pseudosymmetry above it is sought.

  • lift=True: it is additionally run through the exact upward search (canonicalize()) to find higher pseudosymmetry the recognition missed. This is exact but can be expensive – minutes and beyond for low-symmetry, many-atom cells.

Tolerance bound: the recognition stage is held to the base tolerance – every returned atom sits within base of the input. Under lift=False that is the whole bound (no further hops). Under lift=True each lift hop can move coordinates and snap the metric by up to another base and the residual/path are not re-checked here, so the returned structure’s distance from the input is bounded roughly by base * (1 + hops).

Determinism: the recognition stage is floating-point/spglib-based, so its outcome is reproducible on one platform but may differ across floating-point architectures or spglib builds. The exact stage is platform-independent and erases spglib’s representational freedom for ordinary rational crystallographic Gram matrices, so cross-platform variation is confined to which symmetry is accepted near a tolerance boundary, never to how an accepted symmetry is represented. An exact non-rational Gram whose canonical Cartesian factor requires nested radicals outside the supported surd field remains idempotent but can retain its input’s global Cartesian rotation. Free-parameter values are least-squares fits of the measured coordinates, so two noisy measurements of the same crystal reach the same Wyckoff choices but slightly different rational parameter values.

Parameters:
  • structure (httk.atomistic.models.structure.like.StructureLike) – The measured structure, UnitcellStructure or ASUStructure.

  • tolerance (float | None) – The base Cartesian tolerance, or None to derive it from the structure’s stated precision (structure_tolerance()).

  • factors (tuple[fractions.Fraction | float | int, ...]) – Multipliers for the recognition symprec sweep; each candidate symprec is base * factor.

  • lift (bool) – Whether to search upward for pseudosymmetry above the recognized group (default False: return the canonical representative of the recognized symmetry).

  • preserve_chirality (bool) – How enantiomorphic space groups are canonicalized. By default (True) the recognized group is kept, so a genuinely chiral crystal retains its handedness. When False a result landing in the higher member of one of the 11 enantiomorphic pairs (76/78, 91/95, 92/96, 144/145, 151/153, 152/154, 169/170, 171/172, 178/179, 180/181, 212/213) is mapped to the LOWER-numbered member by an exact chirality-flipping transformation (fractional coordinates f -> (-f) mod 1 with the cell basis unchanged – the Cartesian inversion r -> -r – and the group swapped to its partner), so an enantiomorphic pair shares one canonical representative and the canonical labels of the two partners coincide. The exact bridge normalize_chirality() maps a preserved (True) result to the normalized (False) one directly, without re-canonicalizing. A structure carrying site moments is never flipped (axial vectors are out of scope under improper maps) and is left in its own group regardless of this flag.

Returns:

The canonical asymmetric unit.

Raises:
  • ImportError – If spglib is unavailable when symmetry must be searched (the error names the httk-atomistic[default] extra).

  • ValueError – If recognition fails or is rejected at every swept tolerance.

Return type:

httk.atomistic.models.structure.asu.ASUStructure