mod symmetrise

module symmetrise

Making a structure exactly symmetric about the symmetry it nearly has.

Oakley, Johnston and Wales, Symmetrisation schemes for global optimisation of atomic clusters, Phys. Chem. Chem. Phys. 15, 3965 (2013).

High-symmetry structures are over-represented at both ends of the energy distribution, so the global minimum of a cluster is more often symmetric than a typical minimum is. That is a searchable fact: a structure that is nearly symmetric can be pushed onto the symmetry it nearly has, and if the answer is symmetric the push lands near it. The paper reports the mean first encounter time for the 98-point Lennard-Jones cluster, whose global minimum is tetrahedral, improving by more than seventyfold.

What this is not

crate::movekernel::Symmetrise already exists and is a different thing. It picks a random axis and a random rotation order, then blends each point a fraction of the way toward its image. Nothing about it refers to the structure’s own symmetry, so on a structure that is nearly tetrahedral it is overwhelmingly likely to symmetrise about an axis the structure has no relationship to, and the result is a perturbation with extra steps.

The scheme here measures first. Candidate axes come from the structure, the deviation from each candidate symmetry is computed, and the operation is applied about the best one and applied fully rather than blended. A structure with no approximate symmetry is left alone, which is the case where the random version does its damage.

Types

type Rot

A rotation as a 3x3 matrix, row-major.

Functions

fn detect(x: ArrayView1<f64>, n: usize, orders: &[usize], tolerance: f64) -> Option<Candidate>

The best approximate rotational symmetry of x, over the given orders.

None when nothing is even approximately symmetric, which is the signal to leave the structure alone.

Proper rotations only, because symmetrise averages a point around its orbit under a rotation and a reflection has no such orbit. Mirror planes are found by detect_all, which exists to build a group rather than to push a structure along one operation.

fn detect_all(x: ArrayView1<f64>, n: usize, orders: &[usize], tolerance: f64) -> Vec<Candidate>

All approximate symmetries of x, proper and improper.

detect returns only the best one, which is enough to symmetrise toward a single operation and not enough to build a group: a tetrahedral structure needs a three-fold axis and a plane together, and either alone generates a subgroup that is not the answer.

fn deviation(x: ArrayView1<f64>, n: usize, axis: [f64; 3], order: usize) -> f64

Root-mean-square distance between each point and its nearest image under a rotation of order about axis.

The matching is nearest-image, which is what makes this a measure of approximate symmetry rather than of exact symmetry: an exactly symmetric structure permutes onto itself and every distance is zero.

fn generate_group(cands: &[Candidate], cap: usize) -> Vec<Rot>

The rotation group generated by a set of approximate symmetries.

A point group is not an axis, and this is the difference between the scheme and a single rotation. The 98-point global minimum is tetrahedral, and the tetrahedral rotation group is generated by a three-fold and a two-fold axis together: averaging orbits under either one alone does not make a structure tetrahedral, it makes it axially symmetric, which is a different and much weaker constraint.

Closed by repeated multiplication until nothing new appears or cap is reached. The cap is a guard against a set of axes that are not quite commensurate generating an unbounded pseudo-group out of rounding; the icosahedral rotation group has sixty elements, so anything past that is a sign the detection was loose rather than a real group.

fn mirror_matrix(axis: [f64; 3]) -> Rot

Reflection in the plane through the centroid with normal axis.

fn plane_deviation(x: ArrayView1<f64>, n: usize, axis: [f64; 3]) -> f64

How far x is from being symmetric under the plane whose normal is axis.

The same statistic as deviation for a rotation: each point is reflected and matched to its nearest partner, and the root-mean-square of those distances is what “approximately symmetric” means here.

fn symmetrise(x: ArrayView1<f64>, n: usize, cand: &Candidate, pair_cutoff: f64) -> Array1<f64>

Makes x exactly symmetric under the rotation cand describes.

Each point is followed around its orbit under the rotation, the orbit is averaged after rotating every member back to the first one’s frame, and every member is replaced by the rotated average. A point whose orbit does not close, meaning some image has no partner within pair_cutoff, is left where it is rather than dragged onto a partner it does not have.

Applied fully rather than blended. A partial push toward a symmetry the structure nearly has produces a structure that is neither, and the point of the scheme is to land in the symmetric basin so the relaxation can take it from there.

fn symmetrise_detected(x: ArrayView1<f64>, n: usize, orders: &[usize], tolerance: f64, pair_cutoff: f64) -> Option<(Array1<f64>, Candidate)>

Detects and applies in one step, or returns None when there is no approximate symmetry worth using.

fn symmetrise_group(x: ArrayView1<f64>, n: usize, group: &[Rot], pair_cutoff: f64) -> Array1<f64>

Makes x symmetric under a whole group, not one rotation.

Each point’s orbit is collected by applying every group element and taking the nearest partner, then the orbit is averaged in the frame of the element that produced it and every member is replaced. A point whose orbit does not close under some element is left alone rather than dragged onto a partner it does not have.

Structs and Unions

struct Candidate

An approximate rotational symmetry a structure was found to have.

axis: [f64; 3]

Unit vector along the rotation axis, through the centroid.

order: usize

Rotation order; the operation is by 2 pi / order.

Order 1 with improper set is a plane: the reflection in the plane through the centroid whose normal is axis.

improper: bool

Whether the operation carries a reflection.

The group a structure has is not always a rotation group. The 98-point global minimum is tetrahedral and the 38-point one is octahedral, and both of those are defined by their mirror planes: the proper rotations alone give T and O, which are index-two subgroups missing exactly the operations that pick out the structure. A generator set closed only under proper rotations cannot express either, so the scheme could symmetrise toward a subgroup of the target and never toward the target.

deviation: f64

Root-mean-square distance between a point and its matched image.

Zero for an exact symmetry. This is what “approximate” is measured by, and what decides whether symmetrising is worth doing.