1 #!/bin/env python
2 #
3 # File: VinaPerformDocking.py
4 # Author: Manish Sud <msud@san.rr.com>
5 #
6 # Acknowledgments: Diogo Santos-Martins and Stefano Forli
7 #
8 # Copyright (C) 2026 Manish Sud. All rights reserved.
9 #
10 # The functionality available in this script is implemented using AutoDockVina
11 # and Meeko, open source software packages for docking, and RDKit, an open
12 # source toolkit for cheminformatics developed by Greg Landrum.
13 #
14 # This file is part of MayaChemTools.
15 #
16 # MayaChemTools is free software; you can redistribute it and/or modify it under
17 # the terms of the GNU Lesser General Public License as published by the Free
18 # Software Foundation; either version 3 of the License, or (at your option) any
19 # later version.
20 #
21 # MayaChemTools is distributed in the hope that it will be useful, but without
22 # any warranty; without even the implied warranty of merchantability of fitness
23 # for a particular purpose. See the GNU Lesser General Public License for more
24 # details.
25 #
26 # You should have received a copy of the GNU Lesser General Public License
27 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
28 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
29 # Boston, MA, 02111-1307, USA.
30 #
31
32 from __future__ import print_function
33
34 import os
35 import sys
36 import time
37 import re
38 import tempfile
39 import json
40 import glob
41 import multiprocessing as mp
42
43 # AutoDock Vina imports...
44 try:
45 from vina import Vina
46 from vina import __version__ as vinaVersion
47 except ImportError as ErrMsg:
48 sys.stderr.write("\nFailed to import AutoDock Vina module/package: %s\n" % ErrMsg)
49 sys.stderr.write("Check/update your Vina environment and try again.\n\n")
50 sys.exit(1)
51
52 # AutoDock Meeko imports...
53 try:
54 from meeko import __version__ as meekoVersion
55 from meeko import MoleculePreparation
56 from meeko import PDBQTMolecule
57 from meeko import RDKitMolCreate
58 from meeko import PDBQTWriterLegacy
59 except ImportError as ErrMsg:
60 sys.stderr.write("\nFailed to import AutoDock Meeko module/package: %s\n" % ErrMsg)
61 sys.stderr.write("Check/update your Meeko environment and try again.\n\n")
62 sys.exit(1)
63
64 # RDKit imports...
65 try:
66 from rdkit import rdBase
67 from rdkit import Chem
68 from rdkit.Chem import rdMolTransforms
69 except ImportError as ErrMsg:
70 sys.stderr.write("\nFailed to import RDKit module/package: %s\n" % ErrMsg)
71 sys.stderr.write("Check/update your RDKit environment and try again.\n\n")
72 sys.exit(1)
73
74 # MayaChemTools imports...
75 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
76 try:
77 from docopt import docopt
78 import MiscUtil
79 import RDKitUtil
80 except ImportError as ErrMsg:
81 sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
82 sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
83 sys.exit(1)
84
85 ScriptName = os.path.basename(sys.argv[0])
86 Options = {}
87 OptionsInfo = {}
88
89
90 def main():
91 """Start execution of the script."""
92
93 MiscUtil.PrintInfo(
94 "\n%s (Vina v%s; Meeko v%s; RDKit v%s; MayaChemTools v%s; %s): Starting...\n"
95 % (
96 ScriptName,
97 vinaVersion,
98 meekoVersion,
99 rdBase.rdkitVersion,
100 MiscUtil.GetMayaChemToolsVersion(),
101 time.asctime(),
102 )
103 )
104
105 (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
106
107 # Retrieve command line arguments and options...
108 RetrieveOptions()
109
110 # Process and validate command line arguments and options...
111 ProcessOptions()
112
113 # Perform actions required by the script...
114 PerformDocking()
115
116 MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
117 MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
118
119
120 def PerformDocking():
121 """Perform docking."""
122
123 # Setup a molecule reader...
124 MiscUtil.PrintInfo("\nProcessing file %s..." % OptionsInfo["Infile"])
125 Mols = RDKitUtil.ReadMolecules(OptionsInfo["Infile"], **OptionsInfo["InfileParams"])
126
127 # Set up molecule writers...
128 Writer, WriterFlexRes = SetupWriters()
129 if WriterFlexRes is None:
130 MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"])
131 else:
132 MiscUtil.PrintInfo("Generating files %s and %s..." % (OptionsInfo["Outfile"], OptionsInfo["OutfileFlexRes"]))
133
134 MolCount, ValidMolCount, DockingFailedCount = ProcessMolecules(Mols, Writer, WriterFlexRes)
135
136 CloseWriters(Writer, WriterFlexRes)
137
138 MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount)
139 MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount)
140 MiscUtil.PrintInfo("Number of molecules failed during docking: %d" % DockingFailedCount)
141 MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount + DockingFailedCount))
142
143
144 def ProcessMolecules(Mols, Writer, WriterFlexRes):
145 """Process and dock molecules."""
146
147 if OptionsInfo["MPMode"]:
148 return ProcessMoleculesUsingMultipleProcesses(Mols, Writer, WriterFlexRes)
149 else:
150 return ProcessMoleculesUsingSingleProcess(Mols, Writer, WriterFlexRes)
151
152
153 def ProcessMoleculesUsingSingleProcess(Mols, Writer, WriterFlexRes):
154 """Process and dock molecules using a single process."""
155
156 VinaHandle = InitializeVina(OptionsInfo["QuietMode"])
157 MolPrepHandle = InitializeMeekoMolPrepration(OptionsInfo["QuietMode"])
158 if not OptionsInfo["QuietMode"]:
159 MiscUtil.PrintInfo("\nVina configuration:\n%s" % VinaHandle)
160
161 MiscUtil.PrintInfo("\nDocking molecules (Mode: %s)..." % OptionsInfo["Mode"])
162
163 (MolCount, ValidMolCount, DockingFailedCount) = [0] * 3
164 for Mol in Mols:
165 MolCount += 1
166
167 if Mol is None:
168 continue
169
170 if not CheckAndValidateMolecule(Mol, MolCount):
171 continue
172
173 ValidMolCount += 1
174 CalcStatus, PoseMol, PoseMolEnergies, PoseMolFlexRes = DockMolecule(VinaHandle, MolPrepHandle, Mol, MolCount)
175
176 if not CalcStatus:
177 if not OptionsInfo["QuietMode"]:
178 MiscUtil.PrintWarning("Failed to dock molecule %s" % RDKitUtil.GetMolName(Mol, MolCount))
179
180 DockingFailedCount += 1
181 continue
182
183 WriteMolPoses(Writer, Mol, MolCount, PoseMol, PoseMolEnergies, WriterFlexRes, PoseMolFlexRes)
184
185 return (MolCount, ValidMolCount, DockingFailedCount)
186
187
188 def ProcessMoleculesUsingMultipleProcesses(Mols, Writer, WriterFlexRes):
189 """Process and calculate energy of molecules using multiprocessing."""
190
191 MiscUtil.PrintInfo("\nDocking molecules using multiprocessing...")
192 MiscUtil.PrintInfo("\nDocking molecules (Mode: %s)..." % OptionsInfo["Mode"])
193
194 MPParams = OptionsInfo["MPParams"]
195
196 # Setup data for initializing a worker process...
197 InitializeWorkerProcessArgs = (
198 MiscUtil.ObjectToBase64EncodedString(Options),
199 MiscUtil.ObjectToBase64EncodedString(OptionsInfo),
200 )
201
202 # Setup a encoded mols data iterable for a worker process...
203 WorkerProcessDataIterable = RDKitUtil.GenerateBase64EncodedMolStrings(Mols)
204
205 # Setup process pool along with data initialization for each process...
206 if not OptionsInfo["QuietMode"]:
207 MiscUtil.PrintInfo(
208 "\nConfiguring multiprocessing using %s method..."
209 % ("mp.Pool.imap()" if re.match("^Lazy$", MPParams["InputDataMode"], re.I) else "mp.Pool.map()")
210 )
211 MiscUtil.PrintInfo(
212 "NumProcesses: %s; InputDataMode: %s; ChunkSize: %s\n"
213 % (
214 MPParams["NumProcesses"],
215 MPParams["InputDataMode"],
216 ("automatic" if MPParams["ChunkSize"] is None else MPParams["ChunkSize"]),
217 )
218 )
219
220 ProcessPool = mp.Pool(MPParams["NumProcesses"], InitializeWorkerProcess, InitializeWorkerProcessArgs)
221
222 # Start processing...
223 if re.match("^Lazy$", MPParams["InputDataMode"], re.I):
224 Results = ProcessPool.imap(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"])
225 elif re.match("^InMemory$", MPParams["InputDataMode"], re.I):
226 Results = ProcessPool.map(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"])
227 else:
228 MiscUtil.PrintError(
229 'The value, %s, specified for "--inputDataMode" is not supported.' % (MPParams["InputDataMode"])
230 )
231
232 (MolCount, ValidMolCount, DockingFailedCount) = [0] * 3
233 for Result in Results:
234 MolCount += 1
235
236 MolIndex, EncodedMol, CalcStatus, EncodedPoseMol, PoseMolEnergies, EncodedPoseMolFlexRes = Result
237
238 if EncodedMol is None:
239 continue
240
241 ValidMolCount += 1
242
243 if not CalcStatus:
244 if not OptionsInfo["QuietMode"]:
245 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol)
246 MolName = RDKitUtil.GetMolName(Mol, MolCount)
247 MiscUtil.PrintWarning("Failed to dock molecule %s" % MolName)
248
249 DockingFailedCount += 1
250 continue
251
252 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol)
253 PoseMol = None if EncodedPoseMol is None else RDKitUtil.MolFromBase64EncodedMolString(EncodedPoseMol)
254 PoseMolFlexRes = (
255 None if EncodedPoseMolFlexRes is None else RDKitUtil.MolFromBase64EncodedMolString(EncodedPoseMolFlexRes)
256 )
257
258 WriteMolPoses(Writer, Mol, MolCount, PoseMol, PoseMolEnergies, WriterFlexRes, PoseMolFlexRes)
259
260 return (MolCount, ValidMolCount, DockingFailedCount)
261
262
263 def InitializeWorkerProcess(*EncodedArgs):
264 """Initialize data for a worker process."""
265
266 global Options, OptionsInfo
267
268 if not OptionsInfo["QuietMode"]:
269 MiscUtil.PrintInfo("Starting process (PID: %s)..." % os.getpid())
270
271 # Decode Options and OptionInfo...
272 Options = MiscUtil.ObjectFromBase64EncodedString(EncodedArgs[0])
273 OptionsInfo = MiscUtil.ObjectFromBase64EncodedString(EncodedArgs[1])
274
275 # Initialize in a quiet mode...
276 OptionsInfo["VinaHandle"] = InitializeVina(True)
277 OptionsInfo["MolPrepHandle"] = InitializeMeekoMolPrepration(True)
278
279
280 def WorkerProcess(EncodedMolInfo):
281 """Process data for a worker process."""
282
283 MolIndex, EncodedMol = EncodedMolInfo
284
285 CalcStatus, PoseMol, PoseMolEnergies, PoseMolFlexRes = [False, None, None, None]
286
287 if EncodedMol is None:
288 return [MolIndex, None, CalcStatus, PoseMol, PoseMolEnergies, PoseMolFlexRes]
289
290 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol)
291 MolCount = MolIndex + 1
292
293 if not CheckAndValidateMolecule(Mol, MolCount):
294 return [MolIndex, None, CalcStatus, PoseMol, PoseMolEnergies, PoseMolFlexRes]
295
296 CalcStatus, PoseMol, PoseMolEnergies, PoseMolFlexRes = DockMolecule(
297 OptionsInfo["VinaHandle"], OptionsInfo["MolPrepHandle"], Mol, MolCount
298 )
299
300 EncodedPoseMol = (
301 None
302 if PoseMol is None
303 else RDKitUtil.MolToBase64EncodedMolString(
304 PoseMol, PropertyPickleFlags=Chem.PropertyPickleOptions.MolProps | Chem.PropertyPickleOptions.PrivateProps
305 )
306 )
307
308 EncodedPoseMolFlexRes = (
309 None
310 if PoseMolFlexRes is None
311 else RDKitUtil.MolToBase64EncodedMolString(
312 PoseMolFlexRes,
313 PropertyPickleFlags=Chem.PropertyPickleOptions.MolProps | Chem.PropertyPickleOptions.PrivateProps,
314 )
315 )
316
317 return [MolIndex, EncodedMol, CalcStatus, EncodedPoseMol, PoseMolEnergies, EncodedPoseMolFlexRes]
318
319
320 def DockMolecule(VinaHandle, MolPrepHandle, Mol, MolNum=None):
321 """Dock molecule."""
322
323 Status, PoseMol, PoseMolEnergies, PoseMolFlexRes = [False, None, None, None]
324
325 if OptionsInfo["VinaVerbosity"] != 0:
326 MiscUtil.PrintInfo("\nProcessing molecule %s..." % RDKitUtil.GetMolName(Mol, MolNum))
327
328 PDBQTMolStr = PrepareMolecule(MolPrepHandle, Mol)
329 if PDBQTMolStr is None:
330 return (Status, PoseMol, PoseMolEnergies, PoseMolFlexRes)
331 VinaHandle.set_ligand_from_string(PDBQTMolStr)
332
333 if OptionsInfo["ScoreOnlyMode"]:
334 return ProcessMoleculeForScoreOnlyMode(VinaHandle, Mol)
335 elif OptionsInfo["LocalOptimizationOnlyMode"]:
336 return ProcessMoleculeForLocalOptimizationOnlyMode(VinaHandle, Mol)
337 elif OptionsInfo["DockMode"]:
338 return ProcessMoleculeForDockMode(VinaHandle, Mol)
339 else:
340 MiscUtil.PrintError(
341 'The value specified, %s, for option "-m, --mode" is not valid. Supported values: Dock LocalOptimizationOnly ScoreOnly'
342 % OptionsInfo["Mode"]
343 )
344
345 return (Status, PoseMol, PoseMolEnergies, PoseMolFlexRes)
346
347
348 def ProcessMoleculeForScoreOnlyMode(VinaHandle, Mol):
349 """Score molecule without performing any docking."""
350
351 Status, PoseMol, Energies, PoseMolFlexRes = [False, None, None, None]
352
353 # Score molecule...
354 try:
355 Energies = VinaHandle.score()
356 except Exception as ErrMsg:
357 if not OptionsInfo["QuietMode"]:
358 MiscUtil.PrintWarning("Failed to score molecule:\n%s\n" % ErrMsg)
359 return (False, None, None, None)
360
361 if len(Energies) == 0:
362 return (False, None, None, None)
363
364 Status = True
365 PoseMol = Mol
366
367 return (Status, PoseMol, Energies, PoseMolFlexRes)
368
369
370 def ProcessMoleculeForLocalOptimizationOnlyMode(VinaHandle, Mol):
371 """Score molecule after a local optimization wthout any docking."""
372
373 Status, PoseMol, Energies, PoseMolFlexRes = [False, None, None, None]
374
375 # Optimize and score molecule...
376 try:
377 Energies = VinaHandle.optimize()
378 except Exception as ErrMsg:
379 if not OptionsInfo["QuietMode"]:
380 MiscUtil.PrintWarning("Failed to perform local optimization:\n%s\n" % ErrMsg)
381 return (False, None, None, None)
382
383 if len(Energies) == 0:
384 return (False, None, None, None)
385
386 # Write optimize pose to a temporray file and retrieve the PDBQT string for the pose...
387 (_, TmpFile) = tempfile.mkstemp(suffix=".pdbqt", prefix="VinaOptimize_", text=True)
388 VinaHandle.write_pose(TmpFile, overwrite=True)
389
390 TmpFH = open(TmpFile, "r")
391 PosePDBQTOutputStr = TmpFH.read()
392 TmpFH.close()
393
394 os.remove(TmpFile)
395
396 # Setup a mol containing optimized pose...
397 try:
398 PosePDBQTOutputMol = PDBQTMolecule(PosePDBQTOutputStr)
399 PoseMols = RDKitMolCreate.from_pdbqt_mol(PosePDBQTOutputMol)
400 except Exception as ErrMsg:
401 if not OptionsInfo["QuietMode"]:
402 MiscUtil.PrintWarning("Failed to retrieve optimize pose:\n%s\n" % ErrMsg)
403 return (False, None, None, None)
404
405 if len(PoseMols) == 0:
406 return (False, None, None, None)
407
408 Status = True
409 PoseMol = PoseMols[0]
410
411 return (Status, PoseMol, Energies, PoseMolFlexRes)
412
413
414 def ProcessMoleculeForDockMode(VinaHandle, Mol):
415 """Dock and score molecule."""
416
417 Status, PoseMol, Energies, PoseMolFlexRes = [False, None, None, None]
418
419 # Dock molecule...
420 try:
421 VinaHandle.dock(
422 exhaustiveness=OptionsInfo["Exhaustiveness"],
423 n_poses=OptionsInfo["NumPoses"],
424 min_rmsd=OptionsInfo["MinRMSD"],
425 max_evals=OptionsInfo["MaxEvaluations"],
426 )
427 except Exception as ErrMsg:
428 if not OptionsInfo["QuietMode"]:
429 MiscUtil.PrintWarning("Failed to dock molecule:\n%s\n" % ErrMsg)
430 return (False, None, None, None)
431
432 # Retrieve poses...
433 try:
434 PosePDBQTOutputStr = VinaHandle.poses(
435 n_poses=OptionsInfo["NumPoses"], energy_range=OptionsInfo["EnergyRange"], coordinates_only=False
436 )
437 except Exception as ErrMsg:
438 if not OptionsInfo["QuietMode"]:
439 MiscUtil.PrintWarning("Failed to retrieve docked poses:\n%s\n" % ErrMsg)
440 return (False, None, None, None)
441
442 PoseMol, PoseMolFlexRes = SetupPoseMols(PosePDBQTOutputStr)
443 if PoseMol is None:
444 return (False, None, None, None)
445
446 # Retrieve energies...
447 try:
448 Energies = VinaHandle.energies(n_poses=OptionsInfo["NumPoses"], energy_range=OptionsInfo["EnergyRange"])
449 except Exception as ErrMsg:
450 if not OptionsInfo["QuietMode"]:
451 MiscUtil.PrintWarning("Failed to retrieve energies for docked poses:\n%s\n" % ErrMsg)
452 return (False, None, None, None)
453
454 if len(Energies) == 0:
455 return (False, None, None, None)
456
457 Status = True
458
459 return (Status, PoseMol, Energies, PoseMolFlexRes)
460
461
462 def SetupPoseMols(PosePDBQTOutputStr):
463 """Process PDBQT Vina poses string to setup pose mols for the docked
464 molecule and any flexible residues."""
465
466 PoseMol, PoseMolFlexRes = [None, None]
467
468 # Setup a mol containing poses as conformers...
469 try:
470 PosePDBQTOutputMol = PDBQTMolecule(PosePDBQTOutputStr)
471 PoseMols = RDKitMolCreate.from_pdbqt_mol(PosePDBQTOutputMol)
472 except Exception as ErrMsg:
473 if not OptionsInfo["QuietMode"]:
474 MiscUtil.PrintWarning("Failed to retrieve docked poses:\n%s\n" % ErrMsg)
475 return (None, None)
476
477 if len(PoseMols) == 0:
478 return (None, None)
479
480 # First mol is the pose for docked molecule...
481 PoseMol = PoseMols.pop(0)
482
483 # Collect pose mols foe flexible side chain residues...
484 PoseMolsFlexRes = []
485 for Mol in PoseMols:
486 if not Mol.HasProp("meeko"):
487 continue
488 MeekoPropMap = json.loads(Mol.GetProp("meeko"))
489 if type(MeekoPropMap) is dict:
490 if "is_sidechain" in MeekoPropMap:
491 if MeekoPropMap["is_sidechain"]:
492 PoseMolsFlexRes.append(Mol)
493
494 # Combine pose mols for flexible side chain residues into a single pose mol...
495 if len(PoseMolsFlexRes):
496 for Mol in PoseMolsFlexRes:
497 if PoseMolFlexRes is None:
498 PoseMolFlexRes = Mol
499 else:
500 PoseMolFlexRes = Chem.CombineMols(PoseMolFlexRes, Mol)
501
502 if PoseMolFlexRes is not None:
503 PoseMolConfCount = PoseMol.GetNumConformers()
504 PoseMolFlexResConfCount = PoseMolFlexRes.GetNumConformers()
505 if PoseMolConfCount != PoseMolFlexResConfCount:
506 if not OptionsInfo["QuietMode"]:
507 MiscUtil.PrintWarning(
508 "The number of poses, %s, for flexible residues doesn't match number of poses, %s, for docked molecule...\n"
509 % (PoseMolFlexResConfCount, PoseMolConfCount)
510 )
511
512 return (PoseMol, PoseMolFlexRes)
513
514
515 def PrepareMolecule(MolPrepHandle, Mol):
516 """Prepare molecule for docking."""
517
518 try:
519 PreppedMols = MolPrepHandle.prepare(Mol)
520 except Exception as ErrMsg:
521 if not OptionsInfo["QuietMode"]:
522 MiscUtil.PrintWarning("Failed to prepare molecule for docking:\n%s\n" % ErrMsg)
523 return None
524
525 if len(PreppedMols) == 0:
526 return None
527
528 PreppedMol = PreppedMols[0]
529
530 # Setup PDBQT mole string...
531 try:
532 PDBQTMolStr, Status, ErrMsg = PDBQTWriterLegacy.write_string(PreppedMol)
533 except Exception as ExceptionErrMsg:
534 if not OptionsInfo["QuietMode"]:
535 MiscUtil.PrintWarning("Failed to prepare molecule for docking:\n%s\n" % ExceptionErrMsg)
536 return None
537
538 if not Status:
539 if not OptionsInfo["QuietMode"]:
540 MiscUtil.PrintWarning("Failed to prepare molecule for docking:\n%s\n" % ErrMsg)
541 return None
542
543 if MiscUtil.IsEmpty(PDBQTMolStr):
544 return None
545
546 return PDBQTMolStr
547
548
549 def InitializeVina(Quiet=False):
550 """Initialize AutoDock Vina."""
551
552 if not Quiet:
553 MiscUtil.PrintInfo("\nInitializing Vina...")
554
555 VinaHandle = Vina(
556 sf_name=OptionsInfo["Forcefield"],
557 cpu=OptionsInfo["NumThreads"],
558 seed=OptionsInfo["RandomSeed"],
559 no_refine=OptionsInfo["SkipRefinement"],
560 verbosity=OptionsInfo["VinaVerbosity"],
561 )
562
563 SetupReceptor(VinaHandle, Quiet)
564 SetupForcefieldWeights(VinaHandle, Quiet)
565 SetupReceptorMaps(VinaHandle, Quiet)
566
567 return VinaHandle
568
569
570 def SetupReceptor(VinaHandle, Quiet=False):
571 """Setup receptor"""
572
573 if OptionsInfo["UseReceptorFile"] and OptionsInfo["UseReceptorFlexFile"]:
574 VinaHandle.set_receptor(
575 rigid_pdbqt_filename=OptionsInfo["ReceptorFile"], flex_pdbqt_filename=OptionsInfo["ReceptorFlexFile"]
576 )
577 elif OptionsInfo["UseReceptorFile"]:
578 VinaHandle.set_receptor(rigid_pdbqt_filename=OptionsInfo["ReceptorFile"], flex_pdbqt_filename=None)
579 elif OptionsInfo["UseReceptorFlexFile"]:
580 VinaHandle.set_receptor(rigid_pdbqt_filename=None, flex_pdbqt_filename=OptionsInfo["ReceptorFlexFile"])
581
582
583 def SetupForcefieldWeights(VinaHandle, Quiet=False):
584 """Setup forcefield weights."""
585
586 Weights = OptionsInfo["ForcefieldWeightParams"]
587 Forcefield = OptionsInfo["Forcefield"]
588 if not OptionsInfo["ForcefieldWeightParamsSpecified"]:
589 if not Quiet:
590 MiscUtil.PrintInfo("\nUsing default forcefield weights for %s..." % Forcefield)
591 return
592
593 if not Quiet:
594 MiscUtil.PrintInfo("\nSetting specified forcefield weights for %s..." % Forcefield)
595
596 if OptionsInfo["UseAD4Forcefield"]:
597 VinaHandle.set_weights(
598 [
599 Weights["AD4Vdw"],
600 Weights["AD4HydrogenBond"],
601 Weights["AD4Electrostatic"],
602 Weights["AD4Desolvation"],
603 Weights["AD4GlueLinearAttraction"],
604 Weights["AD4Rot"],
605 ]
606 )
607 elif OptionsInfo["UseVinaForcefield"]:
608 VinaHandle.set_weights(
609 [
610 Weights["VinaGaussian1"],
611 Weights["VinaGaussian2"],
612 Weights["VinaRepulsion"],
613 Weights["VinaHydrophobic"],
614 Weights["VinaHydrogenBond"],
615 Weights["VinaGlueLinearAttraction"],
616 Weights["VinaRot"],
617 ]
618 )
619 elif OptionsInfo["UseVinardoForcefield"]:
620 VinaHandle.set_weights(
621 [
622 Weights["VinardoGaussian1"],
623 Weights["VinardoRepulsion"],
624 Weights["VinardoHydrophobic"],
625 Weights["VinardoHydrogenBond"],
626 Weights["VinardoGlueLinearAttraction"],
627 Weights["VinardoRot"],
628 ]
629 )
630 else:
631 MiscUtil.PrintError(
632 'The value specified, %s, for option "-f, --forcefield" is not valid. Supported values: AD4 Vina Vinardo'
633 % Forcefield
634 )
635
636
637 def SetupReceptorMaps(VinaHandle, Quiet=False):
638 """Setup receptor maps."""
639
640 if not Quiet:
641 MiscUtil.PrintInfo("\nSetting up receptor and maps for %s forcefield..." % OptionsInfo["Forcefield"])
642
643 if OptionsInfo["UseAD4Forcefield"]:
644 # Load maps for rigid portion of the receptor...
645 VinaHandle.load_maps(OptionsInfo["ReceptorMapsPrefix"])
646 elif OptionsInfo["UseVinaForcefield"] or OptionsInfo["UseVinardoForcefield"]:
647 # Load or compute maps for rigid portion of the receptor...
648 if OptionsInfo["UseReceptorMapsPrefix"]:
649 VinaHandle.load_maps(OptionsInfo["ReceptorMapsPrefix"])
650 else:
651 VinaHandle.compute_vina_maps(
652 center=OptionsInfo["GridCenterList"],
653 box_size=OptionsInfo["GridSizeList"],
654 spacing=OptionsInfo["GridSpacing"],
655 force_even_voxels=False,
656 )
657 else:
658 MiscUtil.PrintError(
659 'The value specified, %s, for option "-f, --forcefield" is not valid. Supported values: AD4 Vina Vinardo'
660 % OptionsInfo["Forcefield"]
661 )
662
663
664 def InitializeMeekoMolPrepration(Quiet=False):
665 """Initialize meeko molecule prepration."""
666
667 if OptionsInfo["MergeHydrogens"]:
668 MolPrep = MoleculePreparation(merge_these_atom_types=("H",))
669 else:
670 MolPrep = MoleculePreparation(merge_these_atom_types="")
671
672 return MolPrep
673
674
675 def CheckAndValidateMolecule(Mol, MolCount=None):
676 """Validate molecule for docking."""
677
678 MolName = RDKitUtil.GetMolName(Mol, MolCount)
679 if RDKitUtil.IsMolEmpty(Mol):
680 if not OptionsInfo["QuietMode"]:
681 MiscUtil.PrintWarning("Ignoring empty molecule: %s\n" % MolName)
682 return False
683
684 if not OptionsInfo["ValidateMolecules"]:
685 return True
686
687 # Check for 3D flag...
688 if not Mol.GetConformer().Is3D():
689 if not OptionsInfo["QuietMode"]:
690 MiscUtil.PrintWarning("3D tag is not set for molecule: %s\n" % MolName)
691
692 # Check for missing hydrogens...
693 if RDKitUtil.AreHydrogensMissingInMolecule(Mol):
694 if not OptionsInfo["QuietMode"]:
695 MiscUtil.PrintWarning("Missing hydrogens in molecule: %s\n" % MolName)
696
697 return True
698
699
700 def WriteMolPoses(Writer, Mol, MolNum, PoseMol, Energies, WriterFlexRes=None, PoseMolFlexRes=None):
701 """Write molecule."""
702
703 if OptionsInfo["ScoreOnlyMode"]:
704 return WriteMolPoseForScoreOnlyMode(Writer, Mol, MolNum, PoseMol, Energies)
705 elif OptionsInfo["LocalOptimizationOnlyMode"]:
706 return WriteMolPoseForLocalOptimizationOnlyMode(Writer, Mol, MolNum, PoseMol, Energies)
707 elif OptionsInfo["DockMode"]:
708 return WriteMolPosesForDockMode(Writer, Mol, MolNum, PoseMol, Energies, WriterFlexRes, PoseMolFlexRes)
709 else:
710 MiscUtil.PrintError(
711 'The value specified, %s, for option "-m, --mode" is not valid. Supported values: Dock LocalOptimizationOnly ScoreOnly'
712 % OptionsInfo["Mode"]
713 )
714
715
716 def WriteMolPoseForScoreOnlyMode(Writer, Mol, MolNum, PoseMol, Energies):
717 """Write out molecule and associated information for score only mode."""
718
719 ClearMeekoMolProperties(PoseMol)
720
721 MolName = RDKitUtil.GetMolName(Mol, MolNum)
722 PoseMol.SetProp("_Name", MolName)
723
724 SetupEnergyProperties(PoseMol, Energies)
725 Writer.write(PoseMol)
726
727 return
728
729
730 def WriteMolPoseForLocalOptimizationOnlyMode(Writer, Mol, MolNum, PoseMol, Energies):
731 """Write out molecule and associated information for score only mode."""
732
733 ClearMeekoMolProperties(PoseMol)
734
735 MolName = RDKitUtil.GetMolName(Mol, MolNum)
736 PoseMol.SetProp("_Name", MolName)
737
738 SetupEnergyProperties(PoseMol, Energies)
739 Writer.write(PoseMol)
740
741
742 def WriteMolPosesForDockMode(Writer, Mol, MolNum, PoseMol, Energies, WriterFlexRes=None, PoseMolFlexRes=None):
743 """Write out molecule and associated information for dock mode."""
744
745 MolName = RDKitUtil.GetMolName(Mol, MolNum)
746
747 # Write out poses for docked molecule...
748 ClearMeekoMolProperties(PoseMol)
749 for PoseMolConfIndex, PoseMolConf in enumerate(PoseMol.GetConformers()):
750 PoseMolName = "%s_Pose%s" % (MolName, (PoseMolConfIndex + 1))
751 PoseMol.SetProp("_Name", PoseMolName)
752
753 SetupEnergyProperties(PoseMol, Energies[PoseMolConfIndex])
754
755 Writer.write(PoseMol, confId=PoseMolConf.GetId())
756
757 # Write out poses for flexible reside side chains...
758 if WriterFlexRes is None or PoseMolFlexRes is None:
759 return
760
761 ClearMeekoMolProperties(PoseMolFlexRes)
762 for PoseMolFlexResConfIndex, PoseMolFlexResConf in enumerate(PoseMolFlexRes.GetConformers()):
763 PoseMolFlexResName = "%s_Flex_Receptor_Pose%s" % (MolName, (PoseMolFlexResConfIndex + 1))
764 PoseMolFlexRes.SetProp("_Name", PoseMolFlexResName)
765
766 WriterFlexRes.write(PoseMolFlexRes, confId=PoseMolFlexResConf.GetId())
767
768
769 def ClearMeekoMolProperties(Mol):
770 """Clear Meeko molecule properties."""
771
772 for PropName in ["meeko"]:
773 if Mol.HasProp(PropName):
774 Mol.ClearProp(PropName)
775
776
777 def SetupEnergyProperties(Mol, Energies):
778 """Setup energy properties."""
779
780 Precision = OptionsInfo["Precision"]
781
782 for Index, EnergyLabel in enumerate(OptionsInfo["EnergyLabelsList"]):
783 EnergyValueIndex = OptionsInfo["EnergyValueIndicesList"][Index]
784 EnergyValue = "%.*f" % (Precision, Energies[EnergyValueIndex])
785 Mol.SetProp(EnergyLabel, EnergyValue)
786
787
788 def SetupWriters():
789 """Setup writers for output files."""
790
791 Writer, WriterFlexRes = [None, None]
792
793 Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"])
794 if Writer is None:
795 MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"])
796
797 if OptionsInfo["DockMode"] and OptionsInfo["UseReceptorFlexFile"]:
798 WriterFlexRes = RDKitUtil.MoleculesWriter(OptionsInfo["OutfileFlexRes"], **OptionsInfo["OutfileParams"])
799 if WriterFlexRes is None:
800 MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["OutfileFlexRes"])
801
802 return (Writer, WriterFlexRes)
803
804
805 def CloseWriters(Writer, WriterFlexRes):
806 """Close writers."""
807
808 if Writer is not None:
809 Writer.close()
810
811 if WriterFlexRes is not None:
812 WriterFlexRes.close()
813
814
815 def ComputeGridCenter(LigandFile):
816 """Compute grid center from ligand file."""
817
818 GridCenter = []
819
820 MiscUtil.PrintInfo("\nComputing grid center from reference ligand file %s..." % LigandFile)
821
822 Mols = RDKitUtil.ReadMolecules(LigandFile)
823 Mol = Mols[0]
824
825 Centroid = rdMolTransforms.ComputeCentroid(Mol.GetConformer())
826
827 GridCenter = [Centroid.x, Centroid.y, Centroid.z]
828
829 GridCenterFormatted = ["%.3f" % Value for Value in GridCenter]
830 MiscUtil.PrintInfo("GridCenter: %s" % (" ".join(GridCenterFormatted)))
831
832 return GridCenter
833
834
835 def ProcessReceptorOptions():
836 """Process receptor options."""
837
838 ReceptorFile, ReceptorMapsPrefix, UseReceptorFile, UseReceptorMapsPrefix = [None, None, False, False]
839
840 Receptor = Options["--receptor"]
841 if os.path.isfile(Receptor):
842 ReceptorFile = Receptor
843 UseReceptorFile = True
844 else:
845 ReceptorMapsPrefix = Receptor
846 UseReceptorMapsPrefix = True
847
848 OptionsInfo["Receptor"] = Receptor
849
850 OptionsInfo["ReceptorFile"] = ReceptorFile
851 OptionsInfo["UseReceptorFile"] = UseReceptorFile
852
853 OptionsInfo["ReceptorMapsPrefix"] = ReceptorMapsPrefix
854 OptionsInfo["UseReceptorMapsPrefix"] = UseReceptorMapsPrefix
855
856 UseReceptorFlexFile = False
857 ReceptorFlexFile = None
858 if not re.match("^None$", Options["--receptorFlexFile"], re.I):
859 UseReceptorFlexFile = True
860 ReceptorFlexFile = Options["--receptorFlexFile"]
861 OptionsInfo["ReceptorFlexFile"] = ReceptorFlexFile
862 OptionsInfo["UseReceptorFlexFile"] = UseReceptorFlexFile
863
864 if OptionsInfo["UseAD4Forcefield"]:
865 if OptionsInfo["UseReceptorFile"]:
866 MiscUtil.PrintError(
867 'The value specified, %s, for option "-r, --receptor" is not valid for %s forcefield. Supported value: Affinity maps prefix.'
868 % (OptionsInfo["Receptor"], Options["--forcefield"])
869 )
870
871
872 def ProcessForcefieldWeightParamatersOption(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
873 """Process forcefield weight paramaters option."""
874
875 ParamsInfo = {
876 "AD4Vdw": 0.1662,
877 "AD4HydrogenBond": 0.1209,
878 "AD4Electrostatic": 0.1406,
879 "AD4Desolvation": 0.1322,
880 "AD4GlueLinearAttraction": 50.0,
881 "AD4Rot": 0.2983,
882 "VinaGaussian1": -0.035579,
883 "VinaGaussian2": -0.005156,
884 "VinaRepulsion": 0.840245,
885 "VinaHydrophobic": -0.035069,
886 "VinaHydrogenBond": -0.587439,
887 "VinaGlueLinearAttraction": 50.0,
888 "VinaRot": 0.05846,
889 "VinardoGaussian1": -0.045,
890 "VinardoRepulsion": 0.8,
891 "VinardoHydrophobic": -0.035,
892 "VinardoHydrogenBond": -0.600,
893 "VinardoGlueLinearAttraction": 50.0,
894 "VinardoRot": 0.05846,
895 }
896
897 # Setup a canonical paramater names...
898 ValidParamNames = []
899 CanonicalParamNamesMap = {}
900 for ParamName in sorted(ParamsInfo):
901 ValidParamNames.append(ParamName)
902 CanonicalParamNamesMap[ParamName.lower()] = ParamName
903
904 # Update default values...
905 if ParamsDefaultInfo is not None:
906 for ParamName in ParamsDefaultInfo:
907 if ParamName not in ParamsInfo:
908 MiscUtil.PrintError(
909 'The default parameter name, %s, specified using "%s" to function ProcessForcefieldWeightParamatersOption is not a valid name. Supported parameter names: %s'
910 % (ParamName, ParamsDefaultInfo, " ".join(ValidParamNames))
911 )
912 ParamsInfo[ParamName] = ParamsDefaultInfo[ParamName]
913
914 if re.match("^auto$", ParamsOptionValue, re.I):
915 return ParamsInfo
916
917 ParamsOptionValueWords = ParamsOptionValue.split(",")
918 if len(ParamsOptionValueWords) % 2:
919 MiscUtil.PrintError(
920 'The number of comma delimited paramater names and values, %d, specified using "%s" option must be an even number.'
921 % (len(ParamsOptionValueWords), ParamsOptionName)
922 )
923
924 # Validate paramater name and value pairs...
925 for Index in range(0, len(ParamsOptionValueWords), 2):
926 Name = ParamsOptionValueWords[Index].strip()
927 Value = ParamsOptionValueWords[Index + 1].strip()
928
929 CanonicalName = Name.lower()
930 if CanonicalName not in CanonicalParamNamesMap:
931 MiscUtil.PrintError(
932 'The parameter name, %s, specified using "%s" is not a valid name. Supported parameter names: %s'
933 % (Name, ParamsOptionName, " ".join(ValidParamNames))
934 )
935
936 ParamName = CanonicalParamNamesMap[CanonicalName]
937
938 if not MiscUtil.IsFloat(Value):
939 MiscUtil.PrintError(
940 'The parameter value, %s, specified for parameter name, %s, using "%s" must be a float.'
941 % (Value, Name, ParamsOptionName)
942 )
943 ParamValue = float(Value)
944
945 ParamsInfo[ParamName] = ParamValue
946
947 return ParamsInfo
948
949
950 def ProcessModeOption():
951 """Process mode option."""
952
953 Mode = Options["--mode"]
954 DockMode, LocalOptimizationOnlyMode, ScoreOnlyMode = [False] * 3
955 if re.match("^Dock$", Mode, re.I):
956 Mode = "Dock"
957 DockMode = True
958 elif re.match("^LocalOptimizationOnly$", Mode, re.I):
959 Mode = "LocalOptimizationOnly"
960 LocalOptimizationOnlyMode = True
961 elif re.match("^ScoreOnly$", Mode, re.I):
962 Mode = "ScoreOnly"
963 ScoreOnlyMode = True
964 else:
965 MiscUtil.PrintError(
966 'The value specified, %s, for option "-m, --mode" is not valid. Supported values: Dock LocalOptimizationOnly ScoreOnly'
967 % OptionsInfo["Mode"]
968 )
969
970 OptionsInfo["Mode"] = Mode
971 OptionsInfo["DockMode"] = DockMode
972 OptionsInfo["LocalOptimizationOnlyMode"] = LocalOptimizationOnlyMode
973 OptionsInfo["ScoreOnlyMode"] = ScoreOnlyMode
974
975
976 def ProcessEnergyLabelOptions():
977 """Process energy label options."""
978
979 Forcefield = OptionsInfo["Forcefield"]
980
981 EnergyLabel = Options["--energyLabel"]
982 if re.match("^auto$", EnergyLabel, re.I):
983 EnergyLabel = "%s_Total_Energy (kcal/mol)" % Forcefield
984 OptionsInfo["EnergyLabel"] = EnergyLabel
985
986 EnergyLabelsList = []
987 DefaultLabels = [
988 "%s_Intermolecular_Energy (kcal/mol)" % (Forcefield),
989 "%s_Internal_Energy (kcal/mol)" % (Forcefield),
990 "%s_Torsions_Energy (kcal/mol)" % (Forcefield),
991 ]
992
993 EnergyLabels = Options["--energyComponentsLabels"]
994 if not re.match("^auto$", EnergyLabels, re.I):
995 EnergyLabelsWords = EnergyLabels.split(",")
996 if len(EnergyLabelsWords) != 3:
997 MiscUtil.PrintError(
998 'The specified value, %s, for option "--energyComponentsLabels " is not valid. It must contain 3 text values separated by comma.'
999 % EnergyLabels
1000 )
1001
1002 for LabelIndex, Label in enumerate(EnergyLabelsWords):
1003 Label = Label.strip()
1004 if re.match("^auto$", Label, re.I):
1005 Label = DefaultLabels[LabelIndex]
1006
1007 EnergyLabelsList.append(Label)
1008 else:
1009 EnergyLabelsList = DefaultLabels
1010
1011 OptionsInfo["EnergyComponentsLabels"] = EnergyLabels
1012 OptionsInfo["EnergyComponentsLabelsList"] = EnergyLabelsList
1013
1014 SetupEnergyLabelsAndIndices()
1015
1016
1017 def SetupEnergyLabelsAndIndices():
1018 """Setup energy data labels and indices for writing out energy values."""
1019
1020 EnergyLabelsList = []
1021 EnergyValueIndicesList = []
1022
1023 # Total energy is always at index 0 in the list retured by vina.score (),
1024 # vina.optimize(), and vina.energies() during ScoreOnly, LocalOptimizationOnly
1025 # and Dock modes...
1026 EnergyLabelsList.append(OptionsInfo["EnergyLabel"])
1027 EnergyValueIndicesList.append(0)
1028
1029 OptionsInfo["EnergyLabelsList"] = EnergyLabelsList
1030 OptionsInfo["EnergyValueIndicesList"] = EnergyValueIndicesList
1031
1032 if not OptionsInfo["EnergyComponents"]:
1033 return
1034
1035 # Setup energy labels and indices for energy components...
1036 if OptionsInfo["ScoreOnlyMode"]:
1037 # vina.score returns a list containing the following values:
1038 #
1039 # Vina/Vinardo FF: columns=[total, lig_inter, flex_inter, other_inter, flex_intra, lig_intra, torsions, lig_intra best pose]
1040 # AutoDock FF: [total, lig_inter, flex_inter, other_inter, flex_intra, lig_intra, torsions, -lig_intra]
1041 #
1042 IntermolecularEnergyIndex, IntramolecularEnergyIndex, TorsionEnergyIndex = [1, 5, 6]
1043 elif OptionsInfo["LocalOptimizationOnlyMode"]:
1044 # vina.optimize returns a list containing the following values:
1045 #
1046 # Vina/Vinardo FF: [total, lig_inter, flex_inter, other_inter, flex_intra, lig_intra, torsions, lig_intra best pose]
1047 # AutoDock FF: [total, lig_inter, flex_inter, other_inter, flex_intra, lig_intra, torsions, -lig_intra]
1048 #
1049 IntermolecularEnergyIndex, IntramolecularEnergyIndex, TorsionEnergyIndex = [1, 5, 6]
1050 elif OptionsInfo["DockMode"]:
1051 # vina.energies returns a list containing the following values:
1052 #
1053 # Vina/Vinardo FF: [total, inter, intra, torsions, intra best pose]
1054 # AutoDock FF: [total, inter, intra, torsions, -intra]
1055 #
1056 IntermolecularEnergyIndex, IntramolecularEnergyIndex, TorsionEnergyIndex = [1, 2, 3]
1057 else:
1058 MiscUtil.PrintError(
1059 'The value specified, %s, for option "-m, --mode" is not valid. Supported values: Dock LocalOptimizationOnly ScoreOnly'
1060 % OptionsInfo["Mode"]
1061 )
1062
1063 OptionsInfo["EnergyLabelsList"].extend(OptionsInfo["EnergyComponentsLabelsList"])
1064 OptionsInfo["EnergyValueIndicesList"].extend(
1065 [IntermolecularEnergyIndex, IntramolecularEnergyIndex, TorsionEnergyIndex]
1066 )
1067
1068
1069 def ProcessOptions():
1070 """Process and validate command line arguments and options."""
1071
1072 MiscUtil.PrintInfo("Processing options...")
1073
1074 # Validate options...
1075 ValidateOptions()
1076
1077 OptionsInfo["Infile"] = Options["--infile"]
1078 ParamsDefaultInfoOverride = {"RemoveHydrogens": False}
1079 OptionsInfo["InfileParams"] = MiscUtil.ProcessOptionInfileParameters(
1080 "--infileParams",
1081 Options["--infileParams"],
1082 InfileName=Options["--infile"],
1083 ParamsDefaultInfo=ParamsDefaultInfoOverride,
1084 )
1085
1086 OptionsInfo["Outfile"] = Options["--outfile"]
1087 OptionsInfo["OutfileParams"] = MiscUtil.ProcessOptionOutfileParameters(
1088 "--outfileParams", Options["--outfileParams"]
1089 )
1090
1091 FileDir, FileName, FileExt = MiscUtil.ParseFileName(Options["--outfile"])
1092 OptionsInfo["OutfileFlexRes"] = "%s_Flex_Receptor.%s" % (FileName, FileExt)
1093
1094 GridCenterLigandFile, GridCenterList, GridCenterByLigandFile = [None, None, False]
1095 GridCenter = Options["--gridCenter"]
1096 if re.search(",", GridCenter, re.I):
1097 GridCenterList = [float(Value) for Value in GridCenter.split(",")]
1098 else:
1099 GridCenterByLigandFile = True
1100 GridCenterLigandFile = GridCenter
1101 GridCenterList = ComputeGridCenter(GridCenterLigandFile)
1102
1103 OptionsInfo["GridCenter"] = GridCenter
1104 OptionsInfo["GridCenterList"] = GridCenterList
1105 OptionsInfo["GridCenterLigandFile"] = GridCenterLigandFile
1106 OptionsInfo["GridCenterByLigandFile"] = GridCenterByLigandFile
1107
1108 OptionsInfo["EnergyComponents"] = True if re.match("^yes$", Options["--energyComponents"], re.I) else False
1109
1110 OptionsInfo["EnergyRange"] = float(Options["--energyRange"])
1111 OptionsInfo["Exhaustiveness"] = int(Options["--exhaustiveness"])
1112
1113 Forcefield = Options["--forcefield"]
1114 UseAD4Forcefield, UseVinaForcefield, UseVinardoForcefield = [False, False, False]
1115 if re.match("^AD4$", Forcefield, re.I):
1116 Forcefield = "AD4"
1117 UseAD4Forcefield = True
1118 elif re.match("^Vina$", Forcefield, re.I):
1119 Forcefield = "Vina"
1120 UseVinaForcefield = True
1121 elif re.match("^Vinardo$", Forcefield, re.I):
1122 Forcefield = "Vinardo"
1123 UseVinardoForcefield = True
1124 else:
1125 MiscUtil.PrintError(
1126 'The value specified, %s, for option "-f, --forcefield" is not valid. Supported values: AD4 Vina Vinardo'
1127 )
1128 OptionsInfo["Forcefield"] = Forcefield
1129 OptionsInfo["UseAD4Forcefield"] = UseAD4Forcefield
1130 OptionsInfo["UseVinaForcefield"] = UseVinaForcefield
1131 OptionsInfo["UseVinardoForcefield"] = UseVinardoForcefield
1132
1133 OptionsInfo["ForcefieldWeightParams"] = ProcessForcefieldWeightParamatersOption(
1134 "--forcefieldWeightParams", Options["--forcefieldWeightParams"]
1135 )
1136 OptionsInfo["ForcefieldWeightParamsSpecified"] = (
1137 False if re.match("^auto$", Options["--forcefieldWeightParams"], re.I) else True
1138 )
1139
1140 GridSize = Options["--gridSize"]
1141 GridSizeList = [float(Value) for Value in GridSize.split(",")]
1142 OptionsInfo["GridSize"] = GridSize
1143 OptionsInfo["GridSizeList"] = GridSizeList
1144
1145 OptionsInfo["GridSpacing"] = float(Options["--gridSpacing"])
1146
1147 OptionsInfo["MaxEvaluations"] = int(Options["--maxEvaluations"])
1148 OptionsInfo["MinRMSD"] = float(Options["--minRMSD"])
1149
1150 MergeHydrogens = Options["--mergeHydrogens"]
1151 if re.match("^auto$", MergeHydrogens, re.I):
1152 MergeHydrogens = True if OptionsInfo["UseAD4Forcefield"] else False
1153 else:
1154 MergeHydrogens = True if re.match("^yes$", MergeHydrogens, re.I) else False
1155 OptionsInfo["MergeHydrogens"] = MergeHydrogens
1156
1157 ProcessModeOption()
1158
1159 OptionsInfo["MPMode"] = True if re.match("^yes$", Options["--mp"], re.I) else False
1160 OptionsInfo["MPParams"] = MiscUtil.ProcessOptionMultiprocessingParameters("--mpParams", Options["--mpParams"])
1161
1162 OptionsInfo["NumPoses"] = int(Options["--numPoses"])
1163
1164 if re.match("^auto$", Options["--numThreads"], re.I):
1165 NumThreads = 1 if OptionsInfo["MPMode"] else 0
1166 else:
1167 NumThreads = int(Options["--numThreads"])
1168 OptionsInfo["NumThreads"] = NumThreads
1169
1170 OptionsInfo["Precision"] = int(Options["--precision"])
1171 OptionsInfo["RandomSeed"] = int(Options["--randomSeed"])
1172
1173 OptionsInfo["SkipRefinement"] = True if re.match("^yes$", Options["--skipRefinement"], re.I) else False
1174
1175 OptionsInfo["ValidateMolecules"] = True if re.match("^yes$", Options["--validateMolecules"], re.I) else False
1176
1177 if re.match("^auto$", Options["--vinaVerbosity"], re.I):
1178 VinaVerbosity = 0 if OptionsInfo["MPMode"] else 1
1179 else:
1180 VinaVerbosity = int(Options["--vinaVerbosity"])
1181 OptionsInfo["VinaVerbosity"] = VinaVerbosity
1182
1183 OptionsInfo["Overwrite"] = Options["--overwrite"]
1184 OptionsInfo["QuietMode"] = True if re.match("^yes$", Options["--quiet"], re.I) else False
1185
1186 ProcessEnergyLabelOptions()
1187 ProcessReceptorOptions()
1188
1189
1190 def RetrieveOptions():
1191 """Retrieve command line arguments and options."""
1192
1193 # Get options...
1194 global Options
1195 Options = docopt(_docoptUsage_)
1196
1197 # Set current working directory to the specified directory...
1198 WorkingDir = Options["--workingdir"]
1199 if WorkingDir:
1200 os.chdir(WorkingDir)
1201
1202 # Handle examples option...
1203 if "--examples" in Options and Options["--examples"]:
1204 MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
1205 sys.exit(0)
1206
1207
1208 def ValidateOptions():
1209 """Validate option values."""
1210
1211 MiscUtil.ValidateOptionFilePath("-i, --infile", Options["--infile"])
1212 MiscUtil.ValidateOptionFileExt("-i, --infile", Options["--infile"], "sdf sd mol")
1213
1214 MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "sdf sd")
1215 MiscUtil.ValidateOptionsOutputFileOverwrite(
1216 "-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"]
1217 )
1218 MiscUtil.ValidateOptionsDistinctFileNames(
1219 "-i, --infile", Options["--infile"], "-o, --outfile", Options["--outfile"]
1220 )
1221
1222 FileDir, FileName, FileExt = MiscUtil.ParseFileName(Options["--receptor"])
1223 if not MiscUtil.IsEmpty(FileExt):
1224 MiscUtil.ValidateOptionFilePath("-r, --receptor", Options["--receptor"])
1225 MiscUtil.ValidateOptionFileExt("-r, --receptor", Options["--receptor"], "pdbqt")
1226 else:
1227 AffinityMapFiles = glob.glob("%s.*.map" % Options["--receptor"])
1228 if len(AffinityMapFiles) == 0:
1229 MiscUtil.PrintError(
1230 'The receptor affinity map files, %s.*.map, corresponding to maps prefix, %s, specified using option, "-r, --receptor" option don\'t exist.'
1231 % (Options["--receptor"], Options["--receptor"])
1232 )
1233
1234 if not re.match("^None$", Options["--receptorFlexFile"], re.I):
1235 MiscUtil.ValidateOptionFilePath("--receptorFlexFile", Options["--receptorFlexFile"])
1236 MiscUtil.ValidateOptionFileExt("--receptorFlexFile", Options["--receptorFlexFile"], "pdbqt")
1237 if os.path.isfile(Options["--receptor"]):
1238 MiscUtil.ValidateOptionsDistinctFileNames(
1239 "-r, --receptor", Options["--receptor"], "--receptorFlexFile", Options["--receptorFlexFile"]
1240 )
1241
1242 if re.search(",", Options["--gridCenter"], re.I):
1243 MiscUtil.ValidateOptionNumberValues("-g, --gridCenter", Options["--gridCenter"], 3, ",", "float", {">=": 0.0})
1244 else:
1245 MiscUtil.ValidateOptionFilePath("-g, --gridCenter", Options["--gridCenter"])
1246 MiscUtil.ValidateOptionFileExt("-g, --gridCenter", Options["--gridCenter"], "sdf sd mol pdb")
1247
1248 MiscUtil.ValidateOptionTextValue("--energyComponents", Options["--energyComponents"], "yes no")
1249
1250 MiscUtil.ValidateOptionFloatValue("--energyRange", Options["--energyRange"], {">": 0})
1251
1252 MiscUtil.ValidateOptionIntegerValue("--exhaustiveness", Options["--exhaustiveness"], {">": 0})
1253
1254 MiscUtil.ValidateOptionTextValue("-f, --forcefield", Options["--forcefield"], "AD4 Vina Vinardo")
1255
1256 MiscUtil.ValidateOptionNumberValues("--gridSize", Options["--gridSize"], 3, ",", "float", {">": 0.0})
1257 MiscUtil.ValidateOptionFloatValue("--gridSpacing", Options["--gridSpacing"], {">": 0})
1258
1259 MiscUtil.ValidateOptionIntegerValue("--maxEvaluations", Options["--maxEvaluations"], {">=": 0})
1260 MiscUtil.ValidateOptionFloatValue("--minRMSD", Options["--minRMSD"], {">": 0})
1261
1262 MiscUtil.ValidateOptionTextValue("--mergeHydrogens", Options["--mergeHydrogens"], "yes no auto")
1263
1264 MiscUtil.ValidateOptionTextValue("-m, --mode", Options["--mode"], "Dock LocalOptimizationOnly ScoreOnly")
1265
1266 MiscUtil.ValidateOptionTextValue("--mp", Options["--mp"], "yes no")
1267
1268 MiscUtil.ValidateOptionIntegerValue("--numPoses", Options["--numPoses"], {">": 0})
1269
1270 if not re.match("^auto$", Options["--numThreads"], re.I):
1271 MiscUtil.ValidateOptionIntegerValue("--numThreads", Options["--numThreads"], {">": 0})
1272
1273 MiscUtil.ValidateOptionIntegerValue("-p, --precision", Options["--precision"], {">": 0})
1274 MiscUtil.ValidateOptionIntegerValue("--randomSeed", Options["--randomSeed"], {})
1275
1276 MiscUtil.ValidateOptionTextValue("--skipRefinement", Options["--skipRefinement"], "yes no")
1277
1278 MiscUtil.ValidateOptionTextValue("-v, --validateMolecules", Options["--validateMolecules"], "yes no")
1279
1280 if not re.match("^auto$", Options["--vinaVerbosity"], re.I):
1281 MiscUtil.ValidateOptionIntegerValue("--vinaVerbosity", Options["--vinaVerbosity"], {">=": 0})
1282 MiscUtil.ValidateOptionTextValue("--vinaVerbosity", Options["--vinaVerbosity"], "0 1 2")
1283
1284 MiscUtil.ValidateOptionTextValue("-q, --quiet", Options["--quiet"], "yes no")
1285
1286
1287 # Setup a usage string for docopt...
1288 _docoptUsage_ = """
1289 VinaPerformDocking.py - Perform docking
1290
1291 Usage:
1292 VinaPerformDocking.py [--energyComponents <yes or no>] [--energyComponentsLabels <Label1, label2, Label3>]
1293 [--energyLabel <text>] [--energyRange <number>] [--exhaustiveness <number>]
1294 [--forcefield <AD4, Vina, or Vinardo>] [--forcefieldWeightParams <Name,Value,...>] [--gridSpacing <number>]
1295 [--gridSize <xsize,ysize,zsize>] [--infileParams <Name,Value,...>] [--maxEvaluations <number>]
1296 [--mergeHydrogens <yes or no>] [--minRMSD <number>] [--mode <Dock, LocalOptimizationOnly, ScoreOnly>] [--mp <yes or no>]
1297 [--mpParams <Name, Value,...>] [--numPoses <number>] [--numThreads <number>] [--outfileParams <Name,Value,...> ]
1298 [--overwrite] [--precision <number>] [--quiet <yes or no>] [--randomSeed <number>] [--receptorFlexFile <receptor flex file>]
1299 [--skipRefinement <yes or no>] [--validateMolecules <yes or no>] [--vinaVerbosity <number>]
1300 [-w <dir>] -g <RefLigandFile or x,y,z> -r <receptorfile or maps prerfix> -i <infile> -o <outfile>
1301 VinaPerformDocking.py -h | --help | -e | --examples
1302
1303 Description:
1304 Dock molecules against a protein receptor using AutoDock Vina [Ref 168, 169].
1305 The molecules must have 3D coordinates in input file. In addition, the hydrogens
1306 must be present for all molecules in input file.
1307
1308 No protein receptor preparation is performed during docking. It must be prepared
1309 employing standalone scripts available as part of AutoDock Vina. You may
1310 optionally specify flexible residues in the binding pocket to prepare a flexible
1311 receptor file and employ it for docking molecules along with the fixed receptor
1312 file.
1313
1314 The following three forecefileds are available to score molecules: AD4
1315 (AutoDock4), Vina, and Vinardo (Vina RaDii Optimized) [Ref 170].
1316
1317 The supported input file formats are shown below:
1318
1319 Rigid/Flexible protein receptor files - PDBQT(.pdbqt)
1320 Reference ligand file: PDB(.pdb), Mol (.mol), SD (.sdf, .sd)
1321
1322 Input molecules file - Mol (.mol), SD (.sdf, .sd)
1323
1324 The supported output file format is: SD (.sdf, .sd).
1325
1326 The following output files are generated:
1327
1328 <OutfileRoot>.<OutfileExt> - Docked/scored molecules
1329 <OutfileRoot>_Flex_Receptor.<OutfileExt> - Docked poses for flexible
1330 residues
1331
1332 The flexible receptor output file contains docked poses corresponding to
1333 flexible residues. It is only generated during 'Dock' value of '-m, --mode'
1334 option. The number of poses in this file matches those written to the
1335 output file containing docked molecules.
1336
1337 Options:
1338 --energyComponents <yes or no> [default: no]
1339 Write out binding energy components of the total binding energy docking
1340 score to outfile. The following three energy components are written to
1341 outfile: intermolecula energy, internal energy, and torsions energy.
1342 --energyComponentsLabels <Label1, label2, Label3> [default: auto]
1343 A triplet of comma delimited values corresponding to energy data field
1344 labels for writing out the binding energy components to outfile. You must
1345 specify all three values. A value of 'None' implies the use of the default
1346 labels as shown below:
1347
1348 Label1: <ForcefieldName>_Intermolecular_Energy (kcal/mol)
1349 Label2: <ForcefieldName>_Internal_Energy (kcal/mol)
1350 Label3: <ForcefieldName>_Torsions_Energy (kcal/mol)
1351
1352 --energyLabel <text> [default: auto]
1353 Energy data field label for writing out binding energy docking score to
1354 output file. Default: <ForcefieldName>_Total_Energy (kcal/mol).
1355 --energyRange <number> [default: 3.0]
1356 Maximum energy difference from the best pose during the generation of
1357 poses. Units: kcal/mol.
1358 -e, --examples
1359 Print examples.
1360 --exhaustiveness <number> [default: 8]
1361 Exhaustiveness of global MC search. The higher values make the search
1362 more exhaustive and it takes longer to complete. You may want to use
1363 '16' or '32' as the value of '--exhaustiveness ' to increase the accuracy of
1364 your pose prediction.
1365 -f, --forcefield <AD4, Vina, or Vinardo> [default: Vina]
1366 Forcefield to use for scoring. Possible values: AD4 (AutoDock 4), Vina
1367 [Ref 169, 169], or Vinardo (Vina RaDii Optimized) [Ref 170].
1368
1369 You must specify affinity maps using '-r, --receptor' option during the use
1370 of 'AD4' forcefield.
1371 --forcefieldWeightParams <Name,Value,...> [default: auto]
1372 A comma delimited list of parameter name and value pairs for forcefield
1373 scoring.
1374
1375 The supported parameter names along with their default values are
1376 are shown below for different forcefields:
1377
1378 AD4 (6 weights):
1379
1380 ad4Vdw, 0.1662, ad4HydrogenBond, 0.1209, ad4Electrostatic, 0.1406,
1381 ad4Desolvation, 0.1322, ad4GlueLinearAttraction, 50.0,
1382 ad4Rot, 0.2983
1383
1384 Vina (7 weights):
1385
1386 vinaGaussian1, -0.035579, vinaGaussian2, -0.005156,
1387 vinaRepulsion, 0.840245, vinaHydrophobic, -0.035069,
1388 vinaHydrogenBond, -0.587439, vinaGlueLinearAttraction, 50.0,
1389 vinaRot, 0.05846
1390
1391 Vinardo (6 weights):
1392
1393 vinardoGaussian1, -0.045, vinardoRepulsion, 0.8,
1394 vinardoHydrophobic, -0.035, vinardoHydrogenBond, -0.600
1395 vinardoGlueLinearAttraction, 50.0, vinardoRot, 0.05846
1396
1397 The glue weight parameter corresponds to linear attraction for macrocycle
1398 closure and has the same value for AD4, Vina, and Vinardo. The rot weight
1399 has the same value for Vina and Vinardo.
1400 -g, --gridCenter <RefLigandFile or x,y,z>
1401 Reference ligand file for calculating the docking grid center or a triplet
1402 of comma delimited values in Angstrom corresponding to grid center.
1403
1404 This is required option. However, it is ignored during the specification
1405 of maps prefix for '-r, --receptor' option.
1406 --gridSize <xsize,ysize,zsize> [default: 25.0, 25.0, 25.0]
1407 Docking grid size in Angstrom.
1408 --gridSpacing <number> [default: 0.375]
1409 Docking grid spacing in Angstrom.
1410 -h, --help
1411 Print this help message.
1412 -i, --infile <infile>
1413 Input file name containing molecules for docking against a receptor. The
1414 molecules must have 3D coordinates in input file. In addition, the hydrogens
1415 must be present for all molecules in input file. The input file may contain 3D
1416 conformers.
1417 --infileParams <Name,Value,...> [default: auto]
1418 A comma delimited list of parameter name and value pairs for reading
1419 molecules from files. The supported parameter names for different file
1420 formats, along with their default values, are shown below:
1421
1422 SD, MOL: removeHydrogens,no,sanitize,yes,strictParsing,yes
1423
1424 --maxEvaluations <number> [default: 0]
1425 Maximum number of evaluations to perform for each MC run during docking.
1426 By default, its value is set 0 and the number of MC evaluations is determined
1427 using heuristic rules.
1428 --mergeHydrogens <yes or no> [default: auto]
1429 Merge hydrogens during preparation of molecules for docking. The hydrogens
1430 are automatically merged during 'AD4' value of '-f, --forcefield' option and its
1431 value is set to 'yes'. Otherwise, it's set to 'no'.
1432 --minRMSD <number> [default: 1.0]
1433 Minimum RMSD between output poses in Angstrom.
1434 -m, --mode <Dock, LocalOptimizationOnly, ScoreOnly> [default: Dock]
1435 Dock molecules or simply score molecules without performing any docking.
1436 The supported values along with a brief explanation of the expected
1437 behavior are shown below:
1438
1439 Dock: Global search along with local optimization and scoring after
1440 docking
1441 LocalOptimizationOnly: Local optimization and scoring without any docking
1442 ScoreOnly: Scoring without any local optimizatiom and docking
1443
1444 The 'ScoreOnly" allows you to score 3D moleculed from input file which
1445 are already positioned in a binding pocket of a receptor.
1446 --mp <yes or no> [default: no]
1447 Use multiprocessing.
1448
1449 By default, input data is retrieved in a lazy manner via mp.Pool.imap()
1450 function employing lazy RDKit data iterable. This allows processing of
1451 arbitrary large data sets without any additional requirements memory.
1452
1453 All input data may be optionally loaded into memory by mp.Pool.map()
1454 before starting worker processes in a process pool by setting the value
1455 of 'inputDataMode' to 'InMemory' in '--mpParams' option.
1456
1457 A word to the wise: The default 'chunkSize' value of 1 during 'Lazy' input
1458 data mode may adversely impact the performance. The '--mpParams' section
1459 provides additional information to tune the value of 'chunkSize'.
1460 --mpParams <Name,Value,...> [default: auto]
1461 A comma delimited list of parameter name and value pairs to configure
1462 multiprocessing.
1463
1464 The supported parameter names along with their default and possible
1465 values are shown below:
1466
1467 chunkSize, auto
1468 inputDataMode, Lazy [ Possible values: InMemory or Lazy ]
1469 numProcesses, auto [ Default: mp.cpu_count() ]
1470
1471 These parameters are used by the following functions to configure and
1472 control the behavior of multiprocessing: mp.Pool(), mp.Pool.map(), and
1473 mp.Pool.imap().
1474
1475 The chunkSize determines chunks of input data passed to each worker
1476 process in a process pool by mp.Pool.map() and mp.Pool.imap() functions.
1477 The default value of chunkSize is dependent on the value of 'inputDataMode'.
1478
1479 The mp.Pool.map() function, invoked during 'InMemory' input data mode,
1480 automatically converts RDKit data iterable into a list, loads all data into
1481 memory, and calculates the default chunkSize using the following method
1482 as shown in its code:
1483
1484 chunkSize, extra = divmod(len(dataIterable), len(numProcesses) * 4)
1485 if extra: chunkSize += 1
1486
1487 For example, the default chunkSize will be 7 for a pool of 4 worker processes
1488 and 100 data items.
1489
1490 The mp.Pool.imap() function, invoked during 'Lazy' input data mode, employs
1491 'lazy' RDKit data iterable to retrieve data as needed, without loading all the
1492 data into memory. Consequently, the size of input data is not known a priori.
1493 It's not possible to estimate an optimal value for the chunkSize. The default
1494 chunkSize is set to 1.
1495
1496 The default value for the chunkSize during 'Lazy' data mode may adversely
1497 impact the performance due to the overhead associated with exchanging
1498 small chunks of data. It is generally a good idea to explicitly set chunkSize to
1499 a larger value during 'Lazy' input data mode, based on the size of your input
1500 data and number of processes in the process pool.
1501
1502 The mp.Pool.map() function waits for all worker processes to process all
1503 the data and return the results. The mp.Pool.imap() function, however,
1504 returns the the results obtained from worker processes as soon as the
1505 results become available for specified chunks of data.
1506
1507 The order of data in the results returned by both mp.Pool.map() and
1508 mp.Pool.imap() functions always corresponds to the input data.
1509 -n, --numPoses <number> [default: 1]
1510 Number of docked poses to generate for each molecule and write out
1511 to output file. This option is only valid for 'Dock' value of '-m, --mode'
1512 option.
1513 --numThreads <number> [default: auto]
1514 Number of threads/CPUs to use for MC search calculation in Vina. The
1515 default value is set to 1 during multiprocessing for 'Yes' value of '--mp'
1516 option. Otherwise, it's set to 0 and rely on Vina detect and use all
1517 available CPUs for multi-threading.
1518 -o, --outfile <outfile>
1519 Output file name for writing out molecules. The flexible receptor residues
1520 are written to <OutfileRoot>_Flex_Receptor.<OutfileExt>.
1521 --outfileParams <Name,Value,...> [default: auto]
1522 A comma delimited list of parameter name and value pairs for writing
1523 molecules to files. The supported parameter names for different file
1524 formats, along with their default values, are shown below:
1525
1526 SD: kekulize,yes,forceV3000,no
1527
1528 --overwrite
1529 Overwrite existing files.
1530 --precision <number> [default: 2]
1531 Floating point precision for writing energy values.
1532 -q, --quiet <yes or no> [default: no]
1533 Use quiet mode. The warning and information messages will not be printed.
1534 --randomSeed <number> [default: 0]
1535 Random seed for MC search calculations. A value of zero implies it's randomly
1536 chosen by Vina during the calculation.
1537 -r, --receptor <receptor file or maps prerfix>
1538 Protein receptor file name or prefix for affinity map files corresponding
1539 to the fixed portion of the receptor.
1540
1541 You must specify affinity map files for 'AD4' forcefield. The affinity map
1542 files correspond to <MapsPrefix>.*.map and must be present
1543
1544 The supported receptor file format is PDBQT (.pdbqt). It must contain a
1545 prepared protein receptor ready for docking. You may prepare a PDBQT
1546 receptor file from a PDB file employing the command line scripts available
1547 with AutoDock Vina and Meeko. For example: prepare_receptor,
1548 prepare_flexreceptor.py, or or mk_make_recepror.py.
1549
1550 You may want to perform the following steps to clean up your PDB file
1551 before generating a PDBQT receptor file: Remove extraneous molecules
1552 such as solvents, ions, and ligand etc.; Extract data for a chain containing
1553 the binding pocket of interest.
1554 --receptorFlexFile <receptor flex file> [default: none]
1555 Protein receptor file name corresponding to the flexible portion of the
1556 receptor. The supported receptor file format is PDBQT (.pdbqt). It must
1557 contain a prepared protein receptor ready for docking. You may prepare
1558 a flexible PDBQT receptor file from a PDB file employing the command line
1559 script prepare_flexreceptor or mk_make_recepror.py available with Autodock
1560 Vina and Meeko.
1561 --skipRefinement <yes or no> [default: no]
1562 Skip refinement. Vina is initialized to skip the use of explicit receptor atoms,
1563 instead of precalculated grids, during the following three docking modes:
1564 Dock, LocalOptimizationOnly, and ScoreOnly.
1565 -v, --validateMolecules <yes or no> [default: yes]
1566 Validate molecules for docking. The input molecules must have 3D coordinates
1567 and the hydrogens must be present. You may skip validation of molecules in
1568 input file containing all valid molecules.
1569 --vinaVerbosity <number> [default: auto]
1570 Verbosity level for running Vina. Possible values: 0 - No output; 1 - Normal
1571 output; 2 - Verbose. Default: 0 during multiprocessing for 'Yes' value of '--mp'
1572 option; otherwise, its set to 1. A non-zero value is not recommended during
1573 multiprocessing. It doesn't work due to the mingling of the Vina output
1574 from multiple processes.
1575 -w, --workingdir <dir>
1576 Location of working directory which defaults to the current directory.
1577
1578 Examples:
1579 To dock molecules using Vina forcefield against a prepared receptor
1580 corresponding to chain A extracted from PDB file 1R4L.pdb, multi-threading
1581 across all available CPUs during Vina MC search, calculating grid center form
1582 a reference ligand file, using grid box size of 25 Angstrom, generating one
1583 pose for each molecule, and write out a SD file containing docked molecules,
1584 type:
1585
1586 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1587 -r SampleACE2Receptor.pdbqt -i SampleACE2Ligands.sdf
1588 -o SampleACE2LigandsOut.sdf
1589
1590 To run the first example for generating multiple docked poses for each
1591 molecule and write out all energy terms to a SD file, type:
1592
1593 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1594 -r SampleACE2Receptor.pdbqt --numPoses 5 --energyComponents yes
1595 -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1596
1597 To run the first example for docking molecules using Vinardo forcefield and write
1598 out a SD file, type:
1599
1600 % VinaPerformDocking.py -f Vinardo -g SampleACE2RefLigand.pdb
1601 -r SampleACE2Receptor.pdbqt -i SampleACE2Ligands.sdf
1602 -o SampleACE2LigandsOut.sdf
1603
1604 To run the first example for docking molecules using AD4 forcefield relying on
1605 the presence of affinity maps in the working directory and write out a SD file,
1606 type:
1607
1608 % VinaPerformDocking.py -f AD4 -g SampleACE2RefLigand.pdb
1609 -r SampleACE2Receptor -i SampleACE2Ligands.sdf
1610 -o SampleACE2LigandsOut.sdf
1611
1612 To run the first example for docking molecules using a set of explicit values
1613 for grid dimensions and write out a SD file, type:
1614
1615 % VinaPerformDocking.py -g "41.399, 5.851, 28.082"
1616 --gridSize "25.0, 25.0, 25.0" --gridSpacing 0.375
1617 -r SampleACE2Receptor.pdbqt -i SampleACE2Ligands.sdf
1618 -o SampleACE2LigandsOut.sdf
1619
1620 To run the first example for only scoring molecules already positioned in the
1621 binding pocket and write out a SD file, type:
1622
1623 % VinaPerformDocking.py -m ScoreOnly -g SampleACE2RefLigand.sdf
1624 -r SampleACE2Receptor.pdbqt -i SampleACE2RefLigandWithHs.sdf
1625 -o SampleACE2LigandsOut.sdf
1626
1627 To run the first example for docking molecules to increase the accuracy of
1628 pose predictions and write out a SD file, type:
1629
1630 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1631 -r SampleACE2Receptor.pdbqt --exhaustiveness 24
1632 -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1633
1634 To run the first example in multiprocessing mode on all available CPUs
1635 without loading all data into memory, a single thread for Vina docking, and
1636 write out a SD file, type:
1637
1638 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1639 -r SampleACE2Receptor.pdbqt --mp yes
1640 -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1641
1642 To run the first example in multiprocessing mode on all available CPUs
1643 by loading all data into memory, a single thread for Vina, and write out
1644 a SD file, type:
1645
1646 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1647 -r SampleACE2Receptor.pdbqt --mp yes --mpParams "inputDataMode,
1648 InMemory" -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1649
1650 To run the first example in multiprocessing mode on specific number of CPUs
1651 and chunk size without loading all data into memory along with a specific number
1652 of threads for Vina docking and write out a SD file, type:
1653
1654 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1655 -r SampleACE2Receptor.pdbqt --mp yes --mpParams "inputDataMode,lazy,
1656 numProcesses,4,chunkSize,2" --numThreads 2
1657 -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1658
1659 To run the first example for docking molecules employing a flexible portion
1660 of the receptor corresponding to ARG273 and write out a SD file, type:
1661
1662 % VinaPerformDocking.py -g SampleACE2RefLigand.pdb
1663 -r SampleACE2RigidReceptor.pdbqt
1664 --receptorFlexFile SampleACE2FlexReceptor.pdbqt
1665 -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1666
1667 To run the first example for docking molecules using specified parameters and
1668 write out a SD file, type:
1669
1670 % VinaPerformDocking.py -g "41.399, 5.851, 28.082"
1671 --gridSize "25.0, 25.0, 25.0" --gridSpacing 0.375 --energyComponents
1672 yes --exhaustiveness 32 --forcefield Vina --mode dock --numPoses 2
1673 --numThreads 4 --randomSeed 42 --validateMolecules no
1674 --vinaVerbosity 0 -r SampleACE2Receptor.pdbqt
1675 -i SampleACE2Ligands.sdf -o SampleACE2LigandsOut.sdf
1676
1677 Author:
1678 Manish Sud(msud@san.rr.com)
1679
1680 Acknowledgments:
1681 Diogo Santos-Martins and Stefano Forli
1682
1683 See also:
1684 PyMOLConvertLigandFileFormat.py, PyMOLExtractSelection.py,
1685 PyMOLInfoMacromolecules.py, PyMOLVisualizeMacromolecules.py,
1686 RDKitConvertFileFormat.py, RDKitEnumerateTautomers.py,
1687 RDKitGenerateConformers.py, RDKitPerformMinimization.py,
1688 RDKitPerformConstrainedMinimization.py
1689
1690 Copyright:
1691 Copyright (C) 2026 Manish Sud. All rights reserved.
1692
1693 The functionality available in this script is implemented using AutoDockVina
1694 and Meeko, open source software packages for docking, and RDKit, an open
1695 source toolkit for cheminformatics developed by Greg Landrum.
1696
1697 This file is part of MayaChemTools.
1698
1699 MayaChemTools is free software; you can redistribute it and/or modify it under
1700 the terms of the GNU Lesser General Public License as published by the Free
1701 Software Foundation; either version 3 of the License, or (at your option) any
1702 later version.
1703
1704 """
1705
1706 if __name__ == "__main__":
1707 main()