Skip to content

Commit 2822051

Browse files
committed
Testing new protocol for restraints
1 parent bdf1030 commit 2822051

File tree

7 files changed

+207
-22
lines changed

7 files changed

+207
-22
lines changed

bin/post/lgd_filter_membrane.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/env python
2+
3+
"""Filter LightDock final swarm results depending on the compatibility with the membrane"""
4+
5+
from __future__ import print_function
6+
import sys
7+
import os
8+
import argparse
9+
import shutil
10+
import re
11+
from prody.measure.contacts import Contacts
12+
from prody import parsePDB, confProDy
13+
from lightdock.util.logger import LoggingManager
14+
from lightdock.util.analysis import read_ranking_file
15+
from lightdock.pdbutil.PDBIO import parse_complex_from_file
16+
from lightdock.structure.complex import Complex
17+
18+
19+
# Disable ProDy output
20+
confProDy(verbosity='info')
21+
filtered_folder = 'filtered'
22+
23+
log = LoggingManager.get_logger('lgd_filter_membrane')
24+
25+
26+
def get_structures(ranking, base_path='.'):
27+
structures = []
28+
for rank in ranking:
29+
swarm_id = rank.id_cluster
30+
glowworm_id = rank.id_glowworm
31+
structures.append(os.path.join(base_path,
32+
'swarm_{}'.format(swarm_id),
33+
'lightdock_{}.pdb'.format(glowworm_id)))
34+
return structures
35+
36+
37+
def get_restraints(restraints_file):
38+
restraints_receptor = set()
39+
restraints_ligand = set()
40+
with open(restraints_file) as handle:
41+
for line in handle:
42+
line = line.rstrip(os.linesep)
43+
if line:
44+
if line.startswith('R'):
45+
restraints_receptor.add(line.split()[-1])
46+
if line.startswith('L'):
47+
restraints_ligand.add(line.split()[-1])
48+
return restraints_receptor, restraints_ligand
49+
50+
51+
def calculate_membrane_height(parsed_receptor_file, restraints):
52+
atoms, residues, chains = parse_complex_from_file(parsed_receptor_file)
53+
receptor = Complex(chains, atoms)
54+
z_coord = []
55+
for restraint in restraints:
56+
chain_id, residue_name, residue_number = restraint.split(".")
57+
residue = receptor.get_residue(chain_id, residue_name, residue_number)
58+
ca = residue.get_calpha()
59+
z_coord.append(ca.z)
60+
return min(z_coord)
61+
62+
63+
def parse_command_line():
64+
"""Parses command line arguments"""
65+
parser = argparse.ArgumentParser(prog='lgd_filter_restraints')
66+
67+
parser.add_argument("ranking_file", help="Path of ranking to be used", metavar="ranking_file")
68+
parser.add_argument("restraints_file", help="File including restraints", metavar="restraints_file")
69+
parser.add_argument("parsed_receptor_file", help="Receptor PDB parsed by LightDock", metavar="parsed_receptor_file")
70+
parser.add_argument("receptor_chains", help="Chains on the receptor partner", metavar="receptor_chains")
71+
parser.add_argument("ligand_chains", help="Chains on the receptor partner", metavar="ligand_chains")
72+
parser.add_argument("--cutoff", "-cutoff", "-c", help="Interaction cutoff",
73+
dest="cutoff", type=float, default=1.0)
74+
75+
return parser.parse_args()
76+
77+
78+
if __name__ == '__main__':
79+
80+
# Parse command line
81+
args = parse_command_line()
82+
83+
log.info("Cutoff for membrane is {:3.1f}A".format(args.cutoff))
84+
85+
# Get ranking
86+
ranking = read_ranking_file(args.ranking_file)
87+
88+
# Get all the PDB structures in a given directory
89+
base_path = os.path.abspath(os.path.dirname(args.ranking_file))
90+
structures = get_structures(ranking, base_path)
91+
92+
restraints_receptor, restraints_ligand = get_restraints(args.restraints_file)
93+
94+
membrane_height_z = calculate_membrane_height(args.parsed_receptor_file, restraints_receptor)
95+
96+
if os.path.exists(filtered_folder):
97+
raise SystemExit("Folder {} already exists".format(filtered_folder))
98+
else:
99+
os.makedirs(filtered_folder)
100+
101+
filter_passed = {}
102+
percentages = {}
103+
for pdb_file in structures:
104+
try:
105+
swarm_id = int(re.findall(r'swarm_\d+', pdb_file)[0].split('_')[-1])
106+
glowworm_id = int(re.findall(r'lightdock_\d+', pdb_file)[0].split('_')[-1])
107+
108+
# Read molecule and split by receptor and ligand
109+
molecule = parsePDB(pdb_file)
110+
ca_ligand = molecule.select('protein and chain {} and calpha'.format(args.ligand_chains))
111+
112+
# Contacts on ligand side
113+
out = 0
114+
for ca in ca_ligand:
115+
coord = ca.getCoords()
116+
if coord[-1] >= membrane_height_z:
117+
out += 1
118+
perc = out / float(len(ca_ligand))
119+
120+
if perc >= args.cutoff:
121+
percentages[(swarm_id, glowworm_id)] = perc
122+
shutil.copyfile(pdb_file, os.path.join(filtered_folder, 'swarm_{}_{}.pdb'.format(swarm_id, glowworm_id)))
123+
try:
124+
filter_passed[swarm_id].append(glowworm_id)
125+
except:
126+
filter_passed[swarm_id] = [glowworm_id]
127+
print("{:40s} {:5.3f}".format(pdb_file, perc))
128+
129+
except Exception, e:
130+
log.error('Filtering has failed for structure {}. Please see error:'.format(pdb_file))
131+
log.error(str(e))
132+
133+
134+
filtered_ranking = os.path.join(filtered_folder, 'rank_filtered.list')
135+
with open(filtered_ranking, 'w') as handle:
136+
for rank in ranking:
137+
if rank.id_cluster in filter_passed and rank.id_glowworm in filter_passed[rank.id_cluster]:
138+
handle.write('swarm_{}_{}.pdb {:5.3f} {:5.3f}'.format(rank.id_cluster,
139+
rank.id_glowworm, rank.scoring, percentages[(rank.id_cluster, rank.id_glowworm)]) + os.linesep)

