本帖最后由 shenzp 于 2023-5-3 14:39 编辑
后来莫名发现对于NO分子,数值梯度也可以做了,不知道是不是在无意识的时候改了一下脚本(x)。不过对于较大的体系会很吃力,gaussian的数值梯度感觉也不是特别好用,(也有可能是我的脚本的问题)所以还是慎用。数值梯度的输入文件也已放入附件中。
----------------------------分割线----------------------------------
第二天:折腾了好久,百思不得其解,偶然发现是读取梯度数据时的正则表达式错了,没有读取E指数部分,已在原文中修改(这部分代码是让chatgpt写的,chatgpt写的代码果然容易出小bug不会写代码真是痛苦)。修改后经简单测试能正常运行。另外,对于没有解析梯度的方法(如NEVPT2),经过简单测试,通过输入文件写opt=(enonly,ef)、脚本算单点的方式去做,优化会失败,在两个结构间反复横跳。(一开始其实是想做NEVPT2优化的脚本的,所以中间文件名都用了NEVPT2,尴尬)不过目前觉得还是用CASSCF优化比较现实,所以暂时也懒得去查问题出在哪儿,若有老师能指点,还是不吝赐教。帖子还是放在这儿,在MOKIT官方的结构优化功能实现前,有需要的小伙伴还是可以用有解析梯度的方法做优化和数值频率脚本和测试的输入文件都放在了附件中。
----------------------------分割线----------------------------------
各位老师好,我最近想做CASSCF的几何优化,苦于molpro的预编译版在新电脑上无法运行,其它多参考程序又不会用,于是决定斗胆写一个将gaussian和邹神的MOKIT联用做几何优化的脚本。脚本是在Gaussian-MOKIT-Molpro 联用方案 gmm.py(http://bbs.keinsci.com/forum.php ... 33837&fromuid=38665)一文的基础上修改得到的,总体思路是先调用gaussian算UHF并检验波函数稳定性,之后用MOKIT调用pyscf等程序做多参考计算,然后返回能量及梯度给原始gaussian程序,这样能充分发挥gaussian的几何优化功能和stable=opt的功能,以及MOKIT方便地做多参考的功能,计算结果也能方便地用gv查看。但是我在用这个脚本调用pyscf做多参考,NO分子作测试的时候,发现automr输出的能量和梯度都能正确读取,gaussian的输出文件中也能看到这些值,但是在优化过程中梯度很大的情况下分子结构却几乎不变(图片在最后),感觉像是gaussian的optimizer出了问题,想请教一下大家问题出在哪里?
下面是涉及到的脚本及输入文件(本人小白,可能有写错或不妥的地方,请大佬们指正)
脚本gp.py:(与gmm.py的主要区别:1. gaussian输入文件多了G_BASIS,方便混合基组的输入。2. 把生成molpro的输入文件变成了生成automr的输入文件。由于automr从fch文件中读取坐标等信息,因此输入模板中随便写就可以。3. 针对automr程序输出文件的格式,对能量和梯度的读取进行了修改。4. 这个脚本仅针对有解析梯度的方法)
- #!/path/to/python python3
- import sys
- import os
- import json
- import re
- from xml.dom.minidom import parse
- # parse settings file
- with open("gp.json") as fo:
- settings = json.load(fo)
- G_NPROC = settings["Gaussian"]["nproc"]
- G_MEMORY = settings["Gaussian"]["memory"]
- G_LEVEL = settings["Gaussian"]["level"]
- G_BASIS = settings["Gaussian"]["basis"]
- M_NPROC = settings["mokit"]["nproc"]
- M_MEMORY = settings["mokit"]["memory"]
- M_LEVEL = settings["mokit"]["level"]
- M_COMMANDS = settings["mokit"]["commands"]
- M_TOFIND = settings["mokit"]["tofind"]
- if not os.path.exists("tmp"):
- os.mkdir("tmp")
- os.chdir("tmp")
- # Gaussian UHF calculation input file templete
- MOKIT_INP = f"""%nproc={G_NPROC}
- %mem={G_MEMORY}
- %chk=mokit.chk
- {G_LEVEL}
- MOKIT TASK
- """
- ANG2BOHR = 1.8897259886
- ELEMENTS = [
- "Bq",
- "H ", "He",
- "Li", "Be", "B ", "C ", "N ", "O ", "F ", "Ne",
- "Na", "Mg", "Al", "Si", "P ", "S ", "Cl", "Ar",
- "K ", "Ca", "Sc", "Ti", "V ", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr",
- "Rb", "Sr", "Y ", "Zr", "Nb", "Mo", "Te", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I ", "Xe",
- "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W ", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn",
- "Fr", "Ra", "Ac", "Th", "Pa", "U ", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
- ]
- (layer, InputFile, OutputFile, MsgFile, FChkFile, MatElFile) = sys.argv[1:]
- atoms = []
- coords = []
- with open(InputFile, "r") as fi:
- (atoms, derivs, charge, spin) = [int(x) for x in fi.readline().split()]
- MOKIT_INP += f"{charge} {spin}\n"
- for i in range(0, atoms):
- arr = fi.readline().split()
- atom = ELEMENTS[int(arr[0])]
- coord = [f"{(float(x) / ANG2BOHR)}" for x in arr[1:4]]
- MOKIT_INP += f" {atom}"
- MOKIT_INP += " " * 4
- MOKIT_INP += (" " * 4).join(coord)
- MOKIT_INP += "\n"
- MOKIT_INP += "\n"
- MOKIT_INP = f"""{G_BASIS}
- """
- with open("MOKIT.gjf", "w") as fo:
- fo.write(MOKIT_INP)
- print(">>> Starting UHF Calculation...")
- os.system("g16 MOKIT.gjf")
- os.system("formchk MOKIT.chk")
- os.system("mv MOKIT.fchk MOKIT.fch")
- print(">>> UHF Calculation Done!")
- print(">>> Preparing automr input file...")
- NEVPT2_INP = f"""%nproc={M_NPROC}
- %mem={M_MEMORY}
- {M_LEVEL}
- mokit{{ {M_COMMANDS} }}
- 0 1
- C 0.0 0.0 0.0
- """
- with open("NEVPT2.gjf", "w") as fo:
- fo.write(NEVPT2_INP)
- # call MOKIT to do automr calculation
- print(">>> Starting automr Calculation...")
- os.system(f"automr NEVPT2.gjf >& NEVPT2.out")
- print(">>> automr Calculation Done!")
复制代码 # extract automr output file
print(">>> Extracting automr output file ...")
# energy part
with open("NEVPT2.out","r") as f:
lines = f.readlines()
for line in lines:
if M_TOFIND in line:
match = re.search(r'[-+]\d+\.\d+',line)
if match:
energy = float(match.group())
with open(OutputFile, "w") as fo:
fo.writelines(f"{energy:20.12E}{0:20.12E}{0:20.12E}{0:20.12E}\n")
# gradients part
with open("NEVPT2.out","r") as fi, open(OutputFile, "a") as fo:
pattern = re.compile(r'Cartesian gradient \(HARTREE\/BOHR\):.*')
lines = fi.readlines()
for i, line in enumerate(lines):
if pattern.match(line):
break
lines = lines[i+1:]
gradients = []
for line in lines:
matches = re.findall(r'[-+]?\d*\.\d+E[-+]\d+', line)
if not matches:
break
gradients += [float(x) for x in matches]
for i in range(0, len(gradients), 3):
fo.write(f"{float(gradients):20.12E}{float(gradients[i+1]):20.12E}{float(gradients[i+2]):20.12E}\n")
(后面这段总是blockquote掉,干脆就不放代码框里了)
gp.json:(这一块主要区别在于1.gaussian的基组统一采用gen或genecp。2.满足automr输入文件格式。3. 针对automr中能量输出的关键词修改tofind,如SC-NEVPT2的tofind就应为"tofind": "E(SC-NEVPT2) ="。 )
- {
- "Gaussian": {
- "nproc": "8",
- "memory": "32GB",
- "level": "#p uhf gen stable=opt scf=(noincfock,novaracc,xqc) nosymm int=(nobasistransform)",
- "basis":[
- "n o",
- "6-31g*",
- "****",
- "",
- ""
- ]
- },
- "mokit": {
- "nproc": "8",
- "memory": "32GB",
- "level":"casscf(5,5)/gen",
- "commands": "casscf_prog=pyscf,force,ist=2,readuhf="mokit.fch"",
- "tofind": "E(CASSCF) ="
- }
- }
复制代码 输入文件:
- %nprocshared=1
- %chk=no.chk
- #p opt=(nomicro) external='python -u gp.py'
- t
- 0 2
- n 0.0 0.0 0.0
- o 0.0 0.0 1.3
- --link1--
- %nprocshared=1
- %chk=no.chk
- #p freq=num geom=allcheck external='python -u gp.py'
复制代码
|