pautodock 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.1
2
+ Name: pautodock
3
+ Version: 1.0.0
4
+ Summary: A simple tool to parallelize AutoDock JOBs
5
+ Home-page: https://github.com/gmrandazzo/PAutoDock
6
+ License: lglpv3
7
+ Author: Giuseppe Marco Randazzo
8
+ Author-email: gmrandazzo@gmail.com
9
+ Requires-Python: >=3.8,<4.0
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
12
+ Classifier: License :: Other/Proprietary License
13
+ Classifier: Operating System :: MacOS :: MacOS X
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
22
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
23
+ Project-URL: Repository, https://github.com/gmrandazzo/PAutoDock
24
+ Description-Content-Type: text/markdown
25
+
26
+ # PAutodock - Parallelize AutoDock JOBs
27
+
28
+ PAutodock is a powerful set of scripts designed to parallelize AutoDock jobs, enabling fast screening across multiple CPUs. This tool is particularly useful for researchers and scientists working in computational biology and drug discovery, allowing them to efficiently manage and execute docking simulations.
29
+
30
+ ## Table of Contents
31
+
32
+ - [License](#license)
33
+ - [Dependencies](#dependencies)
34
+ - [Changelog](#changelog)
35
+ - [Usage](#usage)
36
+ - [Contributing](#contributing)
37
+ - [Contact](#contact)
38
+
39
+ ## License
40
+
41
+ PAutodock is distributed under the GPLv3 license. For detailed information on how the license works, please refer to the file "LICENSE" or visit [GNU GPLv3 License](http://www.gnu.org/licenses/gpl-3.0.en.html).
42
+
43
+ Copyright © Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
44
+
45
+ ## Dependencies
46
+
47
+ To run PAutodock, you will need the following software installed:
48
+
49
+ - [AutoDock](http://autodock.scripps.edu/)
50
+ - [AutoGrid](http://autodock.scripps.edu/resources/autogrid)
51
+ - [AutoDock Vina](http://vina.scripps.edu/)
52
+ - [OpenBabel](http://openbabel.org/index.html)
53
+
54
+ Ensure that these dependencies are properly installed and accessible from your command line.
55
+
56
+ ## Changelog
57
+
58
+ - **2024**: Revamp in a more organized form
59
+ - **2022**: First time online
60
+ - **2017**: Initial release
61
+
62
+ ## Usage
63
+
64
+ To use PAutodock for parallelizing AutoDock jobs, follow these steps:
65
+
66
+ 1. **Prepare the Receptor and Ligand**:
67
+ - Ensure you have a receptor file (in PDB format) that represents the target protein or enzyme.
68
+ - Prepare a ligand file (also in PDB format) that contains the molecule you want to dock with the receptor.
69
+
70
+ 2. **Create a Multimol2 File**:
71
+ - Prepare a multimol2 file that includes all the ligands you wish to screen.
72
+ - Each ligand in the file must have:
73
+ - **Partial Charges**: Ensure that the ligands have Gasteiger partial charges assigned.
74
+ - **3D Coordinates**: The ligands should be represented in 3D space.
75
+ - **Unique Names**: Each molecule must have a unique name to avoid conflicts during the screening process.
76
+
77
+ 3. **Execute the Command**:
78
+ - Once your receptor and multimol2 file are ready, execute the following command in your terminal:
79
+
80
+ ```bash
81
+ cd data/3EML
82
+ pautodock --receptor rec.pdb --cx -9.06364 --cy -7.1446 --cz 55.8626 --db dataset.mol2 --wdir example_calculation --out screening_results.csv --vina ON --atd OFF
83
+
@@ -0,0 +1,57 @@
1
+ # PAutodock - Parallelize AutoDock JOBs
2
+
3
+ PAutodock is a powerful set of scripts designed to parallelize AutoDock jobs, enabling fast screening across multiple CPUs. This tool is particularly useful for researchers and scientists working in computational biology and drug discovery, allowing them to efficiently manage and execute docking simulations.
4
+
5
+ ## Table of Contents
6
+
7
+ - [License](#license)
8
+ - [Dependencies](#dependencies)
9
+ - [Changelog](#changelog)
10
+ - [Usage](#usage)
11
+ - [Contributing](#contributing)
12
+ - [Contact](#contact)
13
+
14
+ ## License
15
+
16
+ PAutodock is distributed under the GPLv3 license. For detailed information on how the license works, please refer to the file "LICENSE" or visit [GNU GPLv3 License](http://www.gnu.org/licenses/gpl-3.0.en.html).
17
+
18
+ Copyright © Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
19
+
20
+ ## Dependencies
21
+
22
+ To run PAutodock, you will need the following software installed:
23
+
24
+ - [AutoDock](http://autodock.scripps.edu/)
25
+ - [AutoGrid](http://autodock.scripps.edu/resources/autogrid)
26
+ - [AutoDock Vina](http://vina.scripps.edu/)
27
+ - [OpenBabel](http://openbabel.org/index.html)
28
+
29
+ Ensure that these dependencies are properly installed and accessible from your command line.
30
+
31
+ ## Changelog
32
+
33
+ - **2024**: Revamp in a more organized form
34
+ - **2022**: First time online
35
+ - **2017**: Initial release
36
+
37
+ ## Usage
38
+
39
+ To use PAutodock for parallelizing AutoDock jobs, follow these steps:
40
+
41
+ 1. **Prepare the Receptor and Ligand**:
42
+ - Ensure you have a receptor file (in PDB format) that represents the target protein or enzyme.
43
+ - Prepare a ligand file (also in PDB format) that contains the molecule you want to dock with the receptor.
44
+
45
+ 2. **Create a Multimol2 File**:
46
+ - Prepare a multimol2 file that includes all the ligands you wish to screen.
47
+ - Each ligand in the file must have:
48
+ - **Partial Charges**: Ensure that the ligands have Gasteiger partial charges assigned.
49
+ - **3D Coordinates**: The ligands should be represented in 3D space.
50
+ - **Unique Names**: Each molecule must have a unique name to avoid conflicts during the screening process.
51
+
52
+ 3. **Execute the Command**:
53
+ - Once your receptor and multimol2 file are ready, execute the following command in your terminal:
54
+
55
+ ```bash
56
+ cd data/3EML
57
+ pautodock --receptor rec.pdb --cx -9.06364 --cy -7.1446 --cz 55.8626 --db dataset.mol2 --wdir example_calculation --out screening_results.csv --vina ON --atd OFF
@@ -0,0 +1,41 @@
1
+ [tool.black]
2
+ line-length = 88
3
+ target-version = ["py311"]
4
+
5
+ [tool.isort]
6
+ profile = "black"
7
+
8
+ [tool.poetry]
9
+ name = "pautodock"
10
+ version = "1.0.0"
11
+ description = "A simple tool to parallelize AutoDock JOBs"
12
+ authors = ["Giuseppe Marco Randazzo <gmrandazzo@gmail.com>"]
13
+ readme = "Readme.md"
14
+ license = "lglpv3"
15
+ repository = "https://github.com/gmrandazzo/PAutoDock"
16
+ packages = [{include = "pautodock", from = "src"}]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Operating System :: MacOS :: MacOS X",
22
+ "Topic :: Scientific/Engineering :: Bio-Informatics"
23
+ ]
24
+
25
+ [tool.poetry.dependencies]
26
+ python = "^3.8"
27
+ requests = "^2.32.3"
28
+
29
+ [tool.poetry.dev-dependencies]
30
+ pytest = "^7.4.0"
31
+ pytest-cov = "^4.1.0"
32
+ pre-commit = "^3.3.3"
33
+ tox = "^4.2.3"
34
+
35
+ [tool.poetry.scripts]
36
+ pautodock = "pautodock.__main__:main"
37
+ pautodock-recover-output = "pautodock.__recover_output__:main"
38
+
39
+ [build-system]
40
+ requires = ["poetry-core"]
41
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """main.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+
13
+ Provides the basic main function to run autodock screening
14
+ in parallel.
15
+ """
16
+
17
+ import argparse
18
+ import sys
19
+
20
+ from pautodock.adparallel import ADParallel
21
+
22
+
23
+ def main():
24
+ """
25
+ main.py: with that you run the program.
26
+ """
27
+ p = argparse.ArgumentParser()
28
+ p.add_argument("--receptor", default=None, type=str, help="receptor")
29
+ p.add_argument("--ligand", default=None, type=str, help="ligand PDB")
30
+ p.add_argument("--cx", default=None, type=float, help="center x")
31
+ p.add_argument("--cy", default=None, type=float, help="center y")
32
+ p.add_argument("--cz", default=None, type=float, help="center z")
33
+ p.add_argument("--gx", default=30, type=int, help="grid x size")
34
+ p.add_argument("--gy", default=30, type=int, help="grid y size")
35
+ p.add_argument("--gz", default=30, type=int, help="grid z size")
36
+ p.add_argument("--db", default=None, type=str, help="multimol2 database")
37
+ p.add_argument("--wdir", default=None, type=str, help="work directory")
38
+ p.add_argument("--smode", default="fast", type=str, help="screening mode")
39
+ p.add_argument("--out", default=None, type=str, help="screening output")
40
+ p.add_argument("--atd", default="OFF", type=str, help="Autodock ON")
41
+ p.add_argument("--vina", default="ON", type=str, help="Vina ON")
42
+ args = p.parse_args(sys.argv[1:])
43
+
44
+ if args.receptor is None or args.ligand is None and args.cx is None:
45
+ print("\nUsage: %s --receptor [input pdb]" % sys.argv[0])
46
+ print(" --ligand [input pdb/mol2]")
47
+ print(" --cx [center x]")
48
+ print(" --cy [center y]")
49
+ print(" --cz [center z]")
50
+ print(" --db [multi mol2]")
51
+ print(" --wdir [work path]")
52
+ print(" --smode=[slow,medium,fast]")
53
+ print(" --gx=[grid x size]")
54
+ print(" --gy=[grid y size]")
55
+ print(" --gz=[grid z size]")
56
+ print(" --out [screening output]")
57
+ print(" --atd [ON;OFF]")
58
+ print(" --vina [ON;OFF]")
59
+ else:
60
+ # Load import pdb; pdb.set_trace()#
61
+ dock = ADParallel(args.receptor, args.ligand, args.db, args.wdir)
62
+ if args.ligand is None:
63
+ dock.cx = args.cx
64
+ dock.cy = args.cy
65
+ dock.cz = args.cz
66
+
67
+ if args.atd == "OFF":
68
+ dock.atd = False
69
+
70
+ if args.vina == "ON":
71
+ dock.vina = True
72
+
73
+ dock.speed = args.smode
74
+ dock.gsize_x = args.gx
75
+ dock.gsize_y = args.gy
76
+ dock.gsize_z = args.gz
77
+ dock.virtual_screening(args.out)
78
+ return 0
79
+
80
+
81
+ if __name__ == "__main__":
82
+ main()
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """recover_output.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+ Provides a commandline script to recover the output result of a virtualscreening.
13
+ """
14
+
15
+ import argparse
16
+ import os
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ from pautodock.adparallel import ADParallel
21
+
22
+
23
+ def main():
24
+ """
25
+ main.py
26
+ """
27
+ p = argparse.ArgumentParser()
28
+ p.add_argument("--wdir", default=None, type=str, help="work directory")
29
+ p.add_argument("--out", default=None, type=str, help="screening output")
30
+ p.add_argument("--ligand", default=None, type=str, help="ligand")
31
+ args = p.parse_args(sys.argv[1:])
32
+
33
+ if args.wdir is None or args.out is None:
34
+ print("\nUsage: %s --receptor [input pdb]" % sys.argv[0])
35
+ print(" --wdir [work path]")
36
+ print(" --ligand [ligand PDB]")
37
+ print(" --out [screening output]")
38
+ else:
39
+ dock = ADParallel("", None, None, args.ligand, None, args.wdir)
40
+ vinalogout = []
41
+ dpfout = []
42
+ mnames = []
43
+ for root, directories, filenames in os.walk(str(Path(args.wdir).absolute())):
44
+ for filename in filenames:
45
+ if "vina_log.txt" in filename:
46
+ vinalogout.append(os.path.join(root, filename))
47
+ mname = str(Path(vinalogout[-1]).parents[0].name)
48
+ if mname not in mnames:
49
+ mnames.append(mname)
50
+ elif "ind.dlg" in filename:
51
+ dpfout.append(os.path.join(root, filename))
52
+ mname = str(Path(dpfout[-1]).parents[0].name)
53
+ if mname not in mnames:
54
+ mnames.append(mname)
55
+ else:
56
+ continue
57
+ dock.gen_vs_output(vinalogout, dpfout, mnames, args.out)
58
+
59
+
60
+ if __name__ == "__main__":
61
+ main()
@@ -0,0 +1,429 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """adparallel.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+
13
+ Provides the basic code to run autodock in parallel on a machine.
14
+
15
+ """
16
+
17
+ import logging
18
+ import math
19
+ import multiprocessing
20
+ import os
21
+ import shutil
22
+ import tempfile
23
+ from pathlib import Path
24
+
25
+ from pautodock import molop, multimol2op
26
+ from pautodock.fileutils import get_bin_path
27
+ from pautodock.mgltoolsinstall import install_mgltools
28
+
29
+
30
+ class ADParallel(object):
31
+ def __init__(self, receptor, ligand, db, wpath):
32
+ try:
33
+ self.atdpath = get_bin_path("autodock")
34
+ except ValueError:
35
+ self.atdpath = None
36
+ try:
37
+ self.vinapath = get_bin_path("vina")
38
+ except ValueError:
39
+ self.vinapath = None
40
+
41
+ if not self.atdpath and not self.vinapath:
42
+ msg = "Error!! autodock and vina are not installed!\n"
43
+ msg += "Unable to run any calculation."
44
+ raise ValueError(msg)
45
+
46
+ self.mglpath = Path(f"{Path.home()}/.pautodock/MGLTools")
47
+ if not self.mglpath.exists():
48
+ install_mgltools(f"{Path.home()}/.pautodock")
49
+ self.receptor = receptor
50
+ self.ligand = ligand
51
+ self.db = db
52
+ self.wpath = wpath
53
+ self.results = []
54
+ self.cx = 0.0
55
+ self.cy = 0.0
56
+ self.cz = 0.0
57
+ self.gsize_x = 30
58
+ self.gsize_y = 30
59
+ self.gsize_z = 30
60
+ self.speed = "slow"
61
+ self.atd = True
62
+ self.vina = True
63
+
64
+ def read_atom_types(self, rec_mol):
65
+ """
66
+ Read atom types in pdb and return in a list
67
+ """
68
+ atlst = []
69
+ f = open(rec_mol, "r")
70
+ for line in f:
71
+ if "ATOM" in line:
72
+ at = line.strip().split(" ")[-1]
73
+ if at in atlst:
74
+ continue
75
+ else:
76
+ if len(at) > 0:
77
+ atlst.append(at)
78
+ else:
79
+ continue
80
+ f.close()
81
+ atlst = list(set(atlst))
82
+ atypes_str = "%s" % atlst[0]
83
+ for i in range(1, len(atlst)):
84
+ atypes_str += " %s" % atlst[i]
85
+ return atypes_str, atlst
86
+
87
+ def write_autodock_param_files(self, path, rec_pdbqt, mol_pdbqt, cc):
88
+ path_ = Path(path).absolute()
89
+ rat_str, _ = self.read_atom_types(rec_pdbqt)
90
+ lat_str, lat_lst = self.read_atom_types(path + "/" + mol_pdbqt)
91
+ # write the GPF
92
+ f = open(path + "/grid.gpf", "w")
93
+ f.write(
94
+ "npts %d %d %d # num.grid points in xyz\n"
95
+ % (self.gsize_x, self.gsize_y, self.gsize_z)
96
+ )
97
+ f.write("gridfld %s/receptor_model.maps.fld # grid_data_file\n" % (path_))
98
+ f.write("spacing 0.33 # spacing(A)\n")
99
+ f.write("receptor_types %s # receptor atom types\n" % (rat_str))
100
+ f.write("ligand_types %s # ligand atom types\n" % (lat_str))
101
+ f.write("receptor %s # macromolecule\n" % (rec_pdbqt))
102
+ f.write(
103
+ "gridcenter %.3f %.3f %.3f # xyz-coordinates or auto\n"
104
+ % (cc[0], cc[1], cc[2])
105
+ )
106
+ f.write("smooth 0.5 # store minimum energy w/in rad(A)\n")
107
+ for at in lat_lst:
108
+ f.write(
109
+ "map %s/receptor_model.%s.map # atom-specific aff. map\n" % (path_, at)
110
+ )
111
+ f.write("elecmap %s/receptor_model.e.map # El. Pot potential map\n" % (path_))
112
+ f.write("dsolvmap %s/receptor_model.d.map # desolv. potential map\n" % (path_))
113
+ f.write("dielectric -0.1465 # <0, AD4 dist-dep.diel;>0, constant\n")
114
+ f.close()
115
+
116
+ # Write autodock file
117
+ f = open(path + "/ind.dpf", "w")
118
+ f.write("autodock_parameter_version 4.2")
119
+ f.write("# used by autodock to validate parameter set\n")
120
+ f.write("outlev 1 # diagnostic output level\n")
121
+ f.write("intelec # calculate internal electrostatics\n")
122
+ f.write("seed time pid # seeds for random generator\n")
123
+ f.write("ligand_types %s # atoms types in ligand\n" % (lat_str))
124
+ f.write("fld %s/receptor_model.maps.fld # grid_data_file\n" % (path_))
125
+ for at in lat_lst:
126
+ f.write(
127
+ "map %s/receptor_model.%s.map # atom-specific aff. map\n" % (path_, at)
128
+ )
129
+ f.write("elecmap %s/receptor_model.e.map # electrostatics map\n" % (path_))
130
+ f.write("desolvmap %s/receptor_model.d.map # desolvation map\n" % (path_))
131
+ f.write("move %s/%s # small molecule\n" % (path_, mol_pdbqt))
132
+ f.write(
133
+ "about %.4f %.4f %.4f # small molecule center\n"
134
+ % (cc[0], cc[1], cc[2])
135
+ )
136
+ f.write("tran0 %.4f %.4f %.4f " % (cc[0], cc[1], cc[2]))
137
+ f.write("# initial coordinates/A or random\n")
138
+ f.write("quaternion0 random ")
139
+ f.write("# initial orientation\n")
140
+ f.write("dihe0 random ")
141
+ f.write("# initial dihedrals (relative) or random\n")
142
+ f.write("torsdof 5 ")
143
+ f.write("# torsional degrees of freedom\n")
144
+ f.write("rmstol 2.0 # cluster_tolerance/A\n")
145
+ f.write("extnrg 1000.0 # external grid energy\n")
146
+ f.write("e0max 0.0 10000 ")
147
+ f.write("# max initial energy; max number of retries\n")
148
+ f.write("ga_pop_size 150 ")
149
+ f.write("# number of individuals in population\n")
150
+ if self.speed == "slow":
151
+ f.write("ga_num_evals 25000000 ")
152
+ elif self.speed == "medium":
153
+ f.write("ga_num_evals 2500000 ")
154
+ else:
155
+ f.write("ga_num_evals 250000 ")
156
+ f.write(" # maximum number of energy evaluations\n")
157
+ f.write("ga_num_generations 27000 ")
158
+ f.write("# maximum number of generations\n")
159
+ f.write("ga_elitism 1 ")
160
+ f.write("# number of top individuals to survive to next generation\n")
161
+ f.write("ga_mutation_rate 0.02 # rate of gene mutation\n")
162
+ f.write("ga_crossover_rate 0.8 # rate of crossover\n")
163
+ f.write("ga_window_size 10 # \n")
164
+ f.write("ga_cauchy_alpha 0.0 ")
165
+ f.write("# Alpha parameter of Cauchy distribution\n")
166
+ f.write("ga_cauchy_beta 1.0 ")
167
+ f.write("# Beta parameter Cauchy distribution\n")
168
+ f.write("set_ga")
169
+ f.write(" # set the above parameters for GA or LGA\n")
170
+ f.write("sw_max_its 300")
171
+ f.write("# iterations of Solis & Wets local search\n")
172
+ f.write("sw_max_succ 4 ")
173
+ f.write(" # consecutive successes before changing rho\n")
174
+ f.write("sw_max_fail 4 ")
175
+ f.write(" # consecutive failures before changing rho\n")
176
+ f.write("sw_rho 1.0 ")
177
+ f.write("# size of local search space to sample\n")
178
+ f.write("sw_lb_rho 0.01 # lower bound on rho\n")
179
+ f.write("ls_search_freq 0.06 ")
180
+ f.write("# probability of performing local search on individual\n")
181
+ f.write("set_psw1 ")
182
+ f.write("# set the above pseudo-Solis & Wets parameters\n")
183
+ f.write("unbound_model bound ")
184
+ f.write("# state of unbound ligand\n")
185
+ f.write("ga_run 10 ")
186
+ f.write("# do this many hybrid GA-LS runs\n")
187
+ f.write("analysis ")
188
+ f.write("# perform a ranked cluster analysis\n")
189
+ f.close()
190
+ grid_path = Path(path + "/grid.gpf").absolute()
191
+ ind_path = Path(path + "/ind.dpf").absolute()
192
+ return grid_path, ind_path
193
+
194
+ def write_vina_param_files(self, path, cc, ss):
195
+ f = open(path + "/vina_conf.txt", "w")
196
+ f.write("center_x = %.4f\n" % (cc[0]))
197
+ f.write("center_y = %.4f\n" % (cc[1]))
198
+ f.write("center_z = %.4f\n" % (cc[2]))
199
+ f.write("size_x = %d\n" % (ss[0]))
200
+ f.write("size_y = %d\n" % (ss[1]))
201
+ f.write("size_z = %d\n" % (ss[2]))
202
+ f.write("num_modes = 9\n")
203
+ f.close()
204
+ return Path(path + "/vina_conf.txt").absolute()
205
+
206
+ def RunAutoGrid(self, cmd):
207
+ atg_path = str(Path("%s/autogrid4" % (self.atdpath)).absolute())
208
+ return os.system("%s %s" % (atg_path, cmd))
209
+
210
+ def RunAutoDock(self, cmd):
211
+ atd_path = str(Path("%s/autodock4" % (self.atdpath)).absolute())
212
+ return os.system("%s %s" % (atd_path, cmd))
213
+
214
+ def RunVina(self, cmd):
215
+ vina_path = str(Path("%s/vina" % (self.vinapath)).absolute())
216
+ return os.system("%s %s" % (vina_path, cmd))
217
+
218
+ def ReadOutput(self, ofile):
219
+ r = []
220
+ header = []
221
+ benergy = []
222
+ c_rmsd = []
223
+ r_rmsd = []
224
+ f = open(str(Path(ofile).absolute()), "r")
225
+ for line in f:
226
+ if "Partition function, Q =" in line:
227
+ header.append("Part. Func.")
228
+ r.append(molop.nsplit(line.strip(), " ")[4])
229
+ elif "Free energy, A ~" in line:
230
+ r.append(molop.nsplit(line.strip(), " ")[4])
231
+ header.append("Free Energy")
232
+ elif "Internal energy, U =" in line:
233
+ header.append("Internal Energy")
234
+ r.append(molop.nsplit(line.strip(), " ")[4])
235
+ elif "Entropy, S =" in line:
236
+ header.append("Entropy")
237
+ r.append(molop.nsplit(line.strip(), " ")[3])
238
+ elif "RANKING" in line:
239
+ v = molop.nsplit(line.strip(), " ")
240
+ benergy.append(float(v[3]))
241
+ c_rmsd.append(float(v[4]))
242
+ r_rmsd.append(float(v[5]))
243
+ f.close()
244
+ header.append("Binding Energy Average")
245
+ r.append(round(sum(benergy) / float(len(benergy)), 3))
246
+ header.append("Cluster RMSD Average")
247
+ r.append(round(sum(c_rmsd) / float(len(c_rmsd)), 3))
248
+ header.append("Ref. RMSD Average")
249
+ r.append(round(sum(r_rmsd) / float(len(r_rmsd)), 3))
250
+ return header, r
251
+
252
+ def LigandPosesBaricentreDistance(self, dock_pdbqt: str) -> float:
253
+ """
254
+ Calculate the distance between the ligand and docking pose baricentres.
255
+ """
256
+ poses_cc = molop.get_mol_baricentre(dock_pdbqt)
257
+ if int(self.cx) == 0:
258
+ self.cx, self.cy, self.cz = molop.get_mol_baricentre(self.ligand)
259
+ return math.sqrt(
260
+ (self.cx - poses_cc[0]) ** 2
261
+ + (self.cy - poses_cc[1]) ** 2
262
+ + (self.cz - poses_cc[2]) ** 2
263
+ )
264
+
265
+ def read_vina_output(self, ofile):
266
+ benergy = []
267
+ f = open(str(Path(ofile).absolute()), "r")
268
+ getres = False
269
+ for line in f:
270
+ if getres:
271
+ # Filter double outputs
272
+ if "Writing output ... done." in line or "AutoDock Vina" in line:
273
+ getres = False
274
+ else:
275
+ try:
276
+ v = molop.nsplit(line.strip(), " ")
277
+ benergy.append(float(v[1]))
278
+ except ValueError as err:
279
+ logging.error("Error with file %s - %s" % (ofile, err))
280
+ else:
281
+ if "-----+------------+----------+----------" in line:
282
+ getres = True
283
+ else:
284
+ continue
285
+
286
+ f.close()
287
+ if len(benergy) > 0:
288
+ return (
289
+ round(sum(benergy) / float(len(benergy)), 3),
290
+ min(benergy),
291
+ max(benergy),
292
+ )
293
+ else:
294
+ return 9999.0, 9999.0, 9999.0
295
+
296
+ def gen_vs_output(self, vinalogout, dpfout, mnames, otab):
297
+ """
298
+ Collect vina results
299
+ """
300
+ # Collect the vina results
301
+ vbind = []
302
+ for i, vout in enumerate(vinalogout):
303
+ avg_b, min_b, max_b = self.read_vina_output(vout)
304
+ try:
305
+ dock_poses = (
306
+ f"{Path(vout).parent.absolute()}/dock_confs_{mnames[i]}.pdbqt"
307
+ )
308
+ lp_dst = self.LigandPosesBaricentreDistance(dock_poses)
309
+ except FileNotFoundError as err:
310
+ logging.error("%s not found", err)
311
+ lp_dst = 9999.0
312
+ vbind.append([avg_b, min_b, max_b, lp_dst])
313
+ # Collect results
314
+ fo = open(otab, "w")
315
+ firstline = True
316
+ for i in range(len(mnames)):
317
+ h = []
318
+ r = []
319
+ if len(dpfout) > 0:
320
+ if Path(dpfout[i]).is_file():
321
+ h, r = self.ReadOutput(dpfout[i])
322
+ if firstline:
323
+ firstline = False
324
+ fo.write("Molname;")
325
+ for j in range(len(h)):
326
+ fo.write("%s;" % (h[j]))
327
+ fo.write("Avg. vina Binding Energy;")
328
+ fo.write("Min vina Binding Energy;Max vina Binding Energy;")
329
+ fo.write("Template-Ligand Baricenter Distance (docking pose check)\n")
330
+ fo.write("%s;" % (mnames[i]))
331
+ for j in range(len(r)):
332
+ fo.write("%s;" % (r[j]))
333
+ fo.write(
334
+ "%f;%f;%f;%f\n" % (vbind[i][0], vbind[i][1], vbind[i][2], vbind[i][3])
335
+ )
336
+ fo.close()
337
+
338
+ def make_vina_cmd(
339
+ self, vconf_path, rec_pdbqt, mol_pdbqt, mpath, molname, vinalogout
340
+ ) -> str:
341
+ vc = f'--config "{vconf_path}"'
342
+ vc += f' --receptor "{rec_pdbqt}"'
343
+ vc += f' --ligand "{mol_pdbqt}"'
344
+ vc += f' --out "{mpath}/dock_confs_{molname}.pdbqt" >> {vinalogout}'
345
+ return vc
346
+
347
+ def virtual_screening(self, otab):
348
+ # Prepare the receptor
349
+ rec = molop.Receptor(self.receptor, self.mglpath)
350
+ rec_pdbqt = rec.topdbqt()
351
+ if self.ligand is not None:
352
+ self.cx, self.cy, self.cz = molop.get_mol_baricentre(self.ligand)
353
+ # Prepare the database split multi mol2
354
+ tmppath = tempfile.mkdtemp()
355
+ mol2lst = multimol2op.split_mol2(self.db, tmppath)
356
+ agcmdlst = []
357
+ adcmdlst = []
358
+ vinacmdlst = []
359
+ vinalogout = []
360
+ dpfout = []
361
+ mnames = []
362
+ # Create a directory with the name of the mol2 molecule
363
+ # and copy the receptor and itself
364
+ for mol2 in mol2lst:
365
+ molname_ext = str(Path(mol2).resolve().name)
366
+ molname = molname_ext.replace(".mol2", "")
367
+ mnames.append(molname)
368
+ mpath = str(Path(self.wpath + "/" + molname).absolute())
369
+ if not Path(f"{mpath}/dock_confs_{molname}.pdbqt").exists():
370
+ if not Path(mpath).exists():
371
+ os.makedirs(mpath)
372
+ if not Path(mpath + "/" + molname_ext).exists():
373
+ shutil.move(str(Path(mol2).resolve()), mpath)
374
+
375
+ mol = molop.Molecule(
376
+ str(Path(mpath + "/" + molname_ext).absolute()), self.mglpath
377
+ )
378
+ mol_pdbqt = mol.topdbqt([self.cx, self.cy, self.cz])
379
+ mol_pdbqt_name = str(Path(mol_pdbqt).resolve().name)
380
+ if self.atd:
381
+ gpf_path, dpf_path = self.write_autodock_param_files(
382
+ mpath, rec_pdbqt, mol_pdbqt_name, [self.cx, self.cy, self.cz]
383
+ )
384
+ first_arg = str(gpf_path)
385
+ second_arg = str(gpf_path).replace(".gpf", "")
386
+ ag = f'-p "{first_arg}" -l "{second_arg}.glg"'
387
+ agcmdlst.append(ag)
388
+ dpfout.append(str(dpf_path).replace(".dpf", ".dlg"))
389
+ ad = f'-p "{str(dpf_path)}" -l "{dpfout[-1]}"'
390
+ adcmdlst.append(ad)
391
+
392
+ if self.vina:
393
+ vinalogout.append(f"{mpath}/vina_log.txt")
394
+ # If the log and the docking pose extists then
395
+ # there is no need to run the calculation
396
+ vconf_path = self.write_vina_param_files(
397
+ mpath,
398
+ [self.cx, self.cy, self.cz],
399
+ [self.gsize_x, self.gsize_y, self.gsize_z],
400
+ )
401
+ vinacmdlst.append(
402
+ self.make_vina_cmd(
403
+ vconf_path,
404
+ rec_pdbqt,
405
+ mol_pdbqt,
406
+ mpath,
407
+ molname,
408
+ vinalogout[-1],
409
+ )
410
+ )
411
+ else:
412
+ vinalogout.append(f"{mpath}/vina_log.txt")
413
+ shutil.rmtree(tmppath)
414
+ ncpu = multiprocessing.cpu_count()
415
+ if self.atd:
416
+ # Run AutoGrid
417
+ pool = multiprocessing.Pool(ncpu)
418
+ pool.map(self.RunAutoGrid, agcmdlst)
419
+ # RunAutodock
420
+ pool = multiprocessing.Pool(ncpu)
421
+ pool.map(self.RunAutoDock, adcmdlst)
422
+
423
+ if self.vina:
424
+ # RunVina
425
+ pool = multiprocessing.Pool(ncpu)
426
+ pool.map(self.RunVina, vinacmdlst)
427
+
428
+ # Write the output table
429
+ self.gen_vs_output(vinalogout, dpfout, mnames, otab)
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """fileutils.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+ Provides the basic operation for molecular files.
13
+
14
+ """
15
+ import logging
16
+ import platform
17
+ import tarfile
18
+ from pathlib import Path
19
+
20
+ import requests
21
+
22
+
23
+ def get_bin_path(bin_name: str):
24
+ """
25
+ Get the path to the bin_name executable based on the operating system.
26
+ """
27
+ paths = {"Linux": ["/usr/bin/", "/usr/local/bin"], "Darwin": ["/opt/homebrew/bin/"]}
28
+ system = platform.system()
29
+ if system not in paths:
30
+ raise ValueError("Platform not supported")
31
+
32
+ for bin_path in paths.get(system):
33
+ if bin_path and Path(f"{bin_path}/{bin_name}").exists():
34
+ return bin_path
35
+ raise ValueError(f"Unable to find {bin_name} installed.")
36
+
37
+
38
+ def download_file(url, destination):
39
+ """
40
+ Download a file from a URL to a local destination.
41
+ """
42
+ try:
43
+ response = requests.get(url, stream=True)
44
+ response.raise_for_status()
45
+ with open(destination, "wb") as file:
46
+ for chunk in response.iter_content(chunk_size=8192):
47
+ file.write(chunk)
48
+ logging.info(f"Downloaded: {destination}")
49
+ except requests.RequestException as err:
50
+ logging.error(f"Failed to download file: {err}")
51
+ return False
52
+ return True
53
+
54
+
55
+ def extract_tar_gz(file_path, extract_to):
56
+ """
57
+ Extract a .tar.gz file to a specified directory.
58
+ """
59
+ try:
60
+ with tarfile.open(file_path, "r:gz") as tar:
61
+ tar.extractall(path=extract_to)
62
+ logging.info(f"Extracted: {file_path} to {extract_to}")
63
+ except (tarfile.TarError, IOError) as err:
64
+ logging.error(f"Failed to extract file: {err}")
65
+ return False
66
+ return True
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """mgltoolsinstall.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+ Provides the basic operation for molecular files.
13
+
14
+ """
15
+
16
+ import logging
17
+ import platform
18
+ import subprocess
19
+ from pathlib import Path
20
+
21
+ from pautodock.fileutils import download_file, extract_tar_gz
22
+
23
+
24
+ def install_mgltools(dir: str):
25
+ """
26
+ Install MGLTools from the official website.
27
+ """
28
+ directory = Path(dir)
29
+ directory.mkdir(exist_ok=True)
30
+ destination = directory / "mgltools_1.5.7.tar.gz"
31
+ dir_name = None
32
+
33
+ system = platform.system()
34
+ if system == "Linux":
35
+ url = "https://ccsb.scripps.edu/download/532/"
36
+ dir_name = "mgltools_x86_64Linux2_1.5.7"
37
+ elif system == "Darwin":
38
+ url = "https://ccsb.scripps.edu/download/529/"
39
+ dir_name = "mgltools_1.5.7_MacOS-X"
40
+ else:
41
+ logging.error("Unsupported platform")
42
+ return False
43
+
44
+ if not destination.exists():
45
+ if not download_file(url, destination):
46
+ return False
47
+
48
+ if extract_tar_gz(destination, directory):
49
+ install_dir = directory / "MGLTools"
50
+ install_script = directory / dir_name / "install.sh"
51
+ cmd_args = ["sh", str(install_script), "-d", str(install_dir)]
52
+
53
+ try:
54
+ subprocess.check_output(
55
+ cmd_args,
56
+ cwd=directory / dir_name,
57
+ shell=False,
58
+ text=True,
59
+ stderr=subprocess.DEVNULL,
60
+ )
61
+ logging.info("MGLTools installed successfully.")
62
+ return True
63
+ except subprocess.CalledProcessError as err:
64
+ logging.error(f"Installation failed: {err}")
65
+ return False
66
+ else:
67
+ return False
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """molop.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+ Provides the basic operation for molecular files.
13
+
14
+ """
15
+
16
+ import logging
17
+ import subprocess
18
+ from pathlib import Path
19
+
20
+ from pautodock.fileutils import get_bin_path
21
+
22
+
23
+ def nsplit(s, delim=None):
24
+ return [x for x in s.split(delim) if x]
25
+
26
+
27
+ def extract_coordinates(line, ftype):
28
+ if ftype == "pdb":
29
+ if "HETATM" in line:
30
+ x = float(line[29:39].strip())
31
+ y = float(line[39:47].strip())
32
+ z = float(line[47:55].strip())
33
+ return [float(x), float(y), float(z)]
34
+ elif ftype == "pdbqt":
35
+ if "ATOM" in line:
36
+ x = float(line[31:39].strip())
37
+ y = float(line[38:46].strip())
38
+ z = float(line[46:54].strip())
39
+ return [float(x), float(y), float(z)]
40
+ else:
41
+ return None
42
+
43
+
44
+ def get_mol_baricentre(mol: str) -> tuple:
45
+ """
46
+ Get molecular baricentre from a molecule
47
+ """
48
+ cc = [0.0, 0.0, 0.0]
49
+ n = 0
50
+ if mol.endswith(".pdbqt"):
51
+ ftype = "pdbqt"
52
+ elif mol.endswith(".pdb"):
53
+ ftype = "pdb"
54
+ else:
55
+ raise ValueError(
56
+ "Molecual format not supported {mol}. Supported formats: pdb or pdbqt"
57
+ )
58
+
59
+ with open(mol, "r", encoding="utf-8") as f:
60
+ for line in f:
61
+ if ("ATOM" in line or "HETATM" in line) and "REMARK" not in line:
62
+ try:
63
+ ex_cc = extract_coordinates(line.strip(), ftype)
64
+ if ex_cc:
65
+ for i, val in enumerate(ex_cc):
66
+ cc[i] += val
67
+ n += 1
68
+ except IndexError as err:
69
+ logging.error("%s get_mol_baricentre problem with %s", err, line)
70
+ return [cc[i] / float(n) for i in range(len(cc))]
71
+
72
+
73
+ class Receptor(object):
74
+ def __init__(self, receptor, mglpath):
75
+ self.receptor = receptor
76
+ self.mglpath = str(Path(mglpath).resolve())
77
+
78
+ def topdbqt(self):
79
+ python_env = (
80
+ "export LD_LIBRARY_PATH=\"%s/lib\"${LD_LIBRARY_PATH:+':'$LD_LIBRARY_PATH};"
81
+ % (self.mglpath)
82
+ )
83
+ python_env += "%s/bin/python2" % (self.mglpath)
84
+ prep_rec = self.mglpath
85
+ prep_rec += "/MGLToolsPckgs/AutoDockTools/Utilities24/"
86
+ prep_rec += "prepare_receptor4.py"
87
+ pdbqt = self.receptor.replace(".pdb", ".pdbqt")
88
+ cmd = "%s %s -r '%s' -o '%s'" % (python_env, prep_rec, self.receptor, pdbqt)
89
+ subprocess.call([cmd], shell=True)
90
+ return str(Path(pdbqt).resolve())
91
+
92
+
93
+ class Molecule(object):
94
+ def __init__(self, molecule, mglpath):
95
+ self.molecule = molecule
96
+ self.mglpath = str(Path(mglpath).resolve())
97
+ self.obabel_path = get_bin_path("obabel")
98
+
99
+ def topdbqt(self, tran0=[]):
100
+ """
101
+ tran0 is the vector of centre x,y,z where to translate the molecule
102
+ """
103
+ obabel = f"{self.obabel_path}/obabel"
104
+ molname = self.molecule
105
+ if ".mol2" in molname.lower():
106
+ molname = molname.replace(".mol2", ".pdbqt")
107
+ else:
108
+ molname = molname.replace(".pdb", ".pdbqt")
109
+ cmd = "%s -p gastaiger -imol2 '%s' -opdbqt -O '%s'" % (
110
+ obabel,
111
+ self.molecule,
112
+ molname,
113
+ )
114
+ subprocess.call([cmd], shell=True)
115
+ # Translate to the new center
116
+ fpdbqt = str(Path(molname).resolve())
117
+ if len(tran0) > 0:
118
+ mem = []
119
+ fi = open(fpdbqt, "r")
120
+ for line in fi:
121
+ if "ATOM" in line:
122
+ ex_cc = extract_coordinates(line.strip(), "pdbqt")
123
+ if ex_cc:
124
+ copy_line = line
125
+ x = float(ex_cc[0]) + tran0[0]
126
+ copy_line.replace(str(ex_cc[0]), str(x))
127
+ y = float(ex_cc[1]) + tran0[0]
128
+ copy_line.replace(str(ex_cc[1]), str(y))
129
+ z = float(ex_cc[2]) + tran0[0]
130
+ copy_line.replace(str(ex_cc[2]), str(z))
131
+ mem.append(copy_line)
132
+ else:
133
+ msg = "Molecule.topdbqt Error!\n"
134
+ msg += " X Y Z coordinates not found in "
135
+ msg += f"line {line.strip()}"
136
+ raise ValueError(msg)
137
+ else:
138
+ mem.append(line)
139
+ fi.close()
140
+
141
+ fo = open(fpdbqt, "w")
142
+ for line in mem:
143
+ fo.write(line)
144
+ fo.close()
145
+ return fpdbqt
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """multimol2op.py
4
+
5
+ This file is part of PAutoDock.
6
+ Copyright (C) 2020 Giuseppe Marco Randazzo <gmrandazzo@gmail.com>
7
+ PAutoDock is distributed under GPLv3 license.
8
+ To know more in detail how the license work,
9
+ please read the file "LICENSE" or
10
+ go to "http://www.gnu.org/licenses/gpl-3.0.en.html"
11
+
12
+ Provides the basic operation for MOL2 files in parallel
13
+
14
+ """
15
+
16
+ import os
17
+ import shutil
18
+ from pathlib import Path
19
+
20
+
21
+ def read_molname(filemol2: str):
22
+ f = open(filemol2, "r")
23
+ molname = None
24
+ next_is_name = False
25
+ for line in f:
26
+ if line.strip().lower() == "@<TRIPOS>MOLECULE".lower():
27
+ next_is_name = True
28
+ else:
29
+ if next_is_name is True:
30
+ molname = line.strip()
31
+ next_is_name = False
32
+ f.close()
33
+ return molname
34
+
35
+
36
+ def get_mol2_name(filemol2: str):
37
+ molname = read_molname("tmp_")
38
+ filename = molname + ".mol2"
39
+ cc = 1
40
+ while True:
41
+ if os.path.isfile(filename) is False:
42
+ break
43
+ else:
44
+ filename = molname + "_" + str(cc) + ".mol2"
45
+ cc = cc + 1
46
+ return filename
47
+
48
+
49
+ def split_mol2(mmol2, path="./"):
50
+ mol2splitted = []
51
+ fmol2 = open(mmol2, "r")
52
+ ftmp = open("tmp_", "w")
53
+ firstmol = True
54
+ for line in fmol2:
55
+ if line.strip().lower() == "@<TRIPOS>MOLECULE".lower():
56
+ if ftmp.closed is False and firstmol is False:
57
+ ftmp.close()
58
+ filename = get_mol2_name("tmp_")
59
+ mpath = str(Path(path + "/" + filename).absolute())
60
+ if Path(mpath).exists() is False:
61
+ shutil.move("tmp_", mpath)
62
+ mol2splitted.append(mpath)
63
+ else:
64
+ os.remove("tmp_")
65
+ ftmp = open("tmp_", "w")
66
+ firstmol = False
67
+ ftmp.write(line)
68
+ else:
69
+ ftmp.write(line)
70
+
71
+ if ftmp.closed is False:
72
+ ftmp.close()
73
+ filename = get_mol2_name("tmp_")
74
+ mpath = str(Path(path + "/" + filename).absolute())
75
+ if Path(mpath).exists() is False:
76
+ shutil.move("tmp_", mpath)
77
+ mol2splitted.append(mpath)
78
+ else:
79
+ os.remove("tmp_")
80
+ fmol2.close()
81
+ return mol2splitted