Functionals

XC functionals are resolved through libxc at runtime. Any functional name libxc accepts works: short names ("LDA", "PBE", "B3LYP", "PBE0"), libxc XC_… identifiers, weighted-sum custom strings ("0.2*HF + 0.8*GGA_X_PW91, GGA_C_PW91" for PW1PW), and vibe-qc’s own aliases.

⚠️ B3LYP behaviour change at v0.8.0

The b3lyp keyword now resolves to libxc id 475 (VWN5 — the ORCA / ADF convention) rather than id 402 (VWN-RPA, a.k.a. VWN3 — the libxc default and Gaussian convention).

“B3LYP” is a fixed hybrid recipe; codes differ only in which Vosko-Wilk-Nusair parametrisation fills the LSDA-correlation slot. vibe-qc follows the ORCA convention: bare b3lyp is the VWN5 variant. It’s a noticeable shift for users comparing pre- vs post-v0.8.0 numbers:

  • Effect: B3LYP energies move by ~10–15 mHa per heavy atom.

  • On 10-atom organics, the silent disagreement vs ORCA’s bare B3LYP was ~150 mHa pre-fix; post-fix it matches to <1 mHa.

For the Gaussian-compatible VWN3 variant (e.g. for parity with Gaussian or PySCF’s default b3lyp), pass functional="b3lyp/g" — vibe-qc’s alias for the VWN3 variant, mirroring ORCA’s B3LYP / B3LYP/G keyword pair. (functional="402" or functional="XC_HYB_GGA_XC_B3LYP" resolve to the same functional.)

To use the default post-v0.8.0 B3LYP explicitly, either functional="b3lyp" (the default) or functional="XC_HYB_GGA_XC_B3LYP5" is fine.

Recipe table

vibe-qc resolves these short names in xc.cpp::resolve_alias() (plus everything libxc accepts directly):

Name

Type

HF-exchange

libxc id

Notes

lda / svwn

LDA

0 %

1 + 7

Slater exchange + VWN5 correlation. Fast sanity check.

pbe

GGA

0 %

101 + 130

Workhorse for solid state.

blyp

GGA

0 %

106 + 131

Classic molecular GGA.

b3lyp

hybrid

20 %

475 (was 402)

de-facto for organics; VWN5 / ORCA convention; see warning above.

b3lyp/g

hybrid

20 %

402

Gaussian-compatible B3LYP (VWN3); mirrors ORCA’s B3LYP/G.

pbe0 / pbeh

hybrid

25 %

406

PBE + 25% Fock exchange.

pw1pw

hybrid

20 %

weighted-sum

Bredow’s 1-parameter periodic hybrid; cite Bredow & Gerson PRB 61, 5194 (2000).

tpss

meta-GGA

0 %

202 + 231

Non-empirical τ-dependent MGGA; Tao-Perdew-Staroverov-Scuseria PRL 91, 146401 (2003).

tpssh

hybrid meta-GGA

10 %

457

10 % global hybrid of TPSS; Staroverov-Scuseria-Tao-Perdew JCP 119, 12129 (2003).

m06-l (m06l)

meta-GGA

0 %

203 + 233

Pure Minnesota meta-GGA; Zhao-Truhlar JCP 125, 194101 (2006).

m06-2x (m062x)

hybrid meta-GGA

54 %

450 + 236

54 % global hybrid for thermochemistry + non-covalent interactions; Zhao-Truhlar TCA 120, 215 (2008).

scan

meta-GGA

0 %

263 + 267

Strongly-constrained meta-GGA; Sun-Ruzsinszky-Perdew PRL 115, 036402 (2015). Grid-sensitive — use a fine grid (prefer r2scan).

r2scan

meta-GGA

0 %

497 + 498

Re-regularized SCAN — smooth, grid-friendly; Furness et al JPCL 11, 8208 (2020). Recommended default of the family.

r2scan0

hybrid meta-GGA

25 %

660

25 % global hybrid of r²SCAN (PBE0-like).

r2scanh

hybrid meta-GGA

10 %

659

10 % global hybrid of r²SCAN (TPSSh-like).

wb97x

range-sep hybrid

15.77 %→100 %

464

Long-range-corrected hybrid GGA; Chai-Head-Gordon 2008. ω = 0.3. Direct SCF only (see § Range-separated hybrids).

wb97x-d

range-sep hybrid + D

22.2 %→100 %

471

