Пример #1
0
def AddFromFiles(force_field, frcmod_filename, mpdb_filename):
    """Add data from a frcmod and an mpdb file to a force field.

  This will add a new :class:`~ost.mol.mm.BuildingBlock` to `force_field` for
  the residue defined in those files (residue name is extracted from the mpdb
  file which can only contain a single residue). Charges for each atom are
  extracted from the mpdb file. According to the frcmod file, an
  :class:`~ost.mol.mm.Interaction` is added for each bond, angle, dihedral and
  improper. Atom types with masses and non-bonded interactions are added to
  `force_field` as needed.

  :param force_field: A force field object to which the new parameters are
                      added.
  :type force_field:  :class:`~ost.mol.mm.Forcefield`
  :param frcmod_filename: Path to ``frcmod`` file as generated by ``parmchk2``.
  :type frcmod_filename:  :class:`str`
  :param mpdb_filename: Path to mpdb file as generated by ``antechamber``.
  :type mpdb_filename:  :class:`str`
  :return: The updated force field (same as `force_field`).
  :rtype:  :class:`~ost.mol.mm.Forcefield`
  """
    # check files
    if not os.path.exists(frcmod_filename):
        raise RuntimeError("Could not find frcmod file: " + frcmod_filename)
    if not os.path.exists(mpdb_filename):
        raise RuntimeError("Could not find mpdb file: " + mpdb_filename)
    # read in files
    try:
        eh, res_name = _ParseModifiedPDB(mpdb_filename)
    except Exception as ex:
        ost.LogError("Failed to parse mpdb file: " + mpdb_filename)
        raise ex
    try:
        ff_dict = _ParseAmberForceField(frcmod_filename)
    except Exception as ex:
        ost.LogError("Failed to parse frcmod file: " + frcmod_filename)
        raise ex
    ost.LogInfo("Adding force field for " + res_name)
    # add atoms to force field
    for aname, mass in ff_dict['MASS']:
        force_field.AddMass(aname, mass)
    # add LJs
    lj_sigma_scale = 2. / 10. / 2**(1. / 6.)  # Rvdw to sigma in nm
    lj_epsilon_scale = 4.184  # kcal to kJ
    for aname, Rvdw, epsilon in ff_dict['NONB']:
        # fix 0,0 (from OpenMM's processAmberForceField.py)
        if Rvdw == 0 or epsilon == 0:
            Rvdw, epsilon = 1, 0
        lj = mm.Interaction(mm.FuncType.LJ)
        lj.SetTypes([aname])
        lj.SetParam([Rvdw * lj_sigma_scale, epsilon * lj_epsilon_scale])
        force_field.AddLJ(lj)
    # add building block
    bb = _MakeComponentBuildingBlock(eh, ff_dict)
    force_field.AddBuildingBlock(res_name, bb)

    return force_field
