Optimisers

Contents

Optimisers#

class autode.opt.optimisers.base.BaseOptimiser#

Base abstract class for an optimiser

abstract property converged: bool#

Has this optimisation converged

property final_coordinates#
abstract property last_energy_change: PotentialEnergy#

The energy change on between the final two optimisation cycles

run(*args: Any, **kwargs: Any) None#
class autode.opt.optimisers.base.ConvergenceParams(abs_d_e: PotentialEnergy | None = None, rms_g: GradientRMS | None = None, max_g: GradientRMS | None = None, rms_s: Distance | None = None, max_s: Distance | None = None, strict: bool = False)#

Various convergence parameters for optimisers and some common preset convergence tolerances

Parameters:
  • abs_d_e – Absolute change in energy, |E_i - E_i-1|

  • rms_g – RMS of the gradient, RMS(∇E)

  • max_g – Maximum component of gradient, max(∇E)

  • rms_s – RMS of the last step, RMS(x_i - x_i-1)

  • max_s – Maximum component of last step, max(x_i - x_i-1)

  • strict – Whether all criteria must be converged strictly. If False, convergence is signalled when some criteria are overachieved and others are close to convergence

__init__(abs_d_e: PotentialEnergy | None = None, rms_g: GradientRMS | None = None, max_g: GradientRMS | None = None, rms_s: Distance | None = None, max_s: Distance | None = None, strict: bool = False) None#
abs_d_e: PotentialEnergy | None = None#
are_satisfied(other: ConvergenceParams) List[bool]#

Return an elementwise comparison between the current criteria and another set of parameters (comparing only numerical attributes)

Parameters:

other – Another set of parameters

Returns:

List containing True or False

Return type:

(list[bool])

classmethod from_preset(preset_name: str) ConvergenceParams#

Obtains preset values of convergence criteria - given as “loose”, “normal”, “tight” and “verytight”.

Parameters:

preset_name – Must be one of the strings “loose”, “normal” “tight” or “verytight”

Returns:

Optimiser convergence criteria, with

preset values

Return type:

(ConvergenceCriteria)

max_g: GradientRMS | None = None#
max_s: Distance | None = None#
meets_criteria(other: ConvergenceParams) bool#

Does a set of parameters satisfy the current convergence criteria? Will signal convergence if gradient or energy change are overachieved or all other criteria except energy is satisfied

Parameters:

other (ConvergenceParams) – Another set of parameters to be checked against the current set

Return type:

(bool)

rms_g: GradientRMS | None = None#
rms_s: Distance | None = None#
strict: bool = False#
class autode.opt.optimisers.base.ExternalOptimiser#
abstract property converged: bool#

Has this optimisation has converged

abstract property last_energy_change: PotentialEnergy#

The final energy change in this optimisation

class autode.opt.optimisers.base.NDOptimiser(maxiter: int, conv_tol: ConvergenceParams | Literal['loose', 'normal', 'tight', 'verytight'], coords: OptCoordinates | None = None, **kwargs)#

Abstract base class for an optimiser in N-dimensions

__init__(maxiter: int, conv_tol: ConvergenceParams | Literal['loose', 'normal', 'tight', 'verytight'], coords: OptCoordinates | None = None, **kwargs)#

Geometry optimiser. Signature follows that in scipy.minimize so species and method are keyword arguments. Converged when both energy and gradient criteria are met.

Parameters:

conv_tol (ConvergenceParams|ConvergenceTolStr) – Convergence tolerances, indicating thresholds for absolute energy change (|E_i+1 - E_i|), RMS and max. gradients (∇E) and RMS and max. step size (Δx) Either supplied as a dictionary or a ConvergenceParams object

clean_up() None#

Clean up by removing the trajectory file on disk

property conv_tol: ConvergenceParams#

All convergence parameters for this optimiser. If numerical values are unset, they appear as infinity.

Return type:

(ConvergenceParams)

property converged: bool#

Is this optimisation converged? Must be converged based on energy, gradient and step size criteria.

classmethod from_file(filename: str) NDOptimiser#