ωB97X-D — Chai-Head-Gordon 2008. ω = 0.2 + intrinsic CHG dispersion. Use vibeqc.run_wb97x_d for the full XC + dispersion total.

hse06

screened RSH

25 %→0 %

428

Heyd-Scuseria-Ernzerhof screened hybrid; 25 % HF short-range, 0 % long-range, ω = 0.11. The solid-state band-gap workhorse.

The full libxc functional set is also reachable directly. Use the libxc identifier if your shorthand isn’t in the table: functional="XC_HYB_GGA_XC_M06_2X", functional="XC_GGA_X_RPBE,XC_GGA_C_PBE", etc.

PW1PW: Bredow’s periodic hybrid

pw1pw is the first non-libxc-built-in custom hybrid in vibe-qc. The functional is:

PW1PW = 0.20 × HF exchange  +  0.80 × GGA_X_PW91 exchange  +  GGA_C_PW91 correlation

Implemented via libxc’s custom-string path: vibeqc.vibeqc_xc_to_pyscf translates "pw1pw" to ".2*HF + .8*GGA_X_PW91, GGA_C_PW91" for the PySCF-grid V_xc evaluation in periodic UKS / RKS dispatch.

import vibeqc as vq

result = vq.run_periodic_job(
    mgo,
    basis="pob-tzvp",
    method="RKS",
    functional="pw1pw",
    kmesh=(4, 4, 4),
    output="mgo-pw1pw-444",
)

Cite: Bredow, T.; Gerson, A. R. Phys. Rev. B 61, 5194 (2000). PW1PW is the strict-comparison reference for the Peintinger 2013 SI basis- set paper’s HF + PW1PW totals on ~60 compounds.

Choosing a functional (decision tree)

  • Periodic ionic insulator (oxides, halides, sulphides): pw1pw or b3lyp or pbe0 for hybrids; pbe for pure GGA. Cite the published reference for the system class.

  • Periodic semiconductor / metal: pbe (most common). Hybrids hit the dense-Lpq RAM ceiling fast — see multi_k_scf.md § Open issues.

  • Molecular organic geometry optimisation: r²SCAN-3c — the turnkey “Swiss army knife” composite (see composites.md) — or b3lyp with D3(BJ) (see molecules.md) / pbe0 for more reactive systems.

  • Molecular thermochemistry: the r²SCAN-3c / ωB97X-3c / HSE-3c composite methods are runnable today (composites.md); pbe0 + def2-TZVP + D3(BJ) is the conventional mid-tier workhorse.

  • Open-shell radicals: prefer uks driver over rks. Same functional table works.

⚠️ Plain B3LYP for noncovalent interactions

Plain B3LYP (no dispersion correction) systematically under-binds noncovalent interactions by 20–50% on the S22 set. Always pair B3LYP with a dispersion correction when noncovalent interactions matter:

result = vq.run_rks(
    mol,
    basis="def2-tzvp",
    functional="b3lyp",
    options=vq.RHFOptions(dispersion="d3bj"),  # or "d4"
)

D3(BJ) is the standard. D4 (Caldeweyher-Bannwarth-Grimme, 2019) ships alongside D3(BJ): use dispersion="d4" to opt in. There are two D4 backends, the optional dftd4 package (production default) and an in-tree native MPL-2.0 implementation (opt-in via compute_d4(mol, func, backend="native") while the reference dataset is being upgraded). Both are documented in molecules.md § Dispersion.

Meta-GGA functionals (TPSS / TPSSh, M06-L / M06-2X, SCAN / r²SCAN)

vibe-qc evaluates the kinetic-energy density τ(r) = ½ Σ_i |∇ψ_i(r)|² on the DFT grid (using the AO gradients that already power the GGA path), so the τ-dependent meta-GGA family is now available in molecular RKS + UKS:

opts = vq.RKSOptions()
opts.functional = "r2scan"    # or tpss / tpssh / m06-l / m06-2x /
                              # scan / r2scan0 / r2scanh
result = vq.run_rks(mol, basis, opts)

SCAN vs r²SCAN. SCAN (scan) satisfies all 17 exact constraints a semilocal functional can, but its sharp enhancement factor is notoriously grid-sensitive — on vibe-qc’s default medium grid the H₂O/def2-SVP energy sits ~1 mHa off the fine-grid limit. For SCAN, set a fine grid (opts.grid.n_radial = 120, opts.grid.lebedev_order = 41 or finer). r²SCAN (r2scan) is the re-regularized SCAN — same constraint satisfaction, a smooth enhancement factor, grid-stable to ~µHa on the default grid. It is the recommended default of the family; r2scan0 (25 % HF) and r2scanh (10 % HF) are its global hybrids.

