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

  • NN — number of atoms; ncrt=3Nn_\text{crt}=3N Cartesian degrees of freedom.

  • xRncrtx\in\mathbb R^{n_\text{crt}} — Cartesian coordinates; xkR3x_k\in\mathbb R^3 the position of atom kk.

  • qRnricq\in\mathbb R^{n_\text{ric}} — redundant internal coordinates; qiq_i an individual stretch, bend, or torsion.

  • nact=ncrt6n_\text{act}=n_\text{crt}-6 (5 for linear molecules) — number of non-redundant internal degrees of freedom.

  • gx=E/xg_x = \partial E/\partial x, gq=E/qg_q = \partial E/\partial q — gradients in the two coordinate systems.

  • HxH_x, HqH_q — corresponding Hessian matrices.

  • For Hessian-update formulas, the shorthand of the SM is used:

    s=Δq,y=Δgq,z=yHs,s = \Delta q,\qquad y = \Delta g_q,\qquad z = y - H\,s,

    where Δq=q(n+1)q(n)\Delta q = q^{(n+1)}-q^{(n)} and analogously for the gradient.

Overview of one optimization step

Given the current Cartesian geometry x(n)x^{(n)}, energy E(n)E^{(n)}, and Cartesian gradient gx(n)g_x^{(n)}:

  1. Build the Wilson B-matrix at x(n)x^{(n)}B-matrix).

  2. Compute the generalised inverse BB^-Generalised inverse).

  3. Transform the gradient: gq=(B)Tgxg_q = (B^-)^\mathrm T g_x (Eq. 20).

  4. Update the internal-coordinate Hessian HH from (s,y)=(q(n)q(n1),gq(n)gq(n1))(s,y) = (q^{(n)}-q^{(n-1)}, g_q^{(n)}-g_q^{(n-1)})Hessian update). On the first step, take a diagonal guess (§Initial Hessian).

  5. Update the trust radius τ\tau from the previous predicted vs. actual energy change (§Trust region).

  6. Project gradient and Hessian into the non-redundant active space (§Projection).

  7. Solve the rational-function (RFO) sub-problem for a step Δqr\Delta q^\mathrm{r}RFO step); enforce Δqrτ\|\Delta q^\mathrm{r}\|\le\tau by a sphere-restricted minimisation if necessary.

  8. Back-transform Δqr\Delta q^\mathrm{r} to Cartesians iteratively (§Back-transformation).

  9. Test convergence (§Convergence). If not converged, set nn+1n\leftarrow n+1 and repeat.

Coordinate definitions

Bond stretch

For atoms i,ji,j with positions xi,xjR3x_i,x_j\in\mathbb R^3:

rij  =  xixj.r_{ij} \;=\; \|x_i - x_j\|.

B-matrix rows (gradients of rijr_{ij} w.r.t. xi,xjx_i,x_j):

rijxi=xixjrij,rijxj=xixjrij.\frac{\partial r_{ij}}{\partial x_i} = \frac{x_i-x_j}{r_{ij}},\qquad \frac{\partial r_{ij}}{\partial x_j} = -\frac{x_i-x_j}{r_{ij}}.

Bond angle

For atoms i,j,ki,j,k with central atom jj, define v1=xixjv_1 = x_i-x_j, v2=xkxjv_2 = x_k-x_j:

cosθijk  =  v1v2v1v2,0θijkπ.\cos\theta_{ijk} \;=\; \frac{v_1\cdot v_2}{\|v_1\|\,\|v_2\|},\qquad 0 \le \theta_{ijk} \le \pi.

B-matrix rows (Wilson, Decius & Cross [WilsonDeciusCross]; with e^1=v1/v1\hat e_1=v_1/\|v_1\|, e^2=v2/v2\hat e_2=v_2/\|v_2\|):

