mod lattice

module lattice

Candidate structures grown from local order, rather than reached by hopping.

Everything else in this crate decides where a chain hops next. None of it changes what a hop can reach, because reachability is set by the move, and the move is a displacement followed by a quench. Measured on 98 points, 12 million charged evaluations buy 401 177 hops over 11 366 distinct basins, about 35 visits each, on a landscape whose minimum count grows like e^{alpha N}. Filling visited basins pushes the chain into neighbouring unvisited basins in the same funnel, of which there are effectively unboundedly many, and never to the funnel boundary. Cameron reads the same thing off the spectrum: the icosahedral escape mode on 38 points sits around the 245th, with no gap to exploit.

A structure whose local order differs everywhere is a different funnel, and local order is something a structure can be built to have. Points are indistinguishable, so a set of positions is a complete proposal: growing one and quenching into it crosses a funnel boundary in a single step.

Nothing here is specific to one potential

The order to grow is read off the structure the chain is standing on, by taking the neighbour offsets of its best-coordinated point. That works wherever a neighbour shell means anything, needs no template library, and carries no assumption about what is being optimised: at a relaxed Lennard-Jones geometry it reads a close-packed shell, at a relaxed Morse geometry it reads whatever that potential prefers, and at a molecular geometry it reads that.

Source::Named offers the alternative orders instead, from the classifier’s own template library in crate::structure, so a chain sitting in close packing can be handed icosahedral order and the other way round. Which is worth proposing is left to the allocator; nothing here knows that 38 points want a truncated octahedron.

The same construction is what a ring or cage topology would drive for a molecular system, where the repeated unit is a cage rather than a coordination shell. The growth below takes offsets and does not ask where they came from.

Functions

fn candidate<R: Rng + ?Sized>(source: Source, x: ArrayView1<f64>, n: usize, rng: &mut R) -> Array1<f64>

Builds an n-point candidate carrying source’s local order at the length scale of x.

Grown wide and then cut to the n sites nearest a jittered centre, which is what makes the candidate compact. Which polyhedron the cut produces is left to the quench rather than imposed, and the jitter means repeated proposals from one source are different structures: a close-packed lattice cut about a site gives a different cluster from one cut about a hole, and both are minima of that packing at some size.

fn candidate_keeping<R: Rng + ?Sized>(source: Source, x: ArrayView1<f64>, n: usize, keep: f64, rng: &mut R) -> Array1<f64>

As candidate, retaining a keep fraction of the current structure as the seed the new order grows from.

The knob that makes this one move rather than two. At keep = 0 the structure is discarded and a body is grown from nothing, which is the largest step the move set has. At keep = 1 nothing is regrown. In between, the best-coordinated part of the current structure is kept and the new order is grown around it in its own orientation, so the proposal carries an interface between the two: a twin or a stacking fault, which is how a morphology actually changes rather than how it is replaced.

Which value pays is not fixed here. It is a continuous parameter, so it is something a posterior can be held over, which is what crate::construct does.

fn grow(offsets: &[[f64; 3]], want: usize) -> Vec<[f64; 3]>

Grows n sites by repeatedly placing offsets around already placed ones.

Breadth first, so the structure grows outward from the seed and stays compact, which is what a cluster minimum is. A candidate site closer than half a spacing to a placed one is the same site and is dropped.

For an order that tiles space this reproduces its lattice. For one that does not, icosahedral being the case that matters here, the propagation cannot close and the growth accumulates strain, which is the physical situation rather than a defect of the method: that is why icosahedral clusters stop competing above a few hundred points.

fn grow_from(seed: &[[f64; 3]], offsets: &[[f64; 3]], want: usize) -> Vec<[f64; 3]>

As grow, starting from seed rather than from a single point.

A seed of existing positions is what lets a proposal keep part of the structure it came from: the new order grows around the kept part in the growth’s own orientation, so the two meet at an interface instead of one replacing the other.

fn nearest_neighbour_scale(x: ArrayView1<f64>) -> f64

Mean distance to the nearest other point.

The length scale a template is built at, taken from the structure so the move carries no knowledge of the potential.

fn observed_order(x: ArrayView1<f64>, cutoff: f64) -> Vec<[f64; 3]>

Neighbour offsets of the best-coordinated point, in units of the nearest neighbour distance.

The best-coordinated point rather than an average one because that is where the structure’s order is expressed most completely: a surface point’s shell is a fragment, and propagating a fragment grows a fragment.

Enums

enum Source

Where the local order to grow comes from.

Observed

Read off the current structure’s best-coordinated point.

The general case, and the one that assumes nothing.

Named(Template)

One of the classifier’s ideal local environments.

Implementations

impl Source

Functions

fn library() -> Vec<Source>

The sources worth offering as separate arms.

fn name(&self) -> &'static str

Short name for reporting.