Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Møller–Plesset

Møller–Plesset partitioning

Using Rayleigh–Schrödinger perturbation theory (RSPT), the Hamiltonian can be partitioned according to the Møller–Plesset (MP) scheme Szabo & Ostlund (2012)Helgaker et al. (2014)Shavitt & Bartlett (2009)

H^=F^+Φ^\hat{H} = \hat{F} + \hat{\Phi}

where the zeroth-order Hamiltonian, F^\hat{F}, is the Fock operator and the perturbation, Φ^\hat{\Phi}, is known as the fluctuation potential.

The exact solutions to the zeroth-order Hamiltonian are found from the time-independent Schrödinger equation

F^Φn=EnΦn\begin{align*} \hat{F} | \Phi_n \rangle &= {\cal E}_n | \Phi_n \rangle \end{align*}

The exact state solutions to this equation are given by the Hartree–Fock state and its excited determinants

Φ0=ΨHFΦn=Ψijab;n>0\begin{align*} | \Phi_0 \rangle & = | \Psi_\mathrm{HF} \rangle \\ | \Phi_n \rangle & = | \Psi_{ij\ldots}^{ab\ldots} \rangle; \quad n > 0 \end{align*}

and, in terms of orbital energies, the associated exact energies are equal to

E0=ioccεiEijab=εa+εb+εiεj\begin{align*} {\cal E}_0 & = \sum_{i}^\mathrm{occ} \varepsilon_{i} \\ {\cal E}^{ab\cdots}_{ij\cdots} &= \varepsilon_{a} + \varepsilon_{b} + \ldots - \varepsilon_{i} - \varepsilon_{j} - \ldots \\ \end{align*}

Perturbation expansion in the fluctuation potential

The exact ground state is a solution to

H^Ψ=EΨ\hat{H} | \Psi \rangle = E | \Psi \rangle

where Ψ| \Psi \rangle and EE are expanded in orders of the perturbation

Ψ=k=0Ψ(k);E=k=0E(k)| \Psi \rangle = \sum_{k=0}^\infty | \Psi^{(k)} \rangle; \qquad E = \sum_{k=0}^\infty E^{(k)}

From RSPT, we get

E(0)=E0E(1)=ΨHFΦ^ΨHF=12i,joccijij\begin{align*} E^{(0)} & = {\cal E}_0 \\ E^{(1)} & = \langle \Psi_\mathrm{HF} | \hat{\Phi} | \Psi_\mathrm{HF} \rangle = -\frac{1}{2} \sum_{i,j}^\mathrm{occ} \langle ij \| ij \rangle \end{align*}

so that

EHF=E(0)+E(1)E_{\mathrm{HF}} = E^{(0)} + E^{(1)}

The first-order correction to the wave function is obtained from the RSPT master equation

Ψ(1)=14i,jocca,bvirttijabΨijab;tijab=abijEijab| \Psi^{(1)} \rangle = -\frac{1}{4} \sum_{i,j}^\mathrm{occ} \sum_{a,b}^\mathrm{virt} t_{ij}^{ab} | \Psi_{ij}^{ab} \rangle ; \qquad t_{ij}^{ab} = \frac{\langle ab \| ij \rangle}{{\cal E}_{ij}^{ab}}

and, in terms of the introduced tt-amplitudes, we thereby get a second-order energy correction equal to

E(2)=14i,jocca,bvirttijabijabE^{(2)} = - \frac{1}{4} \sum_{i,j}^\mathrm{occ} \sum_{a,b}^\mathrm{virt} t_{ij}^{ab} \langle ij || ab \rangle

such that

EMP2=EHF+E(2)E_{\mathrm{MP2}} = E_{\mathrm{HF}} + E^{(2)}

Closed-shell reference state

For a closed-shell Hartree–Fock state, the MP2 energy correction can be written in terms of sums referring to molecular orbitals (MOs)

E(2)=Eos(2)+Ess(2)E^{(2)} = E_{\mathrm{os}}^{(2)} + E_{\mathrm{ss}}^{(2)}

where

Eos(2)=i,jocca,bvirt(iajb)(iajb)EijabEss(2)=i,jocca,bvirt(iajb)Eijab[(iajb)(ibja)]\begin{align*} E_{\mathrm{os}}^{(2)} & = - \sum_{i,j}^\mathrm{occ} \sum_{a,b}^\mathrm{virt} \frac{(ia|jb)(ia|jb)}{{\cal E}_{ij}^{ab}} \\ E_{\mathrm{ss}}^{(2)} & = - \sum_{i,j}^\mathrm{occ} \sum_{a,b}^\mathrm{virt} \frac{(ia|jb)}{{\cal E}_{ij}^{ab}} \big[ (ia|jb) - (ib|ja) \big] \\ \end{align*}

The chemist’s notation has here been used for the integrals.

Illustration

Let us illustrate the theory with a calculation of the MP2 energy of water.

import veloxchem as vlx
h2o_xyz = """3
water                                                                                                                          
O    0.000000000000        0.000000000000        0.000000000000                         
H    0.000000000000        0.740848095288        0.582094932012                         
H    0.000000000000       -0.740848095288        0.582094932012
"""

