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,
336 attach_asa=
None, attach_esa=
None):
339 Calculates molecular surface by using the external MSMS program
341 This method calculates a molecular surface by invoking the external program
342 MSMS. First, it is checked if the MSMS executable is present, then, the
343 necessary files are prepared in a temporary directory and MSMS is executed.
344 The last step is to remove the temporary directory.
347 :param entity: Entity for which the surface is to be calculated
348 :param density: Surface point density
349 :param radius: Surface probe radius
350 :param all_surf: Calculate surface for all cavities (returns multiple
352 :param no_hydrogens: Calculate surface only for heavy atoms
353 :param selection: Calculate surface for subset of entity
354 :param msms_exe: msms executable (full path to executable)
355 :param msms_env: msms environment variable
356 :param keep_files: Do not delete temporary files
357 :param attach_asa: Attaches per atom SASA to specified FloatProp at atom level
358 :param attach_esa: Attaches per atom SESA to specified FloatProp at atom level
359 :returns: list of :class:`~ost.mol.SurfaceHandle` objects
365 msms_executable=_GetExecutable(msms_exe, msms_env)
376 selection+=
"ishetatm=False"
381 selection+=
"rname!=HOH"
384 (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
387 command=
"%s -if %s -of %s -density %s -probe_radius %s" % (msms_executable,
388 msms_data_file, msms_data_file, density, radius)
391 if attach_asa !=
None or attach_esa !=
None:
392 command+=
" -af %s" % os.path.join(msms_data_dir,
"asa_atom")
395 stdout_value=_RunMSMS(command)
398 if attach_asa !=
None or attach_esa !=
None:
399 _ParseAreaFile(entity, selection, os.path.join(msms_data_dir,
"asa_atom.area"),
400 attach_asa, attach_esa)
404 for line
in stdout_value.splitlines():
405 if re.search(
'RS component [0-9]+ identified',line):
406 num_surf=int(line.split()[2])
409 entity_sel = entity.Select(selection)
411 s = io.LoadSurface(msms_data_file,
"msms")
412 s.Attach(entity_sel, 3+radius)
413 msms_surfaces.append(s)
414 for n
in range(1,num_surf+1):
415 filename=msms_data_file+
'_'+str(n)
416 s = io.LoadSurface(filename,
"msms")
417 s.Attach(entity_sel, 3+radius)
418 msms_surfaces.append(s)
422 _CleanupFiles(msms_data_dir)
def CalculateSurfaceVolume