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 |
|---|---|
|
Two-loop, Newton, or RFO when a host Hessian is present |
|
|
|
Line search for the line-searched arms; default strong Wolfe |
|
FIRE schedule; |
|
Re-evaluate the next start, keep the method memory |
|
Per-atom clip; Cartesian default 0.2, preferred over a Euclidean cap |
|
Drop rigid modes on isolated clusters |
|
L-BFGS distance, angle and curvature resets; empty-memory scale 0.01 |
|
Accepted, no effect: a replayed newest pair leaves BFGS unchanged |
|
Li–Fukushima pair filter |
|
Feasible-set QP; returns 1 without |
|
Embedded geometry; |
|
Per-atom masses for |
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).