本文主要介绍一下如何利用常见的程序做轨道局域化(也称定域化),为后续多参考态计算系列篇做点铺垫。轨道局域化的简介可参看《局域分子轨道简介》一文。至于如何自己写轨道局域化的代码,这又是另一个话题,以后再介绍。
1. Gaussian
高斯做Boys局域化十分简单,例如对苯分子的轨道局域化:
代码语言:javascript复制%chk=ben_6-31Gd.chk
%mem=2GB
%nprocshared=4
#p RHF/6-31G(d)
Title Card Required
0 1
C 1.05889731 -0.35087719 0.00000000
C 2.45405731 -0.35087719 0.00000000
C 3.15159531 0.85687381 0.00000000
C 2.45394131 2.06538281 -0.00119900
C 1.05911631 2.06530481 -0.00167800
C 0.36151531 0.85709881 -0.00068200
H 0.50913831 -1.30319419 0.00045000
H 3.00356531 -1.30339019 0.00131500
H 4.25127531 0.85695381 0.00063400
H 3.00414131 3.01752581 -0.00125800
H 0.50899431 3.01758581 -0.00263100
H -0.73808869 0.85728181 -0.00086200
--Link1--
%chk=ben_6-31Gd.chk
%mem=2GB
%nprocshared=4
#p RHF/6-31G(d) guess=(read,local,only,save) geom=allcheck
即只需在分步任务Link1中写guess=(read,local,only,save)。read表示读取上一步收敛的HF波函数;local表示进行Boys局域化;only表示不做SCF能量计算,此处即做完局域化后就退出程序;save表示将局域化后的轨道存入.chk文件中。四个词缺一不可。注意如果HF计算中写了nosymm关键词,Link1中最好也写上nosymm。geom=allcheck则是读取上一步的Title Card行、电荷、自旋多重度和坐标。高斯默认分别在占据轨道空间与空轨道空间内部做局域化。
局域化完成之后用formchk把.chk转化为.fchk文件,用GaussView打开,绘制轨道(读者也可以用Multiwfn等软件看、绘制轨道)。在占据轨道1-21号中可以很容易找到6根局域的C−H σ键、3根C−C σ键,且在空轨道22-102号中可以很容易找到对应的反键轨道。然而另外3根C−C σ键和3个C−C π键却找不到,因为同一处空间位置上的C−C σ键和π键混合在一起了。无法区分哪个是σ键,哪个是π键,这便是Boys局域化方法的一个著名现象:σ-π混合(不同角度讲既可以看作缺点也可以看作优点)。
Boys局域轨道举例
如果想要不混合的局域轨道,得用Pipek-Mezey (简称PM)局域化,只需在上面输入文件再续一个任务
代码语言:javascript复制--Link1--
%chk=ben_6-31Gd.chk
%mem=2GB
%nprocshared=4
#p RHF/6-31G(d,p) guess=(read,only,save) geom=allcheck iop(4/9=20212)
就可以看到清楚的π键了。需要注意的是,轨道局域化后已经没有轨道能级的概念了,当然也没有HOMO、LUMO这些说法了。不过仍然可以依据分子轨道Fock矩阵对角元值的大小来将局域轨道排序,这一点留待以后讲局域化代码时再介绍。
PM局域轨道举例(其余轨道如C-H键与Boys局域轨道无异)
读者可能会有疑问,为何这个PM局域化要接在Boys局域化后做。这与高斯这个功能写得比较差劲有关,比如苯的Boys局域化,基组从6-31G(d)换成6-31G(d,p)或6-311G(d)就会收敛失败;若用PM局域化,6-31G或6-31G(d)都会收敛失败。而且这种收敛失败并不会在log文件末尾报错体现,而是末尾正常结束Normal termination,仔细往上翻找可以找到Localization failed after …,打开.fchk文件看轨道会发现一团乱麻,所以现今几乎没人会选择用高斯做局域化。此处笔者仅为展示PM局域化关键词如何写,及轨道形状的σ-π分离现象,只好想方设法绕着弯在高斯里做出PM局域轨道。如若使用别的程序大可不必如此,可直接在HF计算后直接做PM局域化。
2. PySCF
PySCF的输入文件示范如下
代码语言:javascript复制from pyscf import gto, scf, lo
from pyscf.tools import molden
mol = gto.M()
mol.atom = '''
[原子坐标]
'''
mol.basis = '6-31G(d)'
mol.max_memory = 2000 # MB
mol.verbose = 4
mol.build()
#RHF calculation
mf = scf.RHF(mol)
mf.kernel()
#localize the occ/unocc separately
occ_idx = range(0,21)
vir_idx = range(21,96)
occ_loc_orb = lo.Boys(mol, mf.mo_coeff[:,occ_idx]).kernel()
mf.mo_coeff[:,occ_idx] = occ_loc_orb
vir_loc_orb = lo.Boys(mol, mf.mo_coeff[:,vir_idx]).kernel()
mf.mo_coeff[:,vir_idx] = vir_loc_orb
#localization done
#output Boys LMOs
molden.from_mo(mol, 'ben_6-31Gd_boys.molden', mf.mo_coeff)
注意#符号后都是python的注释内容,可以省去。PySCF支持对指定的某些轨道做局域化,十分灵活,更多实例可去pyscf/examples/local_orb目录下找。此处笔者写的是(0,21)和(21,96),分别表示整个占据轨道空间和整个空轨道空间(注意Python默认是从0开始计数的,且区间左闭右开)。最后输出.molden文件,用于观看轨道。
可能有读者对96这个数字有疑问,对于6-31G(d)基组,高斯默认采用Cartesian型6D,而PySCF默认采用球谐型5D,因此这里PySCF算的轨道和基函数均只有96个,而在高斯里有102个(每个C原子多出一个基函数,6个C则多出6个基函数,96 6=102。此处无基组线性依赖,因此分子轨道数目也是102)。
若想在PySCF中也使用Cartesian型基函数,则需在基组后加上一行mol.cart = True。注意:对于PySCF-1.6.4之前的版本,在使用Cartesian型时,输出的molden文件内容有误,需用1.6.4(含)之后的版本。
3. Multiwfn
Multiwfn做轨道局域化的详细内容可阅读其作者Sob的博文
http://sobereva.com/380
这里仅简要介绍一下。做完HF计算之后得到.fchk文件,用Multiwfn打开(笔者写稿时用的是2019-Jul-31版),输入19选择轨道局域化,默认是PM局域化且使用Mulliken电荷,可以通过输入-6改为其他局域化方法,如Boys局域化、或改为PM局域化且使用Löwdin电荷,界面上还有其他诸多选项,如是否局域化芯轨道等等,一看便知。
接着输入1表示只局域化占据轨道,输入2则表示分别局域化占据轨道和空轨道。局域化完成之后轨道自动保存进new.fch文件(与之前载入的.fchk文件同一目录),且程序会自动载入局域化后的轨道,可输入0观看局域轨道。
4. GAMESS
GAMESS做轨道局域化输入文件如下
代码语言:javascript复制 $CONTRL SCFTYP=RHF RUNTYP=ENERGY ICHARG=0 MULT=1 NOSYM=1
LOCAL=BOYS $END
$SYSTEM MWORDS=1000 $END
$SCF DIRSCF=.TRUE. DIIS=.TRUE. $END
$BASIS GBASIS=N31 NGAUSS=6 NDFUNC=1 $END
$LOCAL FCORE=.F. $END
$DATA
C12H12
C1 1
[原子坐标]
$END
所有的符号不能顶格,需空一格。在CONTRL里指定LOCAL=BOYS, POP, RUEDNBRG分别可做Boys局域化、PM局域化和ER局域化。局域化细节可以在
5. ORCA
ORCA做轨道局域化输入文件示例(如ben.inp)如下
代码语言:javascript复制%loc
LocMet FB
T_core -1000
Tol 1e-8
OCC true
VIRT false
end
! RHF 6-31G*
* xyz 0 1
[原子坐标]
*
在%loc中指定局域化细节,LocMet表示选取局域化方法,常用的有PM和FB两种,FB也即Boys局域化。除此之外还有NEWBOYS, AHFB, IAOBOYS, IAOIBO等等,不如前两种常用,但各有特点。T_core表示芯轨道能量截断阈值,低于此阈值的会被冻结、不参与局域化,而将其设为-1000则可认为是所有的芯轨道参与局域化。Tol是局域化函数值收敛限。OCC/VIRT表示占据轨道空间/空轨道空间,后面true/false表示是否局域化该空间。其他详细信息请参看ORCA手册。完成后会生成两份轨道文件:ben.gbw(存放正则轨道)和ben.loc(存放局域轨道),可以利用orca_2mkl ben -molden命令将ben.gbw转化为molden文件观看正则轨道。而观看局域轨道则需将ben.loc后缀手动改为gbw,例如ben_boys.gbw,再用orca_2mkl ben_boys -molden命令生成相应的molden文件。Multiwfn软件就支持用molden文件观看轨道。
6. Molcas/OpenMolcas
Molcas/OpenMolcas做轨道局域化输入文件示例(如ben.input)如下
代码语言:javascript复制&GATEWAY
Coord=ben.xyz
Basis=6-31G*
Group=C1
&SEWARD
&SCF
&LOCALISATION
Boys
其中原子坐标存放在另一个文件ben.xyz(第一行写原子数,第二行写Angstrom,第三行开始写坐标)里。局域化的所有参数和选项可以看Molcas手册LOCALISATION程序部分。局域化方法的关键词有Pipek-Mezey, Boys, Edmiston-Ruedenberg, Cholesky, PAO五种可选,默认是Pipek-Mezey。可以用Occupied, Virtual, All指定局域化哪个子空间或全部轨道,默认是Occupied(PAO默认是Virtual)。默认不冻结轨道,可以用Nfrozen指定冻结的轨道,如Nfrozen=6即表示冻结前6个芯轨道。
PS1:本文均以RHF为例,DFT的轨道也可以做局域化,过程一样;而UHF和UDFT有alpha, beta两组轨道,理论上有分别在alpha占据轨道内做局域化、beta占据轨道内做局域化等等类别,较少用到。
PS2:一般而言,轨道局域化默认是分别在占据轨道空间与空轨道空间内部做的,不会涉及一个占据轨道与一个空轨道(即两个空间)之间的轨道旋转,因此不会改变HF能量。初学者可以读入局域轨道再算一次HF,可以发现SCF会1圈(有的程序是第0圈)收敛,收敛之后的轨道又会被重新对角化为离域的正则轨道。这便是HF能量的酉不变性。像在PySCF等程序中支持对指定的轨道作局域化,如果用户指定的轨道中包含了占据轨道和空轨道,则局域化后再算HF就不会一圈收敛了(这并不是缺点,有时会用到这种灵活功能)。类似地,对CASSCF分别在双占据空间/活性空间/空轨道空间每个空间内部做局域化,也不会改变CASSCF能量。
PS3:对于芯轨道(即最内层轨道如1s, 2s等)是否参与局域化,应视具体情况而定,如果要求所有的轨道都是局域的,那么芯轨道最好也参与局域化,因为芯轨道并不总是长得像原子轨道,比如该文中的苯,1-6号正则轨道其实是分布在6个碳原子上的,只有经过局域化才能各自归属给1个碳。如果所研究的问题不涉及芯轨道,则无需参与局域化。
PS4:一般只局域化占据轨道空间,很少直接对整个空轨道空间进行局域化,虽然硬要做也可以,不过对大体系、大基组这么做非常耗时,且局域出的空轨道局域程度较差。实际上有一些其他办法解决/绕开这个问题,以后有机会再介绍。
PS5:局域化方法的入门文献,强烈推荐Pipek和Mezey于1989年发表在JCP上的文章(DOI: 10.1063/1.456588),文中对几种局域化方法都做了简洁明了的介绍,比更早的一些Boys局域化文章讲得更为清楚。