molecule = vlx.Molecule.read_xyz_string(h2o_xyz)
basis = vlx.MolecularBasis.read(molecule, "cc-pvdz", ostream=None)

nocc = molecule.number_of_alpha_electrons()
nvirt = basis.get_dimension_of_basis() - nocc

print("Number of occupied orbitals:", nocc)
print("Number of unoccupied orbitals:", nvirt)
Number of occupied orbitals: 5
Number of unoccupied orbitals: 19
molecule.show()
Loading...

Hartree–Fock reference state

scf_drv = vlx.ScfRestrictedDriver()
scf_drv.ostream.mute()
scf_results = scf_drv.compute(molecule, basis)

We obtain the orbital energies.

E = scf_results["E_alpha"]

Integrals in the MO basis

We create an instance of the MOIntegralsDriver class to get the electron repulsion integrals in the MO basis and in the chemist’s notation.

erimo_drv = vlx.MOIntegralsDriver()

ovov = erimo_drv.compute_in_memory(molecule, basis, scf_drv.mol_orbs, "chem_ovov")
print("(ov|ov):", ovov.shape)
(ov|ov): (5, 19, 5, 19)

The MP2 energy correction

We now have all the ingredients to compute the opposite-spin and same-spin components of the MP2 energy correction.

e_mp2_ss = 0.0
e_mp2_os = 0.0

# extract the occupied subset of the orbital energies
e_o = E[:nocc]
# extract the virtual subset of the orbital energies
e_v = E[nocc:]

for i in range(nocc):
    for j in range(nocc):
        for a in range(nvirt):
            for b in range(nvirt):
                # enegy denominators
                e_ijab = e_v[a] + e_v[b] - e_o[i] - e_o[j]

                # update opposite-spin component of the energy
                e_mp2_os -= (ovov[i, a, j, b] * ovov[i, a, j, b]) / e_ijab

                # update same-spin component of the energy
                e_mp2_ss -= (
                    ovov[i, a, j, b] * (ovov[i, a, j, b] - ovov[i, b, j, a]) / e_ijab
                )
print(f"Opposite-spin MP2 energy: {e_mp2_os:12.8f}")
print(f"Same-spin MP2 energy    : {e_mp2_ss:12.8f}")
print(f"MP2 energy              : {e_mp2_os + e_mp2_ss:12.8f}")
Opposite-spin MP2 energy:  -0.15163083
Same-spin MP2 energy    :  -0.05138187
MP2 energy              :  -0.20301270

Let us compare this result with the MP2 energy obtained with VeloxChem.

mp2_drv = vlx.Mp2Driver()
mp2_drv.ostream.mute()

mp2_results = mp2_drv.compute_conventional(molecule, basis, scf_drv.mol_orbs)
print(f"Energy difference: {mp2_results['mp2_energy']:12.8f}")
Energy difference:  -0.20301270

We note that the two results are in perfect agreement.

Size consistency

We see that to second order, Møller-Plesset perturbation theory only involves up to double excitations from the HF reference. It would thus be natural to consider it an approximation to CISD, and expect it to suffer from the same issue, namely a lack of size consistency. Yet this is not the case as discussed in the RSPT section on this topic.

dimer_xyz = """6
2 water 100 Å apart                                                                                                            
O    0.000000000000        0.000000000000        0.000000000000                         
H    0.000000000000        0.740848095288        0.582094932012                         
H    0.000000000000       -0.740848095288        0.582094932012
O  100.000000000000        0.000000000000        0.000000000000                         
H  100.000000000000        0.740848095288        0.582094932012                         
H  100.000000000000       -0.740848095288        0.582094932012
"""

molecule = vlx.Molecule.read_xyz_string(dimer_xyz)
basis = vlx.MolecularBasis.read(molecule, "cc-pvdz", ostream=None)
scf_results = scf_drv.compute(molecule, basis)

mp2_dimer_results = mp2_drv.compute_conventional(molecule, basis, scf_drv.mol_orbs)
print("=" * 30)
print("MP2 energies")
print("-" * 30)
print(f"Dimer       : {mp2_dimer_results['mp2_energy']:16.10f}")
print(f"Two monomers: {2 * mp2_results['mp2_energy']:16.10f}")
print("=" * 30)
==============================
MP2 energies
------------------------------
Dimer       :    -0.4060254139
Two monomers:    -0.4060254050
==============================

We can see that the two energies match. MP2 is size consistent! So why is it behaving better than CISD in this aspect?

The key is that in MP2, the coefficients of the excited determinants are independent of the system size. Thus a molecule would have the same MP2 energy correction regardless of the presence or not of another, non-interacting, molecule. By contrast, in CISD, the coefficients depend on the system size through normalization, lowering the weight of these determinants as the size of the system increases.

Taylor expansion of the energy

Using RSPT, it is a common practice to use an order parameter λ\lambda for the perturbation

H^(λ)=H0^+λV^\hat{H}(\lambda) = \hat{H_0} + \lambda \hat{V}

