Standard method — full reference¶
This page documents the standard method (SM) for geometry optimization in sufficient detail to reimplement it from scratch. The SM was defined in the appendix of [BirkholzTCA16] as a reference algorithm against which various refinements are compared. The bulk of the formulas below are taken verbatim from that appendix; numbered equations match the original paper so that they can be cross-checked. Sections that the SM defers to other papers (RFO derivation, B-matrix derivatives, trust-region theory, Bofill update, recursive dihedrals) are filled in here with explicit formulas and cited sources.
How to read this page¶
Every block of formulas is self-contained; together they specify the algorithm completely.
Pale-yellow callouts flag places where the SM, or a paper it cites, leaves something unspecified.
Pale-blue callouts flag where PyBerny deviates from, or has not yet implemented, what the SM prescribes. The relevant source location is given when useful.
Note
This page is a specification of the SM. For a higher-level sketch of what PyBerny actually does (with links from each step into the code), see Algorithm.
Notation¶
— number of atoms; Cartesian degrees of freedom.
— Cartesian coordinates; the position of atom .
— redundant internal coordinates; an individual stretch, bend, or torsion.
(5 for linear molecules) — number of non-redundant internal degrees of freedom.
, — gradients in the two coordinate systems.
, — corresponding Hessian matrices.
For Hessian-update formulas, the shorthand of the SM is used:
where and analogously for the gradient.
Overview of one optimization step¶
Given the current Cartesian geometry , energy , and Cartesian gradient :
Build the Wilson B-matrix at (§B-matrix).
Compute the generalised inverse (§Generalised inverse).
Transform the gradient: (Eq. 20).
Update the internal-coordinate Hessian from (§Hessian update). On the first step, take a diagonal guess (§Initial Hessian).
Update the trust radius from the previous predicted vs. actual energy change (§Trust region).
Project gradient and Hessian into the non-redundant active space (§Projection).
Solve the rational-function (RFO) sub-problem for a step (§RFO step); enforce by a sphere-restricted minimisation if necessary.
Back-transform to Cartesians iteratively (§Back-transformation).
Test convergence (§Convergence). If not converged, set and repeat.
Coordinate definitions¶
Bond stretch¶
For atoms with positions :
B-matrix rows (gradients of w.r.t. ):
Bond angle¶
For atoms with central atom , define , :
B-matrix rows (Wilson, Decius & Cross [WilsonDeciusCross]; with , ):
Note (unspecified in [BirkholzTCA16]): the formulas above become singular at or . The SM handles by switching to the linear-bend coordinate system (see Linear bends); for no prescription is given.
Torsion (dihedral)¶
For atoms with central bond , write , , , . The components of perpendicular to are , . Then
Compact B-matrix rows, with , :
These formulas are due to Wilson [WilsonDeciusCross]; the compact form
above (avoiding singularities from the chain rule applied to
) follows Bakken & Helgaker [BakkenHelgaker02] and is
the form Schlegel reviews in [Schlegel1984]. PyBerny implements them
in berny.coords.Dihedral.eval() and includes the
limiting forms there.
Note: the SM appendix simply states that lies in
and does not say how to handle the
-wraparound during back-transformation, only that “some
care must be taken with dihedral angles to avoid extraneous multiples of
360°” (paraphrasing [PengJCC96]). PyBerny resolves this by comparing
each newly computed dihedral against a template and shifting by multiples
of as needed
(berny.coords.InternalCoords.eval_geom()).
Out-of-plane bends¶
The SM lists out-of-plane bends as an admissible coordinate but does not use them, observing that for molecules with more than 4 atoms the redundancy in the standard stretch/bend/torsion set already covers the relevant motions. PyBerny: same — no out-of-plane coordinates are generated.
Linear bends¶
When an angle exceeds 165° and the central atom 2 is bonded to fewer than 5 atoms, the SM replaces it by a dummy-atom construction:
Place a dummy atom d in the plane spanned by (arbitrary plane if the angle is exactly ) such that and equals a fixed constant ( in [BirkholzTCA16]; the choice is explicitly described as “more or less arbitrary”).
Replace by the equivalent sum .
Add the dihedrals and (for every neighbour of atom 1 and of atom 3) and the improper .
Constrain three coordinates per linear bend: , , and one dihedral chosen so that every dummy atom appears in at least one constraint (when only three atoms are involved, the improper is used as the arbitrary dihedral).
The constrained transformation uses a projected B-matrix
assuming that gradient and Hessian elements on dummy atoms are zero. If analytic B-matrix derivatives are used (e.g. for Hessian transformation) they are projected analogously:
The back-transformation is done unconstrained with goal values for the constrained coordinates set to their current values; a second iterative back-transformation (moving only the dummy atom) re-imposes the dihedral constraint if needed.
Not implemented in PyBerny. Linear-bend handling via dummy atoms is
open issue
#30. PyBerny currently
just skips dihedrals through nearly-linear angles (within
of or ; see lin_thre in
berny.coords.get_dihedrals()) via a recursive “chain through the
linear atom” rule (see Construction of the coordinate set), which
works for most cases but is not equivalent to the SM treatment.
Construction of the coordinate set¶
Important caveat: the SM explicitly does not specify a connectivity-detection rule — in [BirkholzTCA16] connectivity was provided manually for every test molecule. The remainder of this sub-section follows the canonical Peng/Ayala/Schlegel/Frisch construction ([PengJCC96]), which is what PyBerny implements.
Bonds. A pair is bonded iff . PyBerny: additional pseudo-bonds are added between disconnected fragments (van-der-Waals radii, gradually inflated) until the molecular graph is connected — this part is a PyBerny choice not present in either the SM or [PengJCC96].
Angles. For each atom , every pair of atoms bonded to defines a candidate angle. PyBerny keeps only angles with .
Dihedrals. For each pair of angles sharing a bond, the corresponding dihedral is added if both 1-2-3 and 2-3-4 angles exceed . If one of those angles is (close to) zero, so that three atoms lie on a line, those three are used as a new base and the search recurses through the linear atom ([PengJCC96]).
Crystal cells. PyBerny-only: for periodic systems, only the periodic image of each internal coordinate closest to the original unit cell is kept.
B-matrix¶
Definition (Eq. 14):
is . Rows are populated by the per-coordinate gradients given in Coordinate definitions.
Generalised inverse¶
is rectangular and rank-deficient (rank ). Two equivalent ways are given in the SM.
Penalty form (Eqs. 15–18)¶
Add a projector onto the 6-dimensional translation-rotation space of :
with, for atom ,
where is the unit vector along Cartesian axis . These vectors span (but are not orthonormal in) the rigid-body subspace. The generalised inverse is
The benefit of this form is that is invertible and amenable to iterative inversion for large systems.
SVD form (Eq. 19)¶
Let be the SVD, with of size , of size , and zero everywhere except for the first diagonal elements. Then
where for non-zero singular values and otherwise. A side benefit is that the active space is read off as the first rows of .
PyBerny variant: instead of either Eq. 18 or Eq. 19 directly,
PyBerny computes
where
is the Moore-Penrose pseudoinverse via SVD with
a gap-based threshold (berny.Math.pinv(),
berny.py:162). This is equivalent at the level of the gradient
transformation that follows, but it does not compute the SM active
space; the projector is used instead, see
Projection.
Gradient and Hessian transformation (Eqs. 20-21)¶
From the chain rule :
For a Cartesian Hessian:
PyBerny note: PyBerny never computes (it only consumes Cartesian gradients) and so Eq. 21 is never invoked. The Hessian is maintained in internal coordinates from step 1, starting from the diagonal guess of Initial Hessian and updated by BFGS thereafter (see Hessian update).
Projection¶
With the active space (top rows of from the SVD), the SM projects gradient and Hessian into the non-redundant subspace:
The step is computed in this reduced space and lifted back via
PyBerny variant — penalty projector from [PengJCC96]. PyBerny does not compute . Instead it forms the projector
and uses the augmented Hessian
(Peng et al., Eq. 9 with au). The
penalty drives the step out of the redundant subspace and is
mathematically equivalent to projecting into the active space when
is large enough relative to the eigenvalues of
([PengJCC96]). The hard-coded constant 1000 a.u. is at
berny.py:191.
RFO step¶
The SM uses rational-function optimisation [BanerjeeJPC85] to compute the step. The PES is approximated locally as
with taken for convenience. The stationary points of Eq. 24 are exactly the eigenvectors of the augmented Hessian
If is the -th eigenpair of , the step is
or, equivalently,
with
For a minimum the most negative eigenvalue of is selected; the resulting is negative and shifts to a positive-definite operator, so Eq. 27 yields a descent step even when itself has negative eigenvalues.
Trust-region restriction¶
If the pure RFO step satisfies , accept it as is. Otherwise solve the sphere-restricted minimisation of Eq. 27, i.e. find the largest for which
and use . PyBerny solves this
1-D equation with a Newton iteration
(berny.Math.findroot()).
Transition states (partitioned RFO)¶
For TS optimisation the SM uses partitioned RFO (pRFO, [BanerjeeJPC85], [Baker1996]): the Hessian is split into an -dimensional minimisation subspace and a 1-D maximisation subspace (usually the eigenvector to be followed uphill), each handled by its own augmented-Hessian sub-problem.
Unspecified in [BirkholzTCA16]: which eigenvector to follow at each step. The SM notes only “usually selected to be eigenvectors of the Hessian”. The original references give detailed eigenvector-mode following rules.
Not implemented in PyBerny. Only minimisation is supported. TS support is part of open issue #29.
Trust region¶
Initial value¶
SM: bohr or rad. PyBerny default:
(berny.BernyParams).
Adaptive update¶
Let
be the quadratic energy change predicted at the previous step, and the actual change observed at the current step. Define the ratio
Update according to:
if and , ;
if , ;
otherwise (implicit in [BirkholzTCA16]): is left unchanged. See [Fletcher00] §5.1 and [DennisSchnabel83] ch. 6 for the theoretical background of these thresholds.
PyBerny deviation: PyBerny implements the branch
exactly as written above, but the upper branch is stricter than the
SM rule. Instead of , PyBerny tests
abs(norm(dq) - trust) < 1e-10 (berny.berny.update_trust()),
which is true only when the previous step landed essentially exactly
on the trust sphere — i.e. when the sphere-restricted minimisation was
actually triggered. Consequently, well-predicted but interior steps
(e.g. with from a
pure RFO solve) grow under the SM rule but leave it
unchanged in PyBerny.
Hessian update¶
Define , , .
BFGS (Eq. 29)¶
Standard choice for minimisation. The update is reliable as long as and remains positive definite.
SR1 / Murtagh-Sargent (Eq. 30)¶
Produces good updates when the change in is large; unstable when is small relative to .
PSB (Eq. 31)¶
Very stable, but updates tend to be small/poor for large Hessian changes.
Bofill / MSP (Eqs. 32-33)¶
This is the [Bofill1994] φ-mixed combination, recommended by the SM for transition-state work.
PyBerny: only BFGS is implemented
(berny.berny.update_hessian(),
berny.py:223). SR1, PSB, and MSP are not available. The SM
itself uses BFGS for minimisations, so for minima PyBerny is in line
with the SM; for transition states the lack of MSP is one of several
missing pieces (see RFO step).
Back-transformation¶
Given a step in internal coordinates at Cartesian geometry , the corresponding Cartesian displacement is defined as the minimiser of the functional
This is solved by the fixed-point iteration
The SM converges when RMS.
PyBerny: capped at 20 iterations; if it does not converge,
PyBerny falls back to the first-iteration estimate
(berny.coords.InternalCoords.update_geom()). This fallback is the
same as that suggested by [PengJCC96] (“in the rare cases in which the
iteration does not converge”). Note that PyBerny’s threshold is
rather than — i.e.
~1.89× looser than the SM in absolute terms.
Initial Hessian¶
The SM appendix is silent on the initial-Hessian model. In the test calculations of [BirkholzTCA16] no extrapolation or multi-step-history updating was used; the Hessian was updated using “only the information at the current point and the most recent point”, but the starting Hessian model is not specified.
PyBerny fills this gap with a Lindh-style diagonal guess ([SwartIJQC06]), expressed in terms of the screening function
so that is at zero distance, at covalent contact, and decays for weak/non-bonded pairs. Diagonal entries are
The prefactors 0.45 / 0.15 / 0.005 are the original Lindh values quoted
in [SwartIJQC06]; PyBerny implements these in
berny.coords.Bond.hessian() and siblings.
Convergence¶
The SM uses the same four-criterion test as Gaussian 09:
RMS internal-coord. step |
bohr/rad |
max |
bohr/rad |
RMS gradient (active space) |
Eh/bohr or Eh/rad |
max gradient (active space) |
Eh/bohr or Eh/rad |
All four must be satisfied simultaneously. The defaults in
berny.BernyParams reproduce these thresholds exactly. When the
sphere-restricted minimisation was triggered on a step, the step-based
criteria are by construction not satisfied; PyBerny then skips the
step-based criteria and demands the gradient-based criteria only
(berny.berny.is_converged()).
Coordinate weighting¶
Not in the SM. PyBerny computes per-coordinate weights derived
from the same screening function ([SwartIJQC06];
see berny.coords.Angle.weight() etc.) and threads them through
to the step-computation routine. However, they are currently not
consumed by the RFO / sphere-restricted-minimisation step
(berny.berny.quadratic_step() receives but ignores them). So in
practice PyBerny’s behaviour matches the SM here; this is a latent
extension point.
Linear search¶
Not in the SM. The SM appendix explicitly notes that “no extrapolation methods were employed” for the test calculations.
PyBerny extension (berny.berny.linear_search()): between
the current point and the best point so far, PyBerny fits a constrained
quartic polynomial to at both endpoints. If the
quartic has a usable minimum on , that
-value is used to interpolate energy and gradient; otherwise
a cubic fit is tried on ; if both fail, the
better-energy endpoint is kept. The interpolated point is then used as
the expansion origin for the RFO step. See the Gaussian
opt documentation, “If a minimum is sought…”, for the original
rationale.
PyBerny vs. SM at a glance¶
Aspect |
SM ([BirkholzTCA16]) |
PyBerny |
|---|---|---|
Coordinate set |
stretches / bends / torsions |
stretches / bends / torsions |
Out-of-plane bends |
not used |
not used |
Linear bends |
dummy-atom construction |
not implemented (issue #30) |
Bond detection |
manual |
plus a vdW shell that grows by 1 Å until cluster fragments are connected |
Initial Hessian |
unspecified |
Lindh diagonal with screening |
B-matrix |
Eq. 14 |
same |
Eq. 18 or Eq. 19 |
via SVD |
|
Active space |
from SVD |
projector + 1000 a.u. penalty |
Hessian transformation (Cart→int) |
Eq. 21 |
never computed (internal-only Hessian) |
RFO step |
Eqs. 24-28 |
same |
Trust region |
adaptive (75/25 rule), |
same rule, |
Sphere-restricted step |
Lagrange-multiplier shift |
same (Newton 1-D root find) |
TS optimisation (pRFO) |
specified |
not implemented (issue #29) |
Hessian update (minima) |
BFGS |
BFGS |
Hessian update (TS) |
BFGS / SR1 / PSB / MSP |
only BFGS available |
Back-transformation |
Eqs. 22-23, RMS Δx |
20-iteration cap, Peng fallback to first estimate |
Convergence criteria |
4 thresholds |
same |
Line search |
not used |
quartic-then-cubic between best and current |
Additional references¶
In addition to the references defined in Algorithm, this page cites:
Wilson, E. B., Decius, J. C. & Cross, P. C. Molecular Vibrations: The Theory of Infrared and Raman Vibrational Spectra. McGraw-Hill (1955). Original source of the Wilson B-matrix and the analytic gradients of stretch / bend / torsion coordinates.
Bakken, V. & Helgaker, T. The efficient optimization of molecular geometries using redundant internal coordinates. J. Chem. Phys. 117, 9160 (2002). Source of the compact, non-singular form of the torsion B-matrix rows used here.
Schlegel, H. B. Estimating the Hessian for gradient-type geometry optimizations. Theor. Chim. Acta 66, 333 (1984). Reviews the analytic B-matrix derivatives for stretch/bend/torsion coordinates (originally due to Wilson [WilsonDeciusCross]).
Bofill, J. M. Updated Hessian matrix and the restricted step method for locating transition structures. J. Comput. Chem. 15(1):1 (1994). Source of the MSP / “Bofill” Hessian update.
Baker, J. & Chan, F. The location of transition states: a comparison of cartesian, Z-matrix, and natural internal coordinates. J. Comput. Chem. 17(7):888 (1996). Eigenvector-following for TS optimisation.
Dennis, J. E. & Schnabel, R. B. Numerical Methods for Unconstrained Optimization and Nonlinear Equations. Prentice-Hall (1983). Chapter 6 covers adaptive trust-region theory.