1. Gaussian 中的 PUHF/PMP2 结果的重新实现#
创建时间:2019-08-31,最后修改:2019-09-01
在这一份笔记中,我们将使用 PySCF 的功能与 NumPy 重复 Gaussian 中计算的 PUHF 与 PMP2 能量结果;并对 PUHF 与 PMP2 的推导作简单的说明。
from pyscf import gto, scf, mp
1.1. 参考结果与体系定义#
1.1.1. Gaussian 结果#
在 Gaussian 中,我们使用以下输入卡可以得到 PUHF/PMP2 能量:
#p UMP2(Full)/6-31G nosymm
H2O
3 4
O 0. 0. 0.
H 1. 0. 0.
H 0. 1. 0.
对于上述分子,其中一些重要的输出结果是
\(E_\mathrm{UHF}\):-73.0451423839
\(E_\mathrm{UMP2, corr}\): -0.02646719276
\(E_\mathrm{UMP2}\): -73.071609576661
\(\langle S_z \rangle\): 1.5
\(\langle S^{2(0)} \rangle\): 3.7531
\(\langle S^{2(0)} \rangle + \langle S^{2(1)} \rangle\): 3.7504
\(E_\mathrm{PUHF}\):-73.046146318
\(E_\mathrm{PMP2}\): -73.072180589
输出文件参见 assets/PUHF_and_PMP2.out
;其中,有效的数据可以通过下述的代码获得:
with open("assets/PUHF_and_PMP2.out", "r") as output:
output_lines = output.read().split("\n")
for line_num, line_text in enumerate(output_lines):
if any([keyword in line_text for keyword in
["SCF Done", "EUMP2", "<S**2>", "(S**2,1)", "E(PMP2)"]]) \
and "Initial guess" not in line_text:
print("line {:03d}: {}".format(line_num, line_text))
line 336: SCF Done: E(UHF) = -73.0451423839 A.U. after 11 cycles
line 338: <Sx>= 0.0000 <Sy>= 0.0000 <Sz>= 1.5000 <S**2>= 3.7531 S= 1.5008
line 370: (S**2,0)= 0.37531D+01 (S**2,1)= 0.37504D+01
line 371: E(PUHF)= -0.73046146318D+02 E(PMP2)= -0.73072180589D+02
line 373: E2 = -0.2646719276D-01 EUMP2 = -0.73071609576661D+02
我们的目标就是近乎准确无误地重复上述八个结果。
1.1.2. PySCF 体系定义#
为了获得与 Gaussian 相同的结果,我们需要定义相同的分子与电荷、多重度环境:
mol = gto.Mole()
mol.atom = """
O 0. 0. 0.
H 1. 0. 0.
H 0. 1. 0.
"""
mol.charge = 3
mol.spin = 3
mol.basis = "6-31G"
mol.build()
<pyscf.gto.mole.Mole at 0x7fa4e5342160>
通过 PySCF 计算 UHF 能量:
scf_eng = scf.UHF(mol)
scf_eng.conv_tol = 1e-10
scf_eng.run();
converged SCF energy = -73.0451423536459 <S^2> = 3.7530824 2S+1 = 4.0015409
上述结果应当能与 \(E_\mathrm{UHF}\) 和 \(\langle S^{2(0)} \rangle\) 对应。\(\langle S_z \rangle = 1.5\) 几乎是显然的。不过,我们仍然不了解 \(\langle S^{2(0)} \rangle\) 是如何生成的。
通过 PySCF 计算 UMP2 能量:
mp2_eng = mp.UMP2(scf_eng)
mp2_eng.run();
E(UMP2) = -73.0716095455079 E_corr = -0.0264671918619837
上述结果应当能与 \(E_\mathrm{UMP2, corr}\) 和 \(E_\mathrm{UMP2}\) 对应。
因此,当前的问题将是回答:如何重复
\(\langle S^{2(0)} \rangle\): 3.7531
\(\langle S^{2(0)} \rangle + \langle S^{2(1)} \rangle\): 3.7504
\(E_\mathrm{PUHF}\):-73.046146318
\(E_\mathrm{PMP2}\): -73.072180589
1.1.3. 部分变量定义#
首先,我们遵从大多数量化文章中的记号
\(i, j\) 代表占据分子轨道
\(a, b\) 代表非占分子轨道
\(p, q\) 代表任意分子轨道
\(\alpha, \beta\) 代表任意原子轨道
变量名 |
元素记号 |
意义与注解 |
标量或区间 |
---|---|---|---|
|
\(n_\mathrm{occ}^\alpha\) |
\(\alpha\) 自旋电子数 |
\(5\) |
|
\(n_\mathrm{occ}^\beta\) |
\(\beta\) 自旋电子数 |
\(2\) |
|
\(N\) |
总电子数 |
\(7\) |
|
\(n_\mathrm{MO}\) |
分子轨道数 |
\(13\) |
|
\(n_\mathrm{AO}\) |
原子轨道数 |
\(13\) |
|
\(S_{\mu \nu}\) |
原子轨道重叠积分 |
|
|
\(\alpha\) 占据轨道分割 |
\([0, 5)\) |
|
|
\(\beta\) 占据轨道分割 |
\([0, 2)\) |
|
|
\(\alpha\) 非占轨道分割 |
\([5, 13)\) |
|
|
\(\beta\) 非占轨道分割 |
\([2, 13)\) |
|
|
\(S_x\) |
\(x\) 分量自旋 |
\(0\) |
|
\(S_y\) |
\(y\) 分量自旋 |
\(0\) |
|
\(S_z\) |
\(z\) 分量自旋 |
\(3/2\) |
变量名 |
元素记号 |
意义与注解 |
---|---|---|
|
\(C_{\mu p}\) |
\(\alpha\) 系数矩阵 |
|
\(C_{\mu \bar p}\) |
\(\beta\) 系数矩阵 |
|
\(e_{p}\) |
\(\alpha\) 轨道能 |
|
\(e_{\bar p}\) |
\(\alpha\) 轨道能 |
|
\(e_{i}\) |
\(\beta\) 占据轨道能 |
|
\(e_{\bar i}\) |
\(\alpha\) 占据轨道能 |
|
\(e_{a}\) |
\(\alpha\) 非占轨道能 |
|
\(e_{\bar a}\) |
\(\beta\) 非占轨道能 |
|
\(D_{ij}^{ab}\) |
\(\alpha, \alpha\) 轨道能差 |
|
\(D_{i \bar j}^{a \bar b}\) |
\(\alpha, \beta\) 轨道能差 |
|
\(D_{\bar i \bar j}^{\bar a \bar b}\) |
\(\beta, \beta\) 轨道能差 |
变量名 |
元素记号 |
意义与注解 |
---|---|---|
|
\(t_{ij}^{ab}\) |
\(\alpha, \alpha\) MP2 激发系数 |
|
\(t_{i \bar j}^{a \bar b}\) |
\(\alpha, \beta\) MP2 激发系数 |
|
\(t_{\bar i \bar j}^{\bar a \bar b}\) |
\(\beta, \beta\) MP2 激发系数 |
|
\(D_{ij}^{ab}\) |
\(\alpha, \alpha\) MP2 激发系数分母 |
|
\(D_{i \bar j}^{a \bar b}\) |
\(\alpha, \beta\) MP2 激发系数分母 |
|
\(D_{\bar i \bar j}^{\bar a \bar b}\) |
\(\beta, \beta\) MP2 激发系数分母 |
上述需要补充说明的公式有:
对于 MP2 激发系数分母,另外两种自旋情况的 \(D_{ij}^{ab}\) 与 \(D_{\bar i \bar j}^{\bar a \bar b}\) 也可以类似地生成。
# === Molecular
# --- Definition
nocc_a, nocc_b = mol.nelec
N = nocc_a + nocc_b
nmo = nao = mol.nao
S = mol.intor("int1e_ovlp")
# --- Derivative
so_a, so_b = slice(0, nocc_a), slice(0, nocc_b)
sv_a, sv_b = slice(nocc_a, nmo), slice(nocc_b, nmo)
Sx, Sy, Sz = 0, 0, 0.5 * (nocc_a - nocc_b)
# === UHF Calculation
# --- Definition
C_a, C_b = scf_eng.mo_coeff
e_a, e_b = scf_eng.mo_energy
# --- Derivative
eo_a, eo_b = e_a[so_a], e_b[so_b]
ev_a, ev_b = e_a[sv_a], e_b[sv_b]
D2_aa = eo_a[:, None, None, None] + eo_a[None, :, None, None] - ev_a[None, None, :, None] - ev_a[None, None, None, :]
D2_ab = eo_a[:, None, None, None] + eo_b[None, :, None, None] - ev_a[None, None, :, None] - ev_b[None, None, None, :]
D2_bb = eo_b[:, None, None, None] + eo_b[None, :, None, None] - ev_b[None, None, :, None] - ev_b[None, None, None, :]
# === MP2 Calculation
t2_aa, t2_ab, t2_bb = mp2_eng.t2
作为对四脚标张量性质的验证,我们计算 MP2 相关能 \(E_\mathrm{MP2, corr}\) 如下:
(+ 0.25 * (t2_aa**2 * D2_aa).sum()
+ 0.25 * (t2_bb**2 * D2_bb).sum()
+ (t2_ab**2 * D2_ab).sum())
-0.02646719186198365
PySCF 所给出的 \(E_\mathrm{MP2, corr}\) 可以给出相同的结果:
mp2_eng.e_corr
-0.02646719186198366
1.2. \(\langle S^2 \rangle\) 相关计算#
1.2.1. 分子轨道基组重叠矩阵 S_pq
\(S_{p \bar q}\)#
若用量子力学记号,上述矩阵元素可能表示为
注意上述的积分是空间坐标的积分,不包含自旋部分的积分。
S_pq = C_a.T @ S @ C_b
S_pq.shape
(13, 13)
我们以后还会使用上述矩阵的占据-占据部分 S_ij
\(S_{i \bar j}\)、占据-非占部分 S_ia
\(S_{i \bar a}\) 与非占-占据部分 S_ai
\(S_{a \bar i} = S_{\bar i a}\):
S_ij, S_ia, S_ai = S_pq[so_a, so_b], S_pq[so_a, sv_b], S_pq[sv_a, so_b]
[S_ij.shape, S_ia.shape, S_ai.shape]
[(5, 2), (5, 11), (8, 2)]
1.2.2. S2_0
\(\langle S^{2(0)} \rangle\)#
\(\langle S^{2(0)} \rangle\) 在程序中通常写为 <S^2>
或 <S**2>
。在 Gaussian 计算 PUHF 处,还写为 (S**2,0)
。这意味着是 UHF 波函数的 \(\langle S^2 \rangle_\mathrm{UHF}\)。相对地,UMP2 波函数给出的对 \(\langle S^2 \rangle\) 的矫正将记作 \(\langle S^{2(1)} \rangle\)。
参考 Chen and Schlegel [1] Table 1, \(0 \rightarrow 0\) 或等价地,Szabo and Ostlund [2] eq (2.271)
S2_0 = Sz * (Sz + 1) + nocc_b - (S_ij**2).sum()
S2_0
3.7530823820890378
Gaussian 的参考值是 3.7531。
为了以后的记号便利,我们在这里定义 L
L = (S_ij**2).sum()
1.2.3. S2_1
\(\langle S^{2(1)} \rangle\)#
上式的第一个等号是 Chen and Schlegel [1] eq (5) 所给出的;而第三个等号是 Table 1 \(0 \rightarrow \alpha \beta (i, a: \alpha; j, b: \beta)\) 给出的。
上式的推导中有一处关于 \(| \Psi^{(1)} \rangle\) 的展开的推导省略。我们知道
但由于利用到 \(\langle 0 | \hat S^2 | \Psi_{ij}^{ab} \rangle = \langle 0 | \hat S^2 | \Psi_{\bar i \bar j}^{\bar a \bar b} \rangle = 0\),因此在第二个等号时只从三个 \(| \Psi^{(1)} \rangle\) 中留下了一项。关于 \(\hat S^2\) 作用在 UHF 波函数与轨道下的性质,可以参考 Schlegel [3] eq (5) 的说明。
S2_1 = - 2 * (t2_ab * S_ia[:, None, None, :] * S_ai.T[None, :, :, None]).sum()
S2_1
-0.002658400959213991
因此,UMP2 矫正过的 \(\langle S^2 \rangle_\mathrm{UMP2} = \langle S^{2(0)} \rangle + \langle S^{2(1)} \rangle\) 的结果是
S2_0 + S2_1
3.7504239811298237
Gaussian 的参考值是 3.7504。
1.2.4. S4SD
\(\texttt{S4SD}\)#
S4SD
的表达式较为复杂,我们也直接使用 \(\texttt{S4SD}\) 而不用其他记号表示该项:
S4SD = (nocc_a - L) * (nocc_b - L) + 2 * L - 2 * (S_ij @ S_ij.T @ S_ij @ S_ij.T).trace() + S2_0**2
S4SD
14.101029785519533
该表达式的来源可能是 Amos and Hall [4]。该文的 eq (7·02) 下方公式中,有通过稍高阶的投影而获得的 \(\langle S^2 \rangle\) 的计算方式
通过这种方式获得的 \(\langle S^2 \rangle\) 近似值可以相当精确,比 \(\langle S^{2(0)} \rangle + \langle S^{2(1)} \rangle\) 还要接近精确值 \(3.75\):
S2_0 + (S4SD - S2_0**2) / (S2_0 - (Sz + 1) * (Sz + 2))
3.749999998117527
相信 \(\texttt{S4SD}\) 的存在意义是用于计算 Schlegel [3] 式 eq (24) 中的 \(\langle \tilde \Phi_1 | \tilde \Phi_1 \rangle = \langle \Phi_0 | A_{s + 1}^\dagger A_{s + 1} | \Phi_0 \rangle\);但关于这一关系我还不确定是否正确。后面计算 PMP2 能量时会使用上 \(\texttt{S4SD}\)。
1.3. 自旋污染矫正能量计算#
1.3.1. EPUHF
\(E_\mathrm{PUHF}\)#
根据 Schlegel [3] eq (22),PUHF 能量可以表达为
其中,\(\hat P_s\) 算符称为 Löwdin 算符 [5] eq (7),
相当于将自旋不纯的波函数纯化为自旋量子数为 \(s\) 的态。在实际使用中,通常使用 \(\hat A_{s + 1} \simeq \hat P_s\) 替代;关于这段讨论可以参考 Rossky and Karplus [6] section V.A 的讨论,而下面公式的形式参考 Schlegel [3] eq (14);其中,\(s\) 一般取 \(S_z\):
关于 \(\hat A_{s + 1}\),一个显然的性质是 \(\langle \Psi_0 | \hat A_{s + 1} | \Psi_0 \rangle = 1\)。
为了程序方便,定义下述临时变量 Y
那么 D_EPUHF
Y = S2_0 - (Sz + 1) * (Sz + 2)
D_EPUHF = - 1 / Y * (t2_ab * D2_ab * S_ia[:, None, None, :] * S_ai.T[None, :, :, None]).sum()
D_EPUHF
-0.0010039336320381543
因而 \(E_\mathrm{PUHF} = E_\mathrm{UHF} + \Delta E_\mathrm{PUHF}\):
scf_eng.e_tot + D_EPUHF
-73.04614628727792
Gaussian 的参考值是 -73.046146318。
1.3.2. EPMP2
\(E_\mathrm{PMP2}\)#
根据 Schlegel [3] eq (24),PMP2 能量可以表达为
关于上式的分数项,分子部分可以写为
而关于分子项,参考在 \(\texttt{S4SD}\) 的讨论,
但作者不能断定上述论断的正确性。
将分子、分母的结果代入 \(\Delta E_\mathrm{PMP2}\) 的算式中,可以得到 D_EPMP2
D_EPMP2 = D_EPUHF * (1 - 0.5 * S2_1 * Y / (S4SD - S2_0**2))
D_EPMP2
-0.0005710125302116336
因而 \(E_\mathrm{PMP2} = E_\mathrm{UMP2} + \Delta E_\mathrm{PMP2}\):
mp2_eng.e_tot + D_EPMP2
-73.07218055803808
Gaussian 的参考值是 -73.072180589。
至此,我们已经完成了使用 PySCF 的功能与 NumPy 重复 Gaussian 的 PUHF、PMP2 的能量结果了。
1.4. 修订时间轴#
2019/08/30 写完文档;文档基于 2019/08/13 的一份笔记。
2019/09/01 补充一部分推导。