需求:有一个需要用一种受体对八千多个小分子对接的任务,故写下此脚本。

对接数据如下:

225f85c99d5c5b60c2a7eea2b5c6326e.png

不同名称的中药

3eac42f37e0f2081005e43f1bddcc0b5.png

其中一种中药含有的各种成分,已经通过 prepare_receptor4.py 批量转换为 pdbqt 文件

对接脚本如下,放到不同中药文件夹的目录下运行即可(linux):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# -*- coding: utf-8 -*-
"""
Created on *********

@author: 真弓快车

该脚本的目的是检查因为异常而未能对接成功的分子,再批量对接

example:
vina --ligand ./*/*.pdbqt --out result.pdbqt --config 2oxe.conf > result.log
"""

import os
import sys
from joblib import Parallel, delayed
from tqdm import tqdm
import time


def docker(ingredient, medname): # 并行处理函数
os.system("vina --ligand ./"+medname+'/' + ingredient + " --out ./"+medname+'/' + str(ingredient).replace(".pdbqt", "") + "_out.pdbqt --config 2oxe.conf > ./"+medname+"/"+ingredient.replace('.pdbqt',".log"))


if __name__ == '__main__':
medList = os.listdir()
for medname in tqdm(medList):
if '.' not in medname:
# print(medname) # 定位到植物
ingredientList = os.listdir('./'+medname+'/')

# print(ingredientList)
ingredientList_outPdbqt = []
for iop in ingredientList:
if '_out' in iop:
ingredientList_outPdbqt.append(iop)

# print(ingredientList_outPdbqt)
ingredientList_outPdbqt_1 = []
for iop1 in ingredientList_outPdbqt:
iop1 = iop1.replace('_out', '')
ingredientList_outPdbqt_1.append(iop1)
# print(ingredientList_outPdbqt_1)

ingredientNotOutNotLogList = []
for inonl in ingredientList:
if '_out' not in inonl:
if '.log' not in inonl:
ingredientNotOutNotLogList.append(inonl)
# print(ingredientNotOutNotLogList)

ingredientNotDock = list(set(ingredientNotOutNotLogList)-set(ingredientList_outPdbqt_1))
# print(ingredientNotDock)


# for ingredient in ingredientNotDock:
# # print(ingredient) # 定位到具体植物具体未对接的成分
# print("vina --ligand ./"+medname+'/' + ingredient + " --out ./"+medname+'/' + str(ingredient).replace(".pdbqt", "") + "_out.pdbqt --config 2oxe.conf > ./"+medname+"/"+ingredient.replace('.pdbqt',".log"))
# pass

Parallel(n_jobs=-1)(delayed(docker)(ingredient, medname) for ingredient in ingredientNotDock)


运行完毕后还需要将所有的结果导出,故写了下列数据整理代码。放到不同中药文件夹的上一级目录,名称改成ingredientPdbqt,或者直接修改脚本也可。示例:

8674f821964996a3af1d5edfaf0770cb.png

数据整理脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# -*- coding: utf-8 -*-
"""
Created on *********

@author: 真弓快车

该脚本的目的是将所有的txt文件整理输出为一个csv文件

example:
vina --ligand ./*/*.pdbqt --out result.pdbqt --config 2oxe.conf > result.log
"""

import os
import sys
import pandas as pd
import numpy as np


def log2List(medfile, pdbqtFile):
# dockResult = []
with open("./ingredientPdbqt/"+medfile+'/'+pdbqtFile, 'r', encoding='UTF-8') as logfile:
# print(pdbqtFile, logfile.readlines()[38][10:18]) # 对接结果
try:
dockResult = logfile.readlines()[38][10:18]
print(pdbqtFile, dockResult)
return dockResult
except IndexError:
return 'None'


if __name__ == '__main__':
# 文件夹初始化
originFileList = os.listdir()
if 'csv' not in originFileList:
os.mkdir('csv')


medfiles = os.listdir("./ingredientPdbqt")
for medfile in medfiles:
# print(medfile) 定位到药食同源文件夹
pdbqtFiles = os.listdir("./ingredientPdbqt/"+medfile)
for pdbqtFile in pdbqtFiles:
if '.log' in pdbqtFile:
dockResult = log2List(medfile, pdbqtFile)
with open("./csv/"+medfile+'.csv', 'a+', encoding='UTF-8') as csvfile:
csvfile.write(pdbqtFile+','+dockResult+'\n')

# 计算对接平均值并改名
csvListDir = os.listdir("./csv")
for csvFile in csvListDir:
csvContent = pd.read_csv('./csv/'+csvFile)
dockingResultList = csvContent.iloc[:, 1]
dockingMean = np.mean(dockingResultList)
print(csvFile+'平均对接分数'+str(dockingMean))
os.rename('./csv/'+csvFile, './csv/'+str(round(float(dockingMean), 4))+'='+csvFile)

注意运行该脚本前,要保证ingredientPdbqt 文件夹只有文件夹,没有任何文件存在。否则会运行错误。

已知 Bug:使用该脚本时有时会出现控制台出现”Killed“字样,这是因为内存不足导致系统强制中止其中一个对接的进程。解决办法是将 Parallel(n_jobs=-1)里面的”-1”改成低于你 cpu 的核数。要么你运行多几次这个脚本。保证每个对接都能顺利进行。
��顺利进行。