diff --git a/loop/src/all_atom_positions.cc b/loop/src/all_atom_positions.cc index 42925e2b5921397231e1f2bbbaf6b95a2b31d3ce..2dad21d0e0c802bd81cc771af31c4de0127a6db5 100644 --- a/loop/src/all_atom_positions.cc +++ b/loop/src/all_atom_positions.cc @@ -7,10 +7,24 @@ namespace promod3 { namespace loop { +namespace { + // default chem. type and class for amino acids const ost::mol::ChemClass aa_chem_class(ost::mol::ChemClass::L_PEPTIDE_LINKING); const ost::mol::ChemType aa_chem_type(ost::mol::ChemType::AMINOACIDS); +// set residue props +void SetResidueProps(ost::mol::ResidueHandle& res, char olc) { + res.SetOneLetterCode(olc); + res.SetChemClass(aa_chem_class); + res.SetChemType(aa_chem_type); + res.SetIsProtein(true); +} + +} // anon ns + +/////////////////////////////////////////////////////////////////////////////// + AllAtomPositions::AllAtomPositions(const String& sequence) : aa_lookup_(AminoAcidLookup::GetInstance()) { Initialize(sequence); @@ -245,9 +259,7 @@ ost::mol::EntityHandle AllAtomPositions::ToEntity() const { } } // set residue data - res.SetOneLetterCode(aa_lookup_.GetOLC(GetAA(res_idx))); - res.SetChemClass(aa_chem_class); - res.SetChemType(aa_chem_type); + SetResidueProps(res, aa_lookup_.GetOLC(GetAA(res_idx))); } // set connections ost::conop::HeuristicProcessor heu_proc; @@ -285,9 +297,7 @@ void AllAtomPositions::InsertInto(uint res_idx, ost::mol::ChainHandle& chain, // rename if needed edi.RenameResidue(res, rname); } - res.SetOneLetterCode(aa_lookup_.GetOLC(aa)); - res.SetChemClass(aa_chem_class); - res.SetChemType(aa_chem_type); + SetResidueProps(res, aa_lookup_.GetOLC(aa)); // set new atom positions bool backbone_added = false; diff --git a/loop/src/backbone.cc b/loop/src/backbone.cc index 0a04aa1260134c0c718f9b05387d298886f9b754..edb4dd63c7dbbf09997f30d0395166e21a9104ad 100644 --- a/loop/src/backbone.cc +++ b/loop/src/backbone.cc @@ -6,10 +6,22 @@ namespace promod3 { namespace loop { +namespace { + // default chem. type and class for amino acids const ost::mol::ChemClass aa_chem_class(ost::mol::ChemClass::L_PEPTIDE_LINKING); const ost::mol::ChemType aa_chem_type(ost::mol::ChemType::AMINOACIDS); +// set residue props +void SetResidueProps(ost::mol::ResidueHandle& res, char olc) { + res.SetOneLetterCode(olc); + res.SetChemClass(aa_chem_class); + res.SetChemType(aa_chem_type); + res.SetIsProtein(true); +} + +} // anon ns + /////////////////////////////////////////////////////////////////////////////// // Backbone public Backbone::Backbone(const geom::Vec3& n, const geom::Vec3& ca, @@ -131,7 +143,8 @@ BackboneList::BackboneList(const String& sequence, } } -ost::mol::EntityHandle BackboneList::ToEntity() const{ +ost::mol::EntityHandle BackboneList::ToEntity() const { + // make entity ost::mol::EntityHandle ent = ost::mol::CreateEntity(); ost::mol::XCSEditor edi = ent.EditXCS(ost::mol::BUFFERED_EDIT); ost::mol::ChainHandle chain = edi.InsertChain("A"); @@ -152,14 +165,14 @@ ost::mol::EntityHandle BackboneList::ToEntity() const{ cb = edi.InsertAtom(res, "CB", GetCB(i), "C"); edi.Connect(ca, cb); } - res.SetOneLetterCode(GetOLC(i)); - res.SetChemClass(aa_chem_class); - res.SetChemType(aa_chem_type); + SetResidueProps(res, GetOLC(i)); if (last.IsValid()) { edi.Connect(last.FindAtom("C"), n); } last = res; } + // set torsions + ost::conop::AssignBackboneTorsions(chain); return ent; } @@ -286,9 +299,7 @@ void BackboneList::InsertInto(ost::mol::ChainHandle& chain, before = edi.AppendResidue(chain, ost::conop::OneLetterCodeToResidueName(GetOLC(0)), n_num); - before.SetOneLetterCode(GetOLC(0)); - before.SetChemClass(aa_chem_class); - before.SetChemType(aa_chem_type); + SetResidueProps(before, GetOLC(0)); ost::mol::AtomHandle n = edi.InsertAtom(before, "N", GetN(0), "N"); ost::mol::AtomHandle ca = edi.InsertAtom(before, "CA", GetCA(0), "C"); ost::mol::AtomHandle c = edi.InsertAtom(before, "C", GetC(0), "C"); @@ -358,9 +369,7 @@ void BackboneList::InsertInto(ost::mol::ChainHandle& chain, } else { // !after.IsValid() after = edi.AppendResidue(chain, ost::conop::OneLetterCodeToResidueName(GetOLC(last_idx)), c_num); - after.SetOneLetterCode(GetOLC(last_idx)); - after.SetChemClass(aa_chem_class); - after.SetChemType(aa_chem_type); + SetResidueProps(after, GetOLC(last_idx)); ost::mol::AtomHandle n = edi.InsertAtom(after, "N", GetN(last_idx), "N"); ost::mol::AtomHandle ca = edi.InsertAtom(after, "CA", GetCA(last_idx), "C"); ost::mol::AtomHandle c = edi.InsertAtom(after, "C", GetC(last_idx), "C"); @@ -399,9 +408,7 @@ void BackboneList::InsertInto(ost::mol::ChainHandle& chain, String rname = ost::conop::OneLetterCodeToResidueName(GetOLC(i)); ost::mol::ResidueHandle res = edi.AppendResidue(chain, rname, last.GetNumber() + 1); - res.SetOneLetterCode(GetOLC(i)); - res.SetChemClass(aa_chem_class); - res.SetChemType(aa_chem_type); + SetResidueProps(res, GetOLC(i)); ost::mol::AtomHandle n = edi.InsertAtom(res, "N", GetN(i), "N"); ost::mol::AtomHandle ca = edi.InsertAtom(res, "CA", GetCA(i), "C"); ost::mol::AtomHandle c = edi.InsertAtom(res, "C", GetC(i), "C"); diff --git a/loop/tests/test_all_atom_positions.cc b/loop/tests/test_all_atom_positions.cc index a37fe16cd956b62324d1a60d2b5fecb14343e07a..bdecca598bd2d86da16db22ec0d2c440f6c818a8 100644 --- a/loop/tests/test_all_atom_positions.cc +++ b/loop/tests/test_all_atom_positions.cc @@ -74,6 +74,29 @@ void CompareResidues(const ost::mol::ResidueHandle& new_res, } } +void CheckEntity(const ost::mol::EntityHandle& ent) { + // look at all residues + ost::mol::ResidueHandleList res_list = ent.GetResidueList(); + for (uint res_idx = 0; res_idx < res_list.size(); ++res_idx) { + // get residues + const ost::mol::ResidueHandle& r = res_list[res_idx]; + const ost::mol::ResidueHandle r_next = r.GetNext(); + const ost::mol::ResidueHandle r_prev = r.GetPrev(); + // check types + BOOST_CHECK(r.IsPeptideLinking()); + BOOST_CHECK(r.IsProtein()); + // peptide links checked in CompareResidues + // check torsions + if (r_prev.IsValid() && ost::mol::InSequence(r_prev, r)) { + BOOST_CHECK(r.GetPhiTorsion().IsValid()); + BOOST_CHECK(r.GetOmegaTorsion().IsValid()); + } + if (r_next.IsValid() && ost::mol::InSequence(r, r_next)) { + BOOST_CHECK(r.GetPsiTorsion().IsValid()); + } + } +} + } BOOST_AUTO_TEST_CASE(test_aap_setup) { @@ -410,6 +433,7 @@ BOOST_AUTO_TEST_CASE(test_aap_to_ost) { for (uint res_idx = 0; res_idx < res_list.size(); ++res_idx) { CompareResidues(new_res_list[res_idx], res_list[res_idx]); } + CheckEntity(new_prot); } BOOST_AUTO_TEST_CASE(test_aap_into_ost) { @@ -469,6 +493,7 @@ BOOST_AUTO_TEST_CASE(test_aap_into_ost) { BOOST_CHECK_EQUAL(new_res.GetNumber(), res_list[res_idx].GetNumber()); CompareResidues(new_res, res_list[res_idx]); } + CheckEntity(new_prot); // check overwrite of residue with killed sidechain atom geom::Vec3 new_pos = atoms.GetPos(2, BB_C_INDEX) + geom::Vec3(1,1,1); diff --git a/loop/tests/test_backbone.cc b/loop/tests/test_backbone.cc index e10dff36e70c62fa4e1d4dc91cf2d35cf2b762f4..4b82781ca072c3ebd504f4a502a59e13a30a4958 100644 --- a/loop/tests/test_backbone.cc +++ b/loop/tests/test_backbone.cc @@ -83,6 +83,65 @@ bool CheckBackbonePlausibility(const BackboneList& bb_list, bool skip_last){ return true; } + +void CheckEntity(const ost::mol::EntityHandle& ent) { + // look at all residues + ost::mol::ResidueHandleList res_list = ent.GetResidueList(); + for (uint res_idx = 0; res_idx < res_list.size(); ++res_idx) { + // get residues + const ost::mol::ResidueHandle& r = res_list[res_idx]; + const ost::mol::ResidueHandle r_next = r.GetNext(); + const ost::mol::ResidueHandle r_prev = r.GetPrev(); + // check types + BOOST_CHECK(r.IsPeptideLinking()); + BOOST_CHECK(r.IsProtein()); + // check links + if (r_next.IsValid() && r_next.GetNumber() - 1 == r.GetNumber()) { + BOOST_CHECK(ost::mol::InSequence(r, r_next)); + } + // check torsions + if (r_prev.IsValid() && ost::mol::InSequence(r_prev, r)) { + BOOST_CHECK(r.GetPhiTorsion().IsValid()); + BOOST_CHECK(r.GetOmegaTorsion().IsValid()); + } + if (r_next.IsValid() && ost::mol::InSequence(r, r_next)) { + BOOST_CHECK(r.GetPsiTorsion().IsValid()); + } + } +} + +void CheckEntityBB(const ost::mol::EntityHandle& ent, + const BackboneList& bb_list) { + // look at all backbone atoms + ost::mol::ResidueHandleList res_list = ent.GetResidueList(); + for (uint res_idx = 0; res_idx < res_list.size(); ++res_idx) { + // get atoms + const ost::mol::ResidueHandle& r = res_list[res_idx]; + ost::mol::AtomHandle n = r.FindAtom("N"); + ost::mol::AtomHandle ca = r.FindAtom("CA"); + ost::mol::AtomHandle c = r.FindAtom("C"); + ost::mol::AtomHandle o = r.FindAtom("O"); + ost::mol::AtomHandle cb = r.FindAtom("CB"); + // check validity + BOOST_CHECK(n.IsValid()); + BOOST_CHECK(ca.IsValid()); + BOOST_CHECK(c.IsValid()); + BOOST_CHECK(o.IsValid()); + // compare pos + BOOST_CHECK_EQUAL(n.GetPos(), bb_list.GetN(res_idx)); + BOOST_CHECK_EQUAL(ca.GetPos(), bb_list.GetCA(res_idx)); + BOOST_CHECK_EQUAL(c.GetPos(), bb_list.GetC(res_idx)); + BOOST_CHECK_EQUAL(o.GetPos(), bb_list.GetO(res_idx)); + // check CB + if (bb_list.GetAA(res_idx) == ost::conop::GLY) { + BOOST_CHECK(!cb.IsValid()); + } else { + BOOST_CHECK(cb.IsValid()); + BOOST_CHECK_EQUAL(cb.GetPos(), bb_list.GetCB(res_idx)); + } + } +} + } BOOST_AUTO_TEST_CASE(test_initialization){ @@ -278,7 +337,7 @@ BOOST_AUTO_TEST_CASE(test_replace_fragment) { BOOST_AUTO_TEST_CASE(test_superpose) { - // get dummy backbone and fragment + // get dummy backbones String seq = "HELLYEAHEYECATCHER"; BackboneList bb_list(seq); BackboneList bb_list2(seq); @@ -296,4 +355,30 @@ BOOST_AUTO_TEST_CASE(test_superpose) { BOOST_CHECK(bb_list.CARMSD(bb_list, true) < 1e-4); } +BOOST_AUTO_TEST_CASE(test_bb_to_ost) { + + // get dummy backbone and fragment + String seq = "HELLYEAHEYECATCHER"; + BackboneList bb_list(seq); + BackboneList frag = bb_list.Extract(4, 9); + + // extract OST entity + ost::mol::EntityHandle ent = bb_list.ToEntity(); + CheckEntity(ent); + CheckEntityBB(ent, bb_list); + + // insert fragment in position of 4th residue (fragment pos.) + ost::mol::ResidueHandleList res_list = ent.GetResidueList(); + ost::mol::ResidueHandle res = res_list[4]; + ost::mol::ChainHandle chain = res.GetChain(); + frag.InsertInto(chain, res.GetNumber()); + CheckEntity(ent); + CheckEntityBB(ent, bb_list); + + // trigger exceptions + ost::mol::ChainHandle invalid_chain; + BOOST_CHECK_THROW(frag.InsertInto(invalid_chain, res.GetNumber()), + promod3::Error); +} + BOOST_AUTO_TEST_SUITE_END(); diff --git a/modelling/src/model.cc b/modelling/src/model.cc index 747513b72c839a16ffc1873ad9422932ea98aba7..4504b7ea1c18b08e6dbcd982f3a53a8e65b29921 100644 --- a/modelling/src/model.cc +++ b/modelling/src/model.cc @@ -1033,6 +1033,7 @@ void BuildRawChain(const ost::seq::AlignmentHandle& aln, } String name=conop::OneLetterCodeToResidueName(col[0]); ResidueHandle dst_res=edi.AppendResidue(chain, name, ResNum(res_num)); + dst_res.SetIsProtein(true); bool form_peptide_bond=false; if (last_num+1!=res_num) { // that's an insertion diff --git a/modelling/tests/test_pipeline.py b/modelling/tests/test_pipeline.py index 95cc8af15c240f72cf39c252556fb9ad759b74cf..b43d05a308e0530df362d3b3e4e2018b31cba31f 100644 --- a/modelling/tests/test_pipeline.py +++ b/modelling/tests/test_pipeline.py @@ -186,8 +186,25 @@ class PipelineTests(unittest.TestCase): return mhandle def checkFinalModel(self, mhandle, exp_gaps=0, num_chains=0): - '''Check if model has exp_gaps and that CheckFinalModel reports it.''' - # setup + '''Check if: + - model has exp_gaps and that CheckFinalModel reports it + - 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()) + # setup gap check self.assertEqual(len(mhandle.gaps), exp_gaps) log = _FetchLog() ost.PushLogSink(log)