Create an optimiser from a trajectory file i.e. reload a saved state

classmethod optimise(species: Species, method: Method, n_cores: int | None = None, coords: OptCoordinates | None = None, maxiter: int = 100, conv_tol: ConvergenceParams | Literal['loose', 'normal', 'tight', 'verytight'] = 'normal', **kwargs) None#

Convenience function for constructing and running an optimiser

Parameters:
  • method (autode.methods.Method)

  • maxiter (int) – Maximum number of iteration to perform

  • conv_tol (ConvergenceParams|ConvergenceTolStr) – Convergence parameters for the absolute energy change, RMS and max gradient, and RMS and max step sizes.

  • coords (OptCoordinates | None) – Coordinates to optimise in

  • n_cores (int | None) – Number of cores to run energy/gradient/hessian evaluations. If None then use ade.Config.n_cores

  • kwargs (Any) – Additional keyword arguments to pass to the constructor

Raises:

(ValueError | RuntimeError)

property optimiser_params#

Optimiser params to save

plot_optimisation(filename: str | None = None, plot_energy: bool = True, plot_rms_grad: bool = True) None#

Draw the plot of the energies and/or rms_gradients of the optimisation so far

Parameters:
  • plot_energy (bool) – Whether to plot energy

  • plot_rms_grad (bool) – Whether to plot RMS of gradient

print_geometries(filename: str | None = None) None#

Writes the trajectory of the optimiser in .xyz format

Parameters:

filename (str|None) – Name of the trajectory file (xyz), if not given, generates name from species

class autode.opt.optimisers.base.NullOptimiser#

An optimiser that does nothing

property converged: bool#

Has this optimisation converged

property final_coordinates#
property last_energy_change: PotentialEnergy#

The energy change on between the final two optimisation cycles

run(**kwargs: Any) None#
class autode.opt.optimisers.base.Optimiser(maxiter: int, coords: OptCoordinates | None = None, callback: Callable | None = None, callback_kwargs: dict | None = None)#

Abstract base class for an optimiser

__init__(maxiter: int, coords: OptCoordinates | None = None, callback: Callable | None = None, callback_kwargs: dict | None = None)#

Optimiser

e.g. CartesianCoordinates. If None then will initialise the coordinates from _species

Parameters:
  • callback – Function that will be called after every step. First called after initialisation and before the first step. Takes the current coordinates (which have energy (e), gradient (g) and hessian (h) attributes) as the only positional argument

  • callback_kwargs – Keyword arguments to pass to the callback function

abstract _step() None#

Take a step with this optimiser. Should only act on self._coords using the gradient (self._coords.g) and hessians (self._coords.h)

abstract property converged: bool#

Has this optimisation converged

property final_coordinates: OptCoordinates | None#
property iteration: int#

Iteration of the optimiser, which is equal to the length of the history minus one, for zero indexing.

property last_energy_change: PotentialEnergy#

Last ∆E found in this

abstract classmethod optimise(species: Species, method: Method, n_cores: int | None = None, coords: OptCoordinates | None = None, **kwargs) None#

Optimise a species using a method

>>> import autode as ade
>>> mol = ade.Molecule(smiles='C')
>>> Optimiser.optimise(mol,method=ade.methods.ORCA())
property optimiser_params: dict#

The parameters which are needed to intialise the optimiser and will be saved in the optimiser trajectory

run(species: Species, method: Method, n_cores: int | None = None, name: str | None = None) None#

Run the optimiser. Updates species.atoms and species.energy

Calculations will use method.keywords.grad for gradient calculations

Parameters:
  • n_cores – Number of cores to use for calculations. If None then use autode.Config.n_cores

  • name – The name of the optimisation save file

class autode.opt.optimisers.base.OptimiserHistory(maxlen: int | None = 2)#

Sequential trajectory of coordinates with a maximum length for storage on memory. Shunts data to disk if trajectory file is opened, otherwise old coordinates more than the maximum number are lost.

__init__(maxlen: int | None = 2) None#
add(coords: OptCoordinates | None) None#

Add a new set of coordinates to this trajectory

Parameters:

