Minimization

Local minimization relaxes a structure to the nearest potential energy minimum using one of several optimization algorithms.

To run a minimization, set job to minimization in the [Main] section:

[Main]
job = minimization

[Optimizer]
opt_method = lbfgs
converged_force = 0.01
max_iterations = 1000

Or programmatically via rgpycrumbs:

from rgpycrumbs.eon.helpers import write_eon_config

config = {
    "Main": {"job": "minimization"},
    "Optimizer": {"opt_method": "lbfgs", "converged_force": 0.01},
}
write_eon_config(config, Path("config.ini"))

The optimizer settings control convergence. See Optimizer for the full list of available optimizers and their parameters.

Tip

Enable [Debug] write_movies = true (and optionally write_deprecated_outs = true) so rgpycrumbs eon plt-min can build energy profiles, 2D landscapes, and convergence panels. For two endpoints, use separate landscape plots (one --job-dir / --label each). See LJ cluster minimization (built-in potential) and Real systems for documentation.

Optimizer selection

Optimizer

Best for

Key parameter

LBFGS

Most minimizations, fast convergence near minima

lbfgs_memory (default 20); optional lbfgs_secant / lbfgs_precon / lbfgs_curvature

FIRE

Systems far from equilibrium, tolerant of bad initial guesses

time_step

CG (default)

Large systems where LBFGS memory is a concern

cg_line_search

QuickMin (token qm)

Simple dynamics-based relaxation

time_step

SD

Debugging, guaranteed descent direction

sd_alpha

The default opt_method is cg. The QuickMin token is qm. quickmin is not a token.

Convergence

The minimization converges when converged_force is met. The number is always in eV/A; convergence_metric chooses which force scalar is compared. The default is eOn’s historical norm, not OPTIM’s RMS.

  • norm (default): Euclidean ||F||_2 of the free-atom force vector (sqrt(sum_i F_i^2)). This is not an RMS: it grows with system size. Chill / OPTIM ||F|| < 1e-2 is a different scalar.

  • rms: ||F||_2 / sqrt(3 N_free), matching OPTIM MYLBFGS (SQRT(SUM(VNEW**2)/(3*NATOMS))). Opt-in for an OPTIM-comparable stop; it is not the eOn default.

  • max_atom: maximum ||F|| on any single free atom

  • max_component: maximum Cartesian component of any free-atom force

L-BFGS memory updates are controlled by lbfgs_curvature (default reset, the ASE wipe). skip drops a pair when s·y < 0.2 sᵀB0s. damped is Powell’s 1978 replacement ŷ = θ y + (1-θ) B0 s with θ = 0.8 sᵀB0s / (sᵀB0s − sᵀy) when sᵀy < 0.2 sᵀB0s (Nocedal and Wright, Numerical Optimization, §18.3). cautious is the Li–Fukushima (2001) rule: keep the pair only if s·y ≥ ε ||s||² ||g||^α. Isolated clusters can set lbfgs_project_rigid = true to remove the six rigid-body modes from the force and the step (those modes are Hessian-null; they should not enter the limited-memory pairs).

Further L-BFGS knobs, all optional and off by default:

  • lbfgs_secant = zhangxu replaces y by the Zhang–Deng–Chen / Zhang–Xu modified secant, which folds the two function values into the pair (JOTA 1999 / 2001). No extra potential call. On Lennard-Jones and Morse pair potentials this pair inflates the force-call count; leave it at standard there.

  • lbfgs_precon selects the two-loop H0 metric. none is H0 I. exp / c1 is the Packwood–Kermode–Csanyi pair Laplacian (J. Chem. Phys. 2016, doi:10.1063/1.4947024). ASE falls back below about 100 atoms; exp on LJ38 costs force calls. lindh is the Lindh stretch model Hessian (Chem. Phys. Lett. 1995, doi:10.1016/0009-2614(95)00646-L): k = μ exp(α (r_nn² - r²)) along each pair, α = lbfgs_precon_A. pair is the Mones–Ortner–Csanyi positive-definite pair Hessian (Sci. Rep. 2018, doi:10.1038/s41598-018-32105-x) of the running potential: analytic V'' and V'/r of LJ (4ε[(σ/r)¹²-(σ/r)⁶], ε=σ=1) or Morse_Pt (D=0.7102, α=1.6047, r0=2.897), with negative pieces dropped. That is the right metric when the energy is itself a pair potential (Morse bulk). pair_abs uses |V''| and |V'/r| so attractive LJ neighbours still contribute; on LJ38 it does not beat an unpreconditioned two-loop. lindh_full adds Lindh bend and torsion blocks (B^T k B). fischer is the Fischer-Almlof 1992 model Hessian (doi:10.1021/j100203a036). schlegel is the Schlegel 1984 estimated Hessian (doi:10.1007/BF00554788). swart is the Swart-Bickelhaupt strong/weak screen of Lindh (doi:10.1002/qua.21049). All four are host Cartesian matrices; [Xtsci] precon takes the same tokens.

