Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

foldx Buildmodel mutation interfact - convenience interface #374

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 47 additions & 34 deletions src/biotite/application/autodock/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@ class VinaApp(LocalApp):
... )
"""
def __init__(self, ligand, receptor, center, size, flexible=None,
bin_path="vina"):
bin_path="vina", custom_ligand_loc = None):
super().__init__(bin_path)

if ligand.bonds is None:
raise ValueError("The ligand has no associated BondList")
if receptor.bonds is None:
raise ValueError("The receptor has no associated BondList")

self._custom_ligand_loc = custom_ligand_loc
self._ligand = ligand.copy()
self._receptor = receptor.copy()
self._center = copy.deepcopy(center)
Expand All @@ -86,7 +87,7 @@ def __init__(self, ligand, receptor, center, size, flexible=None,
self._flex_res_starts = np.unique(get_residue_starts_for(
receptor, flexible_indices
))

self._ligand_file = NamedTemporaryFile(
"w", suffix=".pdbqt", delete=False
)
Expand All @@ -99,7 +100,7 @@ def __init__(self, ligand, receptor, center, size, flexible=None,
self._out_file = NamedTemporaryFile(
"r", suffix=".pdbqt", delete=False
)

@requires_state(AppState.CREATED)
def set_seed(self, seed):
"""
Expand All @@ -114,7 +115,7 @@ def set_seed(self, seed):
The seed for the random number generator.
"""
self._seed = seed

@requires_state(AppState.CREATED)
def set_exhaustiveness(self, exhaustiveness):
"""
Expand All @@ -131,7 +132,7 @@ def set_exhaustiveness(self, exhaustiveness):
Must be greater than 0.
"""
self._exhaustiveness = exhaustiveness

@requires_state(AppState.CREATED)
def set_max_number_of_models(self, number):
"""
Expand All @@ -147,7 +148,7 @@ def set_max_number_of_models(self, number):
The maximum number of generated modes/models.
"""
self._number = number

@requires_state(AppState.CREATED)
def set_energy_range(self, energy_range):
"""
Expand Down Expand Up @@ -178,20 +179,20 @@ def run(self):
))

ligand_file = PDBQTFile()
# Contains 'true' entries for all atoms that have not been
# Contains 'true' entries for all atoms that have not been
# removed from ligand
self._ligand_mask = ligand_file.set_structure(
self._ligand,
rotatable_bonds="all"
)
ligand_file.write(self._ligand_file)
self._ligand_file.flush()

if self._is_flexible:
self._rigid_mask = np.ones(
self._receptor.array_length(), dtype=bool
)
# Contains 'true' entries for all atoms that have not been
# Contains 'true' entries for all atoms that have not been
# removed from receptor in flexible side chains
self._receptor_mask = np.zeros(
self._receptor.array_length(), dtype=bool
Expand Down Expand Up @@ -234,18 +235,30 @@ def run(self):
)
receptor_file.write(self._receptor_file)
self._receptor_file.flush()

arguments = [
"--ligand", self._ligand_file.name,
"--receptor", self._receptor_file.name,
"--out", self._out_file.name,
"--center_x", f"{self._center[0]:.3f}",
"--center_y", f"{self._center[1]:.3f}",
"--center_z", f"{self._center[2]:.3f}",
"--size_x", f"{self._size[0]:.3f}",
"--size_y", f"{self._size[1]:.3f}",
"--size_z", f"{self._size[2]:.3f}",
]
if self._custom_ligand_loc is None:
arguments = [
"--ligand", self._ligand_file.name,
"--receptor", self._receptor_file.name,
"--out", self._out_file.name,
"--center_x", f"{self._center[0]:.3f}",
"--center_y", f"{self._center[1]:.3f}",
"--center_z", f"{self._center[2]:.3f}",
"--size_x", f"{self._size[0]:.3f}",
"--size_y", f"{self._size[1]:.3f}",
"--size_z", f"{self._size[2]:.3f}",
]
else:
arguments = [
"--ligand", self._custom_ligand_loc,
"--receptor", self._receptor_file.name,
"--out", self._out_file.name,
"--center_x", f"{self._center[0]:.3f}",
"--center_y", f"{self._center[1]:.3f}",
"--center_z", f"{self._center[2]:.3f}",
"--size_x", f"{self._size[0]:.3f}",
"--size_y", f"{self._size[1]:.3f}",
"--size_z", f"{self._size[2]:.3f}",
]
if self._seed is not None:
arguments.extend(["--seed", str(self._seed)])
if self._exhaustiveness is not None:
Expand All @@ -259,32 +272,32 @@ def run(self):

