diff --git a/modelling/doc/index.rst b/modelling/doc/index.rst index a0e0a7b513a7b97d8333033aa36de8c87fd85d0c..b7ae5aba1cc2dad4174bf0c68ea61ac2db61938d 100644 --- a/modelling/doc/index.rst +++ b/modelling/doc/index.rst @@ -106,9 +106,23 @@ Closing Gaps .. autofunction:: CloseLargeDeletions +.. function:: CountEnclosedGaps(mhandle, gap) + CountEnclosedInsertions(mhandle, gap) + + Counts all gaps from `mhandle` which are fully enclosed by given `gap`. + This is either all gaps or only insertions. + + :param mhandle: Modelling handle on which to apply change. + :type mhandle: :class:`ModellingHandle` + :param gap: Gap defining range in which gaps are to be removed. + :type gap: :class:`StructuralGap` + + :return: Number of gaps. + :rtype: :class:`int` + .. function:: ClearGaps(mhandle, gap) - Removes all gaps from mhandle which are fully enclosed by given gap. + Removes all gaps from `mhandle` which are fully enclosed by given `gap`. :param mhandle: Modelling handle on which to apply change. :type mhandle: :class:`ModellingHandle` diff --git a/modelling/pymod/_closegaps.py b/modelling/pymod/_closegaps.py index 8cbf086b15ad964e697de80e19b0997bcb2a6818..55f3ba293f9a08e0e72d8de247a9558865cb2589 100644 --- a/modelling/pymod/_closegaps.py +++ b/modelling/pymod/_closegaps.py @@ -502,6 +502,8 @@ def FillLoopsByDatabase(mhandle, scorer, fragment_db, structure_db, # keep copy of original gap gap_orig = mhandle.gaps[gap_idx].Copy() + if score_variant == 0: + gap_ins = CountEnclosedInsertions(mhandle, gap_orig) # terminal gaps are no loops, database needs 2 stems to work on if gap_orig.IsTerminal(): @@ -525,6 +527,9 @@ def FillLoopsByDatabase(mhandle, scorer, fragment_db, structure_db, max_db_loop_len) # iteratively extend actual_gap until we have enough loops while actual_gap.length <= max_db_loop_len: + # check if we have enough + if found_loops >= max_loops_to_search: + break # extend the gap if not actual_extender.Extend(): break @@ -532,10 +537,10 @@ def FillLoopsByDatabase(mhandle, scorer, fragment_db, structure_db, if not actual_gap.before.IsValid() or \ not actual_gap.after.IsValid(): break - - # check if we have enough - if found_loops >= max_loops_to_search: - break + # skip if we try to merge insertions with score_variant=0 + if score_variant == 0 and \ + CountEnclosedInsertions(mhandle, actual_gap) != gap_ins: + continue # get candidates for the current loop candidates = loop.LoopCandidates.FillFromDatabase( @@ -643,6 +648,8 @@ def FillLoopsByMonteCarlo(mhandle, scorer, torsion_sampler, max_loops_to_search= # keep copy of original gap gap_orig = mhandle.gaps[gap_idx].Copy() + if score_variant == 0: + gap_ins = CountEnclosedInsertions(mhandle, gap_orig) # ignore terminal gaps if gap_orig.IsTerminal(): @@ -678,6 +685,10 @@ def FillLoopsByMonteCarlo(mhandle, scorer, torsion_sampler, max_loops_to_search= if not actual_gap.before.IsValid() or \ not actual_gap.after.IsValid(): break + # skip if we try to merge insertions with score_variant=0 + if score_variant == 0 and \ + CountEnclosedInsertions(mhandle, actual_gap) != gap_ins: + continue # setup sampler, closer, scorer and cooler for MC try: diff --git a/modelling/pymod/export_model.cc b/modelling/pymod/export_model.cc index 28e3b743f20410693dccfff250d6a8a1d6a793c3..5f457a2721aa48b1fa08dfd3e8ee52d86bb0090c 100644 --- a/modelling/pymod/export_model.cc +++ b/modelling/pymod/export_model.cc @@ -12,6 +12,14 @@ ModellingHandle (*BuildRawModelHandleList)(const ost::seq::AlignmentList&, bool, const String&)=&BuildRawModel; +namespace { +int WrapCountEnclosedGaps(ModellingHandle& mhandle, const StructuralGap& gap) { + return CountEnclosedGaps(mhandle, gap, false); +} +int WrapCountEnclosedIns(ModellingHandle& mhandle, const StructuralGap& gap) { + return CountEnclosedGaps(mhandle, gap, true); +} +} // anon ns void export_model() { @@ -20,9 +28,11 @@ void export_model() .def_readwrite("gaps", &ModellingHandle::gaps) .def_readwrite("seqres", &ModellingHandle::seqres) ; - def("ClearGaps",ClearGaps,(arg("gap"))); - def("MergeGaps",MergeGaps,(arg("index"))); - def("RemoveTerminalGaps",RemoveTerminalGaps); + def("ClearGaps", ClearGaps, (arg("mhandle"),arg("gap"))); + def("CountEnclosedGaps", WrapCountEnclosedGaps, (arg("mhandle"),arg("gap"))); + def("CountEnclosedInsertions", WrapCountEnclosedIns, (arg("mhandle"),arg("gap"))); + def("MergeGaps", MergeGaps, (arg("mhandle"),arg("index"))); + def("RemoveTerminalGaps", RemoveTerminalGaps, (arg("mhandle"))); def("BuildRawModel", BuildRawModelHandle, (arg("aln"), arg("include_ligands")=false, diff --git a/modelling/src/model.cc b/modelling/src/model.cc index c09654451e87e957fdee9f8a65fb5fec7bcfc298..4c99d1855da596fbb3f6007d8f30a80af6cd518d 100644 --- a/modelling/src/model.cc +++ b/modelling/src/model.cc @@ -48,6 +48,36 @@ bool CheckBackboneAtoms(ResidueView res) } +int CountEnclosedGaps(ModellingHandle& mhandle, const StructuralGap& gap, + bool insertions_only) +{ + int num_gaps = 0; + + // extract info for this gap + String my_chain_name = gap.GetChainName(); + ResNum my_b_res(0); + if (!gap.IsNTerminal()) my_b_res = gap.before.GetNumber(); + ResNum my_a_res = my_b_res + gap.GetLength() + 1; + + for (StructuralGapList::iterator i = mhandle.gaps.begin(); + i != mhandle.gaps.end(); ++i) { + + // skip different chains + if (i->GetChainName() != my_chain_name) continue; + + // get res_nums + ResNum b_res(0); + if (!i->IsNTerminal()) b_res = i->before.GetNumber(); + ResNum a_res = b_res + i->GetLength() + 1; + + // check full overlap + if (b_res >= my_b_res && a_res <= my_a_res) { + if (!insertions_only || i->GetLength() > 0) ++num_gaps; + } + } + return num_gaps; +} + int ClearGaps(ModellingHandle& mhandle, const StructuralGap& gap) { // return -1 if no more gaps diff --git a/modelling/src/model.hh b/modelling/src/model.hh index 8e7be7d2ecc5b6fd0d5f3ed8894d65b4280d2273..6ee3516c4f87a49a8e49ac64dfd354e35fbc00a8 100644 --- a/modelling/src/model.hh +++ b/modelling/src/model.hh @@ -32,6 +32,10 @@ struct ModellingHandle { ost::seq::SequenceList seqres; }; +// see Python doc +int CountEnclosedGaps(ModellingHandle& mhandle, const StructuralGap& gap, + bool insertions_only=false); + // see Python doc int ClearGaps(ModellingHandle& mhandle, const StructuralGap& gap); diff --git a/modelling/tests/test_modelling.py b/modelling/tests/test_modelling.py index 909fc2db60254011ff2a181d154d22706132a827..cfe41f7c361bf06968c2ed1a24e890dd98077d35 100644 --- a/modelling/tests/test_modelling.py +++ b/modelling/tests/test_modelling.py @@ -129,6 +129,49 @@ class ModellingTests(unittest.TestCase): with self.assertRaises(RuntimeError): modelling.MergeGaps(mhandle, 0) + def testCountEnclosedGaps(self): + tpl = io.LoadPDB('data/2dbs.pdb') + aln = seq.CreateAlignment( + seq.CreateSequence('trg', 'GATLNGFTVPAGNTLVLN---PD--KG---ATVTMAGA'), + seq.CreateSequence('tpl', '--NGG--TL--LI--PNGTYHFLGIQMKSNVHIRVE--')) + aln.AttachView(1, tpl.CreateFullView()) + mhandle = modelling.BuildRawModel(aln) + # check + self.assertEqual(len(mhandle.gaps), 8) + for g in mhandle.gaps: + self.assertEqual(modelling.CountEnclosedGaps(mhandle, g), 1) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, g), + 1 if (g.length > 0) else 0) + + mych = mhandle.model.chains[0] + # none + mygap = modelling.StructuralGap(mych.FindResidue(15), + mych.FindResidue(17), "L") + self.assertEqual(modelling.CountEnclosedGaps(mhandle, mygap), 0) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, mygap), 0) + # extended singles + mygap = modelling.StructuralGap(mych.FindResidue(3), + mych.FindResidue(9), "LNGFT") + self.assertEqual(modelling.CountEnclosedGaps(mhandle, mygap), 1) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, mygap), 1) + mygap = modelling.StructuralGap(mych.FindResidue(20), + mych.FindResidue(22), "K") + self.assertEqual(modelling.CountEnclosedGaps(mhandle, mygap), 1) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, mygap), 0) + # doubles + mygap = modelling.StructuralGap(mych.FindResidue(3), + mych.FindResidue(12), "LNGFTVPA") + self.assertEqual(modelling.CountEnclosedGaps(mhandle, mygap), 2) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, mygap), 2) + mygap = modelling.StructuralGap(mych.FindResidue(13), + mych.FindResidue(19), "TLVLN") + self.assertEqual(modelling.CountEnclosedGaps(mhandle, mygap), 2) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, mygap), 1) + mygap = modelling.StructuralGap(mych.FindResidue(20), + mych.FindResidue(25), "KGAT") + self.assertEqual(modelling.CountEnclosedGaps(mhandle, mygap), 2) + self.assertEqual(modelling.CountEnclosedInsertions(mhandle, mygap), 0) + def testClearGapsExceptions(self): tpl = io.LoadPDB('data/1mcg.pdb') aln = seq.CreateAlignment(seq.CreateSequence('trg', 'DDFAGTHN'),