mutadock 1.1__py2.py3-none-any.whl

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.
docking/__init__.py ADDED
@@ -0,0 +1,40 @@
1
+ ################################################################################
2
+ # PROJECT INFORMATION #
3
+ # Name: MUTADOCK #
4
+ # Author: Naisarg Patel #
5
+ # #
6
+ # Copyright (C) 2024 Naisarg Patel (https://github.com/naisarg14) #
7
+ # #
8
+ # Project: https://github.com/naisarg14/mutadock #
9
+ # #
10
+ # This program is free software; you can redistribute it and/or modify it #
11
+ # under the terms of the GNU General Public License version 3 as published #
12
+ # by the Free Software Foundation. #
13
+ # #
14
+ # This program is distributed in the hope that it will be useful, but #
15
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
16
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License #
17
+ # for more details. #
18
+ ################################################################################
19
+
20
+ if __name__ == "__main__":
21
+ print("""
22
+ ################################################################################
23
+ # PROJECT INFORMATION #
24
+ # Name: MUTADOCK #
25
+ # Author: Naisarg Patel #
26
+ # #
27
+ # Copyright (C) 2024 Naisarg Patel (https://github.com/naisarg14) #
28
+ # #
29
+ # Project: https://github.com/naisarg14/mutadock #
30
+ # #
31
+ # This program is free software; you can redistribute it and/or modify it #
32
+ # under the terms of the GNU General Public License version 3 as published #
33
+ # by the Free Software Foundation. #
34
+ # #
35
+ # This program is distributed in the hope that it will be useful, but #
36
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
37
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License #
38
+ # for more details. #
39
+ ################################################################################
40
+ """)
docking/np_docking.py ADDED
@@ -0,0 +1,205 @@
1
+ ################################################################################
2
+ # PROJECT INFORMATION #
3
+ # Name: MUTADOCK #
4
+ # Author: Naisarg Patel #
5
+ # #
6
+ # Copyright (C) 2024 Naisarg Patel (https://github.com/naisarg14) #
7
+ # #
8
+ # Project: https://github.com/naisarg14/mutadock #
9
+ # #
10
+ # This program is free software; you can redistribute it and/or modify it #
11
+ # under the terms of the GNU General Public License version 3 as published #
12
+ # by the Free Software Foundation. #
13
+ # #
14
+ # This program is distributed in the hope that it will be useful, but #
15
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
16
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License #
17
+ # for more details. #
18
+ ################################################################################
19
+
20
+ from itertools import product
21
+ import os, time, sys
22
+ import argparse
23
+ from contextlib import contextmanager
24
+ from tqdm import tqdm
25
+ from vina_helper import prepare_receptor, prepare_ligand, vina_split, add_score_to_csv, dock_vina, read_config, calculate_geometric_center, backup
26
+
27
+
28
+ @contextmanager
29
+ def suppress_stdout():
30
+ with open(os.devnull, "w") as devnull:
31
+ old_stdout = sys.stdout
32
+ sys.stdout = devnull
33
+ try:
34
+ yield
35
+ finally:
36
+ sys.stdout = old_stdout
37
+
38
+
39
+ def naisarg():
40
+ start_time = time.time()
41
+ receptors, ligands, config, autosite, quiet, completed_name, ignore_existing = prepare_inputs()
42
+
43
+ if config is None and autosite is None:
44
+ print("Both config and autosite not provided. Assuming center as [0,0,0] and box_size as [30,30,30].")
45
+
46
+ if config is not None:
47
+ values = read_config
48
+ values = read_config(config)
49
+ if values[0] is False:
50
+ sys.exit(f"Error while reading the config file {config} \nError: {values[1]}")
51
+ _, center, box_size, exhaustiveness, n_poses, n_poses_write, overwrite = values
52
+
53
+ if autosite is not None:
54
+ site = calculate_geometric_center(autosite)
55
+ if site[0] is not False:
56
+ center = site[0]
57
+ else:
58
+ sys.exit(f"Error while calculating the geometric center of the autosite file {autosite} \nError: {site[1]}")
59
+
60
+ try:
61
+ with open(completed_name, "r") as f:
62
+ completed = f.readlines()
63
+ completed = [x.replace("\n", "") for x in completed]
64
+ except FileNotFoundError:
65
+ completed = []
66
+
67
+ if ignore_existing:
68
+ completed = []
69
+
70
+ combinations = list(product(receptors, ligands))
71
+
72
+ combinations = [x for x in combinations if str(x) not in completed]
73
+
74
+ if not quiet and not ignore_existing: print(f"Found {len(completed)} completed receptor-ligand combinations. {len(combinations)} combinations to be docked.")
75
+
76
+ for combination in tqdm(combinations):
77
+ receptor = combination[0]
78
+ ligand = combination[1]
79
+ prepared_receptor = f"{receptor}qt"
80
+
81
+ if ligand.endswith(".sdf"):
82
+ prepared_ligand = f"{ligand.removesuffix(".sdf")}.pdbqt"
83
+ elif ligand.endswith(".mol2"):
84
+ prepared_ligand = f"{ligand.removesuffix(".mol2")}.pdbqt"
85
+
86
+ if not quiet: print(f"Docking the receptor {receptor} to the ligand {ligand}")
87
+ master_folder_receptor, receptor_file = os.path.split(os.path.abspath(receptor))
88
+ master_folder_ligand, ligand_file = os.path.split(os.path.abspath(ligand))
89
+
90
+ output_dir = os.path.join(master_folder_receptor, 'out')
91
+ if not os.path.exists(output_dir):
92
+ os.makedirs(output_dir)
93
+
94
+ out_pdb = os.path.join(output_dir, f'{receptor_file.removesuffix(".pdb")}_{ligand_file.removesuffix(".sdf")}_out.pdb')
95
+ log_file = os.path.join(output_dir, f'{receptor_file.removesuffix(".pdb")}_{ligand_file.removesuffix(".sdf")}_log.txt')
96
+ csv_file = os.path.join(output_dir, "docking_results.csv")
97
+
98
+ backup(out_pdb)
99
+ backup(log_file)
100
+
101
+ try:
102
+ if not quiet: print(f"Docking for {ligand} with {receptor}")
103
+ if not quiet: print("Press Ctrl+D (EOFE Error) to skip this receptor-ligand combination.")
104
+ if not os.path.exists(prepared_receptor) or ignore_existing:
105
+ if not quiet: print(f"Preparing receptor {receptor}")
106
+ with suppress_stdout(): rec_out = prepare_receptor(receptor_filename=receptor, outputfilename=prepared_receptor)
107
+ if not rec_out[0]:
108
+ print(f"Error while preparing receptor {receptor} \nError: {rec_out[1]} \nSkipping this receptor-ligand combination.")
109
+ continue
110
+
111
+ if not os.path.exists(prepared_ligand) or ignore_existing:
112
+ if not quiet: print(f"Preparing ligand {ligand}")
113
+ with suppress_stdout(): lig_out = prepare_ligand(in_file=ligand, out_file=prepared_ligand)
114
+ if not lig_out[0]:
115
+ print(f"Error while preparing ligand {ligand} \nError: {lig_out[1]} \nSkipping this receptor-ligand combination.")
116
+ continue
117
+
118
+ if not quiet: print(f"Starting docking")
119
+ with suppress_stdout(): vina_out = dock_vina(prepared_receptor, prepared_ligand, out_pdb, log_file, center=center, box_size=box_size, exhaustiveness=exhaustiveness, n_poses=n_poses, n_poses_write=n_poses_write, overwrite=overwrite)
120
+ if not vina_out[0]:
121
+ print(f"Error while docking {ligand} to {receptor} \nError: {vina_out[1]} \nSkipping this receptor-ligand combination.")
122
+ continue
123
+ if not quiet: print("Docking Completed, writing log file")
124
+
125
+ if not quiet: print("Getting the ligand 1 after docking")
126
+ ligand_1 = out_pdb.replace('.pdbqt', '_ligand_1.sdf')
127
+ with suppress_stdout(): score, _ = vina_split(input_file=out_pdb, output_file=out_pdb)
128
+ if not quiet: print("Adding affinity to CSV")
129
+ csv_add = add_score_to_csv(out_pdb, csv_file, score)
130
+ if not csv_add[0]:
131
+ print(f"Error while adding affinity to CSV file {csv_file} \nError: {csv_add[1]}")
132
+
133
+ with open(completed_name, "a+") as file: file.write(f"{combination}\n")
134
+
135
+ if not quiet: print(f"Docking completed, log file is {log_file}, ligand_1 is {ligand_1.replace("pdbqt", "sdf")}, docking affinity is {score}. \n")
136
+
137
+ except EOFError:
138
+ continue
139
+
140
+
141
+ end_time = time.time()
142
+ elapsed_time = (end_time - start_time)/60
143
+
144
+ print(f"All Outputs are saved in the folder: {output_dir}")
145
+
146
+ print(f"Completed in {elapsed_time:.2f} minutes!")
147
+
148
+
149
+ def prepare_inputs():
150
+ parser = argparse.ArgumentParser(prog="np_dock", description=None, epilog="Part of mutadock library. Written by Naisarg Patel (https://github.com/naisarg14)")
151
+ parser.add_argument('receptor_txt', help="Text File with all receptors", metavar="RECEPTOR")
152
+ parser.add_argument("ligand_txt", help="Text File with all ligands", metavar="LIGAND")
153
+ parser.add_argument("--config",default=None, help="Text File with all Vina Configuration Settings", metavar="CONFIG")
154
+ parser.add_argument("--autosite",default=None, help="PDB generated by autosite for binding site of protein.", metavar="AUTOSITE")
155
+ parser.add_argument("--quiet", action="store_true", help="Run the Docking in quiet mode (default: False).")
156
+ parser.add_argument("--ignore_existing", action="store_true", help="Run the Docking while ingoring existing files. All dockings will be performed again. (default: False).")
157
+
158
+ args = parser.parse_args()
159
+
160
+ receptor_txt = args.receptor_txt
161
+ ligand_txt = args.ligand_txt
162
+ config = args.config
163
+
164
+ print("Receptor file:", receptor_txt)
165
+ print("Ligands file:", ligand_txt)
166
+ print("Config file:", config)
167
+ for f in [receptor_txt, ligand_txt]:
168
+ if not os.path.exists(f):
169
+ print(f"{f} not found or cannot be opened.")
170
+ try:
171
+ with open(receptor_txt, "r") as rec:
172
+ receptors = rec.readlines()
173
+ except IOError as err:
174
+ sys.exit(f"Error reading the file {receptor_txt}: ".format(receptor_txt, err))
175
+ try:
176
+ with open(ligand_txt, "r") as lig:
177
+ ligands = lig.readlines()
178
+ except IOError as err:
179
+ sys.exit(f"Error reading the file {ligand_txt}: ".format(ligand_txt, err))
180
+
181
+ for i in range(len(receptors)):
182
+ receptors[i] = receptors[i].replace("\n", "")
183
+ if not os.path.isabs(receptors[i]):
184
+ receptors[i] = os.path.join(os.getcwd(), receptors[i])
185
+ for i in range(len(ligands)):
186
+ ligands[i] = ligands[i].replace("\n", "")
187
+ if not os.path.isabs(ligands[i]):
188
+ ligands[i] = os.path.join(os.getcwd(), ligands[i])
189
+
190
+ receptor_basename = os.path.basename(receptor_txt)
191
+ ligand_basename = os.path.basename(ligand_txt)
192
+
193
+ if os.path.isabs(receptor_txt):
194
+ rec_folder = os.path.dirname(receptor_txt)
195
+ else:
196
+ rec_folder = os.path.dirname(os.path.abspath(receptor_txt))
197
+
198
+ completed_file_name = f"{receptor_basename.removesuffix(".txt")}_{ligand_basename.removesuffix(".txt")}_completed.txt"
199
+ completed_name = os.path.join(rec_folder, completed_file_name)
200
+
201
+ return receptors, ligands, config, args.autosite, args.quiet, completed_name, args.ignore_existing
202
+
203
+
204
+ if __name__ == "__main__":
205
+ naisarg()
docking/vina_dock.py ADDED
@@ -0,0 +1,83 @@
1
+ ################################################################################
2
+ # PROJECT INFORMATION #
3
+ # Name: MUTADOCK #
4
+ # Author: Naisarg Patel #
5
+ # #
6
+ # Copyright (C) 2024 Naisarg Patel (https://github.com/naisarg14) #
7
+ # #
8
+ # Project: https://github.com/naisarg14/mutadock #
9
+ # #
10
+ # This program is free software; you can redistribute it and/or modify it #
11
+ # under the terms of the GNU General Public License version 3 as published #
12
+ # by the Free Software Foundation. #
13
+ # #
14
+ # This program is distributed in the hope that it will be useful, but #
15
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
16
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License #
17
+ # for more details. #
18
+ ################################################################################
19
+
20
+
21
+ import sys, argparse
22
+
23
+ def vina_dock(receptor, ligand, output, center=[0, 0, 0], box_size=[30, 30, 30], exhaustiveness=32, n_poses=20, n_poses_write=5, overwrite=True):
24
+ try:
25
+ from vina import Vina
26
+ except ModuleNotFoundError:
27
+ msg = "Error with importing modules for docking using Vina.\n"
28
+ msg += "Easiest way to fix this is to install vina using the following command:\n\n"
29
+ msg += "python -m pip install vina\n"
30
+ msg += "If you already have vina installed, please check the installation.\n"
31
+ msg += "If the problem persists, please create a github issue or contact developer at naisarg.patel14@hotmail.com"
32
+ print(msg)
33
+ sys.exit(2)
34
+ try:
35
+ print("Docking done using mutadock library developed by Naisarg Patel (Github:@naisarg14)")
36
+ v = Vina(sf_name='vina')
37
+
38
+ v.set_receptor(receptor)
39
+ v.set_ligand_from_file(ligand)
40
+ print(v)
41
+ v.compute_vina_maps(center=center, box_size=box_size)
42
+
43
+ v.dock(exhaustiveness=exhaustiveness, n_poses=n_poses)
44
+ v.write_poses(output, n_poses=n_poses_write, overwrite=overwrite)
45
+
46
+ except Exception as e:
47
+ return (False, e)
48
+ return (True, "")
49
+
50
+
51
+ def main():
52
+ parser = argparse.ArgumentParser(description="Run docking using AutoDock vina Python bindings.")
53
+
54
+ parser.add_argument("--receptor", type=str, help="Path to the receptor file.")
55
+ parser.add_argument("--ligand", type=str, help="Path to the ligand file.")
56
+ parser.add_argument("--output", type=str, help="Path for saving the output file.")
57
+ parser.add_argument("--log_file", type=str, help="Path for saving the log file.")
58
+
59
+ parser.add_argument("--center", nargs=3, type=float, default=[0, 0, 0], help="X-dimension of the center of search box (default: [0, 0, 0]).")
60
+
61
+ parser.add_argument("--box_size", nargs=3, type=float, default=[30, 30, 30], help="Size of the search box (default: [30, 30, 30]).")
62
+ parser.add_argument("--exhaustiveness", type=int, default=32, help="Exhaustiveness of the search (default: 32).")
63
+ parser.add_argument("--n_poses", type=int, default=20, help="Number of poses to generate (default: 20).")
64
+ parser.add_argument("--n_poses_write", type=int, default=5, help="Number of poses to write to the output (default: 5).")
65
+ parser.add_argument("--nooverwrite", action="store_false", default=True, help="Do not overwrite existing files.")
66
+
67
+ args = parser.parse_args()
68
+
69
+ vina_dock(
70
+ receptor=args.receptor,
71
+ ligand=args.ligand,
72
+ output=args.output,
73
+ center=args.center,
74
+ box_size=args.box_size,
75
+ exhaustiveness=args.exhaustiveness,
76
+ n_poses=args.n_poses,
77
+ n_poses_write=args.n_poses_write,
78
+ overwrite=args.nooverwrite,
79
+ )
80
+
81
+
82
+ if __name__ == "__main__":
83
+ main()
docking/vina_helper.py ADDED
@@ -0,0 +1,340 @@
1
+ ################################################################################
2
+ # PROJECT INFORMATION #
3
+ # Name: MUTADOCK #
4
+ # Author: Naisarg Patel #
5
+ # #
6
+ # Copyright (C) 2024 Naisarg Patel (https://github.com/naisarg14) #
7
+ # #
8
+ # Project: https://github.com/naisarg14/mutadock #
9
+ # #
10
+ # This program is free software; you can redistribute it and/or modify it #
11
+ # under the terms of the GNU General Public License version 3 as published #
12
+ # by the Free Software Foundation. #
13
+ # #
14
+ # This program is distributed in the hope that it will be useful, but #
15
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
16
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License #
17
+ # for more details. #
18
+ ################################################################################
19
+
20
+
21
+ def backup(file_path):
22
+ import os
23
+ from datetime import datetime
24
+
25
+ if not os.path.exists(file_path):
26
+ return False
27
+ master_folder, file = os.path.split(os.path.abspath(file_path))
28
+ target_directory = os.path.join(master_folder, 'backups')
29
+ if not os.path.exists(target_directory):
30
+ os.makedirs(target_directory)
31
+ modified_time = os.path.getmtime(file_path)
32
+ timestamp = datetime.fromtimestamp(modified_time).strftime("%b-%d-%Y_%H.%M")
33
+ name, ext = os.path.splitext(file)
34
+ target_file = os.path.join(target_directory, f'{name}_{timestamp}{ext}')
35
+ os.rename(file_path, target_file)
36
+ return True
37
+
38
+ def read_pdb_file(file_path):
39
+ import re
40
+ try:
41
+ atoms = []
42
+ pattern = r'^ATOM\s+(\d+)\s+([A-Z]+)\s+([A-Z]{2,3})\s+([A-Z]?)\s*(\d+)\s+(-?\d+\.\d{3})\s+(-?\d+\.\d{3})\s+(-?\d+\.\d{3})\s+(\d+\.\d{1,2})\s+(\d+\.\d{1,3})(?:\s+(\d+\.\d{1,3}))?\s+[A-Z]$'
43
+ with open(file_path, 'r') as file:
44
+ for line in file:
45
+ if line.startswith(('ATOM', 'HETATM')):
46
+ match = re.match(pattern, line)
47
+ if match:
48
+ parts = {
49
+ "atom_serial_number": int(match.group(1)), # Atom Serial Number
50
+ "atom_name": match.group(2).strip(), # Atom Name
51
+ "residue_name": match.group(3).strip(), # Residue Name
52
+ "chain_id": match.group(4).strip() or None, # Chain Identifier (optional)
53
+ "residue_sequence_number": int(match.group(5)), # Residue Sequence Number
54
+ "x": float(match.group(6)), # X Coordinate
55
+ "y": float(match.group(7)), # Y Coordinate
56
+ "z": float(match.group(8)), # Z Coordinate
57
+ "occupancy": float(match.group(9)), # Occupancy
58
+ "temp_factor": float(match.group(10)), # Temperature Factor
59
+ "extra_factor": float(match.group(11)) if match.group(11) else None, # Extra Factor (optional)
60
+ }
61
+ atoms.append(parts)
62
+ return (atoms)
63
+ except Exception as e:
64
+ return (False, e)
65
+
66
+ def calculate_geometric_center(pdb_file):
67
+ atoms = read_pdb_file(pdb_file)
68
+ num_atoms = len(atoms)
69
+ x_sum = sum(atom['x'] for atom in atoms)
70
+ y_sum = sum(atom['y'] for atom in atoms)
71
+ z_sum = sum(atom['z'] for atom in atoms)
72
+
73
+ return (x_sum / num_atoms, y_sum / num_atoms, z_sum / num_atoms)
74
+
75
+ def calculate_radius(pdb_file):
76
+ import math
77
+ atoms = read_pdb_file(pdb_file)
78
+ if isinstance(atoms, tuple):
79
+ return atoms
80
+
81
+ center = calculate_geometric_center(pdb_file)
82
+ max_distance = 0
83
+
84
+ for atom in atoms:
85
+ distance = math.sqrt(
86
+ (atom['x'] - center[0]) ** 2 +
87
+ (atom['y'] - center[1]) ** 2 +
88
+ (atom['z'] - center[2]) ** 2
89
+ )
90
+ if distance > max_distance:
91
+ max_distance = distance
92
+
93
+ return max_distance
94
+
95
+ def vina_split(input_file, output_file=None):
96
+ try:
97
+ import sys
98
+ from meeko import PDBQTMolecule, RDKitMolCreate
99
+ except ModuleNotFoundError:
100
+ msg = "Error with importing modules for preparing ligand files for Docking.\n"
101
+ msg += "Easaies way to fix this is to install meeko using the following command:\n\n"
102
+ msg += "python -m pip install meeko\n"
103
+ msg += "If you already have meeko installed, please check the installation.\n"
104
+ msg += "If the problem persists, please create a github issue or contact developer at naisarg.patel14@hotmail.com"
105
+ print(msg)
106
+ sys.exit(2)
107
+
108
+ if output_file is None:
109
+ output_file = input_file.replace('.pdbqt', '_ligand_1.sdf')
110
+
111
+ pdbqt_string = ""
112
+ with open(input_file, 'r') as infile:
113
+ for line in infile:
114
+ if "vina result" in line.lower():
115
+ score = [float(x) for x in line.split() if x.replace('.', '', 1).replace('-', '', 1).isdigit()][0]
116
+ pdbqt_string += line
117
+ if line.startswith('ENDMDL'):
118
+ break
119
+ molecule = PDBQTMolecule(pdbqt_string)
120
+ sdf_string, failures = RDKitMolCreate.write_sd_string(molecule)
121
+
122
+ if len(failures) > 0:
123
+ msg = "\nCould not convert to RDKit. Maybe this library was not used for preparing\n"
124
+ msg += "the input PDBQT for docking, and the SMILES string is missing?\n"
125
+ msg += "Except for standard protein sidechains, all ligands and flexible residues\n"
126
+ msg += "require a REMARK SMILES line in the PDBQT, which is added automatically by meeko."
127
+ raise RuntimeError(msg)
128
+
129
+ footer_string = f"> <Docking Score>\n{score}\n> <Credits>\nCreated using a script in mutadock library written by Naisarg Patel (https://github.com/naisarg14/mutadock).\n$$$$\n"
130
+ with open(output_file, 'w') as outfile:
131
+ outfile.write(sdf_string.replace('$$$$', footer_string))
132
+
133
+ return (score, output_file)
134
+
135
+ def prepare_ligand(in_file, out_file=None):
136
+ try:
137
+ import sys
138
+ from meeko import MoleculePreparation, PDBQTWriterLegacy
139
+ from rdkit import Chem
140
+ except ModuleNotFoundError:
141
+ msg = "Error with importing modules for preparing ligand files for Docking.\n"
142
+ msg += "Easaies way to fix this is to install meeko and rdkit using the following command:\n\n"
143
+ msg += "python -m pip install meeko rdkit\n"
144
+ msg += "If you already have meeko and rdkit installed, please check the installation.\n"
145
+ msg += "If the problem persists, please create a github issue or contact developer at naisarg.patel14@hotmail.com"
146
+ print(msg)
147
+ sys.exit(2)
148
+
149
+ try:
150
+ #Add support for PDB files
151
+ if out_file is None:
152
+ if in_file.endswith(".sdf"):
153
+ out_file = f"{in_file.removesuffix(".sdf")}.pdbqt"
154
+ elif in_file.endswith(".mol2"):
155
+ out_file = f"{in_file.removesuffix(".mol2")}.pdbqt"
156
+ else:
157
+ return (False, "Input file is not in SDF or MOL2 format.")
158
+
159
+ if in_file.endswith(".sdf"):
160
+ mol = Chem.SDMolSupplier(in_file)[0]
161
+ if in_file.endswith(".mol2"):
162
+ mol = Chem.MolFromMol2File(in_file)
163
+
164
+ mol = Chem.AddHs(mol)
165
+ mp = MoleculePreparation()
166
+ molecule_setups = mp.prepare(mol)
167
+ pdbqt_string, success, error_msg = PDBQTWriterLegacy.write_string(molecule_setups[0])
168
+
169
+ if not success:
170
+ raise RuntimeError(f"Could not convert to PDBQT: {error_msg}")
171
+ with open(out_file, "w") as output_file:
172
+ output_file.write(pdbqt_string)
173
+ except Exception as e:
174
+ return (False, e)
175
+
176
+ return (True, pdbqt_string)
177
+
178
+ def prepare_receptor(receptor_filename, outputfilename="None"):
179
+ try:
180
+ import sys, os
181
+ from MolKit import Read
182
+ from AutoDockTools.MoleculePreparation import AD4ReceptorPreparation
183
+ except ModuleNotFoundError:
184
+ msg = "Error with importing modules for preparing receptor files for Docking.\n"
185
+ msg += "Easaies way to fix this is to install AutoDockTools_py3 using the following command:\n\n"
186
+ msg += "python -m pip install git+https://github.com/Valdes-Tresanco-MS/AutoDockTools_py3\n"
187
+ msg += "If you already have AutoDockTools_py3 installed, please check the installation.\n"
188
+ msg += "If the problem persists, please create a github issue or contact developer at naisarg.patel14@hotmail.com"
189
+ print(msg)
190
+ sys.exit(2)
191
+ finally:
192
+ original_stdout = os.dup(1)
193
+ original_stderr = os.dup(2)
194
+ with open(os.devnull, 'w') as fnull:
195
+ os.dup2(fnull.fileno(), 1)
196
+ os.dup2(fnull.fileno(), 2)
197
+
198
+ if outputfilename is None:
199
+ outputfilename = f"{receptor_filename}qt"
200
+
201
+ # initialize required parameters
202
+ repairs = 'hydrogens'
203
+ charges_to_add = 'gasteiger'
204
+ cleanup = "waters"
205
+
206
+ mode = 'automatic'
207
+ delete_single_nonstd_residues = None
208
+ dictionary = None
209
+ unique_atom_names = False
210
+
211
+ try:
212
+ mols = Read(receptor_filename)
213
+ mol = mols[0]
214
+ if unique_atom_names:
215
+ for at in mol.allAtoms:
216
+ if mol.allAtoms.get(at.name) >1:
217
+ at.name = at.name + str(at._uniqIndex +1)
218
+
219
+ if len(mols)>1:
220
+ #use the molecule with the most atoms
221
+ ctr = 1
222
+ for m in mols[1:]:
223
+ ctr += 1
224
+ if len(m.allAtoms)>len(mol.allAtoms):
225
+ mol = m
226
+
227
+ mol.buildBondsByDistance()
228
+ alt_loc_ats = mol.allAtoms.get(lambda x: "@" in x.name)
229
+ len_alt_loc_ats = len(alt_loc_ats)
230
+ if len_alt_loc_ats:
231
+ print("WARNING!", mol.name, "has",len_alt_loc_ats, ' alternate location atoms!\nUse prepare_pdb_split_alt_confs.py to create pdb files containing a single conformation.\n')
232
+
233
+ RPO = AD4ReceptorPreparation(mol, mode, repairs, charges_to_add,
234
+ cleanup, outputfilename=outputfilename,
235
+ delete_single_nonstd_residues=delete_single_nonstd_residues,
236
+ dict=dictionary)
237
+ except Exception as e:
238
+ os.dup2(original_stdout, 1)
239
+ os.dup2(original_stderr, 2)
240
+ os.close(original_stdout)
241
+ os.close(original_stderr)
242
+ return (False, e)
243
+ finally:
244
+ os.dup2(original_stdout, 1)
245
+ os.dup2(original_stderr, 2)
246
+ os.close(original_stdout)
247
+ os.close(original_stderr)
248
+
249
+ return (True, "")
250
+
251
+ def add_score_to_csv(out_pdb, csv_file, score):
252
+ import csv, os
253
+ try:
254
+ with open(csv_file, "r") as lc:
255
+ final_line = lc.readlines()[-1]
256
+ count = int(final_line.split(",")[0]) + 1
257
+ except FileNotFoundError:
258
+ count = 1
259
+ except ValueError:
260
+ count = 1
261
+ except Exception as e:
262
+ return (False, e)
263
+
264
+ try:
265
+ name = f"{os.path.basename(out_pdb).removesuffix('_out.pdb')}"
266
+ with open(csv_file, "a+") as out:
267
+ writer = csv.DictWriter(out, fieldnames=["sr", "name", "affinity"])
268
+ writer.writerow({"sr": count, "name": name, "affinity": score})
269
+
270
+ except Exception as e:
271
+ return (False, e)
272
+
273
+ return (True, name)
274
+
275
+ def read_config(config_file):
276
+ try:
277
+ config = {}
278
+ with open(config_file, 'r') as file:
279
+ for line in file:
280
+ line = line.strip()
281
+ if line and not line.startswith('#') and "=" in line:
282
+ key, value = line.split('=')
283
+ config[key.strip()] = value.strip()
284
+
285
+ center_x = config.get('center_x', '0.0')
286
+ center_y = config.get('center_y', '0.0')
287
+ center_z = config.get('center_z', '0.0')
288
+ size_x = config.get('size_x', '30.0')
289
+ size_y = config.get('size_y', '30.0')
290
+ size_z = config.get('size_z', '30.0')
291
+ exhaustiveness = config.get('exhaustiveness', '32')
292
+ n_poses = config.get('n_poses', '20')
293
+ n_poses_write = config.get('n_poses_write', '5')
294
+ overwrite = config.get('overwrite', 'True')
295
+
296
+ center = (center_x, center_y, center_z)
297
+ box_size = (size_x, size_y, size_z)
298
+
299
+ return (True, center, box_size, exhaustiveness, n_poses, n_poses_write, overwrite)
300
+
301
+ except Exception as e:
302
+ return (False, e)
303
+
304
+ def dock_vina(receptor, ligand, output, log_file, config=None, autosite=None, center=[0, 0, 0], box_size=[30, 30, 30], exhaustiveness=32, n_poses=20, n_poses_write=5, overwrite=True):
305
+ if config is not None:
306
+ values = read_config(config)
307
+ if values[0] is False:
308
+ return values
309
+ _, center, box_size, exhaustiveness, n_poses, n_poses_write, overwrite = values
310
+
311
+ if autosite is not None:
312
+ center = calculate_geometric_center(autosite)
313
+
314
+ import subprocess, os
315
+
316
+ current_dir = os.path.dirname(os.path.abspath(__file__))
317
+ vina_dock_script = os.path.join(current_dir, 'vina_dock.py')
318
+
319
+ commands = [
320
+ "python3", vina_dock_script,
321
+ "--receptor", receptor,
322
+ "--ligand", ligand,
323
+ "--output", output,
324
+ "--center", str(center[0]), str(center[1]), str(center[2]),
325
+ "--box_size", str(box_size[0]), str(box_size[1]), str(box_size[2]),
326
+ "--exhaustiveness", str(exhaustiveness),
327
+ "--n_poses", str(n_poses),
328
+ "--n_poses_write", str(n_poses_write),
329
+ ]
330
+ if not overwrite: commands.append("--nooverwrite")
331
+ with open(log_file, 'w+') as lfile:
332
+ result = subprocess.run(commands, stdout=lfile, stderr=lfile, text=True)
333
+
334
+ if result.returncode != 0:
335
+ return (False, f"Check the error in {log_file}")
336
+
337
+ return (True, "")
338
+
339
+ if __name__ == "__main__":
340
+ print("This is a dependency file for mutadock (https://github.com/naisarg14/mutadock) library's docking module.")