self.set_arguments(arguments)
super().run()

def evaluate(self):
super().evaluate()
out_file = PDBQTFile.read(self._out_file)

models = out_file.get_structure()

n_ligand_atoms = np.count_nonzero(self._ligand_mask)
self._ligand_models = models[..., :n_ligand_atoms]
self._flex_models = models[..., n_ligand_atoms:]
self._n_models = models.stack_depth()

remarks = out_file.get_remarks()
self._energies = np.array(
# VINA RESULT: -5.8 0.000 0.000
# ^
[float(remark[12:].split()[0]) for remark in remarks]
)

def clean_up(self):
super().clean_up()
cleanup_tempfile(self._ligand_file)
cleanup_tempfile(self._receptor_file)
cleanup_tempfile(self._receptor_flex_file)
cleanup_tempfile(self._out_file)

@requires_state(AppState.JOINED)
def get_energies(self):
"""
Expand All @@ -302,7 +315,7 @@ def get_energies(self):
@requires_state(AppState.JOINED)
def get_ligand_models(self):
"""
Get the ligand structure with the conformations for each
Get the ligand structure with the conformations for each
generated binding mode.

Returns
Expand All @@ -312,7 +325,7 @@ def get_ligand_models(self):
Each model corresponds to one binding mode.
The models are sorted from best to worst predicted binding
affinity.

Notes
-----
The returned structure may contain less atoms than the input
Expand Down Expand Up @@ -343,7 +356,7 @@ def get_ligand_coord(self):
)
coord[:, self._ligand_mask] = self._ligand_models.coord
return coord

@requires_state(AppState.JOINED)
def get_flexible_residue_models(self):
"""
Expand All @@ -360,7 +373,7 @@ def get_flexible_residue_models(self):
Each model corresponds to one binding mode.
The models are sorted from best to worst predicted binding
affinity.

Notes
-----
The returned structure may contain less atoms than the input
Expand All @@ -385,7 +398,7 @@ def get_receptor_coord(self):
affinity.
Missing coordinates due to the removed nonpolar hydrogen
atoms from flexible side chains are set to *NaN*.

Notes
-----
The output is only meaningful, if flexible side chains were
Expand Down Expand Up @@ -433,7 +446,7 @@ def _get_flexible_residue(self, residue_start):
flex_mask = np.zeros(self._receptor.array_length(), dtype=bool)
rigid_mask = np.ones(self._receptor.array_length(), dtype=bool)
return flex_mask, rigid_mask, root_index

# Remove the root bond from the bond list
# to find the atoms involved in the flexible part
bonds = self._receptor.bonds.copy()
Expand All @@ -442,7 +455,7 @@ def _get_flexible_residue(self, residue_start):
if root_index in flexible_indices:
raise BadStructureError(
"There are multiple connections between the flexible and "
"rigid part, maybe a cyclic residue like proline was selected"
"rigid part, maybe a cyclic residue like proline was selected"
)

flex_mask = np.zeros(self._receptor.array_length(), dtype=bool)
Expand All @@ -452,7 +465,7 @@ def _get_flexible_residue(self, residue_start):
flex_mask[root_index] = True

return flex_mask, rigid_mask, root_index


@staticmethod
def dock(ligand, receptor, center, size, flexible=None, bin_path="vina"):
Expand Down
12 changes: 12 additions & 0 deletions src/biotite/application/foldx/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This source code is part of the Biotite package and is distributed
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
# information.

"""
A subpackage for static ligand docking with *FoldX*.
"""

__name__ = "biotite.application.foldX"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__name__ = "biotite.application.foldX"
__name__ = "biotite.application.foldx"

__author__ = "Mojmir Mutny"

from .app import *
Loading