OpenStructure
dssp.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-2009 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 Utility functions to load secondary structure information from DSSP files
21 and assign them to entities.
22 
23 Authors: Pascal Benkert, Marco Biasini
24 """
25 
26 import os
27 import tempfile,subprocess
28 
29 from ost import io,mol
30 from ost import settings
31 
32 
33 def _SkipHeader(stream):
34  line=stream.readline()
35  while line:
36  if line.strip().find('#')==0:
37  return True
38  line=stream.readline()
39  return False
40 
41 
42 def _ExecuteDSSP(path, dssp_bin, temp_dir=None):
43  # use of mktemp is a safty problem (use mkstemp and provide file handle to
44  # subsequent process
45  temp_dssp_path=tempfile.mktemp(suffix=".out",prefix="dssp", dir=temp_dir)
46  dssp_abs_path=settings.Locate(['dsspcmbi','dssp'], env_name='DSSP_EXECUTABLE',
47  explicit_file_name=dssp_bin)
48  if os.path.isdir(dssp_abs_path):
49  raise RuntimeError('"%s" is a directory. Specify path to DSSP binary' % dssp_abs_path)
50  if not os.access(dssp_abs_path, os.X_OK):
51  raise RuntimeError('"%s" is not executable' % dssp_abs_path)
52 
53  ps=subprocess.Popen([dssp_abs_path, path, temp_dssp_path],
54  stderr=subprocess.PIPE)
55  err_lines=ps.stderr.readlines()
56 
57  return temp_dssp_path
58 
59 
60 def _CalcRelativeSA(residue_type, absolute_sa):
61  solvent_max_list=[118,317,238,243,183,262,286,154,258,228,
62  243,278,260,271,204,234,206,300,303,216] #TODO: source?
63  residue_indices = "ARNDCQEGHILKMFPSTWYV"
64  if residue_type.islower()==True:
65  residue_type='C'
66  if residue_indices.find(residue_type)==-1:
67  raise RuntimeError('residue %s is a non-standard residue' %(residue_type))
68  else:
69  rel=float(absolute_sa)/(solvent_max_list[residue_indices.find(residue_type)])
70  return rel
71 
72 
73 def AssignDSSP(ent, pdb_path="", extract_burial_status=False, tmp_dir=None,
74  dssp_bin=None):
75  """
76  Assign secondary structure states to peptide residues in the structure. This
77  function uses the DSSP command line program.
78 
79  If you already have a DSSP output file and would like to assign the secondary
80  structure states to an entity, use :func:`LoadDSSP`.
81 
82  :param ent: The entity for which the secondary structure should be calculated
83  :type ent: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView`
84  :param extract_burial_status: If true, also extract burial status
85  :param tmp_dir: If set, overrides the default tmp directory of the
86  operating system
87  :param dssp_bin: The path to the DSSP executable
88  :raises: :class:`~ost.settings.FileNotFound` if the dssp executable is not
89  in the path.
90  :raises: :class:`RuntimeError` when dssp is executed with errors
91  """
92  entity_saved = False
93 
94  # use of mktemp is a safty problem (use mkstemp and provide file handle to
95  # subsequent process
96  pdb_path=tempfile.mktemp(suffix=".pdb",prefix="temp_entity",
97  dir=tmp_dir)
98  io.SaveEntity(ent, pdb_path)
99  entity_saved_flag = 1
100 
101  #TODO: exception handling (currently errors occuring here
102  # are handled in the parser LoadDSSP)
103  temp_dssp_path=_ExecuteDSSP(pdb_path, dssp_bin)
104  if not os.path.exists(temp_dssp_path):
105  raise RuntimeEror('DSSP output file does not exist.')
106  # assign DSSP to entity
107  try:
108  LoadDSSP(temp_dssp_path, ent, extract_burial_status,
109  entity_saved_flag)
110  except Exception, e:
111  # clean up
112  print "Exception in DSSP:", e
113  if entity_saved_flag == 1:
114  os.remove(pdb_path)
115  os.remove(temp_dssp_path)
116  raise RuntimeError(e)
117 
118  # clean up
119  #print pdb_path, temp_dssp_path
120  if entity_saved_flag == 1:
121  os.remove(pdb_path)
122  os.remove(temp_dssp_path)
123 
124  return ent
125 
126 
127 
128 def LoadDSSP(file_name, model, extract_burial_status=0,
129  entity_saved_flag=0, calculate_relative_sa=True):
130  if model.IsValid() == 0:
131  print "DSSP: model is not valid"
132  stream=open(file_name)
133  if not _SkipHeader(stream):
134  stream.close()
135  raise RuntimeError('Ill-formatted DSSP file')
136 
137  for line in stream:
138  num=line[6:10].strip()
139  ins_code=line[10].strip()
140  chain_name=line[11]
141  solvent_accessibility=float(line[34:39].strip())
142  #solvent_accessibility=line[34:39].strip()
143  amino_acid=line[13]
144  #print line
145 
146 
147  if isinstance(model,mol.ChainView):
148  chain=model
149  else:
150  chain=model.FindChain(chain_name)
151 
152  if not chain.IsValid():
153  continue
154  if num=='':
155  continue
156  residue=None
157  try:
158  if ins_code == "":
159  residue=chain.FindResidue(mol.ResNum(int(num)))
160  else:
161  residue=chain.FindResidue(mol.ResNum(int(num),ins_code))
162 
163  # set property "burial status:
164  if extract_burial_status == 1:
165  #set default (dummy) burial status for incomplete residues:
166  residue.SetStringProp("burial_status", 'X')
167 
168  #handle seleno-methionine appearing as amino acid 'X' in DSSP:
169  if residue.name=="MSE" and amino_acid=='X':
170  amino_acid='M'
171 
172  residue.SetFloatProp("solvent_accessibility",
173  solvent_accessibility)
174  if calculate_relative_sa:
175  relative_sa=_CalcRelativeSA(amino_acid,solvent_accessibility)
176  residue.SetFloatProp("relative_solvent_accessibility",
177  relative_sa)
178  if relative_sa < 0.25:
179  residue.SetStringProp("burial_status", 'b')
180  else:
181  residue.SetStringProp("burial_status", 'e')
182  except Exception, e:
183  print "ERROR:",e
184  continue
185 
186  rtype=line[16:17]
187  rt=mol.SecStructure.COIL
188  if rtype=='H':
189  rt=mol.SecStructure.ALPHA_HELIX
190  elif rtype=='E':
191  rt=mol.SecStructure.EXTENDED
192  elif rtype=='B':
193  rt=mol.SecStructure.BETA_BRIDGE
194  elif rtype=='S':
195  rt=mol.SecStructure.BEND
196  elif rtype=='T':
197  rt=mol.SecStructure.TURN
198  elif rtype=='I':
199  rt=mol.SecStructure.PI_HELIX
200  elif rtype=='G':
201  rt=mol.SecStructure.THREE_TEN_HELIX
202  # for corrupted DSSP files. Catch in calling routine:
203  if residue.IsValid() == 0:
204  #Todo: if residues with occupancy 0 have been removed before
205  #using a selection statement, they are missed here
206  #IMPORTANT: asign DSSP before any selections
207  stream.close()
208  raise RuntimeError('Ill-formatted DSSP file: invalid residue')
209  residue.SetSecStructure(mol.SecStructure(rt))
210  stream.close()