coords (OptCoordinates) – The set of coordinates to be added

clean_up()#

Remove the disk file associated with this history

close()#

Close the Optimiser history by putting the coordinates still in memory onto disk

conv_params(idx: int = -1) ConvergenceParams#

Calculate the convergence parameters for the coordinates at specified index (default -1 i.e. the last set of coordinates)

Parameters:

idx (int) – Index of the set of coordinates for which to calculate the parameter

Return type:

(ConvergenceParams)

property final#

Last set of coordinates in memory

get_opt_params() dict#

Retrieve the stored optimiser parameters from the trajectory file

Returns:

Dictionary of optimiser parameters

Return type:

(dict)

classmethod load(filename: str)#

Reload the state of the trajectory from a file

Parameters:

filename – The name of the trajectory .zip file, could also be a relative path

Returns:

open(filename: str)#

Initialise the trajectory file and write it on disk.

Parameters:

filename (str) – The name of the trajectory file, should be .zip, and NOT a path

property penultimate#

Last but one set of coordinates from memory (the penultimate set)

save_opt_params(params: dict)#

Save optimiser parameters given as a dict into the trajectory savefile

Parameters:

params (dict)

autode.opt.optimisers.base.print_geometries_from(coords_trj: Iterator[OptCoordinates] | OptimiserHistory, species: Species, filename: str) None#

Print geometries from an iterator over a series of coordinates

Parameters:
  • coords_trj – The iterator for coordinates, can be OptimiserHistory

  • species – The Species for which the coordinate history is generated

  • filename – Name of file




class autode.opt.optimisers.rfo.RFOptimiser(*args, init_alpha: Distance | float = 0.1, **kwargs)#

Rational function optimisation in delocalised internal coordinates

__init__(*args, init_alpha: Distance | float = 0.1, **kwargs)#

Rational function optimiser (RFO) using a maximum step size of alpha

Parameters:
  • args – Additional arguments for NDOptimiser

  • kwargs – Additional keywords arguments for NDOptimiser

See also

NDOptimiser

_step() None#

RFO step




Partitioned rational function optimisation

class autode.opt.optimisers.prfo.PRFOptimiser(init_alpha: Distance | float = 0.05, recalc_hessian_every: int = 10, imag_mode_idx: int = 0, *args, **kwargs)#
__init__(init_alpha: Distance | float = 0.05, recalc_hessian_every: int = 10, imag_mode_idx: int = 0, *args, **kwargs)#

Partitioned rational function optimiser (PRFO) using a maximum step size of alpha trying to maximise along a mode while minimising along all others to locate a transition state (TS)


Parameters:
  • init_alpha – Maximum step size (default Å if unit not given)

  • imag_mode_idx – Index of the imaginary mode to follow. Default is 0th mode i.e. the most negative mode

See also

RFOOptimiser

_step() None#

Partitioned rational function step

property should_calculate_hessian: bool#

Should an explicit Hessian calculation be performed?
















class autode.opt.optimisers.hessian_update.BFGSDampedUpdate(min_eigenvalue: float = 1e-05, **kwargs)#

Powell damped BFGS update that ensures reasonable conditioning with the ‘positive definite’ conditions still imposed

property _updated_h: ndarray#

435–459 (10.1007/s12532-016-0101-2)

Type:

Powell damped BFGS from

Type:

Math. Prog. Comp. (2016) 8

class autode.opt.optimisers.hessian_update.BFGSPDUpdate(min_eigenvalue: float = 1e-05, **kwargs)#

BFGS update while ensuring positive definiteness

__init__(min_eigenvalue: float = 1e-05, **kwargs)#

Hessian updater

Keyword Arguments:
  • h_inv (np.ndarray) – Inverse Hessian (\(H^{-1}\)), shape = (N, N)

  • s (np.ndarray) – Coordinate shift. \(s = R_{i+1} - R_i\)

  • y (np.ndarray) – Gradient shift. \(y = \nabla E_{i+1} - \nabla E_i\)

  • subspace_idxs (list(int)) – Indexes of the components of the hessian to update