θxi=cosθe^1e^2v1sinθ,θxk=cosθe^2e^1v2sinθ,θxj=θxiθxk.\begin{aligned} \frac{\partial\theta}{\partial x_i} &= \frac{\cos\theta\,\hat e_1 - \hat e_2}{\|v_1\|\sin\theta}, \\ \frac{\partial\theta}{\partial x_k} &= \frac{\cos\theta\,\hat e_2 - \hat e_1}{\|v_2\|\sin\theta}, \\ \frac{\partial\theta}{\partial x_j} &= -\frac{\partial\theta}{\partial x_i} - \frac{\partial\theta}{\partial x_k}. \end{aligned}

Note (unspecified in [BirkholzTCA16]): the formulas above become singular at θ=0\theta=0 or π\pi. The SM handles θπ\theta\to\pi by switching to the linear-bend coordinate system (see Linear bends); for θ0\theta\to 0 no prescription is given.

Torsion (dihedral)

For atoms i,j,k,li,j,k,l with central bond j ⁣ ⁣kj\!-\!k, write v1=xixjv_1=x_i-x_j, v2=xlxkv_2=x_l-x_k, w=xkxjw=x_k-x_j, e^w=w/w\hat e_w=w/\|w\|. The components of v1,v2v_1,v_2 perpendicular to ww are a1=v1(v1 ⁣e^w)e^wa_1 = v_1-(v_1\!\cdot\hat e_w)\hat e_w, a2=v2(v2 ⁣e^w)e^wa_2 = v_2-(v_2\!\cdot\hat e_w)\hat e_w. Then

cosφijkl=a1a2a1a2,sgnφ=sgndet[v2,v1,w],π<φijklπ.\cos\varphi_{ijkl} = \frac{a_1\cdot a_2}{\|a_1\|\,\|a_2\|},\qquad \mathrm{sgn}\,\varphi = \mathrm{sgn}\,\det[v_2,v_1,w],\qquad -\pi < \varphi_{ijkl} \le \pi.

Compact B-matrix rows, with A=(v1 ⁣e^w)/wA=(v_1\!\cdot\hat e_w)/\|w\|, B=(v2 ⁣e^w)/wB=(v_2\!\cdot\hat e_w)/\|w\|:

φxi=cotφa1a12a2a1a2sinφ,φxl=cotφa2a22a1a1a2sinφ,φxj=(1A)a2Ba1a1a2sinφcotφ[(1A)a1a12Ba2a22],φxk=(1+B)a1+Aa2a1a2sinφcotφ[(1+B)a2a22+Aa1a12].\begin{aligned} \frac{\partial\varphi}{\partial x_i} &= \cot\varphi\,\frac{a_1}{\|a_1\|^2} - \frac{a_2}{\|a_1\|\|a_2\|\sin\varphi}, \\ \frac{\partial\varphi}{\partial x_l} &= \cot\varphi\,\frac{a_2}{\|a_2\|^2} - \frac{a_1}{\|a_1\|\|a_2\|\sin\varphi}, \\ \frac{\partial\varphi}{\partial x_j} &= \frac{(1-A)\,a_2 - B\,a_1}{\|a_1\|\|a_2\|\sin\varphi} - \cot\varphi\left[(1-A)\frac{a_1}{\|a_1\|^2} - B\frac{a_2}{\|a_2\|^2}\right], \\ \frac{\partial\varphi}{\partial x_k} &= \frac{(1+B)\,a_1 + A\,a_2}{\|a_1\|\|a_2\|\sin\varphi} - \cot\varphi\left[(1+B)\frac{a_2}{\|a_2\|^2} + A\frac{a_1}{\|a_1\|^2}\right]. \end{aligned}

These formulas are due to Wilson [WilsonDeciusCross]; the compact form above (avoiding singularities from the chain rule applied to arccos\arccos) follows Bakken & Helgaker [BakkenHelgaker02] and is the form Schlegel reviews in [Schlegel1984]. PyBerny implements them in berny.coords.Dihedral.eval() and includes the φ0,±π\varphi\to 0,\pm\pi limiting forms there.

