Optimizer¶
Note
The eOn optimizers skip a line search when taking the steepest-descent step.
There are several other ways in which the eOn implementations differ from a
standard optimizer software suite[1] . Some prominent reasons are:
They are written for the Nudged elastic band, whose energy surface has no closed form
Especially in the global band optimization approach [OPT_STH08].
They are specialized for atomic systems
The optimizers only see the moving atoms, the frozen atoms are omitted before being passed to the optimizer
Configuration¶
[Optimizer]
- pydantic model eon.schema.OptimizerConfig[source]¶
- Fields:
opt_method (Literal['box', 'cg', 'qm', 'lbfgs', 'fire', 'sd', 'xtsci'])opt_backend (Literal['eon', 'rgmin'])convergence_metric (Literal['norm', 'rms', 'max_atom', 'max_component'])converged_force (float)max_move (float)time_step (float)max_iterations (int)
- field opt_method: Literal['box', 'cg', 'qm', 'lbfgs', 'fire', 'sd', 'xtsci'] = 'cg'¶
- Options:
box: Optimizes the atom positions and box using quickmincg: Conjugate gradientqm: Quickminlbfgs: Limited Memory Broyden-Fletcher-Goldfarb-Shanno QuasiNewton optimizerfire: Fast inertial relaxation enginesd: Steepest descentxtsci: rgmin engine (formerly xtsci-optimize). Pick the solver with[Xtsci] method. Needs a build that links rgmin (-Dwith_rgmin).
The optimization method to use.
- field opt_backend: Literal['eon', 'rgmin'] = 'eon'¶
- Options:
eon: eOn’s own optimizers (default)rgmin: rgmin sessions: lbfgs is rgmin L-BFGS, fire is FIRE, cg is Polak-Ribiere CG, sd is steepest descent, qm is quick-min. Needs a build that links rgmin (-Dwith_rgmin). Applies to every objective whose gradient is the derivative of its energy (relaxations, the per-image IDPP path, BGSD); the nudged elastic band, the collective IDPP band and min-mode translation steps stay on eOn’s optimizers.[LBFGS] lbfgs_memoryand the[Xtsci]session keys still apply.
Who runs the lbfgs, fire, cg, sd and qm optimizers.
- field convergence_metric: Literal['norm', 'rms', 'max_atom', 'max_component'] = 'norm'¶
- Options:
norm: Euclidean||F||_2of the free-atom force vector (default)rms:||F||_2 / sqrt(3 N_free), OPTIM MYLBFGS RMS. Opt-in.max_atom: The maximum force on any non-frozen atommax_component: The maximum force on any non-frozen degree of freedom
The metric to use to determine when an optimization is complete.
- field converged_force: float = 0.01¶
When the convergence_metric is smaller than this value (eV/A), the structure is considered minimized.
Each of the optimizer methods have their own settings as well.
LBFGS¶
[LBFGS]
- pydantic model eon.schema.LBFGSConfig[source]¶
- Fields:
lbfgs_memory (int)lbfgs_inverse_curvature (float)lbfgs_max_inverse_curvature (float)lbfgs_auto_scale (bool)lbfgs_angle_reset (bool)lbfgs_distance_reset (bool)lbfgs_curvature (Literal['reset', 'skip', 'damped', 'cautious'])lbfgs_project_rigid (bool)lbfgs_secant (Literal['standard', 'zhangxu'])lbfgs_precon (Literal['none', 'exp', 'c1', 'lindh', 'lindh_full', 'pair', 'pair_abs', 'pair_full', 'fischer', 'schlegel', 'swart'])lbfgs_step (Literal['lbfgs', 'newton', 'rfo'])lbfgs_h0 (Literal['sy_yy', 'ss_sy', 'adaptive'])lbfgs_accept (Literal['none', 'energy', 'nonmonotone'])lbfgs_extra_updates (int)lbfgs_cautious_eps (float)lbfgs_cautious_alpha (float)lbfgs_precon_A (float)lbfgs_precon_mu (float)lbfgs_precon_rcut (float)
- field lbfgs_memory: int = 20¶
Number of previous gradients and positions to store for the LBFGS method.
- field lbfgs_curvature: Literal['reset', 'skip', 'damped', 'cautious'] = 'reset'¶
- Options:
reset: wipe L-BFGS memory (ASE-style default)skip: skip that pair whens·y < 0.2 sᵀ B0 sdamped: Powell 1978 damping, ŷ = θy+(1-θ)B0 scautious: Li-Fukushima 2001, keep the pair only ifs·y >= ε ||s||² ||g||^α
How to treat a pair with insufficient curvature.
- field lbfgs_project_rigid: bool = False¶
Project translation and rotation out of the L-BFGS force and step. Isolated clusters only.
- field lbfgs_secant: Literal['standard', 'zhangxu'] = 'standard'¶
Secant pair: standard y = g_{k+1}-g_k, or Zhang-Xu modified secant using the two energies.
- field lbfgs_precon: Literal['none', 'exp', 'c1', 'lindh', 'lindh_full', 'pair', 'pair_abs', 'pair_full', 'fischer', 'schlegel', 'swart'] = 'none'¶
Two-loop H0 metric. none is H0 I. exp/c1 is Packwood-Kermode (JCP 2016). lindh is the Lindh 1995 stretch model. pair is the Mones 2018 positive-definite pair Hessian of LJ or Morse. pair_full is the signed pair Hessian for Newton/RFO.
- field lbfgs_step: Literal['lbfgs', 'newton', 'rfo'] = 'lbfgs'¶
lbfgs is the two-loop direction. newton is Levenberg-shifted H^{-1} g. rfo is Banerjee/Baker rational function optimization.
- field lbfgs_h0: Literal['sy_yy', 'ss_sy', 'adaptive'] = 'sy_yy'¶
Initial inverse-Hessian scale: Nocedal-Wright 7.20, Barzilai-Borwein-2, or the smaller of the two.
- field lbfgs_accept: Literal['none', 'energy', 'nonmonotone'] = 'none'¶
none takes the two-loop step (ASE / historical eOn). energy refuses a rise. nonmonotone is a Grippo window of the last five values.
A classic dimer ([Dimer] improved = false) reports |C_tau| as a known
first-step scale when the mode is negative. L-BFGS keeps H0 = 1/|C_tau|
when that step fits in max_move, and also when the mode is milder than
30 eV/Ų and the cap would otherwise set the length. A steeper mode whose
uncapped step exceeds max_move takes one finite-difference probe of the
effective force. Improved dimer and Lanczos do not report |C_tau|. Those
searches climb on the effective force, so the first step is the probe and
max_move is only the cap. Later steps still use the [LBFGS] secant scale.
A build that rotates the mode in rgsaddle uses the same rule.
improved = false reports |C_tau|, and the improved dimer and Lanczos
do not.
QuickMin¶
[QuickMin]
FIRE¶
[FIRE]
CG¶
[CG]
SD¶
[SD]
rgmin backend¶
eOn’s minimizers can run inside rgmin, the Rust minimizer library (formerly xtsci-optimize), instead of eOn’s own C++ code. Two keys select it:
[Optimizer] opt_backend = rgminkeepsopt_methodand hands the step to the rgmin solver of the same name.[Optimizer] opt_method = xtsciruns whichever rgmin solver[Xtsci] methodnames, including those eOn has no native version of (bfgs,newton,rfo,dogleg,fire2, …).
|
rgmin solver under |
|---|---|
|
|
|
|
|
|
|
|
|
|
[Optimizer]
opt_method = lbfgs
opt_backend = rgmin
Both need a client that links rgmin. -Dwith_rgmin=auto (the
default) links an rgmin found by pkg-config and changes nothing until an
input selects it; -Dwith_rgmin=enabled makes a missing rgmin a
configure error. -Dwith_xtsci=true is the deprecated spelling of
enabled. The client needs rgmin 0.4.0 or newer, installed with
cargo cinstall --release --features capi --prefix=$PREFIX
# cinstall regenerates rgmin.h; the C++ client needs the curated header
cp include/rgmin.h $PREFIX/include/
cp -r include/dlpack $PREFIX/include/
eonclient --features lists rgmin minimizers when it is linked.
A client without rgmin rejects opt_backend = rgmin with an error
naming -Dwith_rgmin.
opt_backend only applies where the optimizer minimizes an energy
whose gradient is the force: relaxations in every job, NEB endpoint
minimization, the per-image IDPP path and BGSD. The NEB band, the
collective IDPP band and the min-mode translation step are not
minimizations of an energy, so they keep eOn’s optimizer; the rgsaddle
section below covers the band.
Matter evaluates every energy and force rgmin asks for, so
total_force_calls counts the same calls as with opt_backend = eon.
The host loop applies converged_force, max_iterations and
max_move (as eOn’s largest per-atom move) as before. rgmin reads
time_step for fire and qm, [LBFGS] lbfgs_memory for the
memory, and the [Xtsci] or [LBFGS] preconditioner and acceptance
keys described below. The other [FIRE], [CG], [QuickMin]
and [SD] keys belong to eOn’s own solvers and do not reach rgmin.
Xtsci¶
opt_method = xtsci selects the rgmin engine. The solver inside that
engine is [Xtsci] method. The adapter holds an rgmin_solver_t
session; each step() is one outer iteration so L-BFGS pairs and NLCG
conjugacy survive the host loop.
When eindir-core is on the pkg-config path, the same backend borrows
an eindir_objective_t around the ObjectiveFunction. The adapter
checks the eindir ABI stamp, the gradient feature bit, and the semantic
descriptor (eV, angstrom, analytic forces) before dispatch.
Optimizer::run then calls rgmin_minimize_eindir unless the step
needs a host Hessian. step() stays one rgmin_solver_t iteration.
[Xtsci] qn_step, precon, and accept are the first-class
knobs for an L-BFGS session. They map onto
rgmin_solver_set_qn_step, rgmin_solver_step_hess_fg, and
rgmin_solver_set_accept. Energy and forces share one
potential->force() call. accept = none takes the
maxmove-clipped step (one geometry). nonmonotone is the Grippo
window used by the rematch INI. The pair / Lindh matrix is still
built in eOn. Two-loop plus that matrix is (H_0 = P^{-1});
qn_step = newton is regularized Newton on the same P.
method = newton is a different, memoryless Newton solver.
The native [LBFGS] optimizer is unchanged. lbfgs_step,
lbfgs_precon, and lbfgs_accept still drive it, and the
rgmin adapter falls back to them when the [Xtsci] fields are
left at their defaults.
[Optimizer]
opt_method = xtsci
[Xtsci]
method = lbfgs
qn_step = newton
precon = pair
accept = nonmonotone
- pydantic model eon.schema.XtsciConfig[source]¶
- Fields:
method (Literal['lbfgs', 'bfgs', 'sr1', 'sr2', 'newton', 'rfo', 'steepest', 'adam', 'pso', 'polak_ribiere', 'fletcher_reeves', 'hestenes_stiefel', 'dai_yuan', 'conjugate_descent', 'hager_zhang', 'liu_storey', 'fr_pr', 'fire', 'bb', 'dogleg', 'fire2', 'quickmin'])qn_step (Literal['lbfgs', 'newton', 'rfo'])precon (Literal['none', 'pair', 'pair_abs', 'pair_full', 'exp', 'c1', 'lindh', 'lindh_full', 'fischer', 'schlegel', 'swart'])accept (Literal['none', 'energy', 'nonmonotone'])highs (bool)manifold (Literal['euclidean', 'rigid_quotient', 'mw_rigid', 'sphere', 'so3', 'stiefel', 'se3'])
- field method: Literal['lbfgs', 'bfgs', 'sr1', 'sr2', 'newton', 'rfo', 'steepest', 'adam', 'pso', 'polak_ribiere', 'fletcher_reeves', 'hestenes_stiefel', 'dai_yuan', 'conjugate_descent', 'hager_zhang', 'liu_storey', 'fr_pr', 'fire', 'bb', 'dogleg', 'fire2', 'quickmin'] = 'lbfgs'¶
opt_method = xtsciselects the engine. This field selects the method the engine runs. Tokens matchrgmin_method_t.- Quasi-Newton:
lbfgs: two-loop L-BFGS (Nocedal-Wright 7.4)bfgs: dense inverse-BFGSsr1: inverse SR1sr2: SR2 Hessian update
- Hessian (pair Hessian from eOn,
rgmin_minimize_hess): newton: Levenberg-shifted Newtonrfo: Banerjee / Baker rational function optimization
- First-order:
steepest:d = -gadam: Kingma-Ba Adam with a line searchpso: particle swarmfire: Bitzek FIRE (one fused force per geometry)fire2: Guénolé FIRE 2.0bb: Barzilai-Borwein spectral stepquickmin: quick-min, the velocity projected on the force (rgmin ABI minor 29)
- Trust-region Hessian (pair Hessian from eOn):
dogleg: Powell dogleg on the host pair matrix
- Nonlinear CG (conjugacy is the method token):
polak_ribiere,fletcher_reeves,hestenes_stiefel,dai_yuan,conjugate_descent,hager_zhang,liu_storey,fr_pr
Solver inside the rgmin engine (opt_method = xtsci).
- field qn_step: Literal['lbfgs', 'newton', 'rfo'] = 'lbfgs'¶
Only used when
method = lbfgs.lbfgsis two-loop with optionalpreconas (H_0 = P^{-1}).newton/rfotake that same host matrix as the step (eOn rematch).How an L-BFGS session uses a host Hessian (rgmin_qn_step_t).
- field precon: Literal['none', 'pair', 'pair_abs', 'pair_full', 'exp', 'c1', 'lindh', 'lindh_full', 'fischer', 'schlegel', 'swart'] = 'none'¶
pairis the Mones PSD clip.pair_fullkeeps signed curvature.lindh_full/fischer/schlegel/swartare Cartesian model Hessians (B^T k B). The matrix is assembled in eOn and passed throughrgmin_solver_step_hess.Host pair / model Hessian kind. Built in eOn, not in xtsci.
- field accept: Literal['none', 'energy', 'nonmonotone'] = 'none'¶
nonetakes the maxmove-clipped step (one oracle).energyrefuses a rise.nonmonotoneis the Grippo window of five.How the session takes a proposed step (rgmin_accept_t).
- field highs: bool = False¶
When true, xtsci asks HiGHS for the step: Newton QP on the host pair Hessian if one is passed, otherwise two-loop plus boxes. Needs
--features highson the rgmin build.HiGHS feasible-set step (rgmin_solver_set_highs).
- field manifold: Literal['euclidean', 'rigid_quotient', 'mw_rigid', 'sphere', 'so3', 'stiefel', 'se3'] = 'euclidean'¶
Euclidean is the default. Isolated molecules use
rigid_quotient(Sella Cartesian (R^{3N}/SE(3))) ormw_rigid(Page-McIver / Sella IRC Eckart).sphereis (S^{n-1}),so3a row-major 9-vector,stiefelis (mathrm{St}(n,1)),se3is rotation then translation (length 12).Embedded manifold (rgmin_manifold_t).
Rgsaddle band and min-mode¶
rgsaddle, the Rust saddle-search library, steps the NEB band and rotates
the min-mode dimer when the client is built with -Dwith_rgsaddle=true
(rgsaddle 0.2.0 or newer, found by pkg-config). There is no runtime
switch: in such a build the existing keys pick the rgsaddle path.
Input |
Build without rgsaddle |
Build with |
|---|---|---|
|
eOn optimizer on the band objective |
rgsaddle band session |
|
eOn optimizer |
eOn optimizer |
|
eOn dimer or Lanczos ( |
rotation in an rgsaddle session |
|
eOn |
eOn |
eonclient --features lists rgsaddle band and min-mode in such a
build. In the band session [Xtsci] method = fire is the band stepper
and method = lbfgs selects the L-BFGS session; opt_method = lbfgs
and fire pick the matching stepper. [Optimizer] refine_* does not
apply to a band stepped by rgsaddle. Matter still owns the images, and
the NEB loop still owns climbing policy, resampling, and the spline.
The surface callback returns a status. The first band request carries
every image. Later requests carry the interior images, or one image.
When the coordinates already match, that image stays put and its energy
and forces stay with it. The images that move go out as one batch. The
client resends the band only after a reparameterization, or after
another move outside the session. Every image evaluation goes through
Matter, so force_calls_neb keeps its meaning.
min_mode_method = xtsci rotates the lowest mode in that session
with a zero translation cap. The min-mode callback reads the centre
from its cached evaluation and runs a displaced probe on a copy. The
min-mode saddle search still climbs with the selected optimizer.
min_mode_method = dimer and lanczos rotate in the same session,
lanczos as a Lanczos session. Davidson and the GP dimer keep their
own solvers. Against rgsaddle ABI minor 5 or newer one session serves
every step of the search: the client moves it to each new centre with
the gradient it already has, so the centre costs no extra call, and the
previous mode seeds the next rotation.
The session takes its settings from the dimer and Hessian keys:
rgsaddle setting |
eOn key |
Conversion |
|---|---|---|
|
|
Angstrom; 0.001 when not positive |
|
|
none |
|
|
degrees to radians (ABI minor 5) |
|
|
at least 1 |
|
|
|
|
|
|
|
none |
12 |
rgsaddle has no fourth-order stencil, so fd_scheme = fourth gives
central differences here. [Dimer] rotation_angle is a trial angle
of the host dimer and does not reach the session.
References¶
Daniel Sheppard, Rye Terrell, and Graeme Henkelman. Optimization methods for finding minimum energy paths. The Journal of Chemical Physics, 128(13):134106, April 2008. doi:10.1063/1.2841941.