diff --git a/doc/conf/conf.py b/doc/conf/conf.py index d3d1736f31af330ec5491d2bf6004d4a22ed7537..6de040bb6a3fdcb816eb79c7fe00f45eb0205bb9 100644 --- a/doc/conf/conf.py +++ b/doc/conf/conf.py @@ -79,7 +79,7 @@ exclude_trees = [] # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +add_module_names = False # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. diff --git a/modules/bindings/doc/bindings.rst b/modules/bindings/doc/bindings.rst new file mode 100644 index 0000000000000000000000000000000000000000..fc5357608c5a09becf40ba13b0ebed59fe634769 --- /dev/null +++ b/modules/bindings/doc/bindings.rst @@ -0,0 +1,19 @@ +:mod:`~ost.bindings` -- Interfacing external programs +================================================================================ + +.. module:: ost.bindings + :synopsis: Contains bindings for external programs + +The bindings module contains functions and classes that interface with command-line programs commonly used in bioinformatics. + +If you would like to write your own wrapper, consult :doc:`../external`. + +So far, the binding module includes: + +.. toctree:: + :maxdepth: 1 + + dssp + blast + msms + tmtools diff --git a/modules/bindings/doc/blast.rst b/modules/bindings/doc/blast.rst new file mode 100644 index 0000000000000000000000000000000000000000..2154bddc6b74013bd320034aa56112c97a09c4dc --- /dev/null +++ b/modules/bindings/doc/blast.rst @@ -0,0 +1,16 @@ +:mod:`~ost.bindings.blast` - Search related sequences in databases +================================================================================ + +.. module:: ost.bindings.blast + :synopsis: Search related sequences in databases + + +.. autofunction:: ost.bindings.blast.Blast + +.. autofunction:: ost.bindings.blast.ParseBlastOutput + +.. autoclass:: ost.bindings.blast.AlignedPatch + +.. autoclass:: ost.bindings.blast.BlastHit + +.. autoclass:: ost.bindings.blast.BlastError diff --git a/modules/bindings/doc/dssp.rst b/modules/bindings/doc/dssp.rst new file mode 100644 index 0000000000000000000000000000000000000000..61de495e34f920e85bc801800feb24c4ca5a3305 --- /dev/null +++ b/modules/bindings/doc/dssp.rst @@ -0,0 +1,31 @@ +:mod:`~ost.bindings.dssp` - Secondary structure assignment +================================================================================ + +.. module:: ost.bindings.dssp + :synopsis: Interface to the DSSP commandline utility + +Introduction +-------------------------------------------------------------------------------- + +DSSP is a program developed by Wolfgang Kabsch and Chris Sander to assign secondary structure states to protein structures. The assignment is based on hydrogen bonding patterns and geometric features. + +The program can be downloaded from `<http://swift.cmbi.ru.nl/gv/dssp/>`_. + +Example +-------------------------------------------------------------------------------- + +The following example assigns secondary structure states to an entity by using the DSSP program. + + +.. code-block:: python + + from ost.bindings import dssp + ent=io.LoadPDB('1ake.pdb') + dssp.AssignDSSP(ent) + +DSSP bindings Usage +-------------------------------------------------------------------------------- + +.. autofunction:: ost.bindings.dssp.AssignDSSP + +.. autofunction:: ost.bindings.dssp.LoadDSSP diff --git a/modules/bindings/doc/msms.rst b/modules/bindings/doc/msms.rst new file mode 100644 index 0000000000000000000000000000000000000000..0085571c0a063b15bb78e7ecb6dded7a89ad24ef --- /dev/null +++ b/modules/bindings/doc/msms.rst @@ -0,0 +1,11 @@ +:mod:`~ost.bindings.msms` -- Calculating Molecular Surfaces +================================================================================ + +.. currentmodule:: ost.bindings.msms + + +.. autoclass:: ost.bindings.msms.MsmsProcessError + +.. autofunction:: ost.bindings.msms.CalculateSurfaceArea + +.. autofunction:: ost.bindings.msms.CalculateSurface diff --git a/modules/bindings/doc/tmtools.rst b/modules/bindings/doc/tmtools.rst new file mode 100644 index 0000000000000000000000000000000000000000..7192e730d99e39c9a408b3687cc69e06b9cc6942 --- /dev/null +++ b/modules/bindings/doc/tmtools.rst @@ -0,0 +1,69 @@ +:mod:`~ost.bindings.tmtools` - Structural superposition +================================================================================ + +.. module:: ost.bindings.tmtools + :synopsis: Sequence dependent and independent structure superposition + +The :mod:`~ost.bindings.tmtools` module provides access to the structural +superposition programs TMscore, Tmalign and MMalign developed by Y. Zhang +and J. Skolnick. These programs superpose a model onto a reference structure, +using the positions of the Calpha atoms only. While at their core, these +programs essentially use the same algorithm, they differ on how the Calphas are +paired. TMscore pairs the Calpha atom based on the residue number, TMalign +calculates an optimal pairing of Calpha atom based on heuristics. + +Citation: + + Yang Zhang and Jeffrey Skolnick, Proteins 2004 57: 702-710 + Y. Zhang and J. Skolnick, Nucl. Acids Res. 2005 33, 2302-9 + +Distance measures used by TMscore +-------------------------------------------------------------------------------- + +There are many different ways to describe the structural similarity of two +protein structures at the Calpha level. TMscore calculate several of these +measures. The most common is to describe the difference in terms of the root +mean square deviation of the Calpha positions, the RMSD. Despite its common use, +RMSD has several drawbacks when working with incomplete models. Since the RMSD +highly depends on the set of included atoms, it is relatively easy to obtain a +smaller RMSD by omitting flexible parts of a protein structure. This has lead to +the introduction of the global distance test (GDT). A model is compared to a +reference by calculating the fraction of Calpha atoms that can be superposed +below a certain cutoff, e.g. 1Å. The fractions of several such cutoffs are +combined into the GDT_TS (1, 2, 4 and 8Å) and GDT_HA (0.5, 1, 2, 4Å) and divided +by four to obtain the final measure. In contrast to RSMD, GDT is an agreement +measure. The higher the value, the more similar the two structures are. TM-score +(not to be confused by TMscore, the program), additionally adds a size +dependences to the GDT measure by taking the protein length into account. As +with GDT, the bigger the value, the more similar the two structures are. + +Common Usage +-------------------------------------------------------------------------------- + +The following example shows how to use TMscore to superpose two protein +structures and print the RMSD as well as the GDT_TS and GDT_HA similarity measures. + +.. code-block:: python + + from ost.bindings import tmtools + + pdb1=io.LoadPDB('1ake.pdb', restrict_chains='A') + pdb2=io.LoadPDB('4ake.pdb', restrict_chains='A') + result=tmtools.TMScore(pdb1, pdb2) + print result.rmsd_below_five # 1.9 + print result.gdt_ha # 0.41 + print result.gdt_ts # 0.56 + +Usage of TMalign +-------------------------------------------------------------------------------- + +.. autofunction:: ost.bindings.tmtools.TMAlign + +.. autoclass:: ost.bindings.tmtools.TMAlignResult + +Usage of TMscore +-------------------------------------------------------------------------------- + +.. autofunction:: ost.bindings.tmtools.TMScore + +.. autoclass:: ost.bindings.tmtools.TMScoreResult diff --git a/modules/bindings/pymod/__init__.py b/modules/bindings/pymod/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..388a6054e165dc7fdd572892a11abb4f5f69ae62 100644 --- a/modules/bindings/pymod/__init__.py +++ b/modules/bindings/pymod/__init__.py @@ -0,0 +1,7 @@ +from ost.bindings import dssp +from ost.bindings import msms +from ost.bindings import blast +from ost.bindings import tmtools +from ost.bindings import naccess +from ost.bindings import hbplus +from ost.bindings import clustalw \ No newline at end of file diff --git a/modules/bindings/pymod/blast.py b/modules/bindings/pymod/blast.py index 32e36e3bf37fd4860111b76425efea56c8547659..054bff58c0575848d08642a6f935c09c7912df98 100644 --- a/modules/bindings/pymod/blast.py +++ b/modules/bindings/pymod/blast.py @@ -5,7 +5,30 @@ from ost import io, seq import ost import re import os + class AlignedPatch: + """ + An aligned patch, aka. HSP + + .. attribute:: aln + + The local alignment. Sequence offset of both sequences in the alignment are + set to the starting position in the query and target sequence, respectively. + + :type: :class:`~ost.seq.AlignmentHandle` + + .. attribute:: bit_score + + The bit score of the HSP + + .. attribute:: score + + The score of the HSP + + .. attribute:: evalue + + The E-value of the HSP + """ def __init__(self, aln, bit_score, score, evalue): self.aln=aln self.bit_score=bit_score @@ -16,16 +39,51 @@ class BlastHit: """ A positive match found by BLAST. - Each blast hit consists of one or more aligned patches. + Each blast hit consists of one or more HSPs, encoded by the + :class:`AlignedPatch` class. + .. attribute:: identifier + + The identifier of the matching sequence + + .. attribute:: aligned_patches + + list of :class:`AlignedPatch` instances holding the actual HSPs. """ def __init__(self, identifier, aligned_patches): self.identifier=identifier self.aligned_patches=aligned_patches +class BlastError(RuntimeError): + """ + Raised when something goes wrong during parsing/execution of the blast + executable. + + .. attribute:: brief + + Short explanation of the problem + + .. attribute:: details + + If set, explains in more detail what caused the error. Might be empty. + """ + def __init__(self, brief, details): + self.brief=brief + self.details=details + + def __str__(self): + if self.details: + return '%s\n%s' % (self.brief, self.details) + else: + return self.brief + def ParseBlastOutput(string): """ - Parses the blast output and returns a list of BlastHits + Parses the blast output and returns a list of :class:`BlastHit` instances. + + :raises: :class:`BlastError` if the output could not be parsed. + + This functions is only capable of dealing with the BLAST XML output. """ def _GetText(node): rc='' @@ -57,8 +115,7 @@ def ParseBlastOutput(string): try: doc=minidom.parseString(string) except Exception, e: - ost.LogError('Error while parsing BLAST output: %s' % str(e)) - return None + raise BlastError('Error while parsing BLAST output: %s' % str(e), '') hits=[] query_id=_GetValue(doc, 'BlastOutput_query-def') for hit in doc.getElementsByTagName('Hit'): @@ -69,18 +126,6 @@ def ParseBlastOutput(string): return hits - -class BlastError(RuntimeError): - def __init__(self, brief, details): - self.brief=brief - self.details=details - - def __str__(self): - if self.details: - return '%s\n%s' % (self.brief, self.details) - else: - return self.brief - def Blast(query, database, gap_open=11, gap_ext=1, matrix='BLOSUM62', blast_location=None): """ @@ -100,6 +145,12 @@ def Blast(query, database, gap_open=11, gap_ext=1, matrix='BLOSUM62', :param gap_ext: Gap extension penalty. Only a subset of gap extension penalties are supported for each of the substitution matrices. Consult the blast docs for more information. + + :raises: :class:`~ost.settings.FileNotFound` if the BLAST executable could not + be found + :raises: :class:`BlastError` if there was a problem during execution of BLAST. + :raises: :class:`ValueError` if the substitution matrix is invalid + :raises: :class:`IOError` if the database does not exist """ subst_mats=('BLOSUM45', 'BLOSUM62', 'BLOSUM80', 'PAM30', 'PAM70',) if matrix not in subst_mats: diff --git a/modules/bindings/pymod/dssp.py b/modules/bindings/pymod/dssp.py index 234ba74067f1dd977f0b5018ab22984caf70d930..56f78bd059a60e73977ef918614c6945d030c989 100644 --- a/modules/bindings/pymod/dssp.py +++ b/modules/bindings/pymod/dssp.py @@ -38,16 +38,21 @@ def _SkipHeader(stream): line=stream.readline() return False +def _Cleanup(pdb_path, temp_path, entity_saved): + if entity_saved and os.path.exists(pdb_path): + os.remove(pdb_path) + if os.path.exists(temp_path): + os.remove(temp_path) def _ExecuteDSSP(path, temp_dir=None): # use of mktemp is a safty problem (use mkstemp and provide file handle to # subsequent process temp_dssp_path=tempfile.mktemp(suffix=".out",prefix="dssp", dir=temp_dir) dssp_abs_path=settings.Locate('dssp', env_name='DSSP_EXECUTABLE') - command=dssp_abs_path+" "+path+" "+temp_dssp_path - ps=subprocess.Popen(command, shell=True, stderr=subprocess.PIPE) + assert os.path.exists(path) + ps=subprocess.Popen([dssp_abs_path, path, temp_dssp_path], + stderr=subprocess.PIPE) err_lines=ps.stderr.readlines() - return temp_dssp_path @@ -55,7 +60,10 @@ def _CalcRelativeSA(residue_type, absolute_sa): solvent_max_list=[118,317,238,243,183,262,286,154,258,228, 243,278,260,271,204,234,206,300,303,216] #TODO: source? residue_indices = "ARNDCQEGHILKMFPSTWYV" - if residue_type.islower()==True: + # cysteine bridges are marked with lower-case letters by DSSP. We don't + # really care which cysteines are forming covalent bonds, so let's set the + # one-letter-code to "C". + if residue_type.islower(): residue_type='C' if residue_indices.find(residue_type)==-1: raise RuntimeError('residue %s is a non-standard residue' %(residue_type)) @@ -64,14 +72,30 @@ def _CalcRelativeSA(residue_type, absolute_sa): return rel -def AssignDSSP(ent, pdb_path="", extract_burial_status_flag=0, tmp_dir=None): - entity_saved_flag = 0 +def AssignDSSP(ent, pdb_path="", extract_burial_status=False, tmp_dir=None): + """ + Assign secondary structure states to peptide residues in the structure. This + function uses the DSSP command line program. + + If you already have a DSSP output file and would like to assign the secondary + structure states to an entity, use :func:`LoadDSSP`. + + :param ent: The entity for which the secondary structure should be calculated + :type ent: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView` + :param extract_burial_status: If true, also extract burial status + :param tmp_dir: If set, overrides the default tmp directory of the + operating system + + :raises: :class:`~ost.settings.FileNotFound` if the dssp executable is not + in the path. + """ + entity_saved = False # use of mktemp is a safty problem (use mkstemp and provide file handle to # subsequent process pdb_path=tempfile.mktemp(suffix=".pdb",prefix="temp_entity", - dir=tmp_dir) - io.SaveEntity(ent, pdb_path) - entity_saved_flag = 1 + dir=tmp_dir) + io.SavePDB(ent, pdb_path) + entity_saved = True #TODO: exception handling (currently errors occuring here # are handled in the parser LoadDSSP) @@ -79,30 +103,45 @@ def AssignDSSP(ent, pdb_path="", extract_burial_status_flag=0, tmp_dir=None): # assign DSSP to entity try: - LoadDSSP(temp_dssp_path, ent, extract_burial_status_flag, - entity_saved_flag) + LoadDSSP(temp_dssp_path, ent, extract_burial_status, + entity_saved) except Exception, e: # clean up print "Exception in DSSP:", e - if entity_saved_flag == 1: - os.remove(pdb_path) - os.remove(temp_dssp_path) + _Cleanup(pdb_path, temp_dssp_path, entity_saved) raise RuntimeError(e) # clean up #print pdb_path, temp_dssp_path - if entity_saved_flag == 1: - os.remove(pdb_path) - os.remove(temp_dssp_path) + _Cleanup(pdb_path, temp_dssp_path, entity_saved) return ent -def LoadDSSP(file_name, model, extract_burial_status_flag=0, - entity_saved_flag=0, calculate_relative_sa=True): - if model.IsValid() == 0: - print "DSSP: model is not valid" +def LoadDSSP(file_name, model, extract_burial_status=False, + entity_saved=False, calculate_relative_sa=True): + """ + Loads DSSP output and assigns secondary structure states to the peptidic + residues. + + If you would like to run dssp *and* assign the secondary structure, + use :func:`AssignDSSP` instead. + + :param file_name: The filename of the DSSP output file + :param model: The entity to which the secondary structure states should be + assigned + :param extract_burial_status: If true also calculates burial status of + residues and assigns it to the burial_status string property. + :param calculate_relative_sa: If true also relative solvent accessibility and + and assigns it to the relative_solvent_accessibility float property of + the residue. + :param entity_save: Whether the entity was saved. + """ + if not model.IsValid(): + raise ValueError('model entity is not valid') + if model.atom_count==0: + raise ValueError('model entity does not contain any atoms') stream=open(file_name) if not _SkipHeader(stream): stream.close() @@ -135,24 +174,24 @@ def LoadDSSP(file_name, model, extract_burial_status_flag=0, residue=chain.FindResidue(mol.ResNum(int(num),ins_code)) # set property "burial status: - if extract_burial_status_flag == 1: - #set default (dummy) burial status for incomplete residues: - residue.SetStringProp("burial_status", 'X') - - #handle seleno-methionine appearing as amino acid 'X' in DSSP: - if residue.name=="MSE" and amino_acid=='X': - amino_acid='M' - - residue.SetFloatProp("solvent_accessibility", - solvent_accessibility) - if calculate_relative_sa: - relative_sa=_CalcRelativeSA(amino_acid,solvent_accessibility) - residue.SetFloatProp("relative_solvent_accessibility", - relative_sa) - if relative_sa < 0.25: - residue.SetStringProp("burial_status", 'b') - else: - residue.SetStringProp("burial_status", 'e') + if extract_burial_status: + #set default (dummy) burial status for incomplete residues: + residue.SetStringProp("burial_status", 'X') + + #handle seleno-methionine appearing as amino acid 'X' in DSSP: + if residue.name=="MSE" and amino_acid=='X': + amino_acid='M' + + residue.SetFloatProp("solvent_accessibility", + solvent_accessibility) + if calculate_relative_sa: + relative_sa=_CalcRelativeSA(amino_acid,solvent_accessibility) + residue.SetFloatProp("relative_solvent_accessibility", + relative_sa) + if relative_sa < 0.25: + residue.SetStringProp("burial_status", 'b') + else: + residue.SetStringProp("burial_status", 'e') except Exception, e: print "ERROR:",e continue @@ -174,7 +213,7 @@ def LoadDSSP(file_name, model, extract_burial_status_flag=0, elif rtype=='G': rt=mol.SecStructure.THREE_TEN_HELIX # for corrupted DSSP files. Catch in calling routine: - if residue.IsValid() == 0: + if not residue.IsValid(): #Todo: if residues with occupancy 0 have been removed before #using a selection statement, they are missed here #IMPORTANT: asign DSSP before any selections diff --git a/modules/bindings/pymod/msms.py b/modules/bindings/pymod/msms.py index d928f6c57ae1ddcdd8abd0f1af3d3163e070eac0..92f9494cf836c149e5a4330e922c008c63ba9c2f 100644 --- a/modules/bindings/pymod/msms.py +++ b/modules/bindings/pymod/msms.py @@ -25,12 +25,11 @@ from ost import settings from ost import geom - -## \brief custom exception that substitutes CalledProcessError -# -# Python 2.4 does not include the CalledProcessError exception. -# This one substitutes it class MsmsProcessError(Exception): + """ + Python 2.4 and older do not include the CalledProcessError exception. This + class substitutes it. + """ def __init__(self, returncode,command): self.returncode = returncode self.command = command @@ -39,6 +38,9 @@ class MsmsProcessError(Exception): def GetVersion(msms_exe=None, msms_env=None): + """ + Get version of MSMS executable + """ msms_executable = _GetExecutable(msms_exe, msms_env) command = "%s" % (msms_executable) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) @@ -53,24 +55,32 @@ def GetVersion(msms_exe=None, msms_env=None): LogWarning('Could not parse MSMS version string') return -## \brief Method to check if MSMS executable is present -# -# \param msms_exe Explicit path to msms executable -# \param msms_env Environment variable pointing to msms executable -# \return Path to the executable -# \exception FileNotFound if executable is not found + def _GetExecutable(msms_exe, msms_env): + """ + Function to check if MSMS executable is present + + :param msms_exe: Explicit path to msms executable + :param msms_env: Environment variable pointing to msms executable + :returns: Path to the executable + :raises: :class:`~ost.FileNotFound` if executable is not found + """ return settings.Locate('msms', explicit_file_name=msms_exe, env_name=msms_env) -## \brief Setup files for MSMS calculation in temporary directory -# -# \param entity EntityHandle or EntityView to calculate surface -# \param selection Calculate surface for subset of entity -# \return Touple containing temporary directory and msms input file -# \exception RuntimeError if selection is not valid + def _SetupFiles(entity, selection): - # create temporary directory + """ + Setup files for MSMS calculation in temporary directory + + :param entity: The entity for which the surface is to be calculated + :type entity: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityHandle` + :param selection: Calculate surface for subset of entity + :type selection: :class:`str` + :returns: tuple containing temporary directory and msms input file + :raises: :class:`RuntimeError` if selection is not valid + """ + # create temporary directory tmp_dir_name=tempfile.mkdtemp() # select only heavy atoms if no_hydrogens is true @@ -89,46 +99,55 @@ def _SetupFiles(entity, selection): return (tmp_dir_name, tmp_file_name) -## \brief Reads Area file (-af) and attach sasa and sesa per atom to an entitiy -# -# \param entity EntityHandle or EntityView for attaching sasa and sesa on atom level -# \param file Filename of area file -# \param asa_prop Name of the float property for SASA -# \param esa_prop Name of the float property for SESA -# \exception RuntimeError if number of atoms in file != number of atoms in entity + def _ParseAreaFile(entity,file, asa_prop, esa_prop): - 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)) - for l in area_lines: - atom_no, sesa, sasa = l.split() - a = entity.atoms[int(atom_no)] - if asa_prop: - a.SetFloatProp(asa_prop, float(sasa)) - if esa_prop: - a.SetFloatProp(esa_prop, float(sesa)) + """ + Reads Area file (-af) and attach sasa and sesa per atom to an entitiy + + :param entity: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView` + for attaching sasa and sesa on atom level + :param file: Filename of area file + :param asa_prop: Name of the float property for SASA + :param esa_prop: Name of the float property for SESA + :raises: :class:`RuntimeError` if number of atoms in file != number of atoms in entity + """ + 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)) + for l in area_lines: + atom_no, sesa, sasa = l.split() + a = entity.atoms[int(atom_no)] + if asa_prop: + a.SetFloatProp(asa_prop, float(sasa)) + if esa_prop: + a.SetFloatProp(esa_prop, float(sesa)) -## \brief Method which recursively deletes a directory -# -# \warning This method removes also non-empty directories without asking, so -# be careful! -def __CleanupFiles(dir_name): + +def _CleanupFiles(dir_name): + """ + Function which recursively deletes a directory and all the files contained + in it. *Warning*: This method removes also non-empty directories without + asking, so be careful! + """ import shutil shutil.rmtree(dir_name) -## \brief Method to run the MSMS surface calculation -# -# This method starts the external MSMS executable and returns the stdout of MSMS -# -# \param command Command to execute -# \return stdout of MSMS -# \exception CalledProcessError for non-zero return value def _RunMSMS(command): + """ + Run the MSMS surface calculation + + This functions starts the external MSMS executable and returns the stdout of + MSMS. + + :param command: Command to execute + :returns: stdout of MSMS + :raises: :class:`CalledProcessError` for non-zero return value + """ proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) stdout_value, stderr_value = proc.communicate() @@ -140,33 +159,36 @@ def _RunMSMS(command): return stdout_value -## \brief Calculates analytical solvent excluded and solvent accessible surface -# area by using the external MSMS program -# -# This method calculates the molecular surface areas 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 -# \return Touplet of lists for (SES, SAS) + def CalculateSurfaceArea(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 analytical solvent excluded and solvent accessible surface + area by using the external MSMS program. + + This method calculates the molecular surface areas 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 @@ -222,35 +244,38 @@ def CalculateSurfaceArea(entity, density=1.0, radius=1.5, all_surf=False, # clean up if not keep_files: - __CleanupFiles(msms_data_dir) + _CleanupFiles(msms_data_dir) return (msms_ases, msms_asas) -## \brief Calculates molecular surface by using the external MSMS program -# -# This method calculates a 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 for all cavities (returns multiple -# surfaces 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 -# \return list of OST SurfaceHandle objects + def CalculateSurface(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): + """ + Calculates molecular surface by using the external MSMS program + + This method calculates a 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: Entity for which the surface is to be calculated + :param density: Surface point density + :param radius: Surface probe radius + :param all_surf: Calculate surface for all cavities (returns multiple + surfaces 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 + :returns: list of :class:`~ost.mol.SurfaceHandle` objects + """ import os import re @@ -300,7 +325,7 @@ def CalculateSurface(entity, density=1.0, radius=1.5, all_surf=False, # clean up if not keep_files: - __CleanupFiles(msms_data_dir) + _CleanupFiles(msms_data_dir) return msms_surfaces diff --git a/modules/bindings/pymod/tmtools.py b/modules/bindings/pymod/tmtools.py index df545b9c116e10ccca2a8d4ece559a2d5fc21f78..2b0c712149e3337de117812fa12b82af58917e46 100644 --- a/modules/bindings/pymod/tmtools.py +++ b/modules/bindings/pymod/tmtools.py @@ -43,7 +43,35 @@ def _CleanupFiles(dir_name): shutil.rmtree(dir_name) class TMAlignResult: - def __init__(self, rmsd, tm_score, aligned_length, transform, ref_sequence, alignment): + """ + Holds the result of running TMalign + + .. attribute:: rmsd + + The RMSD of the common Calpha atoms of both structures + + .. attribute:: transform + + The transform that superposes the model onto the reference structure. + + :type: :class:`~ost.geom.Mat4` + + .. attribute:: alignment + + The alignment of the structures, that is the pairing of Calphas of both + structures. Since the programs only read ATOM records, residues consisting + of HETATMs (MSE) are not included in the alignment. + + :type: :class:`~ost.seq.AlignmentHandle` + + .. attribute:: tm_score + + The TM-score of the structural superposition + + """ + def __init__(self, rmsd, tm_score, aligned_length, transform, + ref_sequence, alignment): + self.rmsd=rmsd self.tm_score=tm_score self.aligned_length=aligned_length @@ -133,6 +161,36 @@ def _RunMmAlign(mmalign, tmp_dir): return _ParseMmAlign(lines) class TMScoreResult: + """ + Holds the result of running TMscore + + .. attribute:: rmsd_common + + The RMSD of the common Calpha atoms of both structures + + .. attribute:: rmsd_below_five + + The RMSD of all Calpha atoms that can be superposed below five Angstroem + + .. attribute:: tm_score + + The TM-score of the structural superposition + + .. attribute:: transform + + The transform that superposes the model onto the reference structure. + + :type: :class:`~ost.geom.Mat4` + + .. attribute:: gdt_ha + + The GDT_HA of the model to the reference structure. + + .. attribute:: gdt_ts + + The GDT_TS of the model to the reference structure. + + """ def __init__(self, rmsd_common, tm_score, max_sub, gdt_ts, gdt_ha, rmsd_below_five, transform): self.rmsd_common=rmsd_common @@ -182,7 +240,21 @@ def _RunTmScore(tmscore, tmp_dir): def TMAlign(model1, model2, tmalign=None): """ - Run tmalign on two protein structures + Performs a sequence independent superposition of model1 onto model2, the + reference. + + + :param model1: The model structure. If the superposition is successful, will + be superposed onto the reference structure + :type model1: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle` + :param model2: The reference structure + :type model2: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle` + :param tmalign: If not None, the path to the tmalign executable. + :returns: The result of the tmscore superposition + :rtype: :class:`TMAlignResult` + + :raises: :class:`~ost.settings.FileNotFound` if tmalign could not be located. + :raises: :class:`RuntimeError` if the superposition failed """ tmp_dir_name=_SetupFiles((model1, model2)) result=_RunTmAlign(tmalign, tmp_dir_name) @@ -202,7 +274,20 @@ def MMAlign(model1, model2, mmalign=None): def TMScore(model1, model2, tmscore=None): """ - Run tmscore on two protein structures + Performs a sequence dependent superposition of model1 onto model2, + the reference. + + :param model1: The model structure. If the superposition is successful, will + be superposed onto the reference structure + :type model1: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle` + :param model2: The reference structure + :type model2: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle` + :param tmscore: If not None, the path to the tmscore executable. + :returns: The result of the tmscore superposition + :rtype: :class:`TMScoreResult` + + :raises: :class:`~ost.settings.FileNotFound` if tmalign could not be located. + :raises: :class:`RuntimeError` if the superposition failed """ tmp_dir_name=_SetupFiles((model1, model2)) result=_RunTmScore(tmscore, tmp_dir_name) diff --git a/modules/index.rst b/modules/index.rst index d44b3aaa9c303f3d9818a072afbfeddebe9a614a..05c38c4dc9b944734eefbcf037196fe2f788ebc2 100644 --- a/modules/index.rst +++ b/modules/index.rst @@ -18,6 +18,8 @@ OpenStructure documentation seq/base/seq seq/alg/seqalg + bindings/bindings + io/io gfx/gfx gui/gui