Note: the SM appendix simply states that φ\varphi lies in (π,π](-\pi,\pi] and does not say how to handle the ±π\pm\pi-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 π\pi 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 θ123\theta_{123} 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 r12,r23r_{12}, r_{23} (arbitrary plane if the angle is exactly π\pi) such that θ12d=θ32d\theta_{12d}=\theta_{32d} and r2dr_{2d} equals a fixed constant (2a02\,a_0 in [BirkholzTCA16]; the choice is explicitly described as “more or less arbitrary”).

  • Replace θ123\theta_{123} by the equivalent sum θ12d+θ32d\theta_{12d}+\theta_{32d}.

  • Add the dihedrals φn12d\varphi_{n12d} and φd23m\varphi_{d23m} (for every neighbour nn of atom 1 and mm of atom 3) and the improper φ12d3\varphi_{12d3}.

  • Constrain three coordinates per linear bend: r2dr_{2d}, θ12dθ32d\theta_{12d}-\theta_{32d}, and one dihedral chosen so that every dummy atom appears in at least one constraint (when only three atoms are involved, the improper φ12d3\varphi_{12d3} is used as the arbitrary dihedral).

The constrained transformation uses a projected B-matrix

Bprj  =  BoptBoptBconstrBconstr,B_\text{prj} \;=\; B_\text{opt} - B_\text{opt}\,B_\text{constr}^-\,B_\text{constr},

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:

[Bprj]i  =  (IBcnsBcns)[Bopt]i(IBcnsBcns).[\partial B_\text{prj}]_i \;=\; (I - B_\text{cns}^-\,B_\text{cns})\,[\partial B_\text{opt}]_i\,(I - B_\text{cns}^-\,B_\text{cns}).

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 5° of 00 or π\pi; 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.

  1. Bonds. A pair (i,j)(i,j) is bonded iff rij<1.3(Ricov+Rjcov)r_{ij} < 1.3\,(R_i^\text{cov}+R_j^\text{cov}). 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].

  2. Angles. For each atom jj, every pair (i,k)(i,k) of atoms bonded to jj defines a candidate angle. PyBerny keeps only angles with θijk>π/4\theta_{ijk}>\pi/4.

  3. 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 π/4\pi/4. 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]).

  4. 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):

Bia  =  qixa    δqi=aBiaδxa.B_{ia} \;=\; \frac{\partial q_i}{\partial x_a}\;\Longrightarrow\; \delta q_i = \sum_a B_{ia}\,\delta x_a.

BB is nric×ncrtn_\text{ric}\times n_\text{crt}. Rows are populated by the per-coordinate gradients given in Coordinate definitions.

Generalised inverse

BB is rectangular and rank-deficient (rank nact=ncrt6n_\text{act}=n_\text{crt}-6). Two equivalent ways are given in the SM.

Penalty form (Eqs. 15–18)

Add a projector onto the 6-dimensional translation-rotation space of BTBB^\mathrm T B:

PTR  =  i=13(titiT+ririT)(Eq. 15)P_\text{TR} \;=\; \sum_{i=1}^{3}\Bigl(t_i t_i^\mathrm T + r_i r_i^\mathrm T\Bigr) \qquad\text{(Eq. 15)}

with, for atom kk,

ti,k=ei,ri,k=xk×ei(Eqs. 16-17)t_{i,k} = e_i,\qquad r_{i,k} = x_k\times e_i \qquad\text{(Eqs. 16-17)}

where eie_i is the unit vector along Cartesian axis ii. These vectors span (but are not orthonormal in) the rigid-body subspace. The generalised inverse is

B  =  (BTB+PTR)1BT.(Eq. 18)B^- \;=\; \bigl(B^\mathrm T B + P_\text{TR}\bigr)^{-1} B^\mathrm T. \qquad\text{(Eq. 18)}

The benefit of this form is that BTB+PTRB^\mathrm T B + P_\text{TR} is invertible and amenable to iterative inversion for large systems.

SVD form (Eq. 19)

Let B=UΣVTB = U\,\Sigma\,V^\mathrm T be the SVD, with UU of size nricn_\text{ric}, VV of size ncrtn_\text{crt}, and Σ\Sigma zero everywhere except for the first nactn_\text{act} diagonal elements. Then

B  =  VΣUT,(Eq. 19)B^- \;=\; V\,\Sigma^-\,U^\mathrm T, \qquad\text{(Eq. 19)}

