mod activation

module activation

History-conditioned escape feedback, after Goedecker’s minima hopping. Activation: climb the ridge out of a basin, then quench the other side.

This is valley-floor / ridge following, not a quench. Quapp’s gradient extremal of the smallest Hessian eigenvalue is the valley floor or the ridge (Quapp, Chem. Phys. Lett. 1996, 253, 286, <https://doi.org/10.1016/0009-2614(96)00255-2>). Reduced-gradient following traces the same curves (Quapp, Hirsch, Imig, Heidrich, J. Comput. Chem. 1998, 19, 1087). Barkema and Mousseau’s ART (Phys. Rev. Lett. 1996, 77, 4358, <https://doi.org/10.1103/PhysRevLett.77.4358>; Malek and Mousseau, Phys. Rev. E 2000, 62, 7723, <https://doi.org/10.1103/PhysRevE.62.7723>) climbs that direction until the curvature turns over. Henkelman and Jónsson’s dimer (J. Chem. Phys. 1999, 111, 7010, <https://doi.org/10.1063/1.480097>) and Plasencia’s SoftSaddle MMF (J. Chem. Theory Comput. 2017, 13, 125, <https://doi.org/10.1021/acs.jctc.5b01216>) invert the force along the minimum mode and minimise the rest: that is the same ridge walk to a first-order saddle. Xiao, Wu and Henkelman (J. Chem. Phys. 2014, 141, 164111, <https://doi.org/10.1063/1.4898664>) distinguish that local ridge (force perpendicular to the negative mode) from the true basin-boundary ridge; a quench is taken only after the force along the mode has changed sign, so the landing is past the saddle and not back down the local ridge into the well.

A single displacement along the softest mode does not leave a basin. It is the right direction and the wrong distance: the mode points at the low saddle, but relaxing from a point still inside the basin returns to the minimum it came from. Measured on LJ38 with the escape controller driving a straight displacement, 576 quenches in 959 came back to the basin they left and 10 found anything new.

Goedecker’s answer is molecular dynamics, which carries kinetic energy over the saddle. The answer that needs only gradients is to climb: push along the mode, relax the components perpendicular to it so the structure stays on the valley floor, and repeat until the curvature along the mode turns negative and the force along the climb has flipped. That is the ridge, and a quench from the overshoot falls into a different basin.

What this costs is honest and worth stating. Each climbing step is a curvature pass and a few perpendicular relaxation steps, so an activation is several hundred charged evaluations where a random displacement is one. It buys escapes that actually leave.

Relation to the rest of the crate

The perpendicular relaxation is the same projection crate::path uses to hold a band off its endpoints, and the mode comes from crate::curvature. The controller in crate::methods::minima_hopping sets how far to climb; this module decides when to stop.

Functions

fn activate<G>(x: ArrayView1<f64>, mut grad: G, cfg: &Activation, sign: f64) -> Option<ActivationOutcome>
where
    G: FnMut(ArrayView1<f64>) -> Option<Array1<f64>>

Climbs out of the basin containing x.

grad returns the gradient or None when the caller’s budget is spent, in which case the climb stops and reports what it has. sign picks which way along the mode to go; the two ends of a soft direction are different saddles.

Returns None only when the first curvature pass fails, since there is then no direction to climb along.

fn activate_along<G>(x: ArrayView1<f64>, direction: ArrayView1<f64>, mut grad: G, cfg: &Activation) -> Option<ActivationOutcome>
where
    G: FnMut(ArrayView1<f64>) -> Option<Array1<f64>>

Climb along direction first, then track the minimum mode.

The first steps follow the supplied vector. Later steps replace it with the softest mode, keeping the sense of travel. direction is what selects the half-space; the mode is what the ridge becomes.

fn activate_from_origin<G>(x: ArrayView1<f64>, origin: ArrayView1<f64>, mut grad: G, cfg: &Activation) -> Option<ActivationOutcome>
where
    G: FnMut(ArrayView1<f64>) -> Option<Array1<f64>>

Climb away from origin: the first mode is aligned with (x-x_0) so the walk goes up the covering half-space, not back into the well.

fn cover_climb_quench<G, Q>(origin: ArrayView1<f64>, rmsd: f64, cover_index: usize, mut grad: G, mut quench: Q, cfg: &Activation) -> Array1<f64>
where
    G: FnMut(ArrayView1<f64>) -> Option<Array1<f64>>,
    Q: FnMut(ArrayView1<f64>) -> Array1<f64>

One covering displacement, the minimum-mode climb, then the caller’s quench.

The start is only a point and a force. No target energy is read. cover_index selects one point of the hypersphere cover. The climb walks away from origin. The quench is whatever the caller uses for a local minimisation of the same force.

fn cover_climb_quench_min<G, Q, E>(origin: ArrayView1<f64>, rmsd: f64, cover_index: usize, mut grad: G, mut quench: Q, mut energy: E, cfg: &Activation) -> Array1<f64>
where
    G: FnMut(ArrayView1<f64>) -> Option<Array1<f64>>,
    Q: FnMut(ArrayView1<f64>) -> Array1<f64>,
    E: FnMut(ArrayView1<f64>) -> f64

Covering displacement, fivefold openings of the same shell, a minimum-mode climb, then a quench. The lowest minimum is kept.

The hypersphere cover picks a direction. On a shell that still has pentagonal axes, those axes are further covering directions: they are read off the coordinates, not off a target minimum. No target energy is supplied.

Covering displacements, a minimum-mode climb, and a quench.

Each hop takes one direction of the hypersphere cover. The climb holds that direction and relaxes the force perpendicular to it, then follows the lowest mode once its curvature changes sign. The quench is the caller’s local minimiser, taken past that ridge. No target energy is read.

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

Length of the modified-dimer probe, as a fraction of the nearest neighbour.

A probe of a tenth of the contact reaches the repulsive wall. The dimer then aligns with that clash. One hundredth of the contact stays where the curvature is still the soft mode.

Structs and Unions

struct Activation

How the climb is run.

step: f64

Distance moved along the mode per climbing step.

max_steps: usize

Climbing steps before giving up.

A cap rather than a convergence criterion: some directions do not reach negative curvature at all, and a climb that has not turned over after this many steps is abandoned rather than run to exhaustion.

perp_steps: usize

Perpendicular relaxation steps between climbs.

perp_rate: f64

Step size of the perpendicular relaxation.

perp_max_move: f64

Largest displacement one perpendicular step may make.

A fixed rate is not safe on a potential whose gradient spans decades. On a Lennard-Jones cluster two points a little too close carry a gradient of order a thousand, and a rate of 0.02 against that moves the structure twenty units and destroys it: measured on LJ38, 6 relaxations in 1589 reached a minimum and the returned structure had a gradient of 1.0 where a minimum has 1e-6. The cap makes the step a direction with a bounded length rather than a length proportional to the gradient.

lanczos_steps: usize

Lanczos steps per curvature pass.

epsilon: f64

Finite-difference step for the curvature.

refresh: usize

Climbing steps between recomputing the mode.

Recomputing every step is the accurate choice and the expensive one. The mode rotates slowly along a valley floor, so reusing it for a few steps costs little accuracy and divides the curvature bill.

overshoot: f64

Extra push along the mode once the curvature has turned over, in units of step, before the quench.

min_rise: f64

Ignore a ridge whose integrated rise is below this.

The first saddle out of a low minimum is often a shallow step to a neighbour of similar depth. A later ridge, several energy units up, is the one that can open another funnel. Zero keeps every ridge.

later_ridges: bool

Keep climbing after the first ridge and retain the later ones.

The default stops at the first ridge so a short budget still crosses one barrier. A search that is trying to leave a deep funnel has to see the ridge after that, because the first one usually returns to the same well.

Traits implemented

impl Default for Activation
struct ActivationOutcome

Where a climb ended.

state: Array1<f64>

The activated structure, to be quenched by the caller.

lambda: f64

Curvature along the mode at the end of the climb.

steps: usize

Climbing steps taken.

crossed: bool

Whether the curvature turned negative, so the ridge is behind.

evaluations: usize

Gradient evaluations spent, all of them charged by the caller.

ridges: Vec<Array1<f64>>

Ridge points kept when Activation::later_ridges is set, each already pushed past its turning point.