分子轨道处理懒人脚本
One-Key Research Scripts for Molecular Orbitals
Jiawei Xu
Released: 2022-11-18 / Updated: 2022-11-18
当有大量分子轨道数据需要处理和作图时,懒人脚本是十分实用的。类似的做法也可以用于处理其他格点数据的作图。
1. 提取分子轨道能量
使用方法:python OrbEne.py Gaussian16.log [orblist.txt] [orbene.txt]
程序默认从当前目录下的orblist.txt获取需要输出能量的分子轨道序号,从Gaussian16.log获取结果输出到orbene.txt。orblist.txt的语法格式示例:
15 18 to 24 30 to 28 # Get MOs numbered with 15, 18-24 and 28-30.
h to h-5 l+1 # HOMO-5 to HOMO and LUMO+1
a h-3 to l+3 # Alpha-MOs from HOMO-3 to LUMO+3
程序会自动识别是否为开壳层体系。可在orblist.txt中写入多行,程序会全部读取、整理排序后输出,并同时输出HOMO-LUMO gap信息。
import sys
def is_number(s):
try:
float(s)
return True
except ValueError:
pass
try:
import unicodedata
unicodedata.numeric(s)
return True
except (TypeError, ValueError):
pass
return False
def orb_ene(output,spin=0):
flag=False
occ,vir=[],[]
ab=['Alpha','Beta']
with open(output,'r') as read:
for line in read.readlines():
l=line.split()
if len(l)>4:
if l[0]=='The' and l[1]=='electronic' and l[2]=='state':
flag=True
occ,vir=[],[]
continue
if flag and l[0]==ab[spin] and l[1]=='occ.' and l[2]=='eigenvalues':
for i in range(len(l)-4):
occ.append(l[4+i])
continue
elif flag and l[0]==ab[spin] and l[1]=='virt.' and l[2]=='eigenvalues':
for i in range(len(l)-4):
vir.append(l[4+i])
continue
if l[0]=='Condensed' and l[1]=='to' and l[2]=='atoms':
flag=False
return occ,vir
def parse(occ,src):
res=0
mo1=['h','l']
mo2=['-','+']
for i in range(2):
if is_number(src):
res=int(src)
elif src[0]==mo1[i]:
if src==mo1[i]:
res=len(occ)+i
elif len(src)>2 and src[1]==mo2[i]:
dis=int(src[2:])
res=len(occ)+dis*(2*i-1)+i
return res
def relist(occ,listfile):
orblist=[[],[]]
tmp1,tmp2=0,0
spin=0
with open(listfile,'r') as read:
for line in read.readlines():
l=line.split()
if l[0]!='b':
pass
else:
spin=1
if len(l)!=0:
for i in range(len(l)):
if is_number(l[i]) or l[i][0]=='h' or l[i][0]=='l':
tmp1=parse(occ[spin],l[i])
orblist[spin].append(tmp1)
elif l[i]=='to':
tmp1,tmp2=parse(occ[spin],l[i-1]),parse(occ[spin],l[i+1])
for j in range(abs(tmp1-tmp2)-1):
orblist[spin].append(1+j+min(tmp1,tmp2))
elif i==0 and (l[i]=='a' or l[i]=='b'):
pass
else:
print('Error in input! Exit program')
exit()
read.close()
aorblist,borblist=orblist[0],orblist[1]
aorblist.sort(),borblist.sort()
return aorblist,borblist
def list_ene(output,listfile,writefile):
aocc,avir=orb_ene(output,0)
aorb=aocc+avir
bocc,bvir=orb_ene(output,1)
borb=bocc+bvir
occ=[aocc,bocc]
vir=[avir,bvir]
orb=[aorb,borb]
smallab,bigab=['a','b'],['Alpha','Beta']
orblist=relist(occ,listfile)
with open(writefile,'w') as ene:
for spin in range(2):
if len(bocc)==0 and spin==1:
break
orbs=orb[spin]
ene.write(bigab[spin]+'-HOMO is orbital '+str(len(occ[spin]))+smallab[spin]+'\n')
gap=float(orbs[len(occ[spin])])-float(orbs[len(occ[spin])-1])
ene.write(bigab[spin]+'-HOMO-LUMO gap is '+format(gap,'.5f')+' a.u. or '+format(gap*27.2114,'.5f')+' eV\n')
for i in range(len(orblist[spin])):
orbene_au=orbs[orblist[spin][i]-1]
orbene_ev=format(float(orbene_au)*27.2114,'.5f')
ene.write(str(orblist[spin][i])+smallab[spin]+'\t'+orbene_au+'\t'+orbene_ev+'\n')
ene.write('\n')
ene.close()
return
output=sys.argv[1]
listfile='orblist.txt'
try:
listfile=sys.argv[2]
except:
pass
writefile='orbene.txt'
try:
writefile=sys.argv[3]
except:
pass
list_ene(output,listfile,writefile)
输出示例:
Alpha-HOMO is orbital 217a
Alpha-HOMO-LUMO gap is 0.06212 a.u. or 1.69037 eV
213a -0.25040 -6.81373
214a -0.24144 -6.56992
215a -0.23823 -6.48257
216a -0.23769 -6.46788
217a -0.14421 -3.92416
218a -0.08209 -2.23378
219a -0.07925 -2.15650
220a -0.07452 -2.02779
221a -0.03748 -1.01988
222a -0.02886 -0.78532
Beta-HOMO is orbital 215b
Beta-HOMO-LUMO gap is 0.05099 a.u. or 1.38751 eV
211b -0.24697 -6.72040
212b -0.24529 -6.67468
213b -0.23739 -6.45971
214b -0.23734 -6.45835
215b -0.23716 -6.45346
216b -0.18617 -5.06595
217b -0.07925 -2.15650
218b -0.07677 -2.08902
219b -0.07473 -2.03351
220b -0.07442 -2.02507
2. 批量提取分子轨道能量
搭配1中脚本使用,一次性获取当前目录下所有.log文件记录的分子轨道信息。对于优化任务,默认获取最后一帧结构的信息。
for i in ./*.log
do
fname=`basename $i .log`
orbene $i ./orblist.txt ./orbene_$fname.txt
done
mkdir orb_ene
mv ./orbene_*.txt orb_ene/
3. 批量导出分子轨道格点数据
前线轨道的分布是时常会关心的问题,以下脚本会调用Multiwfn(假定通过mwfn命令运行)产生.cub文件,接受一个参数N用于定义轨道范围。事实上也可以与1中脚本结合,使轨道范围定义更佳灵活,不过一般我们只关心前线轨道,使用一个参数定义已经足够。
使用方法:./FMO.sh N(产生HOMO-(N-1)至LUMO-(N-1)范围的分子轨道格点数据)
function judge_u(){
mwfn $1 > ./null << EOF
q
EOF
set `grep 'determinant' ./null`
rm -f ./null
if [ $4 = 'unrestricted' ]
then
return 1
else
return 0
fi
}
function get_orb(){
mwfn $1 > ./null << EOF
200
3
$2
3
0
q
EOF
rm -f ./null
}
mkdir fmos
for i in ./*fchk
do
fname=`basename $i .fchk`
mkdir fmos/$fname
judge_u $i
if [ $? = 0 ]
then
get_orb $i h
get_orb $i l
j=1
while ((j<$1))
do
get_orb $i h-$j
get_orb $i l+$j
((j++))
done
else
for s in {a,b}
do
get_orb $i h$s
get_orb $i l$s
j=1
while ((j<$1))
do
get_orb $i h$s-$j
get_orb $i l$s+$j
((j++))
done
done
fi
mv ./*.cub fmos/$fname
done
4. 批量渲染分子轨道等值面图
该脚本需要安装VMD1.9.3和vcube2.0,可从http://bbs.keinsci.com/thread-18150-1-1.html下载。运行后自动调用VMD和vcube,使用Tachyon渲染器进行批量渲染。需要当前目录下有一个show.tcl文件用作可视化模板,使用时先对一个分子进行调整,效果满意后将操作过程通过VMD导出即可。
使用方法:./MO_Isosurface.sh
for i in ./*.cub
do
fname=`basename $i .cub`
vmd << EOF
vmol $i
`cat ./show.tcl`
vrender
n
quit
EOF
rm -f ./VCUBE/renderall.bat ./VCUBE/renderall.sh
mv ./VCUBE/renderall.dat $fname.dat
done
cd ./VCUBE
for i in ./*.dat
do
/usr/local/lib/vmd/tachyon_LINUXAMD64 $i -format BMP -o $i.bmp -trans_raster3d -res 2000 1500 -numthreads 16 -aasamples 24 -mediumshade
done
cd ..