The MP2 family

The largest method family here. Every variant is density-fitted (RI): each needs an orbital basis and a matching RI auxiliary basis ([mp2] auxbasis, or the auxbasis argument in Python). Formal cost is O(N⁵) for the RI-MP2 transformation. Grades per method.kind are on Capabilities and validation. The [mp2] keys are in Input file.

RI-MP2

What it is. Second-order Møller–Plesset theory on an RHF reference (UHF for an open shell, below) with 3-centre/2-centre density fitting. Canonical (non-RI) MP2 is also implemented, for cross-validation, not production.

Open shells. rimp2 and oo-rimp2 accept an open-shell molecule (multiplicity > 1) from the CLI, for task = "energy" only: they solve the same plain UHF that kind = "uhf" runs, then take unrestricted RI-MP2 (UMP2, as PySCF mp.MP2(uhf)) or unrestricted OO-RI-MP2. There is no unrestricted MP2 nuclear gradient, and [mp2] kappa is refused on an open shell. From Python, run_rimp2 does the same (UHF + UMP2 when multiplicity > 1; result.reference says which, and kappa raises); run_oo_rimp2 is closed shell only. Both unrestricted methods are validated on the CH3 doublet at cc-pVDZ: U-RI-MP2 against ORCA RI-MP2 NoRI, U-OO-RI-MP2 against an independent numpy OO-RI-MP2 (see the anchors).

The other MP2-family kinds (mp3, att-rimp2, scs-mp2, scs-mp2-2terfc, laplace-mp2, laplace-sos-mp2, rs-mp2-rpa) and their Python drivers are closed shell only: set multiplicity = 1. mp2-v switches to a UHF reference when multiplicity > 1 (CLI, energy only); Python run_mp2_v is closed shell only.

Run it. method.kind = "rimp2" (examples/water-rimp2.toml, examples/water-rimp2-frozen-core.toml); Python ferric.run_rimp2(mol, bs, aux).

Accuracy. Proven. RI-MP2 is size-extensive to 2e-12 Ha for a well-separated dimer against twice the monomer (ferric-mp2/tests/rimp2_size_extensivity.rs, which asserts 1e-7).

Knobs. frozen_core defaults to 0 (all electrons correlated). Several published parameterizations below assume frozen core, so set it when you use them.

Attenuated MP2

What it is. MP2 with the Coulomb operator in the correlation energy replaced by a short-range one. Two forms are implemented:

  • erfc: \( \mathrm{erfc}(\omega r)/r \), which is \( 1/r \) at short range and decays to zero beyond roughly \( 1/\omega \).
  • terfc: a short-range operator that is Coulombic inside a cutoff radius \( r_0 \) and attenuated outside it, with a controlled curvature (Dutoi & Head-Gordon 2008). It needs precomputed interpolation tables (FERRIC_TERF_TABLE_DIR, generated under terf-tables/); without them the run errors rather than substituting another operator.

Why. MP2's error for non-covalent interactions has two parts that partly cancel in small basis sets: basis-set superposition error, and an error in the long-range part of the correlation energy. Attenuation removes the long-range part. That also means attenuated MP2 has no long-range dispersion at all: its asymptotic \( C_6 \) is zero. The method works in the basis and on the systems it was fitted for; MP2-V (below) adds long-range dispersion back through VV10.

Parameterization. The attenuation parameters are fitted, not derived, and each fit belongs to one basis. The aug-cc-pVTZ sets that ferric ships as defaults were fitted on S66 without counterpoise and with frozen core (stated in crates/ferric-mp2/src/scs.rs):

VariantParametersBasis of the fitSource
erfcω; ferric's default is 0.420 Å⁻¹, recorded in the code as the dissertation's erfc optimumaug-cc-pVDZ in the 2012 paperGoldey & Head-Gordon 2012
terfcone cutoff \( r_0 \)aug-cc-pVTZGoldey, Dutoi & Head-Gordon 2013
SCS-MP2(2terfc)\( r_0(1) \) = 0.75 Å, \( r_0(2) \) = 1.05 Å, cOS = 1.27, cSS = 4.05aug-cc-pVTZ, no counterpoise, frozen coreGoldey & Head-Gordon 2014
MP2-V\( r_0 \) = 1.00 Å, b = 11.0, C = 0.0089, terfcaug-cc-pVTZ, no counterpoise, frozen coreGoldey, Belzunces & Head-Gordon 2015

Running a fitted variant in another basis, with counterpoise, or with frozen_core = 0 (the default) is extrapolation outside the fit.

Run it.

