Hold a stateful solver#

Geometry hosts such as eOn call Optimizer::step() once per outer iteration. rgmin_minimize is a full solve. The session type rgmin_solver_t (Rust Solver) is the matching handle: create once, step many times, free at the end.

Rust#

use eindir_core::objectives::Rosenbrock;
use ndarray::array;
use rgmin::{Accept, Control, Method, QnStep, Solver};

let obj = Rosenbrock::<2>::new();
let mut x = array![-1.2, 1.0];
let mut solver = Solver::new(Method::lbfgs(), Control::default(), 2)
    .with_gtol(1e-8);
solver.set_qn_step(QnStep::Newton);
solver.set_accept(Accept::None);
let report = solver.step(&obj, &mut x).unwrap();

step is one outer iteration. step_hess / step_hess_fg take a host Hessian. forget drops pair history, conjugacy, and moments. set_atom_maxmove is the eOn per-atom clip. A fresh Cartesian session starts with that clip at 0.2, which is ASE Optimizer.defaults maxstep at tag 3.29.0 (https://gitlab.com/ase/ase/-/blob/3.29.0/ase/optimize/optimize.py) and eOn max_move (https://henkelmanlab.org/eon/optimizer.html; OptimizerOptions.maxMove in schema/eon_params.capnp at 4be157d4, https://github.com/TheochemUI/eOn/blob/4be157d43265af6b1140aaac0e52e42add62693f/schema/eon_params.capnp). The number is in the coordinate unit, so a geometry stored in angstroms is capped at 0.2 Å. scale_step_atom limits the largest per-atom displacement. It does not limit the Euclidean norm of the whole step. A positive argument replaces the default. A non-positive argument clears the cap, and that choice stays in force if set_maxmove or set_manifold is called later. A positive Control.maxmove, with no call to set_atom_maxmove, is the Euclidean step limit and leaves the per-atom default off. A non-Cartesian manifold has no default.

Method::QuickMin is the projection-then-Euler step in quick-min. set_quickmin_adapt(false) keeps the reference fixed time step. set_quickmin_cell(at) gives the atoms and the cell their own velocities. The displacement cap is the same set_atom_maxmove the other methods use.

To run eOn’s quick-min, or the per-atom variant, set the options after building the session:

use rgmin::{Control, Method, QuickMinOptions, Solver};

let control = Control { istep: 0.1, ..Control::default() };
let mut solver = Solver::new(Method::QuickMin, control, x.len());
solver.set_atom_maxmove(0.2);
solver.set_quickmin_options(QuickMinOptions::per_atom()); // or ::eon()
let report = solver.step(&obj, &mut x).unwrap();

From C, rgmin_solver_set_quickmin_variant(s, RGMIN_QUICKMIN_PER_ATOM) (or RGMIN_QUICKMIN_EON, RGMIN_QUICKMIN_RGMIN) on a session created with RGMIN_QUICKMIN. set_project_rigid projects translations and rotations on isolated clusters.

C#

#include "xts.h"

rgmin_control_t ctrl = { .maxiter = 200, .gtol = 1e-8, .istep = 1.0, .memory = 8 };
rgmin_solver_t *s = rgmin_solver_create(RGMIN_LBFGS, &ctrl, n);
rgmin_report_t report;
while (!done) {
    rgmin_solver_set_maxmove(s, max_move);
    rgmin_solver_set_qn_step(s, RGMIN_QN_NEWTON);
    rgmin_solver_set_accept(s, RGMIN_ACCEPT_NONE);
    rgmin_solver_step_hess_fg(s, evalgrad, hess, user, x, &report);
}
rgmin_solver_free(s);

Callbacks are arguments of each step, not stored on the handle. rgmin_solver_step_fg / rgmin_solver_step_hess_fg take one fused (f, g) callback so a host that already bills energy and forces together is not asked twice.

Setters#

Setter

Role

set_qn_step

Two-loop, Newton, or RFO when a host Hessian is present

set_accept

none / energy / nonmonotone / step

set_linesearch

Line search for the line-searched arms; default strong Wolfe

set_fire_variant

FIRE schedule; Guenole2020 is FIRE 2.0 as published

forget_evaluation

Re-evaluate the next start, keep the method memory

set_atom_maxmove

Per-atom clip; Cartesian default 0.2, preferred over a Euclidean cap

set_project_rigid

Drop rigid modes on isolated clusters

set_lbfgs_neb_guards

L-BFGS distance, angle and curvature resets; empty-memory scale 0.01

set_extra_updates

Accepted, no effect: a replayed newest pair leaves BFGS unchanged

set_cautious

Li–Fukushima pair filter

set_highs

Feasible-set QP; returns 1 without --features highs

set_manifold

Embedded geometry; rigid_quotient for 3N clusters

set_masses

Per-atom masses for mw_rigid (Page–McIver)

The C entry of each setter is rgmin_solver_<setter>. rgmin_solver_forget_evaluation and rgmin_solver_set_lbfgs_neb_guards need abi_minor 28.

When to use rgmin_minimize instead#

Scripts that want a cold-start solve to gtol still call rgmin_minimize / minimize_method. Hopping chains that own the pair history hold Lbfgs directly (see embed in anneal).