Short-Range Density Functional Theory
In the short-range density functional theory model (srDFT), the total energy is calculated as a long-range interaction by wavefunction theory and a short-range by density functional theory. The philosophy of this method is to use the good semi-local description of DFT, and then describe the long-range with wavefunction methods.
Here \(g(r_{12},\mu)\) is a range-separation function, with a range-separation parameter \(\mu\). The usual form of the range-separation function is,
It can be noted that KS-DFT and regular wavefunction theory is recovered in the limiting cases of \(\mu \rightarrow 0\) and \(\mu \rightarrow \infty\), respectively.
and,
HF–srDFT
In Hartree–Fock srDFT both the exchange and correlation functional are range-separated. This makes HF–srDFT similar to long-range corrected DFT (LRC-DFT) with the difference that only the exchange functional is range-separated in LRC-DFT. An HF–srDFT calculation can be run as:
import daltonproject as dp
molecule, basis = dp.mol_reader('water.mol')
hfsrdft = dp.QCMethod('HFsrDFT', 'SRPBEGWS')
hfsrdft.range_separation_parameter(0.4)
prop = dp.Property(energy=True)
hfsrdft_result = dp.dalton.compute(molecule, basis, hfsrdft, prop)
print('HFsrPBE energy =', hfsrdft_result.energy)
# HFsrPBE energy = -73.502309263107
The specification QCMethod('HFsrDFT', 'SRPBEGWS')
signifies that an
HF–srDFT calculation will be performed with the short-range PBE functional of
Goll, Werner and, Stoll. Furthermore,
range_separation_parameter(0.4)
sets the range-separation parameter
to \(0.4\ \mathrm{bohr^{-1}}\), which is the recommended value.
The HF–srDFT method can also be used to do LRC-DFT calculations, in which case the range-separation is only applied to the exchange fucntional.
import daltonproject as dp
molecule, basis = dp.mol_reader('water.mol')
hfsrdft = dp.QCMethod('HFsrDFT', 'LRCPBEGWS')
hfsrdft.range_separation_parameter(0.4)
prop = dp.Property(energy=True)
hfsrdft_result = dp.dalton.compute(molecule, basis, hfsrdft, prop)
print('LRCPBE energy =', hfsrdft_result.energy)
# LRCPBE energy = -73.527807924557
The setup is the same as for the HF–srDFT calculation but the functional
have been changed QCMethod('HFsrDFT', 'LRCPBEGWS')
.
MP2–srDFT
MP2 with srDFT is also supported. The main reason to use this method is as an orbital generator for CAS–srDFT calculations. MP2–srDFT is setup very similar to HF–srDFT.
import daltonproject as dp
molecule, basis = dp.mol_reader('pyridine.mol')
molecule.analyze_symmetry()
mp2srdft = dp.QCMethod('MP2srDFT', 'SRPBEGWS')
mp2srdft.range_separation_parameter(0.4)
prop = dp.Property(energy=True)
mp2srdft_result = dp.dalton.compute(molecule, basis, mp2srdft, prop)
print(mp2srdft_result.filename)
# 282603d082ffdea3ff8ef1432f5dfe1f69c12db7
print('MP2srPBE energy =', mp2srdft_result.energy)
# MP2srPBE energy = -244.7774549828
Note here, that MP2srDFT have been specified instead of HFsrDFT
QCMethod('MP2srDFT', 'SRPBEGWS')
.
If the natural orbital occupations are inspected it can be seen that they are closer to 2 or 0 than for the full-range MP2 in Picking CAS based on Natural Orbital Occupations.
import daltonproject as dp
mps2srdft_output = dp.dalton.OutputParser('282603d082ffdea3ff8ef1432f5dfe1f69c12db7')
nat_occs = mps2srdft_output.natural_occupations
print(dp.natural_occupation.scan_occupations(nat_occs))
Inspecting the natural orbital occupations uses the same methods as for full-range MP2.
Strongly occupied natural orbitals Weakly occupied natural orbitals
Symmetry Occupation Change in occ. Diff. to 2 Symmetry Occupation Change in occ.
4 1.9879 0.0000 0.0121 2 0.0124 0.0000
2 1.9882 0.0003 0.0118 4 0.0120 0.0004
--------------------------------------------------- 3 0.0026 0.0094
--------------------------------------------------- 1 0.0023 0.0003
--------------------------------------------------- 1 0.0020 0.0002
CAS–srDFT
Doing CAS calculations with srDFT also requires the choosing of an active-space. The same methods presented in Complete Active Space Self-Consistent Field can be used for CAS–srDFT also. As an example of an CAS–srDFT calculation, lets start with the MP2 natural orbitals calculated in MP2–srDFT.
import daltonproject as dp
molecule, basis = dp.mol_reader('pyridine.mol')
molecule.analyze_symmetry()
cassrdft = dp.QCMethod('CASsrDFT', 'SRPBEGWS')
cassrdft.range_separation_parameter(0.4)
prop = dp.Property(energy=True)
mp2srdft_output = dp.dalton.OutputParser('282603d082ffdea3ff8ef1432f5dfe1f69c12db7')
nat_occs = mp2srdft_output.natural_occupations
electrons, cas, inactive = dp.natural_occupation.pick_cas_by_thresholds(nat_occs, 1.99, 0.01)
cassrdft.complete_active_space(electrons, cas, inactive)
cassrdft.input_orbital_coefficients(mp2srdft_output.orbital_coefficients)
cassrdft_result = dp.dalton.compute(molecule, basis, cassrdft, prop)
print('CASsrDFT energy =', cassrdft_result.energy)
# CASsrDFT energy = -244.761631596478