Coverage:

  • Molecular RKS / UKS — closed-shell + open-shell SCF live; parity to PySCF.dft within grid-quadrature noise (~µHa on def2-SVP / medium grid for closed-shell H₂O; ~10–50 µHa on STO-3G / grids.level=5 for O₂ triplet UKS).

  • Periodic SCFnot yet. cpp/src/periodic_xc.cpp will reject meta-GGA functionals at the Functional::eval_* call with a clear error pointing here. Periodic τ-grid + V_τ is a follow-up workstream.

  • Analytic gradientsavailable for molecular RKS + UKS (vibeqc.compute_gradient_rks / compute_gradient_uks). The XC Pulay force includes the τ term; finite-difference validated to ~3e-9 (TPSS/TPSSh) / ~1e-7 (M06-2X) on H₂/STO-3G. Geometry optimisation with meta-GGAs works end-to-end.

  • Analytic Hessian / CPKSnot yet. The meta-GGA second-derivative kernel (eval_unpolarised_fxc) raises on MGGA; finite-difference Hessians work as a workaround.

  • Laplacian-dependent meta-GGAs (TB09, …) — not supported. vibe-qc populates τ but not ∇²ρ on the grid; libxc functionals with XC_FLAGS_NEEDS_LAPLACIAN are refused at Functional construction with a clear error.

Range-separated hybrids (ωB97X, ωB97X-D)

A range-separated (CAM) hybrid makes the exact-exchange admixture position-dependent:

EXX(r₁₂) = cam_alpha + cam_beta · erf(ω · r₁₂)

so the exchange operator is cam_alpha·(1/r₁₂) + cam_beta·(erf(ω·r₁₂)/r₁₂). vibe-qc reads the (ω, α, β) triple from libxc at construction — Functional("wb97x").is_range_separated / rsh_omega / cam_alpha / cam_beta — and the SCF driver builds the second, erf-attenuated exchange matrix K_erf(ω) alongside the ordinary K.

wb97x (Chai-Head-Gordon 2008) is the first range-separated hybrid in vibe-qc: a long-range-corrected functional — 15.77 % HF at short range ramping to 100 % HF at long range, ω = 0.3 bohr⁻¹.

opts = vq.RKSOptions()
opts.functional = "wb97x"
result = vq.run_rks(mol, basis, opts)

ωB97X-D — range-separated hybrid + dispersion

wb97x-d (Chai-Head-Gordon 2008) is the dispersion-corrected re-parameterisation of ωB97X (ω = 0.2 bohr⁻¹, 22.2 % HF short-range → 100 % long-range). It has two pieces: the range-separated-hybrid XC functional (libxc XC_HYB_GGA_XC_WB97X_D), and an intrinsic empirical “-D” dispersion correction of the older “DFT-D2” family. The dispersion is geometry-only — no SCF coupling — so the complete ωB97X-D energy is E_SCF + E_disp. Use the dispatcher :func:vibeqc.run_wb97x_d for the full total:

result = vq.run_wb97x_d(mol, basis)          # closed- or open-shell
print(result.e_total)        # E_SCF + E_dispersion
print(result.scf.energy, result.dispersion.energy)

The CHG dispersion is E_disp = −Σ_{A<B} C6_AB/R^6 · 1/(1 + 6·(R/R0_AB)^-12) with the Grimme-2006 D2 atomic C6 / vdW-radius tables (H–Xe); a heavier element raises a clear error. vibeqc.compute_chg_dispersion(mol) exposes the standalone term. The bare functional="wb97x-d" alias through run_rks / run_uks gives the XC/SCF part only (the range-separated hybrid) — the same alias-vs-dispatcher split as b2plyp / run_b2plyp; use run_wb97x_d for the published total.