Newton and RFO are not L-BFGS. They live in rgmin (formerly xtsci-optimize) as Method::Newton. Build eOn against rgmin (-Dwith_rgmin=enabled, see Optimizer) and select them from the INI:

[Optimizer]
opt_method = xtsci
converged_force = 0.01

[Xtsci]
method = newton

[LBFGS]
lbfgs_precon = pair

[Xtsci] highs = true asks HiGHS for the step (Newton QP on the host pair matrix, or two-loop plus boxes). Build rgmin with --features capi,highs.

method = rfo is Banerjee RFO. The pair Hessian is still built in eOn (lbfgs_precon) and handed to Rust through rgmin_minimize_hess. The engine also runs the other rgmin methods (lbfgs, bfgs, sr1, sr2, steepest, adam, pso, quickmin, and the NLCG conjugacies).

To keep opt_method = lbfgs, fire, cg, sd or qm and only move the step into rgmin, set [Optimizer] opt_backend = rgmin; the method map is in Optimizer.

  • lbfgs_h0 = sy_yy (Nocedal–Wright 7.20), ss_sy (Barzilai–Borwein 2), or adaptive (the smaller of the two when both are positive).

  • lbfgs_accept = none (default) takes the two-loop step, matching ASE and historical eOn. energy refuses a rise (OPTIM-style shrink; each trial is a potential call). nonmonotone is the Grippo–Lampariello–Lucidi window of the last five energies (SIAM J. Numer. Anal. 1986).

  • lbfgs_extra_updates = p reuses the newest pair p extra times in the two-loop recursion (Al-Baali, 2000/2014).

Refinement

For paths far from the minimum, a two-stage optimization can be faster: start with QuickMin or FIRE and switch to LBFGS after the forces drop below a threshold. The client reads [Refine] only when that section is present. [Refine] is absent from eon/config.yaml, so a file the server loads exits before the client runs.

[Optimizer]
opt_method = fire

[Refine]
opt_method = lbfgs
threshold = 0.5

This runs FIRE until the max force drops below 0.5 eV/A, then switches to LBFGS for final convergence.

Output

The minimization writes:

  • min.con: the minimized structure

  • results.dat: energy, force calls, convergence status

With write_movies = true (in [Debug]), minimization.con is written as a concatenated structure movie (one frame per iteration). Each frame stores structured JSON metadata in the second CON header line via readcon-core, including energy, frame_index, step_size, and convergence.

Set write_deprecated_outs = true in [Debug] to also emit the legacy minimization.dat sidecar during the compatibility window.

Configuration

The minimization job reads [Optimizer]. Its opt_method defaults to cg. An optional [Refine] block is client-only: the client reads it when the section is present, and the server exits on the unknown section before the client runs.

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 quickmin

  • cg: Conjugate gradient

  • qm: Quickmin

  • lbfgs: Limited Memory Broyden-Fletcher-Goldfarb-Shanno QuasiNewton optimizer

  • fire: Fast inertial relaxation engine

  • sd: Steepest descent

  • xtsci: 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_memory and 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||_2 of 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 atom

  • max_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.

field max_move: float = 0.2

Maximum distance that an atom may be moved in a single optimization step (Angstroms).

field time_step: float = 1.0

The dynamical timestep for the quickmin algorithm (fs).

field max_iterations: int = 1000

The maximum number of optimization iterations that will be performed.

pydantic model eon.schema.RefineConfig[source]
Fields:
  • refine_opt_method (Literal['none', 'cg', 'lbfgs', 'fire', 'box', 'qm'])

  • refine_threshold (float)

field refine_opt_method: Literal['none', 'cg', 'lbfgs', 'fire', 'box', 'qm'] = 'none'
Options:
  • none: No refinement optimization

  • cg: Conjugate gradient

  • lbfgs: Limited Memory Broyden-Fletcher-Goldfarb-Shanno QuasiNewton optimizer

  • fire: Fast inertial relaxation engine

  • box: Optimizes the atom positions and box using quickmin

  • qm: Quickmin

The optimization method to use for refinement.

field refine_threshold: float = 0.5

Threshold for refinement optimization.