property conditions_met: bool#

Are all the conditions met to update the Hessian

class autode.opt.optimisers.hessian_update.BFGSSR1Update(**kwargs)#

Interpolates between BFGS and SR1 update in a fashion similar to Bofill updates, but suited for minimisations. Proposed by Farkas and Schlegel in J. Chem. Phys., 111, 1999, 10806

property _updated_h: ndarray#

Hybrid BFGS and SR1 update. The mixing parameter phi is defined as the square root of the (1 - phi_Bofill) used in Bofill update.

Returns:

The updated hessian

Return type:

(np.ndarray)

property _updated_h_inv: ndarray#

For BFGS-SR1 update, only hessian is available

property conditions_met: bool#

No conditions need to be satisfied for BFGS-SR1 update

class autode.opt.optimisers.hessian_update.BFGSUpdate(**kwargs)#
property _updated_h: ndarray#

Update the Hessian with a BFGS like update

\[H_{new} = H + \frac{y y^T}{y^T s} - \frac{H s s^T H} {s^T H s}\]
property _updated_h_inv#

Sherman–Morrison inverse matrix update

\[H_{new}^{-1} = H^{-1} + \frac{(s^Ty + y^T H^{-1} y) s^T s} {s^T y} - \frac{H^{-1} y s^T + s y^T H^{-1}} {s^T y}\]

where \(s = x_{l} - x_{l-1},\; \boldsymbol{y} = \nabla E_l - \nabla E_{l-1}\).

property conditions_met: bool#

BFGS update must meet the secant condition

class autode.opt.optimisers.hessian_update.BofillUpdate(**kwargs)#

Hessian update strategy suggested by Bofill[2] with notation taken from ref. [1].

[1] V. Bakken, T. Helgaker, JCP, 117, 9160, 2002 [2] J. M. Bofill, J. Comput. Chem., 15, 1, 1994

property _updated_h: ndarray#

Bofill Hessian update, interpolating between MS and PBS update strategies. Follows ref. [1] where the notation is

\[ \begin{align}\begin{aligned}h = \boldsymbol{G}_{i-1}\\y = \Delta\boldsymbol{g} = \boldsymbol{g}_i - \boldsymbol{g}_{i-1}\\s = \Delta\boldsymbol{x} = \boldsymbol{x}_i - \boldsymbol{x}_{i-1}\end{aligned}\end{align} \]
property _updated_h_inv: ndarray#

Updated inverse Hessian is available only from the updated H

property conditions_met: bool#

No conditions are need to be satisfied to perform a Bofill update, apart from that on the shapes of the vectors

min_update_tol = 1e-06#
class autode.opt.optimisers.hessian_update.FlowchartUpdate(**kwargs)#

A hybrid update scheme combining BFGS, SR1 and PSB Hessian update formulae. Proposed in A. B. Birkholz and H. B. Schlegel in Theor. Chem. Acc., 135 (84), 2016. This implementation is slightly modified.

property _updated_h: ndarray#

Flowchart (or FlowPSB) Hessian update scheme, that dynamically switches between BFGS and SR1 depending on some criteria.

Alternatively switches to PSB update as a fallback if none of the criteria are satisfied. Notation follows A. B. Birkholz, H. B. Schlegel, Theor. Chem. Acc., 135 (84), 2016.

Returns:

H

Return type:

(np.ndarray)

property _updated_h_inv: ndarray#

Flowchart update is only available for Hessian

property conditions_met: bool#

Flowchart update does not have any conditions, as update scheme is dynamically selected

class autode.opt.optimisers.hessian_update.HessianUpdater(**kwargs)#

Update strategy for the (inverse) Hessian matrix

__init__(**kwargs)#

Hessian updater

Keyword Arguments:
  • h_inv (np.ndarray) – Inverse Hessian (\(H^{-1}\)), shape = (N, N)

  • s (np.ndarray) – Coordinate shift. \(s = R_{i+1} - R_i\)

  • y (np.ndarray) – Gradient shift. \(y = \nabla E_{i+1} - \nabla E_i\)

  • subspace_idxs (list(int)) – Indexes of the components of the hessian to update

