6 This module is for calculating MSMS surfaces as well as surface areas
7 (SESA, SASA) from OpenStructure using the external program MSMS.
9 How To Use This Module:
10 1. Import it (e.g. as "from ost.bindings import msms")
11 2. Use it (e.g. as "surfaces_list = msms.CalculateSurface(entity)"
12 "(sesa,sasa) = msms.CalculateSurfaceArea(entity)")
24 from ost
import settings
30 Python 2.4 and older do not include the CalledProcessError exception. This
42 Get version of MSMS executable
44 msms_executable = _GetExecutable(msms_exe, msms_env)
45 command =
"%s" % (msms_executable)
46 proc = subprocess.Popen(command, shell=
True, stdout=subprocess.PIPE)
47 stdout_value, stderr_value = proc.communicate()
50 for l
in stdout_value.splitlines():
52 version = l.split(
' ')[1]
55 LogWarning(
'Could not parse MSMS version string')
59 def _GetExecutable(msms_exe, msms_env):
61 Function to check if MSMS executable is present
63 :param msms_exe: Explicit path to msms executable
64 :param msms_env: Environment variable pointing to msms executable
65 :returns: Path to the executable
66 :raises: :class:`~ost.FileNotFound` if executable is not found
68 return settings.Locate(
'msms', explicit_file_name=msms_exe,
72 def _SetupFiles(entity, selection):
74 Setup files for MSMS calculation in temporary directory
76 :param entity: The entity for which the surface is to be calculated
77 :type entity: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityHandle`
78 :param selection: Calculate surface for subset of entity
79 :type selection: :class:`str`
80 :returns: tuple containing temporary directory and msms input file
81 :raises: :class:`RuntimeError` if selection is not valid
84 tmp_dir_name=tempfile.mkdtemp()
87 entity_view=entity.Select(selection)
88 if not entity_view.IsValid():
89 raise RuntimeError,
"Could not create view for selection (%s)"%(selection)
92 tmp_file_name=os.path.join(tmp_dir_name,
"entity")
93 tmp_file_handle=open(tmp_file_name,
'w')
94 for a
in entity_view.GetAtomList():
96 tmp_file_handle.write(
'%8.3f %8.3f %8.3f %4.2f\n' % (position[0],
97 position[1], position[2], a.radius))
98 tmp_file_handle.close()
100 return (tmp_dir_name, tmp_file_name)
103 def _ParseAreaFile(entity, selection, file, asa_prop, esa_prop):
105 Reads Area file (-af) and attach sasa and sesa per atom to an entitiy
107 :param entity: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView`
108 for attaching sasa and sesa on atom level
109 :param file: Filename of area file
110 :param asa_prop: Name of the float property for SASA
111 :param esa_prop: Name of the float property for SESA
112 :raises: :class:`RuntimeError` if number of atoms in file != number of atoms in entity
114 view=entity.Select(selection)
116 area_lines = area_fh.readlines()
119 area_lines = area_lines[1:]
120 if view.GetAtomCount() != len(area_lines):
121 raise RuntimeError,
"Atom count (%d) unequeal to number of atoms in area file (%d)" % (view.GetAtomCount(), len(area_lines))
123 atom_no, sesa, sasa = l.split()
124 a = view.atoms[int(atom_no)]
126 a.SetFloatProp(asa_prop, float(sasa))
128 a.SetFloatProp(esa_prop, float(sesa))
132 def _CleanupFiles(dir_name):
134 Function which recursively deletes a directory and all the files contained
135 in it. *Warning*: This method removes also non-empty directories without
136 asking, so be careful!
139 shutil.rmtree(dir_name)
141 def _RunMSMS(command):
143 Run the MSMS surface calculation
145 This functions starts the external MSMS executable and returns the stdout of
148 :param command: Command to execute
149 :returns: stdout of MSMS
150 :raises: :class:`CalledProcessError` for non-zero return value
152 proc = subprocess.Popen(command, shell=
True, stdout=subprocess.PIPE)
153 stdout_value, stderr_value = proc.communicate()
156 if proc.returncode!=0:
157 print "WARNING: msms error\n", stdout_value
165 no_hydrogens=
False, no_hetatoms=
False, no_waters=
False,
167 msms_exe=
None, msms_env=
None, keep_files=
False,
168 attach_asa=
None, attach_esa=
None):
170 Calculates analytical solvent excluded and solvent accessible surface
171 area by using the external MSMS program.
173 This method calculates the molecular surface areas by invoking the external
174 program MSMS. First, it is checked if the MSMS executable is present, then,
175 the necessary files are prepared in a temporary directory and MSMS is
176 executed. The last step is to remove the temporary directory.
179 :param entity: OST entity to calculate surface
180 :param density: Surface point density
181 :param radius: Surface probe radius
182 :param all_surf: Calculate surface area for all cavities (returns multiple
183 surfaces areas as a list)
184 :param no_hydrogens: Calculate surface only for hevy atoms
185 :param selection: Calculate surface for subset of entity
186 :param msms_exe: msms executable (full path to executable)
187 :param msms_env: msms environment variable
188 :param keep_files: Do not delete temporary files
189 :param attach_asa: Attaches per atom SASA to specified FloatProp at atom level
190 :param attach_esa: Attaches per atom SESA to specified FloatProp at atom level
191 :returns: Tuple of lists for (SES, SAS)
196 msms_executable=_GetExecutable(msms_exe, msms_env)
207 selection+=
"ishetatm=False"
212 selection+=
"rname!=HOH"
215 (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
218 command=
"%s -if %s -of %s -density %s -probe_radius %s -surface ases" % \
219 (msms_executable, msms_data_file, msms_data_file, density, radius)
222 if attach_asa !=
None or attach_esa !=
None:
223 command+=
" -af %s" % os.path.join(msms_data_dir,
"asa_atom")
225 stdout_value=_RunMSMS(command)
228 if attach_asa !=
None or attach_esa !=
None:
229 _ParseAreaFile(entity, selection, os.path.join(msms_data_dir,
"asa_atom.area"),
230 attach_asa, attach_esa)
236 for line
in stdout_value.splitlines():
237 if re.match(
'MSMS terminated normally', line):
240 (ses_,sas_)=line.split()[5:7]
241 msms_ases.append(float(ses_))
242 msms_asas.append(float(sas_))
243 if re.match(
' Comp. probe_radius, reent, toric, contact SES SAS', line):
248 _CleanupFiles(msms_data_dir)
250 return (msms_ases, msms_asas)
253 no_hydrogens=
False, no_hetatoms=
False, no_waters=
False,
255 msms_exe=
None, msms_env=
None, keep_files=
False,
256 attach_asa=
None, attach_esa=
None):
258 Calculates the volume of the solvent excluded surface by using the external MSMS program.
260 This method calculates the volume of the molecular surface by invoking the external
261 program MSMS. First, it is checked if the MSMS executable is present, then,
262 the necessary files are prepared in a temporary directory and MSMS is
263 executed. The last step is to remove the temporary directory.
266 :param entity: OST entity to calculate surface
267 :param density: Surface point density
268 :param radius: Surface probe radius
269 :param all_surf: Calculate surface area for all cavities (returns multiple
270 surfaces areas as a list)
271 :param no_hydrogens: Calculate surface only for hevy atoms
272 :param selection: Calculate surface for subset of entity
273 :param msms_exe: msms executable (full path to executable)
274 :param msms_env: msms environment variable
275 :param keep_files: Do not delete temporary files
276 :param attach_asa: Attaches per atom SASA to specified FloatProp at atom level
277 :param attach_esa: Attaches per atom SESA to specified FloatProp at atom level
278 :returns: Tuple of lists for (SES, SAS)
283 msms_executable=_GetExecutable(msms_exe, msms_env)
294 selection+=
"ishetatm=False"
299 selection+=
"rname!=HOH"
302 (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
305 command=
"%s -if %s -of %s -density %s -probe_radius %s " % \
306 (msms_executable, msms_data_file, msms_data_file, density, radius)
309 if attach_asa !=
None or attach_esa !=
None:
310 command+=
" -af %s" % os.path.join(msms_data_dir,
"asa_atom")
312 stdout_value=_RunMSMS(command)
315 if attach_asa !=
None or attach_esa !=
None:
316 _ParseAreaFile(entity, selection, os.path.join(msms_data_dir,
"asa_atom.area"),
317 attach_asa, attach_esa)
321 for line
in stdout_value.splitlines():
322 if re.match(
' Total ses_volume:', line):
323 ses_volume=float(line.split(
':')[1])
327 _CleanupFiles(msms_data_dir)
333 no_hydrogens=
False, no_hetatoms=
False, no_waters=
False,
335 msms_exe=
None, msms_env=
None, keep_files=
False):
338 Calculates molecular surface by using the external MSMS program
340 This method calculates a molecular surface by invoking the external program
341 MSMS. First, it is checked if the MSMS executable is present, then, the
342 necessary files are prepared in a temporary directory and MSMS is executed.
343 The last step is to remove the temporary directory.
346 :param entity: Entity for which the surface is to be calculated
347 :param density: Surface point density
348 :param radius: Surface probe radius
349 :param all_surf: Calculate surface for all cavities (returns multiple
351 :param no_hydrogens: Calculate surface only for heavy atoms
352 :param selection: Calculate surface for subset of entity
353 :param msms_exe: msms executable (full path to executable)
354 :param msms_env: msms environment variable
355 :param keep_files: Do not delete temporary files
356 :returns: list of :class:`~ost.mol.SurfaceHandle` objects
362 msms_executable=_GetExecutable(msms_exe, msms_env)
373 selection+=
"ishetatm=False"
378 selection+=
"rname!=HOH"
381 (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
384 command=
"%s -if %s -of %s -density %s -probe_radius %s" % (msms_executable,
385 msms_data_file, msms_data_file, density, radius)
390 stdout_value=_RunMSMS(command)
394 for line
in stdout_value.splitlines():
395 if re.search(
'RS component [0-9]+ identified',line):
396 num_surf=int(line.split()[2])
399 entity_sel = entity.Select(selection)
401 s = io.LoadSurface(msms_data_file,
"msms")
402 s.Attach(entity_sel, 3+radius)
403 msms_surfaces.append(s)
404 for n
in range(1,num_surf+1):
405 filename=msms_data_file+
'_'+str(n)
406 s = io.LoadSurface(filename,
"msms")
407 s.Attach(entity_sel, 3+radius)
408 msms_surfaces.append(s)
412 _CleanupFiles(msms_data_dir)