00001 '''
00002 MSMS module
00003
00004 Author: Tobias Schmidt
00005
00006 This module is for calculating MSMS surfaces as well as surface areas
00007 (SESA, SASA) from OpenStructure using the external program MSMS.
00008
00009 How To Use This Module:
00010 1. Import it (e.g. as "from ost.bindings import msms")
00011 2. Use it (e.g. as "surfaces_list = msms.CalculateSurface(entity)"
00012 "(sesa,sasa) = msms.CalculateSurfaceArea(entity)")
00013
00014 Requirement:
00015 - MSMS installed
00016 '''
00017
00018 import tempfile
00019 import subprocess
00020 import os
00021
00022 from ost import io
00023 from ost import mol
00024 from ost import settings
00025 from ost import geom
00026
00027
00028
00029
00030
00031
00032
00033 def _GetExecutable(msms_exe, msms_env):
00034 return settings.Locate('msms', explicit_file_name=msms_exe,
00035 env_name=msms_env)
00036
00037
00038
00039
00040
00041
00042
00043 def _SetupFiles(entity, selection):
00044
00045 tmp_dir_name=tempfile.mkdtemp()
00046
00047
00048 entity_view=entity.Select(selection)
00049 if not entity_view.IsValid():
00050 raise RuntimeError, "Could not create view for selection (%s)"%(selection)
00051
00052
00053 tmp_file_name=os.path.join(tmp_dir_name,"entity")
00054 tmp_file_handle=open(tmp_file_name, 'w')
00055 for a in entity_view.GetAtomList():
00056 position=a.GetPos()
00057 tmp_file_handle.write('%8.3f %8.3f %8.3f %4.2f\n' % (position[0],
00058 position[1], position[2], a.GetAtomProps().radius))
00059 tmp_file_handle.close()
00060
00061 return (tmp_dir_name, tmp_file_name)
00062
00063
00064
00065
00066
00067
00068
00069
00070 def _ParseAreaFile(entity,file, asa_prop, esa_prop):
00071 area_fh = open(file)
00072 area_lines = area_fh.readlines()
00073 area_fh.close()
00074
00075 area_lines = area_lines[1:]
00076 if entity.GetAtomCount() != len(area_lines):
00077 raise RuntimeError, "Atom count (%d) unequeal to number of atoms in area file (%d)" % (entity.GetAtomCount(), len(area_lines))
00078 for l in area_lines:
00079 atom_no, sesa, sasa = l.split()
00080 a = entity.atoms[int(atom_no)]
00081 if asa_prop:
00082 a.SetFloatProp(asa_prop, float(sasa))
00083 if esa_prop:
00084 a.SetFloatProp(esa_prop, float(sesa))
00085
00086
00087
00088
00089
00090
00091 def __CleanupFiles(dir_name):
00092 import shutil
00093 shutil.rmtree(dir_name)
00094
00095
00096
00097
00098
00099
00100
00101
00102 def _RunMSMS(command):
00103 proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
00104 stdout_value, stderr_value = proc.communicate()
00105
00106
00107 if proc.returncode!=0:
00108 print "WARNING: msms error\n", stdout_value
00109 raise subprocess.CalledProcessError(proc.returncode, command)
00110
00111 return stdout_value
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 def CalculateSurfaceArea(entity, density=1.0, radius=1.5, all_surf=False,
00137 no_hydrogens=False, selection="",
00138 msms_exe=None, msms_env=None, keep_files=False,
00139 attach_asa=None, attach_esa=None):
00140 import re
00141
00142
00143 msms_executable=_GetExecutable(msms_exe, msms_env)
00144
00145
00146 if no_hydrogens:
00147 if selection=="":
00148 selection="ele!=H"
00149 else:
00150 selection+=" and ele!=H"
00151
00152
00153 (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
00154
00155
00156 command="%s -if %s -of %s -density %s -probe_radius %s -surface ases" % \
00157 (msms_executable, msms_data_file, msms_data_file, density, radius)
00158 if all_surf:
00159 command+=" -all"
00160 if attach_asa != None:
00161 command+=" -af %s" % os.path.join(msms_data_dir, "asa_atom")
00162
00163 stdout_value=_RunMSMS(command)
00164
00165
00166 if attach_asa != None:
00167 _ParseAreaFile(entity, os.path.join(msms_data_dir, "asa_atom.area"),
00168 attach_asa, attach_esa)
00169
00170
00171 msms_ases=[]
00172 msms_asas=[]
00173 data_paragraph=False
00174 for line in stdout_value.splitlines():
00175 if re.match('MSMS terminated normally', line):
00176 data_paragraph=False
00177 if data_paragraph:
00178 (ses_,sas_)=line.split()[5:7]
00179 msms_ases.append(float(ses_))
00180 msms_asas.append(float(sas_))
00181 if re.match(' Comp. probe_radius, reent, toric, contact SES SAS', line):
00182 data_paragraph=True
00183
00184
00185 if not keep_files:
00186 __CleanupFiles(msms_data_dir)
00187
00188 return (msms_ases, msms_asas)
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 def CalculateSurface(entity, density=1.0, radius=1.5, all_surf=False,
00211 no_hydrogens=False, selection="",
00212 msms_exe=None, msms_env=None, keep_files=False):
00213 import os
00214 import re
00215
00216
00217 msms_executable=_GetExecutable(msms_exe, msms_env)
00218
00219
00220 if no_hydrogens:
00221 if selection=="":
00222 selection="ele!=H"
00223 else:
00224 selection+=" and ele!=H"
00225
00226
00227
00228 (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
00229
00230
00231 command="%s -if %s -of %s -density %s -probe_radius %s" % (msms_executable,
00232 msms_data_file, msms_data_file, density, radius)
00233 if all_surf:
00234 command+=" -all"
00235
00236
00237 stdout_value=_RunMSMS(command)
00238
00239
00240 num_surf=0
00241 for line in stdout_value.splitlines():
00242 if re.search('RS component [0-9]+ identified',line):
00243 num_surf=int(line.split()[2])
00244
00245
00246 msms_surfaces=[]
00247 msms_surfaces.append(io.LoadSurface(msms_data_file, "msms"))
00248 for n in range(1,num_surf+1):
00249 filename=msms_data_file+'_'+str(n)
00250 msms_surfaces.append(io.LoadSurface(filename, "msms"))
00251
00252
00253 if not keep_files:
00254 __CleanupFiles(msms_data_dir)
00255
00256 return msms_surfaces
00257