where Σii=1/Σii\Sigma^-_{ii}=1/\Sigma_{ii} for non-zero singular values and 00 otherwise. A side benefit is that the active space is read off as the first nactn_\text{act} rows of UU.

PyBerny variant: instead of either Eq. 18 or Eq. 19 directly, PyBerny computes B=BT(BBT)+B^- = B^\mathrm T\bigl(B B^\mathrm T\bigr)^+ where (BBT)+(B B^\mathrm T)^+ 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 P=BBP = B B^- is used instead, see Projection.

Gradient and Hessian transformation (Eqs. 20-21)

From the chain rule gx=BTgqg_x = B^\mathrm T g_q:

gq  =  (B)Tgx.(Eq. 20)g_q \;=\; (B^-)^\mathrm T g_x. \qquad\text{(Eq. 20)}

For a Cartesian Hessian:

Hq  =  (B)T ⁣(HxgqTBx) ⁣B.(Eq. 21)H_q \;=\; (B^-)^\mathrm T\! \left(H_x - g_q^\mathrm T\,\frac{\partial B}{\partial x}\right)\!B^-. \qquad\text{(Eq. 21)}

PyBerny note: PyBerny never computes HxH_x (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 UactU_\text{act} (top nactn_\text{act} rows of UU from the SVD), the SM projects gradient and Hessian into the non-redundant subspace:

gr=Uactgq,Hr=UactHqUactT.g_\text{r} = U_\text{act}\,g_q,\qquad H_\text{r} = U_\text{act}\,H_q\,U_\text{act}^\mathrm T.

The step Δqr\Delta q^\mathrm{r} is computed in this reduced space and lifted back via

Δq0  =  UactTΔqr.\Delta q_0 \;=\; U_\text{act}^\mathrm T\,\Delta q^\mathrm{r}.

PyBerny variant — penalty projector from [PengJCC96]. PyBerny does not compute UactU_\text{act}. Instead it forms the projector

P  =  BB=(B)TBT,P \;=\; B\,B^- = (B^-)^\mathrm T B^\mathrm T,

and uses the augmented Hessian

Hproj  =  PHP+α(IP),α=1000  a.u.H_\text{proj} \;=\; P\,H\,P + \alpha\,(I - P),\qquad \alpha=1000\;\text{a.u.}

(Peng et al., Eq. 9 with α=1000\alpha=1000 au). The α(IP)\alpha(I-P) penalty drives the step out of the redundant subspace and is mathematically equivalent to projecting into the active space when α\alpha is large enough relative to the eigenvalues of HH ([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

ERF(q0+Δq)  =  E0+ΔqTg0+12ΔqTH0Δq1+ΔqTSΔq,(Eq. 24)E_\text{RF}(q_0+\Delta q) \;=\; E_0 + \frac{\Delta q^\mathrm T g_0 + \tfrac12 \Delta q^\mathrm T H_0\,\Delta q} {1 + \Delta q^\mathrm T S\,\Delta q}, \qquad\text{(Eq. 24)}

with S=IS = I taken for convenience. The n+1n+1 stationary points of Eq. 24 are exactly the eigenvectors of the augmented Hessian

Haug  =  (HggT0).(Eq. 25)H_\text{aug} \;=\; \begin{pmatrix} H & g \\ g^\mathrm T & 0 \end{pmatrix}. \qquad\text{(Eq. 25)}

If (vm,λm)(v_m,\lambda_m) is the mm-th eigenpair of HaugH_\text{aug}, the step is

ΔqRFO,m  =  1vm,n+1(vm,1,vm,2,,vm,n)T,(Eq. 26)\Delta q_{\text{RFO},m} \;=\; \frac{1}{v_{m,n+1}}\bigl(v_{m,1},v_{m,2},\dots,v_{m,n}\bigr)^\mathrm T, \qquad\text{(Eq. 26)}

or, equivalently,

ΔqRFO,m  =  (HλmI)1g(Eq. 27),\Delta q_{\text{RFO},m} \;=\; -(H - \lambda_m I)^{-1} g \qquad\text{(Eq. 27)},

with

λm  =  ΔqRFO,mTg.(Eq. 28)\lambda_m \;=\; \Delta q_{\text{RFO},m}^\mathrm T\,g. \qquad\text{(Eq. 28)}

For a minimum the most negative eigenvalue of HaugH_\text{aug} is selected; the resulting λm\lambda_m is negative and shifts HH to a positive-definite operator, so Eq. 27 yields a descent step even when HH itself has negative eigenvalues.

Trust-region restriction

If the pure RFO step satisfies Δqτ\|\Delta q\|\le\tau, accept it as is. Otherwise solve the sphere-restricted minimisation of Eq. 27, i.e. find the largest λ<λmin(H)\lambda<\lambda_\text{min}(H) for which

(λIH)1g  =  τ,\bigl\|(\lambda I - H)^{-1} g\bigr\| \;=\; \tau,

and use Δq=(λIH)1g\Delta q = (\lambda I - H)^{-1} g. 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 (n1)(n-1)-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: τ0=0.5\tau_0 = 0.5 bohr or rad. PyBerny default: τ0=0.3\tau_0 = 0.3 (berny.BernyParams).

Adaptive update

Let

ΔEquad  =  ΔqTg+12ΔqTHΔq\Delta E_\text{quad} \;=\; \Delta q^\mathrm T g + \tfrac12\,\Delta q^\mathrm T H\,\Delta q

be the quadratic energy change predicted at the previous step, and ΔEact\Delta E_\text{act} the actual change observed at the current step. Define the ratio

r  =  ΔEactΔEquad.r \;=\; \frac{\Delta E_\text{act}}{\Delta E_\text{quad}}.

Update τ\tau according to:

  • if r>0.75r > 0.75 and Δq0.8τ\|\Delta q\| \ge 0.8\,\tau, τ2τ\tau \leftarrow 2\tau;

  • if r<0.25r < 0.25, τ14Δq\tau \leftarrow \tfrac14\,\|\Delta q\|;

  • otherwise (implicit in [BirkholzTCA16]): τ\tau is left unchanged. See [Fletcher00] §5.1 and [DennisSchnabel83] ch. 6 for the theoretical background of these thresholds.

PyBerny deviation: PyBerny implements the r<0.25r<0.25 branch exactly as written above, but the upper branch is stricter than the SM rule. Instead of Δq0.8τ\|\Delta q\|\ge 0.8\,\tau, 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. r>0.75r>0.75 with Δq0.85τ\|\Delta q\|\approx 0.85\,\tau from a pure RFO solve) grow τ\tau under the SM rule but leave it unchanged in PyBerny.

Hessian update

Define s=Δqs = \Delta q, y=Δgqy = \Delta g_q, z=yHsz = y - H s.

BFGS (Eq. 29)

ΔHBFGS  =  yyTyTsHssTHsTHs.\Delta H_\text{BFGS} \;=\; \frac{y\,y^\mathrm T}{y^\mathrm T s} - \frac{H\,s\,s^\mathrm T H}{s^\mathrm T H s}.

Standard choice for minimisation. The update is reliable as long as sTy>0s^\mathrm T y > 0 and HH remains positive definite.

SR1 / Murtagh-Sargent (Eq. 30)

ΔHSR1  =  zzTzTs.\Delta H_\text{SR1} \;=\; \frac{z\,z^\mathrm T}{z^\mathrm T s}.

Produces good updates when the change in HH is large; unstable when sTzs^\mathrm T z is small relative to zTzz^\mathrm T z.

PSB (Eq. 31)

ΔHPSB  =  szT+zsTsTs(sTz)ssT(sTs)2.\Delta H_\text{PSB} \;=\; \frac{s\,z^\mathrm T + z\,s^\mathrm T}{s^\mathrm T s} - \frac{(s^\mathrm T z)\,s\,s^\mathrm T}{(s^\mathrm T s)^2}.

Very stable, but updates tend to be small/poor for large Hessian changes.

Bofill / MSP (Eqs. 32-33)

ΔHMSP  =  ϕMSPΔHSR1+(1ϕMSP)ΔHPSB,ϕMSP  =  (sTz)2(zTz)(sTs).\Delta H_\text{MSP} \;=\; \phi_\text{MSP}\,\Delta H_\text{SR1} + (1-\phi_\text{MSP})\,\Delta H_\text{PSB}, \qquad \phi_\text{MSP} \;=\; \frac{(s^\mathrm T z)^2}{(z^\mathrm T z)\,(s^\mathrm T s)}.

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 Δq0\Delta q_0 in internal coordinates at Cartesian geometry x0x_0, the corresponding Cartesian displacement is defined as the minimiser of the functional

F(x0+Δx)  =  12q0+Δq0q(x0+Δx)2.(Eq. 22)F(x_0 + \Delta x) \;=\; \tfrac12\bigl\|q_0 + \Delta q_0 - q(x_0+\Delta x)\bigr\|^2. \qquad\text{(Eq. 22)}

This is solved by the fixed-point iteration

xi+1  =  xi+BiΔqi,Δqi+1  =  Δqi(q(xi+1)q(xi)).(Eq. 23)x_{i+1} \;=\; x_i + B_i^-\,\Delta q_i,\qquad \Delta q_{i+1} \;=\; \Delta q_i - \bigl(q(x_{i+1}) - q(x_i)\bigr). \qquad\text{(Eq. 23)}

The SM converges when RMS(Δxi)<106  a0(\Delta x_i)<10^{-6}\;a_0.

PyBerny: capped at 20 iterations; if it does not converge, PyBerny falls back to the first-iteration estimate x0+B0Δq0x_0 + B_0^- \Delta q_0 (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 106A˚10^{-6}\,\text{Å} rather than 106a010^{-6}\,a_0 — 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

ρij  =  exp ⁣(1rijRicov+Rjcov),\rho_{ij} \;=\; \exp\!\left(1 - \frac{r_{ij}}{R_i^\text{cov} + R_j^\text{cov}}\right),

so that ρij\rho_{ij} is e2.72e\approx 2.72 at zero distance, 11 at covalent contact, and decays for weak/non-bonded pairs. Diagonal entries are

kbond=0.45ρij,kangle=0.15ρijρjk,kdihedral=0.005ρijρjkρkl.\begin{aligned} k_\text{bond} &= 0.45\,\rho_{ij}, \\ k_\text{angle} &= 0.15\,\rho_{ij}\,\rho_{jk}, \\ k_\text{dihedral} &= 0.005\,\rho_{ij}\,\rho_{jk}\,\rho_{kl}. \end{aligned}

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

<1.2×103< 1.2\times 10^{-3} bohr/rad

maxΔq|\Delta q|

<1.8×103< 1.8\times 10^{-3} bohr/rad

RMS gradient (active space)

<1.5×104< 1.5\times 10^{-4} Eh/bohr or Eh/rad

max gradient (active space)

<4.5×104< 4.5\times 10^{-4} 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 ρij\rho_{ij} 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.

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

rij<1.3(Ricov+Rjcov)r_{ij}<1.3\,(R_i^\text{cov}+R_j^\text{cov}) plus a vdW shell that grows by 1 Å until cluster fragments are connected

Initial Hessian

unspecified

Lindh diagonal with ρij\rho_{ij} screening

B-matrix

Eq. 14

same

BB^-

Eq. 18 or Eq. 19

BT(BBT)+B^\mathrm T (B B^\mathrm T)^+ via SVD

Active space

UactU_\text{act} from SVD

P=BBP = B B^- 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), τ0=0.5\tau_0=0.5

same rule, τ0=0.3\tau_0=0.3

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 <106<10^{-6}

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:

[WilsonDeciusCross] (1,2,3)

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.

[BakkenHelgaker02]

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.

[Schlegel1984]

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]).

[Bofill1994]

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.

[Baker1996]

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.

[DennisSchnabel83]

Dennis, J. E. & Schnabel, R. B. Numerical Methods for Unconstrained Optimization and Nonlinear Equations. Prentice-Hall (1983). Chapter 6 covers adaptive trust-region theory.