OpenStructure
Loading...
Searching...
No Matches
dockq.py
Go to the documentation of this file.
1import sys
2import os
3import subprocess
4import tempfile
5import shutil
6
7from ost import io
8from ost import mol
9
10def _Setup(mdl, ref, mdl_ch1, mdl_ch2, ref_ch1, ref_ch2):
11 """ Performs parameter checks and dumps files for DockQ
12
13 In case of dimeric interfaces the respective chains are selected from
14 mdl/trg, renamed to A/B and dumped to disk.
15
16 In case of interfaces with more chains involved, we simply select the
17 specified chains and do no renaming before dumping to disk.
18 """
19 if isinstance(mdl_ch1, str):
20 mdl_ch1 = [mdl_ch1]
21 if isinstance(mdl_ch2, str):
22 mdl_ch2 = [mdl_ch2]
23 if isinstance(ref_ch1, str):
24 ref_ch1 = [ref_ch1]
25 if isinstance(ref_ch2, str):
26 ref_ch2 = [ref_ch2]
27
28 if len(mdl_ch1) == 0:
29 raise RuntimeError("mdl_ch1 is empty")
30 if len(mdl_ch2) == 0:
31 raise RuntimeError("mdl_ch2 is empty")
32
33 if len(mdl_ch1) != len(ref_ch1):
34 raise RuntimeError("mdl_ch1/ref_ch1 inconsistent in size")
35 if len(mdl_ch2) != len(ref_ch2):
36 raise RuntimeError("mdl_ch2/ref_ch2 inconsistent in size")
37
38 for cname in mdl_ch1:
39 ch = mdl.FindChain(cname)
40 if not ch.IsValid():
41 raise RuntimeError(f"Chain {cname} specified in mdl_ch1 not "
42 f"present in mdl")
43
44 for cname in mdl_ch2:
45 ch = mdl.FindChain(cname)
46 if not ch.IsValid():
47 raise RuntimeError(f"Chain {cname} specified in mdl_ch2 not "
48 f"present in mdl")
49
50 for cname in ref_ch1:
51 ch = ref.FindChain(cname)
52 if not ch.IsValid():
53 raise RuntimeError(f"Chain {cname} specified in ref_ch1 not "
54 f"present in ref")
55
56 for cname in ref_ch2:
57 ch = ref.FindChain(cname)
58 if not ch.IsValid():
59 raise RuntimeError(f"Chain {cname} specified in ref_ch2 not "
60 f"present in ref")
61
62 mdl_to_dump = mdl.CreateFullView()
63 ref_to_dump = ref.CreateFullView()
64
65 if len(mdl_ch1) == 1 and len(mdl_ch2) == 1:
66 # Dimer processing of mdl => Create new entity only containing
67 # the two specified chains and rename them to A, B
68 mdl_to_dump = mol.CreateEntityFromView(mdl_to_dump, True)
69 tmp = mol.CreateEntity()
70 ed = tmp.EditXCS()
71 ch1 = mdl_to_dump.FindChain(mdl_ch1[0])
72 ed.InsertChain("A", ch1, deep=True)
73 ch2 = mdl_to_dump.FindChain(mdl_ch2[0])
74 ed.InsertChain("B", ch2, deep=True)
75 mdl_ch1 = ["A"]
76 mdl_ch2 = ["B"]
77 mdl_to_dump = tmp
78
79 # Same for ref
80 ref_to_dump = mol.CreateEntityFromView(ref_to_dump, True)
81 tmp = mol.CreateEntity()
82 ed = tmp.EditXCS()
83 ch1 = ref_to_dump.FindChain(ref_ch1[0])
84 ed.InsertChain("A", ch1, deep=True)
85 ch2 = ref_to_dump.FindChain(ref_ch2[0])
86 ed.InsertChain("B", ch2, deep=True)
87 ref_ch1 = ["A"]
88 ref_ch2 = ["B"]
89 ref_to_dump = tmp
90 else:
91 # Interface with more chains...
92 raise NotImplementedError("DockQ computations beyond two interacting "
93 "chains has not been properly tested...")
94
95 # first write structures to string, only create a tmpdir and the actual
96 # files if this succeeds
97 mdl_str = io.EntityToPDBStr(mdl_to_dump)
98 ref_str = io.EntityToPDBStr(ref_to_dump)
99
100 tmp_dir = tempfile.mkdtemp()
101 with open(os.path.join(tmp_dir, "mdl.pdb"), 'w') as fh:
102 fh.write(mdl_str)
103 with open(os.path.join(tmp_dir, "ref.pdb"), 'w') as fh:
104 fh.write(ref_str)
105
106 return (tmp_dir, mdl_ch1, mdl_ch2, ref_ch1, ref_ch2)
107
109 """ DockQ result object
110 """
111 def __init__(self, Fnat, Fnonnat, native_contacts, model_contacts, iRMS,
112 LRMS, DockQ):
113 self._Fnat = Fnat
114 self._Fnonnat = Fnonnat
115 self._native_contacts = native_contacts
116 self._model_contacts = model_contacts
117 self._iRMS = iRMS
118 self._LRMS = LRMS
119 self._DockQ = DockQ
120
121 @property
122 def Fnat(self):
123 """ DockQ - Fnat output
124
125 :type: :class:`float`
126 """
127 return self._Fnat
128
129 @property
130 def Fnonnat(self):
131 """ DockQ - Fnonnat output
132
133 :type: :class:`float`
134 """
135 return self._Fnonnat
136
137 @property
139 """ DockQ - number native contacts
140
141 :type: :class:`int`
142 """
143 return self._native_contacts
144
145 @property
146 def model_contacts(self):
147 """ DockQ - number model contacts
148
149 :type: :class:`int`
150 """
151 return self._model_contacts
152
153 @property
154 def iRMS(self):
155 """ DockQ - iRMS output
156
157 :type: :class:`float`
158 """
159 return self._iRMS
160
161 @property
162 def LRMS(self):
163 """ DockQ - LMRS output
164
165 :type: :class:`float`
166 """
167 return self._LRMS
168
169 @property
170 def DockQ(self):
171 """ DockQ - DockQ output
172
173 :type: :class:`float`
174 """
175 return self._DockQ
176
177 def JSONSummary(self):
178 """ Returns JSON serializable summary
179 """
180 return {"Fnat": self.FnatFnat,
181 "Fnonnat": self.FnonnatFnonnat,
182 "native_contacts": self.native_contactsnative_contacts,
183 "model_contacts": self.model_contactsmodel_contacts,
184 "iRMS": self.iRMSiRMS,
185 "LRMS": self.LRMSLRMS,
186 "DockQ": self.DockQ}
187
188 @staticmethod
189 def FromDockQOutput(output):
190 """ Static constructor from raw DockQ output
191
192 :param output: Raw output from DockQ executable
193 :type output: :class:`str`
194 :returns: Object of type :class:`DockQResult`
195 """
196 Fnat = None
197 Fnonnat = None
198 native_contacts = None
199 model_contacts = None
200 iRMS = None
201 LRMS = None
202 DockQ = None
203
204 for line in output.splitlines():
205 if line.startswith('*'):
206 continue
207 if line.startswith("Fnat"):
208 Fnat = float(line.split()[1])
209 native_contacts = int(line.split()[5])
210 elif line.startswith("Fnonnat"):
211 Fnonnat = float(line.split()[1])
212 model_contacts = int(line.split()[5])
213 elif line.startswith("iRMS"):
214 iRMS = float(line.split()[1])
215 elif line.startswith("LRMS"):
216 LRMS = float(line.split()[1])
217 elif line.startswith("DockQ"):
218 DockQ = float(line.split()[1])
219
220 return DockQResult(Fnat, Fnonnat, native_contacts, model_contacts,
221 iRMS, LRMS, DockQ)
222
223
224def DockQ(dockq_exec, mdl, ref, mdl_ch1, mdl_ch2, ref_ch1,
225 ref_ch2):
226 """ Computes DockQ for specified interface
227
228 DockQ is available from https://github.com/bjornwallner/DockQ -
229 For this binding to work, DockQ must be properly installed and its
230 dependencies must be available (numpy, Biopython).
231
232 :param dockq_exec: Path to DockQ.py script from DockQ repository
233 :type dockq_exec: :class:`str`
234 :param mdl: Model structure
235 :type mdl: :class:`ost.mol.EntityView`/:class:`ost.mol.EntityHandle`
236 :param ref: Reference structure, i.e. native structure
237 :type ref: :class:`ost.mol.EntityView`/:class:`ost.mol.EntityHandle`
238 :param mdl_ch1: Specifies chain(s) in model constituting first part of
239 interface
240 :type mdl_ch1: :class:`str`/:class:`list` of :class:`str`
241 :param mdl_ch2: Specifies chain(s) in model constituting second part of
242 interface
243 :type mdl_ch2: :class:`str`/:class:`list` of :class:`str`
244 :param ref_ch1: ref equivalent of mdl_ch1
245 :type ref_ch1: :class:`str`/:class:`list` of :class:`str`
246 :param ref_ch2: ref equivalent of mdl_ch2
247 :type ref_ch2: :class:`str`/:class:`list` of :class:`str`
248 :returns: Result object of type :class:`DockQResult`
249 """
250 if not os.path.exists(dockq_exec):
251 raise RuntimeError(f"DockQ executable ({dockq_exec}) does not exist")
252
253 tmp_dir, mdl_ch1, mdl_ch2, ref_ch1, ref_ch2 = \
254 _Setup(mdl, ref, mdl_ch1, mdl_ch2, ref_ch1, ref_ch2)
255
256 cmd = [sys.executable, dockq_exec, os.path.join(tmp_dir, "mdl.pdb"),
257 os.path.join(tmp_dir, "ref.pdb")]
258
259 # add mdl/ref chains
260 cmd.append("-model_chain1")
261 cmd += mdl_ch1
262 cmd.append("-model_chain2")
263 cmd += mdl_ch2
264 cmd.append("-native_chain1")
265 cmd += ref_ch1
266 cmd.append("-native_chain2")
267 cmd += ref_ch2
268
269 proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
270
271 shutil.rmtree(tmp_dir) # cleanup, no matter if DockQ executed successfully
272
273 if proc.returncode != 0:
274 raise RuntimeError("DockQ run failed - returncode: " + \
275 str(proc.returncode) + ", stderr: " + \
276 proc.stderr.decode() + ", stdout: " + \
277 proc.stdout.decode())
278
279 if proc.stderr.decode() != "":
280 raise RuntimeError("DockQ run failed - stderr: " + \
281 proc.stderr.decode() + ", stdout: " + \
282 proc.stdout.decode())
283
284 return DockQResult.FromDockQOutput(proc.stdout.decode())
__init__(self, Fnat, Fnonnat, native_contacts, model_contacts, iRMS, LRMS, DockQ)
Definition dockq.py:112
DockQ(dockq_exec, mdl, ref, mdl_ch1, mdl_ch2, ref_ch1, ref_ch2)
Definition dockq.py:225
_Setup(mdl, ref, mdl_ch1, mdl_ch2, ref_ch1, ref_ch2)
Definition dockq.py:10