Variantmethod.kindExamplePython
erfcatt-rimp2examples/water-attmp2.tomlrun_attenuated_rimp2(..., omega=0.420) (Å⁻¹)
terfcatt-rimp2 with [mp2] att_operator = "terfc", att_r0 (Å)examples/water-attmp2-terfc.tomlrun_terfc_rimp2(..., r0=...)
SCS-MP2 (Grimme)scs-mp2examples/water-scs-mp2.tomlrun_scs_mp2(..., c_os=, c_ss=)
SCS-MP2(2terfc)scs-mp2-2terfcexamples/water-scs-mp2-2terfc.tomlrun_scs_mp2_2terfc(...)
MP2-Vmp2-vexamples/water-mp2v.tomlrun_mp2_v(...)

ω is in Å⁻¹ in the CLI and Python and in Bohr⁻¹ in the Rust API. The SCS-MP2 defaults are Grimme's cOS = 1.2, cSS = 0.333.

Accuracy. att-rimp2, scs-mp2 and scs-mp2-2terfc are Proven (the erfc energy is pinned against PySCF/libcint in testdata/reference/h2o_cc-pvdz_attenuated-rimp2-erfc0p420.json). mp2-v is Smoke: its VV10 half is bit-identical to the ωB97X-V code path, but there is no published MP2-V total energy to compare with, and ferric evaluates the VV10 term on the converged HF density (the post-HF variant) on its own 50×50 grid rather than SG-1. Read the header of examples/water-mp2v.toml before quoting a number.

Robust fitting. When the RI metric differs from the operator in the integrals, as it does for attenuated operators, robust (Dunlap) density fitting is required, not optional.

RS-MP2 + LR-RPA

What it is. Short-range MP2 plus long-range direct RPA: the attenuated-MP2 idea with the missing long-range correlation supplied by response rather than by a fitted dispersion term. Two formulations:

  • delta-lr (default): \( E_{MP2}[\text{Coulomb}] + (E_{dRPA}[\text{erf}] - 2E_{OS}[\text{erf}]) \), one dRPA call.
  • coupled-rings: \( E_{MP2}[\text{Coulomb}] + \Delta dRPA[\text{Coulomb}] - \Delta dRPA[\text{erfc}] \), two dRPA calls; includes the mixed short/long-range ring diagrams.

Run it. method.kind = "rs-mp2-rpa" (examples/water-rs-mp2-rpa.toml, [mp2] formulation); Python run_rs_mp2_rpa(..., omega=0.420, formulation="delta-lr").

Accuracy. Smoke. The ω→0 and ω→∞ limits reduce exactly to MP2 and to MP2 + dRPA; numbers at production ω are not established on new systems.

Orbital-optimized MP2 and MP3

OO-RI-MP2 (oo-rimp2, examples/water-oo-rimp2.toml, run_oo_rimp2): orbitals optimized for the MP2 Lagrangian, with a level-shifted Newton step, orbital DIIS, Cayley rotations and backtracking. Proven (narrow): the energy matches an independent numpy OO-RI-MP2 to 7.5e-13 Ha (H2O, NH3, UHF CH3 at cc-pVDZ), and the closed-shell analytic gradient matches a finite difference of its own energy to 8e-9 Ha/Bohr. ORCA 6.1.1's OO-RI-MP2 stops 3.7e-8 to 7.0e-8 Ha above the same minimum, so it is only a loose cross-check.

MP3 (mp3, examples/water-mp3.toml, run_mp3): spin-orbital third-order Møller–Plesset through the einsum! framework. Proven.

Laplace formulations

RI-Laplace MP2 (laplace-mp2, examples/water-laplace-rimp2.toml, run_laplace_mp2): MP2 through a Laplace transform of the energy denominator, using pseudo-density matrices in the AO basis. The implementation is dense. It is the correctness reference for that formulation, not a reduced-scaling path, and no reduced scaling has been measured.

Laplace SOS-MP2 (laplace-sos-mp2, examples/water-laplace-sos-mp2.toml, run_laplace_sos_mp2): opposite-spin-only MP2 (Jung et al. 2004, cOS = 1.3 by default) with a minimax Laplace quadrature (n_quad must be 3, 5 or 7; anything else is an error). There is deliberately no cSS: dropping the same-spin term is what lets the denominator factorize. With cOS = 1.0 it reproduces the opposite-spin component of RI-MP2 to quadrature error, which is the test anchor. Three formulations (sos_formulation):

  • mo (default) and ao are both exact and agree to round-off.
  • ao-sparse restricts each Boys-localized orbital's pseudo-density to an AO domain of radius domain_cutoff_bohr (required, no default). It is the one approximate variant.

What is measured for ao-sparse:

  • Against the exact AO path on n-alkanes (cc-pVDZ, cOS = 1, n_quad = 7, 2026-07-28), chemical accuracy (absolute error below 1.6 mHa) needs a domain radius of 3, 3, 3, 4, 5 and 5 Bohr for C2, C4, C6, C8, C10 and C12. The diameter grows fivefold over that series, so radius/diameter falls from 0.52 to 0.17.
  • In the STO-3G tests, a 12 Bohr domain that is exact for butane (10.5 Bohr across) is also exact for octane (19.9 Bohr across), and a 4 Bohr domain on butane is already within 0.1%.
  • A 71-atom drug molecule (danuglipron, 31.3 Bohr across, STO-3G) is within 0.05% at 4 Bohr.

