计算化学公社
标题:
一个方便用于orca批处理的python模块
[打印本页]
作者Author:
Graphite
时间:
2018-3-19 18:54
标题:
一个方便用于orca批处理的python模块
本帖最后由 Graphite 于 2018-11-15 18:08 编辑
CAUTION: This page is written in Chinese, If you read it via Google Translate, the code below will LOSE ITS FORMAT, so DO NOT copy and paste the code in translated page.
本模块(ChOrca)主要用于解决以下问题:
1.治好用惯了gview的人要用ORCA时, 粘来粘去的毛病
2.节省反复编写输入文件和建文件夹浪费的时间
3.简单调用cclib对输出文件进行解析
环境需求:
1.cclib -- 一个用于解析量化软件输出的库
2.需要自定义settings.json(下文提到)
注意:
本模块仅在windows下测试, linux理论可用.
By the way, 笔者用win10+GView+ORCA+本模块+VisualStudio Code集成终端用的很爽...虚拟机已删...
例: 本文件夹下有数个.gjf文件, 现在想要调用ORCA提取其中的坐标进行计算, 编写如下脚本:
import ChOrca
for gjf in ['a.gjf', 'b.gjf', 'c.gjf', ]:
name = gjf.split('.')[0]
calc = ChOrca.Calculation(name)
calc.set_input_from_template('rank_1_opt', 'mem_1000mb', 0, 1, gjf)
calc.run_orca()
复制代码
这里的'rank_1_opt', 'mem_1000mb'是我们在settings.json里的键, 实际调用其对应的值, 相当于设置了别名. settings.json最好与此脚本放在同一目录下.
{
"orca_path": "D:\\ProgramFiles\\orca\\orca.exe",
"template_keyword_excls": {
"rank_1_opt": "!pal4 blyp def2-svp def2/j d3 miniprint"
},
"template_keyword_prcts": {
"mem_1000mb": "%maxcore 1000"
}
}
复制代码
模块包含的方法和参数, 在代码内部的docstring中都有提到. 源代码如下:
#coding: utf-8
"""
This is a python module for calculation orca jobs conviently.
Import it and enjoy!
Lincense: Whatever, use it, copy it, or modify it as you like.
Author: T. H. Graphite
"""
import json
import os
import re
import subprocess
import sys
import cclib
class Calculation():
"""Calculate orca jobs.
Keyword Arguments:
name {str}-- the instance name, for creating new files and dirs.
work_dir {str} -- work directory, default: the path of module.
Once a instance is created, a new directory work_dir/name will be made.
Thus, all the calcultion will be done at this directory.
Methods:
load_settings(path)
set_input(keyword_excl, keyword_prct, ncharge, nmulti, coordinates)
set_input_from_xyz(keyword_excl, keyword_prct, ncharge, nmulti, path)
Attributes:
parse_json
parse_result
"""
def __init__(self, name, work_dir=sys.path[0]):
self.name = name
self.work_dir = work_dir
os.chdir(self.work_dir)
self.dir = os.path.join(self.work_dir, self.name)
self.load_settings()
if not os.path.exists(self.dir):
os.mkdir(self.dir)
self.input_path = os.path.join(self.dir, self.name + '.inp')
self.output_path = os.path.join(self.dir, self.name + '.out')
def load_settings(self, path=None):
"""Load settings from path.
Keyword Arguments:
path {str} -- the path of json settings file (default: work_dir/settings.json)
"""
if path is None:
path = os.path.join(self.work_dir, 'settings.json')
try:
settings_file = open(path, 'r')
settings_dict = json.load(settings_file)
self.orca_path = settings_dict['orca_path']
self.template_keyword_excls = settings_dict['template_keyword_excls']
self.template_keyword_prcts = settings_dict['template_keyword_prcts']
except Exception:
print('No settings file or invalid format. Exit.')
exit()
def set_input(self, keyword_excl, keyword_prct, ncharge, nmulti, coordinates):
"""Set input contents for calculation
Arguments:
keyword_excl {str} -- keywords start with a !
keyword_prct {str} -- keyword start with a %, a.k.a. the 'block' in orca manual.
ncharge {str or int} -- charge of molecule
nmulti {str or int} -- multiplicity of molecule
coordinates {str} -- coordinates in format like "C 1.000 1.000 1.000\nC 2.000 2.000 2.000..." .
"""
self.input_content = "{kw_excl}\n{kw_prct}\n*xyz {nchg} {nmtp}\n{coord}\n*".format(
kw_excl=keyword_excl,
kw_prct=keyword_prct,
nchg=str(ncharge),
nmtp=str(nmulti),
coord=coordinates)
def set_input_from_xyz(self, keyword_excl, keyword_prct, ncharge, nmulti, path):
"""Set input contents for calculation, coordinates from a xyz-like file
(.xyz, .gjf, or any file can be filter by the regex below)
Arguments:
keyword_excl {str} -- keywords start with a !
keyword_prct {str} -- keyword start with a %
ncharge {str or int} -- charge of molecule
nmulti {str or int} -- multiplicity of molecule
path {str} -- the path of the xyz-like file
"""
regex = r'\ {0,2}[A-Z][a-z]?(\ *-?[0-9]*\.[0-9]*){3,}'
pattern = re.compile(regex)
file_object = open(path, 'r')
coordinates = str()
for line in file_object:
if pattern.match(line):
coordinates += line
file_object.close()
self.set_input(keyword_excl, keyword_prct, ncharge, nmulti, coordinates)
def set_input_from_template(self, temp_excl, temp_prct, ncharge, nmulti, path):
"""Like set_input_from_xyz, but use template names (in the settings file, see: load_settings)
Arguments:
temp_excl {str} -- a key of template_keyword_excls
temp_prct {str} -- a key of template_keyword_prcts
ncharge {str or int} -- charge of molecule
nmulti {str or int} -- multiplicity of molecule
path {str} -- the path of the xyz-like file
"""
keyword_excl = self.template_keyword_excls[temp_excl]
keyword_prct = self.template_keyword_prcts[temp_prct]
self.set_input_from_xyz(keyword_excl, keyword_prct, ncharge, nmulti, path)
def run_orca(self):
"""Running orca
Returns:
Boolean -- whether the calculation is terminated normally or not.
"""
if not os.path.exists(self.orca_path):
raise(EnvironmentError)
input_file = open(self.input_path, 'w')
input_file.write(self.input_content)
input_file.close()
run_command = self.orca_path + ' ' + self.input_path + ' > ' + self.output_path
try:
subprocess.check_call(run_command, shell=True)
return True
except subprocess.CalledProcessError:
return False
@property
def parse_json(self):
"""Parse the output file using cclib.
Returns:
str -- a json string, including lots of interesting infos
"""
parse_target = cclib.ccopen(self.output_path)
if parse_target is not None:
try:
print(parse_target)
parse_result = parse_target.parse()
json = cclib.ccwrite(
parse_result, outputtype='json', returnstr=True)
return json
except Exception:
return None
@property
def parse_result(self):
"""The dictionary version of parse_json.
Returns:
dict -- a flattened dict
"""
def walk(dictionary):
for key, value in dictionary.items():
if isinstance(value, dict):
for tup in walk(value):
yield (key, ) + tup
else:
yield key, value
result = dict()
for tup in walk(json.loads(self.parse_json)):
result.setdefault('/'.join(tup[:-1]), tup[-1])
return result
if __name__ == '__main__':
print(__doc__)
复制代码
作者Author:
ChrisZheng
时间:
2018-3-19 18:56
代码粘过来全部乱码了 看起来很厉害的样子 战略马克
欢迎光临 计算化学公社 (http://bbs.keinsci.com/)
Powered by Discuz! X3.3