bin/simulation/lightdock_setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
receptor_restraints, ligand_restraints,
9090
rec_translation, lig_translation,
9191
args.ftdock_file, args.use_anm, args.anm_seed,
92-
args.anm_rec, args.anm_lig)
92+
args.anm_rec, args.anm_lig, args.membrane)
9393
if len(starting_points_files) != args.swarms:
9494
args.swarms = len(starting_points_files)
9595
log.info('Number of swarms is %d after applying restraints' % args.swarms)

lightdock/prep/poses.py

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import operator
5+
import numpy as np
56
from lightdock.pdbutil.PDBIO import create_pdb_from_points
67
from lightdock.prep.starting_points import calculate_surface_points
78
from lightdock.prep.ftdock import FTDockCoordinatesParser, classify_ftdock_poses
@@ -24,16 +25,40 @@ def get_random_point_within_sphere(number_generator, radius):
2425
if x**2 + y**2 + z**2 <= r2:
2526
return x, y, z
2627

28+
def get_quaternion_for_restraint(rec_residue, lig_residue, cx, cy, cz):
29+
"""Calculates the quaternion required for orienting the ligand towards the restraint"""
30+
r_ca = rec_residue.get_calpha()
31+
l_ca = lig_residue.get_calpha()
32+
a = np.array([r_ca.x, r_ca.y, r_ca.z])
33+
b = np.array([l_ca.x-cx, l_ca.y-cy, l_ca.z-cz])
34+
c = np.cross(a, b)
35+
d = np.dot(a, b)
2736

28-
def populate_poses(to_generate, center, radius, number_generator, rng_nm=None, rec_nm=0, lig_nm=0):
37+
s = np.sqrt( (1+d)*2 )
38+
invs = 1. / s
39+
x = c[0] * invs
40+
y = c[1] * invs
41+
z = c[2] * invs
42+
w = s * 0.5
43+
44+
return Quaternion(w=w, x=x, y=y, z=z).normalize()
45+
46+
47+
def populate_poses(to_generate, center, radius, number_generator, rng_nm=None, rec_nm=0, lig_nm=0,
48+
receptor_restraints=None, ligand_restraints=None):
2949
"""Creates new poses around a given center and a given radius"""
3050
new_poses = []
3151
for _ in xrange(to_generate):
3252
x, y, z = get_random_point_within_sphere(number_generator, radius)
3353
tx = center[0] + x
3454
ty = center[1] + y
3555
tz = center[2] + z
36-
q = Quaternion.random(number_generator)
56+
if receptor_restraints and ligand_restraints:
57+
rec_residue = receptor_restraints[number_generator.randint(0, len(receptor_restraints)-1)]
58+
lig_residue = ligand_restraints[number_generator.randint(0, len(ligand_restraints)-1)]
59+
q = get_quaternion_for_restraint(rec_residue, lig_residue, center[0], center[1], center[2])
60+
else:
61+
q = Quaternion.random(number_generator)
3762
op_vector = [tx, ty, tz, q.w, q.x, q.y, q.z]
3863
if rng_nm:
3964
if rec_nm > 0:
@@ -53,7 +78,8 @@ def create_file_from_poses(pos_file_name, poses):
5378
positions_file.close()
5479