The test sos_ao_sparse_truncation_radius_is_transferable_across_sizes in crates/ferric-mp2/src/laplace.rs pins the STO-3G butane/octane comparison: at 12 Bohr butane is exact (relative error below 1e-9) and octane is within 1e-6, and octane at 3 Bohr is worse than at 12 Bohr. The 4 Bohr butane figure and the danuglipron run (recorded in the test's doc comment) are measurements, not assertions. The alkane sweep is kept in the project's working notes.

How to read it (provisional): the radius needed grows, but far more slowly than the molecule. That points to a finite decay length rather than strict saturation: no single radius is shown to suffice at every size.

What is not claimed: any speedup. The domains discard contributions but the tensor algebra is still dense, so there are no timings to report.

Exact and local MP2

method.kind = "rimp2" is the method; it is computed exactly unless a [local] section asks for a local approximation (see Exact and local correlation). The local approximation is closed shell and energy only.

Amplitude-threshold local MP2 (examples/water-rimp2-local.toml; [local] scheme = "amplitude-threshold", eps = 1e-4; Python run_rimp2(..., local="amplitude-threshold", eps=1e-4)): the single-threshold local MP2 of Wang, Aldossary, Shi, Liu, Li & Head-Gordon (2023), with localized virtuals and per-pair domain-local RI fits. eps has no default: it is part of the model. eps = 0 reproduces RI-MP2 exactly; a finite eps carries a one-sided truncation error that grows faster than linearly in eps. Every printout and run-log record of a local run states eps and the fraction of amplitudes kept.

The exact RI-MP2 reference that measures that error is opt-in. It is a full canonical RI-MP2 and forms the global (naux, nocc·nvir) tensor, so a run with it switched on is not reduced-cost. In the CLI, [local] reference = true computes it and prints the local error against it; without it the output reads E_corr(canonical RI) = not computed (opt-in: set [local] reference = true) and the run log's e_corr_canonical_ri is null. In Python, compute_reference=True computes it; by default result.local["e_corr_canonical_ri"] is None.

Integral-direct local MP2 ([local] integral_direct = true, examples/alkane8-rimp2-local-direct.toml; Python integral_direct=True) is the reduced-cost path. Its correlation assembly never forms the global 3-index tensor; only the opt-in reference does. Locality comes from an integral-free pair gate (gate_cal), per-occupied auxiliary-fit and virtual domains (aux_radius, virt_radius), and truncation of each orbital's AO support (ao_tail). With every map at its trivial setting it reproduces the global 3-index path and canonical RI-MP2 (tests/lmp2_direct.rs).

What is measured for the integral-direct local MP2 (n-alkanes C20 → C48, 6-31G with cc-pVDZ-RI, a quiet machine, 2026-09-07; benchmark bench_direct_alkane_series in crates/ferric-mp2/tests/lmp2_direct.rs). The run froze the carbon cores (frozen_core = number of carbons) and calibrated the pair gate (0.7 Coulomb, 0.02 erfc with ω = 1.0) at eps = 1e-4; the defaults are all-electron with no pair gate. Timings are the correlation stage (assembly + solve) and exclude the canonical reference:

  • Correlation-stage cost grows as about N1.24 with the erfc kernel and N1.4 with Coulomb, fitted to the last three sizes.
  • It is at about parity with canonical RI-MP2 at C20 (about 1.1× slower) and about 6× faster at C32 (5.7–6.3×).

How to read it (provisional): sub-quadratic on this series, but the fit has three points on one family of molecules in one basis. It is not shown to be linear, and it is not measured on 3-D or diffuse systems.

Local MP2 without integral_direct makes no scaling claim. Its assembly is pair-local (no dense J is formed), but it still builds the global 3-index tensor. Use it as the reference implementation and for small systems.

Cite

RI-MP2 auxiliary sets: Weigend et al. 1998. SCS-MP2: Grimme 2003. SOS-MP2: Jung et al. 2004. OO-MP2: Lochan & Head-Gordon 2007; Bozkaya et al. 2011. Laplace MP2: Häser & Almlöf 1992. Attenuated MP2: Goldey & Head-Gordon 2012; terfc: Dutoi & Head-Gordon 2008, Goldey, Dutoi & Head-Gordon 2013; SCS-MP2(2terfc): Goldey & Head-Gordon 2014; MP2-V: Goldey, Belzunces & Head-Gordon 2015. LMP2: Wang et al. 2023. Robust fitting: Dunlap 2000. Full entries in References.