Coverage and caveats:

  • Molecular RKS / UKS energies — live; parity to PySCF.dft at grid-quadrature precision (~µHa, def2-SVP).

  • Direct SCF only — the erf-attenuated K is built by the direct-SCF Fock kernel. density_fit=true with a range-separated functional is rejected with a clear error (the RI path has no erf-attenuated 3-centre integrals yet). The molecular drivers select the direct builder automatically for RSH functionals, so no user action is needed — just leave density_fit at its default.

  • Hard open-shell radicals — ωB97X’s 100 % long-range HF makes open-shell SCF stiffer. O₂, CH₃, and atomic radicals converge with the defaults; an orbital-near-degenerate case such as the OH ²Π radical can plateau near the gradient tolerance with plain DIIS — set opts.level_shift = 0.5 to converge it cleanly (standard QC practice for stiff open-shell SCF).

  • Newton / TRAH second-order acceleration is disabled for RSH functionals (their orbital-Hessian exchange response is not yet range-separation aware); DIIS + SOSCF + the quadratic fallback carry convergence.

  • Analytic gradients for RSH functionals are not yet available (finite-difference works). ωB97X-V and periodic RSH are queued — see below.

HSE06 — screened range-separated hybrid

hse06 (Heyd, Scuseria, Ernzerhof; the Krukau-Vydrov-Izmaylov- Scuseria 2006 re-parameterisation, libxc XC_HYB_GGA_XC_HSE06) is a screened RSH: 25 % HF at short range tapering to 0 % at long range — the opposite ramp direction to ωB97X. In vibe-qc’s erf-form CAM representation this is cam_alpha = +0.25, cam_beta = −0.25 (EXX(r→0) = 0.25, EXX(r→∞) = 0), so it runs through the same erf-attenuated-K machinery as ωB97X — just with a negative long-range coefficient. No separate erfc kernel is needed.

opts = vq.RKSOptions()
opts.functional = "hse06"
result = vq.run_rks(mol, basis, opts)

HSE06 is primarily a solid-state band-gap functional; molecular HSE06 is available here, periodic HSE06 follows once periodic RSH lands.

Queued (not yet shipped)

These functional families are designed but not in the v0.8.0 cut. Track at docs/roadmap.md § XC functional library expansion:

  • Range-separated hybrids — molecular wb97x, wb97x-d (via vibeqc.run_wb97x_d) and hse06 ship now (see § Range-separated hybrids above). Still queued: ωB97X-V / ωB97M-V (need the VV10 non-local correlation), RSH analytic gradients, RSH + density fitting, and periodic RSH.

  • r²SCAN family — molecular scan / r2scan / r2scan0 / r2scanh ship now (see § Meta-GGA functionals above). Still queued: periodic SCAN / r²SCAN (needs periodic meta-GGA support in cpp/src/periodic_xc.cpp).

  • Composite “3c” methodsr²SCAN-3c, ωB97X-3c, and HSE-3c are runnable today (turnkey: functional + matching basis + gCP + D4 in one call); B3LYP-3c / B97-3c / PBEh-3c are PENDING_GCP_DATA (the framework is wired, the per-basis gCP tables are pending). See composites.md for the recipe table, status flags, and worked examples.

  • Double hybridsB2PLYP (Grimme 2006), DSD-PBEP86 (Kozuch-Martin 2011), and PWPB95 (Goerigk-Grimme 2011) ship now via vibeqc.run_b2plyp / vibeqc.run_dsd_pbep86 / vibeqc.run_pwpb95, with vibeqc.run_double_hybrid(name, …) as the generic dispatcher. PWPB95 is vibe-qc’s first meta-GGA double hybrid and its first spin-opposite-scaled one (the same-spin MP2 coefficient is zero). The SCS-MP2 / SOS-MP2 machinery the double-hybrid line rides is also live; see the MP2 and double hybrids page. ωB97M(2) (range-separated meta-GGA double hybrid) remains blocked: it builds on ωB97M-V, which needs the VV10 non-local correlation functional vibe-qc does not yet implement (see the range-separated-hybrids bullet above — the same VV10 gap blocks ωB97X-V / ωB97M-V). D4 dispersion ships via the optional dftd4 package — pass dispersion="d4" to run_b2plyp / run_dsd_pbep86 / run_pwpb95 for the published X-D4 total, or call vibeqc.compute_d4 directly for arbitrary functionals. D3(BJ) is also wired through the molecular runner via the existing vibeqc.compute_d3bj machinery.

Programmatic access

from vibeqc import Functional

fn = Functional("PBE0")
print(fn.hf_exchange_fraction())    # 0.25
print(fn.kind())                    # XCKind.GGA   (well, GGA-hybrid)

# Custom libxc composition strings (comma-separated; X then C):
fn = Functional("XC_LDA_X,XC_LDA_C_VWN")            # explicit Slater + VWN
fn = Functional("XC_GGA_X_PBE,XC_GGA_C_PBE")        # PBE from separate parts