Each order of the perturbation then corresponds to a power of λ\lambda

E(λ)=E(0)+λE(1)+λ2E(2)+E(\lambda) = E^{(0)} + \lambda E^{(1)} + \lambda^2 E^{(2)} + \ldots

The RSPT equations are found by collecting terms in powers of λ\lambda and, at the end, set λ\lambda equal to 1 to recover the correct Hamiltonian. Taking this approach, it is seen that RSPT relates to Taylor expansions. We will here demonstrate that

EFCI(λ)=i=0λiEMP(i)E_\mathrm{FCI}(\lambda) = \sum_{i=0}^\infty \lambda^i E_{\mathrm{MP}}^{(i)}

or, in other words, the nnth-order MP energy correction is given by

EMP(n)=1n!dnEFCI(λ)dλnλ=0E_{\mathrm{MP}}^{(n)} = \frac{1}{n!} \left. \frac{d^n E_\mathrm{FCI}(\lambda)}{d \lambda^n} \right|_{\lambda=0}

The total MP energy to order nn is a sum of the corrections

EMPn=i=0nEMP(i)E_{\mathrm{MPn}} = \sum_{i=0}^n E_{\mathrm{MP}}^{(i)}

We will explicitly create H^(λ)\hat{H}(\lambda) and determine the FCI energy. This allows us to determine the MP2 energy by means of numerical differentiation to second order with respect to λ\lambda.

First, we determine the Hartree–Fock state of water in the 6-31G basis set.

molecule = vlx.Molecule.read_xyz_string(h2o_xyz)
basis = vlx.MolecularBasis.read(molecule, "6-31G", ostream=None)

scf_drv = vlx.ScfRestrictedDriver()
scf_drv.ostream.mute()
scf_results = scf_drv.compute(molecule, basis)
# MO coefficients
C = scf_results["C_alpha"]

# orbital energies
E = scf_results["E_alpha"]

Second, we create H0^=F^\hat{H_0} = \hat{F} and V^=(H^F^)λ=1\hat{V} = (\hat{H} - \hat{F})_{\lambda=1} in the MO basis. The perturbation has a one-electron as well as a two-electron part that we will keep separate

V^=V^1+V^2\hat{V} = \hat{V}_1 + \hat{V}_2
import numpy as np

F = np.diag(E)

# Get the core Hamiltonian in MO basis
T_ao = vlx.compute_kinetic_energy_integrals(molecule, basis)

V_nucpot_ao = vlx.compute_nuclear_potential_integrals(molecule, basis)

h = np.einsum("ai, ab, bj -> ij", C, T_ao + V_nucpot_ao, C)

# Compute the 2-electron integrals
fock_drv = vlx.FockDriver()
g_ao = fock_drv.compute_eri(molecule, basis)

g_1 = np.einsum("ds, abcd -> abcs", C, g_ao)
g_2 = np.einsum("cr, abcs -> abrs", C, g_1)
g_3 = np.einsum("bq, abrs -> aqrs", C, g_2)

g = np.einsum("ap, aqrs -> pqrs", C, g_3)
H0 = F

V_1 = h - F
V_2 = g

Third, we use MultiPsi to determine the FCI energies.

import multipsi as mtp

ci_drv = mtp.CIDriver()
ci_drv.ostream.mute()

space = mtp.OrbSpace(molecule, scf_drv.mol_orbs)
space.fci()

Determine EFCI(λ)E_\mathrm{FCI}(\lambda) and calculate the second derivative with use of a 3-point stencil.

E_FCI = []

for lambda_val in [-0.01, 0, 0.01]:

    ci_drv._update_integrals(
        molecule.effective_nuclear_repulsion_energy(basis), H0 + lambda_val * V_1, lambda_val * V_2
    )

    ci_results = ci_drv.compute(molecule, basis, space, 1)

    E_FCI.append(ci_results["energies"][0])
E_MP2 = 0.5 * (E_FCI[0] + E_FCI[2] - 2 * E_FCI[1]) / 0.01**2
print(f"MP2 energy correction:{E_MP2:12.8f}")
MP2 energy correction: -0.12747116

Perform a reference calculation using the MP2 module in VeloxChem.

mp2_results = mp2_drv.compute(molecule, basis, scf_drv.mol_orbs)
print(f"MP2 energy correction:{mp2_results['mp2_energy']:12.8f}")
MP2 energy correction: -0.12747066

We note the the two results are in perfect agreement. The small discrepancy is due to the use of numerical differentiation in the former case.

References
  1. Szabo, A., & Ostlund, N. S. (2012). Modern Quantum Chemistry: Introduction to Advanced Electronic Structure Theory. Courier Corporation.
  2. Helgaker, T., Jørgensen, P., & Olsen, J. (2014). Molecular electronic-structure theory. John Wiley & Sons. 10.1002/9781119019572
  3. Shavitt, I., & Bartlett, R. J. (2009). Many-Body Methods in Chemistry and Physics: MBPT and Coupled-Cluster Theory. Cambridge University Press. 10.1017/CBO9780511596834