abstract property _updated_h: ndarray#

Calculate H

abstract property _updated_h_inv: ndarray#

Calculate H^{-1}

abstract property conditions_met: bool#

Are the conditions met to update the Hessian with this method?

property updated_h: ndarray#

Calculate H from a previous Hessian, coordinate shift and gradient shift

Raises:

(RuntimeError) – If the update fails

property updated_h_inv: ndarray#

Calculate H^{-1} from a previous inverse Hessian, coordinate shift and gradient shift

Raises:

(RuntimeError) – If the update fails

class autode.opt.optimisers.hessian_update.NullUpdate(**kwargs)#
property _updated_h: ndarray#

Updated H is just the input Hessian

property _updated_h_inv: ndarray#

Updated inverse H is just the input inverse Hessian

property conditions_met: bool#

Conditions are always met for a null optimiser

class autode.opt.optimisers.hessian_update.SR1Update(**kwargs)#
property _updated_h: ndarray#

Update H using a symmetric-rank 1 (SR1) update

\[H_{new} = H + \frac{(y- Hs)(y - Hs)^T} {(y- Hs)^T s}\]
property _updated_h_inv: ndarray#

Update H^-1 using a symmetric-rank 1 (SR1) update

\[H_{new}^{-1} = H^{-1} + \frac{(s- H^{-1}y)(s - H^{-1}y)^T} {(s- Hy)^T y}\]
property conditions_met: bool#

Condition for SR1 update. See: https://en.wikipedia.org/wiki/Symmetric_rank-one

\[|s (y - Hs)| \ge r ||s|| \cdot ||y - Hs||\]

where \(r \in (0, 1)\) = 1E-8.




Dimer method for finding transition states given two points on the PES. Notation follows 1. https://aip.scitation.org/doi/10.1063/1.2815812 based on 2. https://aip.scitation.org/doi/10.1063/1.2104507 3. https://aip.scitation.org/doi/10.1063/1.480097

class autode.opt.optimisers.dimer.Dimer(maxiter: int, coords: ~autode.opt.coordinates.dimer.DimerCoordinates, ratio_rot_iters: int = 10, gtol: float | ~autode.values.GradientRMS = RMS(∇E)(0.001 Ha(Å)^-1), trns_tol: ~autode.values.MWDistance = Mass-weighted Distance(0.001 Å amu^1/2), phi_tol: ~autode.values.Angle = Angle(5.0 °), init_alpha: ~autode.values.MWDistance = Mass-weighted Distance(0.3 Å amu^1/2))#

Dimer spanning two points on the PES with a TS at the midpoint

__init__(maxiter: int, coords: ~autode.opt.coordinates.dimer.DimerCoordinates, ratio_rot_iters: int = 10, gtol: float | ~autode.values.GradientRMS = RMS(∇E)(0.001 Ha(Å)^-1), trns_tol: ~autode.values.MWDistance = Mass-weighted Distance(0.001 Å amu^1/2), phi_tol: ~autode.values.Angle = Angle(5.0 °), init_alpha: ~autode.values.MWDistance = Mass-weighted Distance(0.3 Å amu^1/2))#

Dimer optimiser

the interpolated midpoint

Parameters:
  • ratio_rot_iters – Number of rotations per translation in each dimer step

  • gtol – Tolerance on the gradient at the midpoint for convergence

  • trns_tol – Tolerance on the minimum root mean square translation distance, below which convergence is signaled

  • phi_tol – Tolerance on the rotation angle below which rotation is not performed

  • init_alpha – Initial step size to use in mass-weighted cartesian coordinates

_step() None#

Do a single dimer optimisation step, consisting of several rotation and translation steps.

property converged: bool#

Has the dimer converged?

classmethod optimise(species: Species, method: Method, n_cores: int | None = None, coords: DimerCoordinates | None = None, **kwargs) None#

Optimise a dimer pair of coordinates such that the species coordinates are close to a transition state

Parameters:
  • n_cores – Number of cores to use for the optimisation

  • coords – Dimer coordinates