# Weighted-sum custom strings (PW1PW pattern):
fn = Functional("0.2*HF + 0.8*GGA_X_PW91, GGA_C_PW91")

The Functional ctor docstring lists every known short alias the resolver accepts.

Citations

Every run_job call writes a {stem}.bibtex and {stem}.references sibling alongside {stem}.out, pre-assembled with all the per-functional papers your job needs to cite. The list below is the human-readable equivalent of what the runtime emits; look at the auto-generated files first.

  • B3LYP: Becke, J. Chem. Phys. 98, 5648 (1993); Lee, Yang, Parr, Phys. Rev. B 37, 785 (1988); Stephens, Devlin, Chabalowski, Frisch, J. Phys. Chem. 98, 11623 (1994); Vosko, Wilk, Nusair, Can. J. Phys. 58, 1200 (1980) (the VWN5 correlation now used post-v0.8.0).

  • PBE: Perdew, Burke, Ernzerhof, Phys. Rev. Lett. 77, 3865 (1996).

  • PBE0: PBE 1996 above plus Adamo, Barone, J. Chem. Phys. 110, 6158 (1999).

  • PW91 / PW1PW: Perdew, Chevary, Vosko, Jackson, Pederson, Singh, Fiolhais, Phys. Rev. B 46, 6671 (1992); Bredow, Gerson, Phys. Rev. B 61, 5194 (2000) for the PW1PW hybrid mixing.

  • B2PLYP (and other double hybrids): Grimme, J. Chem. Phys. 124, 034108 (2006), plus the B3LYP components above.

  • TPSS / TPSSh: Tao, Perdew, Staroverov, Scuseria, Phys. Rev. Lett. 91, 146401 (2003); Staroverov, Scuseria, Tao, Perdew, J. Chem. Phys. 119, 12129 (2003) for the 10 % global-hybrid (TPSSh) variant.

  • M06-L / M06-2X: Zhao, Truhlar, J. Chem. Phys. 125, 194101 (2006) (M06-L, pure meta-GGA); Zhao, Truhlar, Theor. Chem. Acc. 120, 215 (2008) (Minnesota M06 family, including the 54 %-hybrid M06-2X).

  • SCAN: Sun, Ruzsinszky, Perdew, Phys. Rev. Lett. 115, 036402 (2015).

  • ωB97X: Chai, Head-Gordon, J. Chem. Phys. 128, 084106 (2008).

  • ωB97X-D (and its CHG / DFT-D2-type dispersion): Chai, Head-Gordon, Phys. Chem. Chem. Phys. 10, 6615 (2008); the D2 atomic C6 / vdW-radius set is Grimme, J. Comput. Chem. 27, 1787 (2006).

  • HSE06: Heyd, Scuseria, Ernzerhof, J. Chem. Phys. 118, 8207 (2003); erratum ibid. 124, 219906 (2006); Krukau, Vydrov, Izmaylov, Scuseria, J. Chem. Phys. 125, 224106 (2006) (the “06” re-parameterisation).

  • r²SCAN (and r2scan0 / r2scanh): Furness, Kaplan, Ning, Perdew, Sun, J. Phys. Chem. Lett. 11, 8208 (2020); erratum ibid. 11, 9248 (2020).

  • D3(BJ) / D4 dispersion: Grimme, Antony, Ehrlich, Krieg, J. Chem. Phys. 132, 154104 (2010); Grimme, Ehrlich, Goerigk, J. Comput. Chem. 32, 1456 (2011) (BJ damping extension); Caldeweyher, Bannwarth, Grimme, J. Chem. Phys. 150, 154122 (2019).

  • libxc itself: Lehtola, Steigemann, Oliveira, Marques, SoftwareX 7, 1 (2018).

Pre-v0.8.x workflows hand-curated this list from docs/citing.md. The runtime database now does it for you — see the citations user guide for the full schema, the auto-citations tutorial for the end-to-end manuscript workflow, and AGENTS.md § “Citation database ownership” for the rule on keeping the database in sync when adding a new functional.

See also

  • density_fitting.md — JKBuilder

    • RIJCOSX (the right Fock build for big-system hybrid DFT).

  • multi_k_scf.md — KRHF / KRKS multi-k periodic SCF. PW1PW + B3LYP + PBE0 work at multi-k via the KRKS driver.

  • molecules.md — molecular SCF + dispersion + analytic gradients.

  • scf_convergence.md — DIIS / EDIIS hybrid + level-shift / quadratic-fallback for stiff functionals.