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::pathuses to hold a band off its endpoints, and the mode comes fromcrate::curvature. The controller incrate::methods::minima_hoppingsets 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.gradreturns the gradient orNonewhen the caller’s budget is spent, in which case the climb stops and reports what it has.signpicks which way along the mode to go; the two ends of a soft direction are different saddles.Returns
Noneonly 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
directionfirst, 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.
directionis 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_indexselects one point of the hypersphere cover. The climb walks away fromorigin. 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.
-
fn cover_climb_search<E, Q>(origin: ArrayView1<f64>, rmsd: f64, max_hops: usize, seed: u64, mut evaluate: E, mut quench: Q, cfg: &Activation) -> Array1<f64>¶
where
E: FnMut(ArrayView1<f64>) -> (f64, Array1<f64>) + Send,
Q: FnMut(ArrayView1<f64>) -> Array1<f64>
¶ 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_ridgesis set, each already pushed past its turning point.
-
fn activate<G>(x: ArrayView1<f64>, mut grad: G, cfg: &Activation, sign: f64) -> Option<ActivationOutcome>¶