OpenStructure
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
tmtools.py
Go to the documentation of this file.
1 #------------------------------------------------------------------------------
2 # This file is part of the OpenStructure project <www.openstructure.org>
3 #
4 # Copyright (C) 2008-2015 by the OpenStructure authors
5 #
6 # This library is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation; either version 3.0 of the License, or (at your option)
9 # any later version.
10 # This library is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 # details.
14 #
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with this library; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #------------------------------------------------------------------------------
19 """
20 Wrappers for the tmalign and tmscore utilities.
21 
22 References:
23 
24 tmscore: Yang Zhang and Jeffrey Skolnick, Proteins 2004 57: 702-710
25 tmalign: Y. Zhang and J. Skolnick, Nucl. Acids Res. 2005 33, 2302-9
26 
27 
28 Authors: Pascal Benkert, Marco Biasini
29 """
30 
31 import subprocess, os, tempfile, platform
32 import ost
33 from ost import settings, io, geom, seq
34 
35 def _SetupFiles(models):
36  # create temporary directory
37  tmp_dir_name=tempfile.mkdtemp()
38  dia = 'PDB'
39  for index, model in enumerate(models):
40  for chain in model.chains:
41  if len(chain.name) > 1:
42  dia = 'CHARMM'
43  break;
44  for res in chain.residues:
45  if len(res.name) > 3:
46  dia = 'CHARMM'
47  break;
48  io.SavePDB(model, os.path.join(tmp_dir_name, 'model%02d.pdb' % (index+1)), dialect=dia)
49  return tmp_dir_name
50 
51 def _CleanupFiles(dir_name):
52  import shutil
53  shutil.rmtree(dir_name)
54 
55 def _ParseTmAlign(lines,lines_matrix):
56  info_line=lines[12].split(',')
57  aln_length=int(info_line[0].split('=')[1].strip())
58  rmsd=float(info_line[1].split('=')[1].strip())
59  tm_score=float(lines[14].split('=')[1].split('(')[0].strip())
60  tf1=[float(i.strip()) for i in lines_matrix[2].split()]
61  tf2=[float(i.strip()) for i in lines_matrix[3].split()]
62  tf3=[float(i.strip()) for i in lines_matrix[4].split()]
63  rot=geom.Mat3(tf1[2], tf1[3], tf1[4], tf2[2], tf2[3],
64  tf2[4], tf3[2], tf3[3], tf3[4])
65  tf=geom.Mat4(rot)
66  tf.PasteTranslation(geom.Vec3(tf1[1], tf2[1], tf3[1]))
67  seq1 = seq.CreateSequence("1",lines[18].strip())
68  seq2 = seq.CreateSequence("2",lines[20].strip())
69  alignment = seq.CreateAlignment()
70  alignment.AddSequence(seq2)
71  alignment.AddSequence(seq1)
72  return ost.bindings.TMAlignResult(rmsd, tm_score, aln_length, tf, alignment)
73 
74 def _RunTmAlign(tmalign, tmp_dir):
75  model1_filename=os.path.join(tmp_dir, 'model01.pdb')
76  model2_filename=os.path.join(tmp_dir, 'model02.pdb')
77  if platform.system() == "Windows":
78  tmalign_path=settings.Locate('tmalign.exe', explicit_file_name=tmalign)
79  command="\"%s\" %s %s -m %s" %(os.path.normpath(tmalign_path), model1_filename, model2_filename, os.path.join(tmp_dir,'matrix.txt'))
80  else:
81  tmalign_path=settings.Locate('tmalign', explicit_file_name=tmalign)
82  command="\"%s\" \"%s\" \"%s\" -m \"%s\"" %(tmalign_path, model1_filename, model2_filename, os.path.join(tmp_dir,'matrix.txt'))
83  ps=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
84  ps.wait()
85  lines=ps.stdout.readlines()
86  if (len(lines))<22:
87  _CleanupFiles(tmp_dir)
88  raise RuntimeError("tmalign superposition failed")
89  matrix_file=open(os.path.join(tmp_dir,'matrix.txt'))
90  lines_matrix=matrix_file.readlines()
91  matrix_file.close()
92  return _ParseTmAlign(lines,lines_matrix)
93 
95  def __init__(self, rmsd, aligned_length, tm_score, transform, alignment):
96  self.rmsd=rmsd
97  self.tm_score=tm_score
98  self.aligned_length=aligned_length
99  self.transform=transform
100  self.alignment=alignment
101 
102 def _ParseMmAlign(lines):
103  info_line=lines[10].split(',')
104  aln_length=float(info_line[0].split('=')[1].strip())
105  rmsd=float(info_line[1].split('=')[1].strip())
106  tm_score=float(info_line[2].split('=')[1].strip())
107  tf1=[float(i.strip()) for i in lines[14].split()]
108  tf2=[float(i.strip()) for i in lines[15].split()]
109  tf3=[float(i.strip()) for i in lines[16].split()]
110  rot=geom.Mat3(tf1[2], tf1[3], tf1[4], tf2[2], tf2[3],
111  tf2[4], tf3[2], tf3[3], tf3[4])
112  tf=geom.Mat4(rot)
113  tf.PasteTranslation(geom.Vec3(tf1[1], tf2[1], tf3[1]))
114  seq1 = seq.CreateSequence("1",lines[19].strip())
115  seq2 = seq.CreateSequence("2",lines[21].strip())
116  alignment = seq.CreateAlignment()
117  alignment.AddSequence(seq2)
118  alignment.AddSequence(seq1)
119 
120  return MMAlignResult(rmsd, tm_score, aln_length, tf, seq2, alignment)
121 
122 def _RunMmAlign(mmalign, tmp_dir):
123  model1_filename=os.path.join(tmp_dir, 'model01.pdb')
124  model2_filename=os.path.join(tmp_dir, 'model02.pdb')
125  if platform.system() == "Windows":
126  mmalign_path=settings.Locate('mmalign.exe', explicit_file_name=mmalign)
127  command="\"%s\" %s %s" %(os.path.normpath(mmalign_path), model1_filename, model2_filename)
128  else:
129  mmalign_path=settings.Locate('MMalign', explicit_file_name=mmalign)
130  command="\"%s\" \"%s\" \"%s\"" %(mmalign_path, model1_filename, model2_filename)
131  ps=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
132  ps.wait()
133  lines=ps.stdout.readlines()
134  if (len(lines))<22:
135  _CleanupFiles(tmp_dir)
136  raise RuntimeError("mmalign superposition failed")
137  return _ParseMmAlign(lines)
138 
140  """
141  Holds the result of running TMscore
142 
143  .. attribute:: rmsd_common
144 
145  The RMSD of the common Calpha atoms of both structures
146 
147  .. attribute:: rmsd_below_five
148 
149  The RMSD of all Calpha atoms that can be superposed below five Angstroem
150 
151  .. attribute:: tm_score
152 
153  The TM-score of the structural superposition
154 
155  .. attribute:: transform
156 
157  The transform that superposes the model onto the reference structure.
158 
159  :type: :class:`~ost.geom.Mat4`
160 
161  .. attribute:: gdt_ha
162 
163  The GDT_HA of the model to the reference structure.
164 
165  .. attribute:: gdt_ts
166 
167  The GDT_TS of the model to the reference structure.
168 
169  """
170  def __init__(self, rmsd_common, tm_score, max_sub,
171  gdt_ts, gdt_ha, rmsd_below_five, transform):
172  self.rmsd_common=rmsd_common
173  self.tm_score=tm_score
174  self.max_sub=max_sub
175  self.gdt_ts=gdt_ts
176  self.gdt_ha=gdt_ha
177  self.rmsd_below_five=rmsd_below_five
178  self.transform=transform
179 
180 def _ParseTmScore(lines):
181  tf1=[float(i.strip()) for i in lines[23].split()]
182  tf2=[float(i.strip()) for i in lines[24].split()]
183  tf3=[float(i.strip()) for i in lines[25].split()]
184  rot=geom.Mat3(tf1[2], tf1[3], tf1[4], tf2[2], tf2[3],
185  tf2[4], tf3[2], tf3[3], tf3[4])
186  tf=geom.Mat4(rot)
187  tf.PasteTranslation(geom.Vec3(tf1[1], tf2[1], tf3[1]))
188  result=TMScoreResult(float(lines[14].split()[-1].strip()),
189  float(lines[16].split()[2].strip()),
190  float(lines[17].split()[1].strip()),
191  float(lines[18].split()[1].strip()),
192  float(lines[19].split()[1].strip()),
193  float(lines[27].split()[-1].strip()),
194  tf)
195  return result
196 
197 def _RunTmScore(tmscore, tmp_dir):
198  model1_filename=os.path.join(tmp_dir, 'model01.pdb')
199  model2_filename=os.path.join(tmp_dir, 'model02.pdb')
200  if platform.system() == "Windows":
201  tmscore_path=settings.Locate('tmscore.exe', explicit_file_name=tmscore)
202  command="\"%s\" %s %s" %(os.path.normpath(tmscore_path), model1_filename,
203  model2_filename)
204  else:
205  tmscore_path=settings.Locate('tmscore', explicit_file_name=tmscore)
206  command="\"%s\" \"%s\" \"%s\"" % (tmscore_path, model1_filename,
207  model2_filename)
208  ps=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
209  ps.wait()
210  lines=ps.stdout.readlines()
211  if (len(lines))<22:
212  _CleanupFiles(tmp_dir)
213  raise RuntimeError("tmscore superposition failed")
214  return _ParseTmScore(lines)
215 
216 
217 def TMAlign(model1, model2, tmalign=None):
218  """
219  Performs a sequence independent superposition of model1 onto model2, the
220  reference.
221 
222 
223  :param model1: The model structure. If the superposition is successful, will
224  be superposed onto the reference structure
225  :type model1: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
226  :param model2: The reference structure
227  :type model2: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
228  :param tmalign: If not None, the path to the tmalign executable.
229  :returns: The result of the tmscore superposition
230  :rtype: :class:`ost.bindings.TMAlignResult`
231 
232  :raises: :class:`~ost.settings.FileNotFound` if tmalign could not be located.
233  :raises: :class:`RuntimeError` if the superposition failed
234  """
235  tmp_dir_name=_SetupFiles((model1, model2))
236  result=_RunTmAlign(tmalign, tmp_dir_name)
237  model1.handle.EditXCS().ApplyTransform(result.transform)
238  _CleanupFiles(tmp_dir_name)
239  return result
240 
241 def MMAlign(model1, model2, mmalign=None):
242  """
243  Run tmalign on two protein structures
244  """
245  tmp_dir_name=_SetupFiles((model1, model2))
246  result=_RunMmAlign(mmalign, tmp_dir_name)
247  model1.handle.EditXCS().ApplyTransform(result.transform)
248  _CleanupFiles(tmp_dir_name)
249  return result
250 
251 def TMScore(model1, model2, tmscore=None):
252  """
253  Performs a sequence dependent superposition of model1 onto model2,
254  the reference.
255 
256  :param model1: The model structure. If the superposition is successful, will
257  be superposed onto the reference structure
258  :type model1: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
259  :param model2: The reference structure
260  :type model2: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
261  :param tmscore: If not None, the path to the tmscore executable.
262  :returns: The result of the tmscore superposition
263  :rtype: :class:`TMScoreResult`
264 
265  :raises: :class:`~ost.settings.FileNotFound` if tmalign could not be located.
266  :raises: :class:`RuntimeError` if the superposition failed
267  """
268  tmp_dir_name=_SetupFiles((model1, model2))
269  result=_RunTmScore(tmscore, tmp_dir_name)
270  model1.handle.EditXCS().ApplyTransform(result.transform)
271  _CleanupFiles(tmp_dir_name)
272  return result
Three dimensional vector class, using Real precision.
Definition: vec3.hh:42