5580

56-
def apply_restraints(swarm_centers, receptor_restraints, distance_cutoff, translation, swarms_per_restraint=10):
81+
def apply_restraints(swarm_centers, receptor_restraints, distance_cutoff, translation,
82+
is_membrane=False, swarms_per_restraint=10):
5783

5884
closer_swarms = []
5985
for i, residue in enumerate(receptor_restraints):
@@ -72,14 +98,25 @@ def apply_restraints(swarm_centers, receptor_restraints, distance_cutoff, transl
7298
if swarms_considered == swarms_per_restraint:
7399
break
74100
closer_swarms = list(set(closer_swarms))
75-
return closer_swarms
101+
if is_membrane:
102+
# Requieres the receptor to be aligned in the Z axis with the membrane
103+
min_z = min([residue.get_calpha().z for residue in receptor_restraints]) + translation[2]
104+
compatible = []
105+
for swarm_id, center in enumerate(swarm_centers):
106+
if swarm_id in closer_swarms:
107+
if center[2] >= min_z:
108+
compatible.append(swarm_id)
109+
return compatible
110+
else:
111+
return closer_swarms
76112

77113

78114
def calculate_initial_poses(receptor, ligand, num_clusters, num_glowworms,
79115
seed, receptor_restraints, ligand_restraints,
80116
rec_translation, lig_translation,
81-
dest_folder, ftdock_file='', nm_mode=False, nm_seed=0, rec_nm=0, lig_nm=0):
82-
"""Calculates the starting points for each of the glowworms using the center of clusters
117+
dest_folder, ftdock_file='', nm_mode=False, nm_seed=0, rec_nm=0, lig_nm=0,
118+
is_membrane=False):
119+
"""Calculates the starting points for each of the glowworms using the center of swarms
83120
and FTDock poses.
84121
"""
85122
# Random number generator for poses
@@ -91,18 +128,19 @@ def calculate_initial_poses(receptor, ligand, num_clusters, num_glowworms,
91128
else:
92129
rng_nm = None
93130

94-
# Calculate cluster centers
95-
cluster_centers, receptor_diameter, ligand_diameter = calculate_surface_points(receptor,
131+
# Calculate swarm centers
132+
swarm_centers, receptor_diameter, ligand_diameter = calculate_surface_points(receptor,
96133
ligand,
97134
num_clusters,
98135
distance_step=1.0)
99136
# Filter cluster centers far from the restraints
100137
if receptor_restraints:
101-
filtered_swarms = apply_restraints(cluster_centers, receptor_restraints, ligand_diameter / 2., rec_translation)
102-
cluster_centers = [cluster_centers[i] for i in filtered_swarms]
138+
filtered_swarms = apply_restraints(swarm_centers, receptor_restraints, ligand_diameter / 2.,
139+
rec_translation, is_membrane=is_membrane)
140+
swarm_centers = [swarm_centers[i] for i in filtered_swarms]
103141

104142
pdb_file_name = os.path.join(dest_folder, CLUSTERS_CENTERS_FILE)
105-
create_pdb_from_points(pdb_file_name, cluster_centers)
143+
create_pdb_from_points(pdb_file_name, swarm_centers)
106144

107145
ligand_center = ligand.center_of_coordinates()
108146
radius = 10. # ligand_diameter / 2.
@@ -114,7 +152,7 @@ def calculate_initial_poses(receptor, ligand, num_clusters, num_glowworms,
114152
raise NotImplementedError('Using FTDock poses with NM is not supported')
115153

116154
poses = FTDockCoordinatesParser.get_list_of_poses(ftdock_file, ligand_center)
117-
clusters = classify_ftdock_poses(poses, cluster_centers, radius)
155+
clusters = classify_ftdock_poses(poses, swarm_centers, radius)
118156

119157
for cluster_id, ftdock_poses in clusters.iteritems():
120158
# Translate FTDock poses into lightdock poses
@@ -131,7 +169,7 @@ def calculate_initial_poses(receptor, ligand, num_clusters, num_glowworms,
131169
# Populate new poses if needed
132170
if len(poses) < num_glowworms:
133171
needed = num_glowworms - len(poses)
134-
poses.extend(populate_poses(needed, cluster_centers[cluster_id], radius, rng))
172+
poses.extend(populate_poses(needed, swarm_centers[cluster_id], radius, rng))
135173

136174
# Save poses as pdb file
137175
pdb_file_name = os.path.join(dest_folder, '%s_%s.pdb' % (DEFAULT_PDB_STARTING_PREFIX, cluster_id))
@@ -144,8 +182,9 @@ def calculate_initial_poses(receptor, ligand, num_clusters, num_glowworms,
144182
positions_files.append(pos_file_name)
145183
create_bild_file(bild_file_name, poses)
146184
else:
147-
for cluster_id, cluster_center in enumerate(cluster_centers):
148-
poses = populate_poses(num_glowworms, cluster_center, radius, rng, rng_nm, rec_nm, lig_nm)
185+
for cluster_id, cluster_center in enumerate(swarm_centers):
186+
poses = populate_poses(num_glowworms, cluster_center, radius, rng, rng_nm, rec_nm, lig_nm,
187+
receptor_restraints, ligand_restraints)
149188
# Save poses as pdb file
150189
pdb_file_name = os.path.join(dest_folder, '%s_%s.pdb' % (DEFAULT_PDB_STARTING_PREFIX, cluster_id))
151190
create_pdb_from_points(pdb_file_name, [[pose[0], pose[1], pose[2]] for pose in poses[:num_glowworms]])

lightdock/prep/simulation.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ def check_starting_file(file_name, glowworms, use_anm, anm_rec, anm_lig):
9494

9595
def calculate_starting_positions(receptor, ligand, swarms, glowworms, starting_points_seed,
9696
receptor_restraints, ligand_restraints, rec_translation, lig_translation, ftdock_file=None,
97-
use_anm=False, anm_seed=0, anm_rec=DEFAULT_NMODES_REC, anm_lig=DEFAULT_NMODES_LIG):
97+
use_anm=False, anm_seed=0, anm_rec=DEFAULT_NMODES_REC, anm_lig=DEFAULT_NMODES_LIG,
98+
is_membrane=False):
9899
"""Defines the starting positions of each glowworm in the simulation.
99100
100101
If the init_folder already exists, uses the starting positions from this folder.
@@ -110,7 +111,8 @@ def calculate_starting_positions(receptor, ligand, swarms, glowworms, starting_p
110111
rec_translation, lig_translation,
111112
init_folder,
112113
ftdock_file, use_anm,
113-
anm_seed, anm_rec, anm_lig)
114+
anm_seed, anm_rec, anm_lig,
115+
is_membrane)
114116
log.info("Generated %d positions files" % len(starting_points_files))
115117
else:
116118
if receptor_restraints:

