diff --git a/modelling/src/model.cc b/modelling/src/model.cc index 4504b7ea1c18b08e6dbcd982f3a53a8e65b29921..5740b93207b3c9d07a9dc790c1fe63f457609ad3 100644 --- a/modelling/src/model.cc +++ b/modelling/src/model.cc @@ -516,6 +516,8 @@ void MergeMHandle(const ModellingHandle& source_mhandle, if(c.IsValid() && n.IsValid()) ed.Connect(c, n); } ed.ReorderResidues(target_chain); + //fix torsions + ost::conop::AssignBackboneTorsions(target_chain); //delete the gaps in the target mhandle or shorten them... num.SetNum(start_resnum); diff --git a/modelling/tests/test_modelling.py b/modelling/tests/test_modelling.py index 56b5588d280c2c4cb944ba25be601cfdae5a89f5..7e1bebee4221149467c1cb435103ab598968bdc2 100644 --- a/modelling/tests/test_modelling.py +++ b/modelling/tests/test_modelling.py @@ -3,9 +3,10 @@ Unit tests for modelling. """ import unittest from promod3 import modelling -from ost import conop, seq, io, mol +from ost import conop, seq, io, mol, geom class ModellingTests(unittest.TestCase): + def setUp(self): compound_lib = conop.CompoundLib.Load( 'data/compounds.chemlib') @@ -14,6 +15,28 @@ class ModellingTests(unittest.TestCase): compound_lib) ####################################################################### + # HELPERs + ####################################################################### + def checkModel(self, mhandle): + ''' + Check if model residues are properly set (peptide_linking, protein, + torsion). + ''' + # check residue properties + for r in mhandle.model.residues: + # check types + self.assertTrue(r.peptide_linking) + self.assertTrue(r.is_protein) + # check links + if r.next.IsValid() and (r.next.number - r.number) == 1: + self.assertTrue(mol.InSequence(r, r.next)) + # check torsions + if r.prev.IsValid() and mol.InSequence(r.prev, r): + self.assertTrue(r.phi_torsion.IsValid()) + self.assertTrue(r.omega_torsion.IsValid()) + if r.next.IsValid() and mol.InSequence(r, r.next): + self.assertTrue(r.psi_torsion.IsValid()) + ####################################################################### def testRaiseNoAttachedView(self): # test that BuildRawModel throws exception when no view is attached @@ -123,6 +146,73 @@ class ModellingTests(unittest.TestCase): ####################################################################### + def testModellingHandleOperations(self): + # handle with gap + tpl = io.LoadPDB('data/1crn_cut.pdb') + aln = io.LoadAlignment('data/1crn.fasta') + aln.AttachView(1, tpl.CreateFullView()) + mhandle = modelling.BuildRawModel(aln) + + # check ModellingHandle + self.assertEqual(len(mhandle.gaps), 1) + self.assertEqual(str(mhandle.gaps[0]), 'A.ALA24-(ICATYT)-A.GLY31') + self.checkModel(mhandle) + + # check copy + mhandle_copy = mhandle.Copy() + self.assertEqual([str(a) for a in mhandle_copy.model.atoms], + [str(a) for a in mhandle.model.atoms]) + self.assertEqual([str(g) for g in mhandle_copy.gaps], + [str(g) for g in mhandle.gaps]) + self.assertEqual([str(s) for s in mhandle_copy.seqres], + [str(s) for s in mhandle.seqres]) + # rest of the fields not checked...yet + + # handle without gap + tpl_closed = io.LoadPDB('data/1crn_build.pdb') + seqres = str(aln.sequences[0]) + aln_closed = seq.CreateAlignment(seq.CreateSequence('trg', seqres), + seq.CreateSequence('tpl', seqres)) + aln_closed.AttachView(1, tpl_closed.CreateFullView()) + mhandle_closed = modelling.BuildRawModel(aln_closed) + + # merge with no overlap (no change) + mhandle_copy = mhandle.Copy() + modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 10, 19, + geom.Mat4()) + self.assertEqual([str(a) for a in mhandle_copy.model.atoms], + [str(a) for a in mhandle.model.atoms]) + self.assertEqual([str(g) for g in mhandle_copy.gaps], + [str(g) for g in mhandle.gaps]) + self.assertEqual([str(s) for s in mhandle_copy.seqres], + [str(s) for s in mhandle.seqres]) + self.checkModel(mhandle_copy) + + # merge with overlap on N-side + mhandle_copy = mhandle.Copy() + modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 20, 29, + geom.Mat4()) + self.assertEqual(len(mhandle_copy.gaps), 1) + self.assertEqual(str(mhandle_copy.gaps[0]), 'A.TYR29-(T)-A.GLY31') + self.checkModel(mhandle_copy) + + # merge with overlap on C-side + mhandle_copy = mhandle.Copy() + modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 27, 35, + geom.Mat4()) + self.assertEqual(len(mhandle_copy.gaps), 1) + self.assertEqual(str(mhandle_copy.gaps[0]), 'A.ALA24-(IC)-A.ALA27') + self.checkModel(mhandle_copy) + + # merge with full overlap + mhandle_copy = mhandle.Copy() + modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 20, 35, + geom.Mat4()) + self.assertEqual(len(mhandle_copy.gaps), 0) + self.checkModel(mhandle_copy) + + ####################################################################### + def testMergeGaps(self): tpl = io.LoadPDB('data/1mcg.pdb') aln = seq.CreateAlignment(seq.CreateSequence('trg', 'DDFAGTHN'),