Пример #2
0
    def Search(self, a3m_file, database, options={}, prefix=''):
        """
        Searches for templates in the given database. Before running the search,
        the hhm file is copied. This makes it possible to launch several hhblits
        instances at once. Upon success, the filename of the result file is
        returned. This file may be parsed with :func:`ParseHHblitsOutput`.

        :param a3m_file: Path to input MSA as produced by :meth:`BuildQueryMSA`
        :type a3m_file: :class:`str`

        :param database: Search database, needs to be the common prefix of the
                         database files
        :type database: :class:`str`

        :param options: Dictionary of options to *hhblits*, one "-" is added in
                        front of every key. Boolean True values add flag without
                        value. Merged with default options {'cpu': 1, 'n': 1},
                        where 'n' defines the number of iterations.
        :type options: :class:`dict`

        :param prefix: Prefix to the result file
        :type prefix: :class:`str`

        :return: The path to the result file
        :rtype: :class:`str`
        """
        opts = {'cpu' : 1, # no. of cpus used
                'n'   : 1}   # no. of iterations
        opts.update(options)
        opt_cmd, opt_str = _ParseOptions(opts)
        base = os.path.basename(os.path.splitext(a3m_file)[0])
        hhr_file = '%s%s_%s.hhr' % (prefix, base, opt_str)
        hhr_file = os.path.join(self.working_dir, hhr_file)
        search_cmd = '%s %s -e 0.001 -Z 10000 -B 10000 -i %s -o %s -d %s' % (
            self.hhblits_bin,
            opt_cmd,
            os.path.abspath(a3m_file),
            os.path.abspath(hhr_file),
            os.path.join(os.path.abspath(os.path.split(database)[0]),
                         os.path.split(database)[1]))
        ost.LogInfo('searching %s' % database)
        ost.LogVerbose(search_cmd)
        job = subprocess.Popen(search_cmd, shell=True, cwd=self.working_dir,
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        sout, serr = job.communicate()
        if job.returncode != 0:
            lines = sout.decode().splitlines()
            for line in lines:
                ost.LogError(line.strip())
            lines = serr.decode().splitlines()
            for line in lines:
                ost.LogError(line.strip())
            return None
        return hhr_file
 def _Select(self):
   scene_selection=gui.SceneSelection.Instance()
   ent=scene_selection.GetActiveNode(0)
   dialog=QueryDialog('Select...')
   if dialog.exec_():
     q=mol.Query(dialog.query)
     if q.IsValid():
       ent.selection=ent.view.Select(dialog.query, dialog.query_flags)
     else:
       ost.LogError("invalid query: %s" % q.error)
Пример #4
0
 def testLogMessage(self):
   ls = _CapturingLogSink()
   ost.PushVerbosityLevel(1)
   ost.PushLogSink(ls)
   ost.LogError('error message')
   self.assertEqual(ls.message, 'error message\n')
   self.assertEqual(ls.severity, 0)
   ost.LogWarning(1, 2, 3)
   self.assertEqual(ls.message, '1 2 3\n')
   self.assertEqual(ls.severity, 1)
   ost.PopLogSink()
  def _SelectViewsSameEntity(self):

    union=gui.SceneSelection.Instance().GetViewUnion()
    dialog=QueryDialog('Select...')
    if dialog.exec_():
      q=mol.Query(dialog.query)    
      if q.IsValid():
        ve=gui.SceneSelection.Instance().GetViewEntity()
        ve.selection=union.Select(q, dialog.query_flags)
      else:    
        ost.LogError("invalid query: %s" % q.error)    
 def _CopyViews(self):
   views_to_add=[]
   scene_selection=gui.SceneSelection.Instance()
   ent=scene_selection.GetActiveNode(0)
   dialog=QueryDialog('Select...')
   if dialog.exec_():
     q=mol.Query(dialog.query)
     if q.IsValid():
       for i in range(scene_selection.GetActiveNodeCount()):
         ent=scene_selection.GetActiveNode(i)
         selected=ent.view.Select(q, dialog.query_flags)
         gfx_ent=gfx.Entity(self._UniqueName(ent),selected)
         gfx.Scene().Add(gfx_ent)
     else:    
       ost.LogError("invalid query: %s" % q.error)
Пример #7
0
def ParseBlastOutput(string, seqid_thres=0, evalue_thres=float("infinity")):
  """
  Parses the blast output and returns a list of BlastHits
  setting no seqid_thres or evalue_thres, restores default behaviour without filtering
  """
  def _GetText(node):
    rc=''
    for child in node.childNodes:
        if child.nodeType==child.TEXT_NODE:
            rc+=child.data
    return rc

  def _GetValue(node, tag_name):
    tag=node.getElementsByTagName(tag_name)
    assert len(tag)==1
    return _GetText(tag[0])

  def _GetInt(node, tag_name):
    return int(_GetValue(node, tag_name))

  def _ParseHsp(query_id, hit_id, hsp, tot_query_len, seqid_thres=0, evalue_thres=float("infinity")):
    bit_score=float(_GetValue(hsp, 'Hsp_bit-score'))
    score=float(_GetValue(hsp, 'Hsp_score'))
    evalue=float(_GetValue(hsp, 'Hsp_evalue'))
    try:
      identity=float(_GetValue(hsp, 'Hsp_identity'))
    except AssertionError:
      # The Hsp_identity tag is not a 'must' in the BLAST XML format. It
      # describes the number of matching characters. Hence we assume, if it is
      # missing, there are 0 matches.
      identity=0
    hsp_align_len=float(_GetValue(hsp, 'Hsp_align-len'))
    seqid=identity/hsp_align_len
    query_offset=_GetInt(hsp, 'Hsp_query-from')-1
    hit_offset=_GetInt(hsp, 'Hsp_hit-from')-1
    query_seq=seq.CreateSequence(str(query_id), str(_GetValue(hsp, 'Hsp_qseq')))
    query_seq.offset=query_offset
    hit_seq=seq.CreateSequence(str(hit_id), str(_GetValue(hsp, 'Hsp_hseq')))
    hit_seq.offset=hit_offset
    try:
      if seqid > float(seqid_thres) and evalue < evalue_thres:
        aln=seq.CreateAlignment(query_seq, hit_seq)
        return AlignedPatch(aln, bit_score, score, evalue, seqid)

    except Exception as e:
      print(str(e), query_seq, hit_seq)

  try:
    doc=minidom.parseString(string)
  except Exception as e:
    ost.LogError('Error while parsing BLAST output: %s' % str(e))
    return None
  hits=[]
  query_id=_GetValue(doc, 'BlastOutput_query-def')
  tot_query_len=_GetValue(doc, 'BlastOutput_query-len')
  for hit in doc.getElementsByTagName('Hit'):
    hit_id=_GetValue(hit, 'Hit_def')
    hsps=hit.getElementsByTagName('Hsp')
    aligned_patches=[_ParseHsp(query_id, hit_id, hsp, tot_query_len, seqid_thres, evalue_thres) for hsp in hsps]
    hits.append(BlastHit(hit_id, aligned_patches))
  return hits
Пример #8
0
def RunAntechamber(res_name,
                   filename,
                   format='ccif',
                   amberhome=None,
                   base_out_dir=None):
    """Run Antechamber to guess force field parameters for a given residue name.

  This requires an installation of AmberTools (tested with AmberTools15) with
  binaries ``antechamber`` and ``parmchk2``.

  This has the same restrictions as Antechamber itself and we assume the input
  to be uncharged. Note that Antechamber cannot deal with metal ions and other
  non-organic elements.

  The results are stored in a separate folder named `res_name` within
  `base_out_dir` (if given, otherwise the current working directory). The main
  output files are ``frcmod`` and ``out.mpdb``. The former contains force field
  parameters and masses. The latter maps atom names to atom types and defines
  the partial charges. The same output could be obtained as follows:

  .. code-block:: console

     $ antechamber -i <FILENAME> -fi <FORMAT> -bk '<RES_NAME>' -o out.mol2 -fo mol2 -c bcc -pf yes
     $ parmchk2 -i out.mol2 -f mol2 -o frcmod -a Y
     $ antechamber -i out.mol2 -fi mol2 -o out.mpdb -fo mpdb -pf yes

  The force field parameters can be manually modified if needed. It can for
  instance happen that some parameters cannot be identified. Those lines will
  be marked with a comment "ATTN, need revision".

  :param res_name: Residue name for which we desire force field parameters.
  :type res_name:  :class:`str`
  :param filename: Path to a file which contains the necessary information for
                   `res_name`. It must include all hydrogens.
  :type filename:  :class:`str`
  :param format: Format of file given with `filename`. Common formats are 'ccif'
                 for PDB's component dictionary or 'pdb' for a PDB file
                 containing the desired residue with all hydrogens.
  :type format:  :class:`str`
  :param amberhome: Base path of your AmberTools installation. If not None,
                    we look for ``antechamber`` and ``parmchk2`` within
                    ``AMBERHOME/bin`` additionally to the system's ``PATH``.
  :type amberhome:  :class:`str`
  :param base_out_dir: Path to a base path, where the output will be stored.
                       If None, the current working directory is used.
  :type base_out_dir:  :class:`str`
  """
    # find antechamber binaries
    if amberhome is None:
        search_paths = []
    else:
        search_paths = [os.path.join(amberhome, 'bin')]
    try:
        antechamber = settings.Locate('antechamber', search_paths=search_paths)
        parmchk2 = settings.Locate('parmchk2', search_paths=search_paths)
    except settings.FileNotFound as ex:
        ost.LogError("Failed to find Antechamber binaries. Make sure you have "
                     "AmberTools installed!")
        raise ex

    # prepare path
    cwd = os.getcwd()
    if base_out_dir is None:
        base_out_dir = cwd
    out_dir = os.path.abspath(os.path.join(base_out_dir, res_name))
    if not os.path.exists(out_dir):
        # note: this creates intermediate folders too
        try:
            os.makedirs(out_dir)
        except Exception as ex:
            ost.LogError("Failed to create output directory " + out_dir + "!")
            raise ex

    # execute it
    os.chdir(out_dir)
    try:
        cmds = [antechamber + " -i " + filename + " -fi " + format + " -bk " \
                + res_name + " -o out.mol2 -fo mol2 -c bcc -pf yes",
                parmchk2 + " -i out.mol2 -f mol2 -o frcmod -a Y",
                antechamber + " -i out.mol2 -fi mol2 -o out.mpdb -fo mpdb -pf yes"]
        all_sout = "Generating force field parameters for " + res_name + "\n"
        all_serr = ""
        for cmd in cmds:
            all_sout += "-" * 70 + "\n" + "Stdout of: " + cmd + "\n" + "-" * 70 + "\n"
            all_serr += "-" * 70 + "\n" + "Stderr of: " + cmd + "\n" + "-" * 70 + "\n"
            job = subprocess.Popen(cmd.split(" "),
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            sout, serr = job.communicate()
            all_sout += sout
            all_serr += serr
            if job.returncode != 0:
                ost.LogError("Unsuccessful execution of " + cmd + ". Return code: "\
                             + str(job.returncode))
        # write command line outputs
        with open("console.stdout", "w") as txt_file:
            txt_file.write(all_sout)
        with open("console.stderr", "w") as txt_file:
            txt_file.write(all_serr)
    except Exception as ex:
        ost.LogError("Failed to excecute antechamber binaries!")
        raise ex

    # get back to original path
    os.chdir(cwd)

    # check result
    frcmod_filename = os.path.join(out_dir, 'frcmod')
    mpdb_filename = os.path.join(out_dir, 'out.mpdb')
    if not os.path.exists(frcmod_filename):
        raise RuntimeError("Failed to generate frcmod file with Antechamber!")
    if not os.path.exists(mpdb_filename):
        raise RuntimeError(
            "Failed to generate out.mpdb file with Antechamber!")
Пример #9
0
def compare_structures(model, reference):
    """ Compare the structures and return an lDDT value. """
    with temporary_file(delete=False) as model_file, \
            temporary_file(delete=False) as target_file, \
            temporary_file(delete=False) as output_file:
        # We'll open/close the file later by name so we don't want python
        # to mess up
        model_file.close()
        target_file.close()
        output_file.close()
        ost.io.SavePDB(model, model_file.name)
        ost.io.SavePDB(reference, target_file.name)
        cmd = [
            '/usr/bin/env',
            'ost',
            'compare-structures',
            '-r',
            target_file.name,
            '-m',
            model_file.name,
            '-o',
            output_file.name,
            '--lddt',
            '-v',
            str(ost.GetVerbosityLevel()),
            '--residue-number-alignment'  # do not re-align
        ]
        proc = subprocess.Popen(cmd,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        if proc.returncode != 0:
            if reference.atom_count == 0:
                # Reference is empty, probably because it covered an other
                # portion of the target sequence that doesn't include our
                # domain of interest. We keep track of this hit with missing
                # values (None)
                ost.LogWarning(
                    "The reference structure appears to be empty. " +
                    "This probably means it didn't cover this " +
                    "domain. Returning missing values.")
                return {
                    'weighted_lddt': None,
                    'oligo_lddt': None,
                    'single_chain_lddt': None,
                    'coverage': None,
                    'chain_mapping': None,
                    'best_chain': None,
                }
            else:
                ost.LogError(
                    "ost compare-structures returned %s, error stream included below "
                    % proc.returncode)
                ost.LogError(stderr)
                raise RuntimeError("ost compare-structure returned %s" %
                                   proc.returncode)
        compare_data = json.load(open(output_file.name))
        try:
            compare_results = compare_data['result'][os.path.basename(
                model_file.name)][os.path.basename(target_file.name)]
        except KeyError:
            ost.LogError("ost compare-structures retured a success code but " +
                         "the expected data is not available. This is " +
                         "probably caused by an acceptable error such as " +
                         "a failure in chain mapping. Returning missing " +
                         "values. STDERR output included below: ")
            ost.LogError(stderr)
            return {
                'weighted_lddt': None,
                'oligo_lddt': None,
                'single_chain_lddt': None,
                'coverage': None,
                'chain_mapping': None,
                'best_chain': None,
            }

        # What is the coverage of the model?
        coverages = []
        for aln_str in compare_results['info']['mapping']['alignments']:
            aln = ost.io.AlignmentFromString(str(aln_str), 'fasta')
            coverages.append(aln.GetCoverage(1))
            assert aln.GetCount() == 2

        lddt_results = compare_results['lddt']
        # single_chain_lddts = []
        best_single_chain_lddt = 0
        best_chain = None
        for sc_lddt in lddt_results['single_chain_lddt']:
            assert sc_lddt['status'] == 'SUCCESS'
            # single_chain_lddts.append(sc_lddt['global_score'])
            if sc_lddt['global_score'] >= best_single_chain_lddt:
                best_single_chain_lddt = sc_lddt['global_score']
                best_chain = sc_lddt['model_chain']

        assert lddt_results['oligo_lddt']['status'] == 'SUCCESS'
        assert lddt_results['weighted_lddt']['status'] == 'SUCCESS'

        return {
            'weighted_lddt': lddt_results['weighted_lddt']['global_score'],
            'oligo_lddt': lddt_results['oligo_lddt']['global_score'],
            'single_chain_lddt': best_single_chain_lddt,
            'best_chain': best_chain,
            'coverage': max(coverages),
            'chain_mapping':
            compare_results['info']['mapping']['chain_mapping'],
        }
Пример #10
0
import ost
from ost.mol.alg import qsscoring

# load two biounits to compare
ent_full = ost.io.LoadPDB('3ia3', remote=True)
ent_1 = ent_full.Select('cname=A,D')
ent_2 = ent_full.Select('cname=B,C')
# get score
ost.PushVerbosityLevel(3)
try:
    qs_scorer = qsscoring.QSscorer(ent_1, ent_2)
    ost.LogScript('QSscore:', str(qs_scorer.global_score))
    ost.LogScript('Chain mapping used:', str(qs_scorer.chain_mapping))
except qsscoring.QSscoreError as ex:
    # default handling: report failure and set score to 0
    ost.LogError('QSscore failed:', str(ex))
    qs_score = 0

print("OST is working!")