lightdock/scoring/fastdfire/driver.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,11 @@ def __call__(self, receptor, receptor_coordinates, ligand, ligand_coordinates):
140140
energy, interface_receptor, interface_ligand = calculate_dfire(receptor, ligand,
141141
self.potential.dfire_energy,
142142
receptor_coordinates, ligand_coordinates)
143-
perc_receptor_restraints = ScoringFunction.restraints_satisfied(receptor.restraints, set(interface_receptor))
144-
perc_ligand_restraints = ScoringFunction.restraints_satisfied(ligand.restraints, set(interface_ligand))
145-
return energy + perc_receptor_restraints * energy + perc_ligand_restraints * energy
143+
# Code to consider contacts in the interface
144+
#perc_receptor_restraints = ScoringFunction.restraints_satisfied(receptor.restraints, set(interface_receptor))
145+
#perc_ligand_restraints = ScoringFunction.restraints_satisfied(ligand.restraints, set(interface_ligand))
146+
#return energy + perc_receptor_restraints * energy + perc_ligand_restraints * energy
147+
return energy
146148

147149
# Needed to dynamically load the scoring functions from command line
148150
DefinedScoringFunction = DFIRE

lightdock/util/parser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ def __init__(self):
101101
parser.add_argument("-rst", "--rst", help="Restraints file",
102102
dest="restraints", type=CommandLineParser.valid_file,
103103
metavar="restraints", default=None)
104+
# Membrane setup
105+
parser.add_argument("-membrane", "--membrane", help="Enables the extra filter for membrane restraints",
106+
dest="membrane", action='store_true', default=False)
104107

105108
self.args = parser.parse_args()
106109

lightdock/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Framework version"""
22

3-
CURRENT_VERSION = "0.5.3"
3+
CURRENT_VERSION = "0.5.4"

0 commit comments

Comments
 (0)