diff --git a/modules/bindings/pymod/msms.py b/modules/bindings/pymod/msms.py index fc50ff1c7b8081f1774d62fc36712bfb8487b4e7..af841ba100c840a5a9bb2195341f61ba55aacd77 100644 --- a/modules/bindings/pymod/msms.py +++ b/modules/bindings/pymod/msms.py @@ -100,7 +100,7 @@ def _SetupFiles(entity, selection): return (tmp_dir_name, tmp_file_name) -def _ParseAreaFile(entity,file, asa_prop, esa_prop): +def _ParseAreaFile(entity, selection, file, asa_prop, esa_prop): """ Reads Area file (-af) and attach sasa and sesa per atom to an entitiy @@ -111,13 +111,14 @@ def _ParseAreaFile(entity,file, asa_prop, esa_prop): :param esa_prop: Name of the float property for SESA :raises: :class:`RuntimeError` if number of atoms in file != number of atoms in entity """ + view=entity.Select(selection) area_fh = open(file) area_lines = area_fh.readlines() area_fh.close() # shift first line area_lines = area_lines[1:] - if entity.GetAtomCount() != len(area_lines): - raise RuntimeError, "Atom count (%d) unequeal to number of atoms in area file (%d)" % (entity.GetAtomCount(), len(area_lines)) + if view.GetAtomCount() != len(area_lines): + raise RuntimeError, "Atom count (%d) unequeal to number of atoms in area file (%d)" % (view.GetAtomCount(), len(area_lines)) for l in area_lines: atom_no, sesa, sasa = l.split() a = entity.atoms[int(atom_no)] @@ -218,14 +219,14 @@ def CalculateSurfaceArea(entity, density=1.0, radius=1.5, all_surf=False, (msms_executable, msms_data_file, msms_data_file, density, radius) if all_surf: command+=" -all" - if attach_asa != None: + if attach_asa != None or attach_esa != None: command+=" -af %s" % os.path.join(msms_data_dir, "asa_atom") # run msms stdout_value=_RunMSMS(command) # add sesa and asa to entity if attach_asa is specified - if attach_asa != None: - _ParseAreaFile(entity, os.path.join(msms_data_dir, "asa_atom.area"), + if attach_asa != None or attach_esa != None: + _ParseAreaFile(entity, selection, os.path.join(msms_data_dir, "asa_atom.area"), attach_asa, attach_esa) # parse MSMS output @@ -248,6 +249,84 @@ def CalculateSurfaceArea(entity, density=1.0, radius=1.5, all_surf=False, return (msms_ases, msms_asas) +def CalculateSurfaceVolume(entity, density=1.0, radius=1.5, all_surf=False, + no_hydrogens=False, no_hetatoms=False, no_waters=False, + selection='', + msms_exe=None, msms_env=None, keep_files=False, + attach_asa=None, attach_esa=None): + """ + Calculates the volume of the solvent excluded surface by using the external MSMS program. + + This method calculates the volume of the molecular surface by invoking the external + program MSMS. First, it is checked if the MSMS executable is present, then, + the necessary files are prepared in a temporary directory and MSMS is + executed. The last step is to remove the temporary directory. + + + :param entity: OST entity to calculate surface + :param density: Surface point density + :param radius: Surface probe radius + :param all_surf: Calculate surface area for all cavities (returns multiple + surfaces areas as a list) + :param no_hydrogens: Calculate surface only for hevy atoms + :param selection: Calculate surface for subset of entity + :param msms_exe: msms executable (full path to executable) + :param msms_env: msms environment variable + :param keep_files: Do not delete temporary files + :param attach_asa: Attaches per atom SASA to specified FloatProp at atom level + :param attach_esa: Attaches per atom SESA to specified FloatProp at atom level + :returns: Tuple of lists for (SES, SAS) + """ + import re + + # check if msms executable is specified + msms_executable=_GetExecutable(msms_exe, msms_env) + + # parse selection + if no_hydrogens: + if selection!='': + selection+=" and " + selection+="ele!=H" + + if no_hetatoms: + if selection!='': + selection+=" and " + selection+="ishetatm=False" + + if no_waters: + if selection!='': + selection+=" and " + selection+="rname!=HOH" + + # setup files for msms + (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection) + + # set command line + command="%s -if %s -of %s -density %s -probe_radius %s " % \ + (msms_executable, msms_data_file, msms_data_file, density, radius) + if all_surf: + command+=" -all" + if attach_asa != None or attach_esa != None: + command+=" -af %s" % os.path.join(msms_data_dir, "asa_atom") + # run msms + stdout_value=_RunMSMS(command) + + # add sesa and asa to entity if attach_asa is specified + if attach_asa != None or attach_esa != None: + _ParseAreaFile(entity, selection, os.path.join(msms_data_dir, "asa_atom.area"), + attach_asa, attach_esa) + + # parse MSMS output + ses_volume=0 + for line in stdout_value.splitlines(): + if re.match(' Total ses_volume:', line): + ses_volume=float(line.split(':')[1]) + + # clean up + if not keep_files: + _CleanupFiles(msms_data_dir) + + return ses_volume def CalculateSurface(entity, density=1.0, radius=1.5, all_surf=False,