diff --git a/modelling/src/model.cc b/modelling/src/model.cc index 5740b93207b3c9d07a9dc790c1fe63f457609ad3..57f4965af95dd426efff9481ba2f4b93f078fbb5 100644 --- a/modelling/src/model.cc +++ b/modelling/src/model.cc @@ -973,8 +973,6 @@ void BuildRawChain(const ost::seq::AlignmentHandle& aln, core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped( "modelling::BuildRawChain", 2); - // FIXME: While conseptually simple, this function is way too long for my - // taste. It should be chopped into smaller pieces. if (aln.GetCount()!=2) { throw promod3::Error("alignment must contain exactly two sequences"); } @@ -1036,7 +1034,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; + bool consecutive_residues=false; if (last_num+1!=res_num) { // that's an insertion gap_list.push_back(StructuralGap(before, dst_res, gap_seq)); @@ -1044,12 +1042,9 @@ void BuildRawChain(const ost::seq::AlignmentHandle& aln, } else if (last_index > -1 && last_index+1 != i) { // that's a deletion gap_list.push_back(StructuralGap(before, dst_res, "")); - //form_peptide_bond=true; } else { - form_peptide_bond=true; + consecutive_residues=true; } - last_num=res_num; - last_index=i; bool has_cbeta=false; if (toupper(col[0])==toupper(col[1])) { CopyConserved(src_res, dst_res, edi, has_cbeta); @@ -1072,13 +1067,21 @@ void BuildRawChain(const ost::seq::AlignmentHandle& aln, if (spdbv_style) { InsertDummyAtoms(dst_res, edi); } - if (form_peptide_bond && before.IsValid()) { + if (consecutive_residues && before.IsValid()) { AtomHandle c_before=before.FindAtom("C"); AtomHandle n_this=dst_res.FindAtom("N"); - edi.Connect(c_before, n_this); + if(ost::conop::IsBondFeasible(c_before, n_this)) { + edi.Connect(c_before, n_this); + } else { + // not possible to generate feasible peptide bond + // add gap to enforce rebuilding during the modelling process + gap_list.push_back(StructuralGap(before, dst_res, "")); + } } - before=dst_res; + last_num=res_num; + last_index=i; + before=dst_res; } // check if we have added anything at all if (last_num == 0) { diff --git a/modelling/tests/CMakeLists.txt b/modelling/tests/CMakeLists.txt index 41792a8b7cd90a6cec0593b801e8cd39df877696..be4d60a8f70218533b3bcd555da3114454075299 100644 --- a/modelling/tests/CMakeLists.txt +++ b/modelling/tests/CMakeLists.txt @@ -55,6 +55,7 @@ set(MODELLING_TEST_DATA data/del.fasta data/ff_NAD.dat data/gly.pdb + data/gly_shifted_nter.pdb data/hetero-punched.pdb data/ins.fasta data/modelCApartial-5tgl1A.pdb diff --git a/modelling/tests/data/gly_shifted_nter.pdb b/modelling/tests/data/gly_shifted_nter.pdb new file mode 100644 index 0000000000000000000000000000000000000000..bc8949cdf00fcc944fccf1f1d7fdad9b7ce6daf6 --- /dev/null +++ b/modelling/tests/data/gly_shifted_nter.pdb @@ -0,0 +1,81 @@ +ATOM 1 N GLY A 1 -9.301 13.863 14.812 1.00 46.35 N +ATOM 2 CA GLY A 1 -8.174 14.241 15.713 1.00 45.84 C +ATOM 3 C GLY A 1 -7.595 13.051 16.465 1.00 44.35 C +ATOM 4 O GLY A 1 -8.219 11.989 16.526 1.00 46.54 O +ATOM 9 N GLY A 2 -6.383 13.240 16.995 1.00 42.02 N +ATOM 10 CA GLY A 2 -5.611 12.243 17.755 1.00 39.04 C +ATOM 11 C GLY A 2 -5.093 11.042 16.960 1.00 35.73 C +ATOM 12 O GLY A 2 -5.875 10.322 16.336 1.00 35.25 O +ATOM 18 N GLY A 3 -5.757 8.838 14.934 1.00 32.59 N +ATOM 19 CA GLY A 3 -5.167 7.704 14.210 1.00 30.22 C +ATOM 20 C GLY A 3 -5.475 6.389 14.924 1.00 28.03 C +ATOM 21 O GLY A 3 -5.774 6.389 16.125 1.00 25.91 O +ATOM 25 N GLY A 4 -5.434 5.288 14.176 1.00 26.73 N +ATOM 26 CA GLY A 4 -5.705 3.960 14.726 1.00 26.95 C +ATOM 27 C GLY A 4 -4.622 3.524 15.706 1.00 27.12 C +ATOM 28 O GLY A 4 -3.426 3.545 15.366 1.00 27.18 O +ATOM 35 N GLY A 5 -5.020 3.161 16.948 1.00 27.05 N +ATOM 36 CA GLY A 5 -4.064 2.725 17.976 1.00 26.49 C +ATOM 37 C GLY A 5 -3.515 1.307 17.792 1.00 25.98 C +ATOM 38 O GLY A 5 -2.801 0.795 18.659 1.00 26.77 O +ATOM 42 N GLY A 6 -3.807 0.705 16.641 1.00 23.73 N +ATOM 43 CA GLY A 6 -3.371 -0.650 16.363 1.00 22.05 C +ATOM 44 C GLY A 6 -2.311 -0.858 15.292 1.00 21.12 C +ATOM 45 O GLY A 6 -1.814 -1.970 15.124 1.00 19.47 O +ATOM 56 N GLY A 7 -1.980 0.191 14.544 1.00 22.58 N +ATOM 57 CA GLY A 7 -0.962 0.055 13.501 1.00 20.39 C +ATOM 58 C GLY A 7 0.393 0.457 14.047 1.00 22.27 C +ATOM 59 O GLY A 7 0.645 1.639 14.340 1.00 22.00 O +ATOM 67 N GLY A 8 1.271 -0.539 14.140 1.00 21.40 N +ATOM 68 CA GLY A 8 2.612 -0.344 14.678 1.00 21.91 C +ATOM 69 C GLY A 8 3.734 -0.393 13.645 1.00 22.34 C +ATOM 70 O GLY A 8 4.910 -0.258 13.998 1.00 24.21 O +ATOM 78 N GLY A 9 3.365 -0.539 12.371 1.00 20.22 N +ATOM 79 CA GLY A 9 4.342 -0.585 11.293 1.00 20.67 C +ATOM 80 C GLY A 9 5.264 -1.780 11.345 1.00 20.79 C +ATOM 81 O GLY A 9 4.834 -2.874 11.700 1.00 19.22 O +ATOM 82 N GLY A 10 6.545 -1.555 11.072 1.00 20.29 N +ATOM 83 CA GLY A 10 7.521 -2.635 11.071 1.00 22.16 C +ATOM 84 C GLY A 10 8.055 -3.014 12.464 1.00 23.01 C +ATOM 85 O GLY A 10 9.266 -3.098 12.676 1.00 23.84 O +ATOM 91 N GLY A 11 7.141 -3.248 13.409 1.00 24.30 N +ATOM 92 CA GLY A 11 7.527 -3.666 14.757 1.00 23.54 C +ATOM 93 C GLY A 11 7.811 -5.171 14.643 1.00 23.07 C +ATOM 94 O GLY A 11 7.027 -5.913 14.030 1.00 23.44 O +ATOM 99 N GLY A 12 9.005 -5.608 15.082 1.00 23.03 N +ATOM 100 CA GLY A 12 9.328 -7.039 15.000 1.00 23.30 C +ATOM 101 C GLY A 12 8.373 -7.936 15.805 1.00 22.52 C +ATOM 102 O GLY A 12 7.733 -7.476 16.760 1.00 21.80 O +ATOM 106 N GLY A 13 8.271 -9.196 15.382 1.00 22.06 N +ATOM 107 CA GLY A 13 7.433 -10.219 16.020 1.00 22.83 C +ATOM 108 C GLY A 13 7.699 -10.347 17.529 1.00 24.10 C +ATOM 109 O GLY A 13 6.768 -10.261 18.334 1.00 23.86 O +ATOM 117 N GLY A 14 8.974 -10.480 17.898 1.00 22.59 N +ATOM 118 CA GLY A 14 9.386 -10.612 19.299 1.00 23.66 C +ATOM 119 C GLY A 14 9.109 -9.356 20.121 1.00 23.97 C +ATOM 120 O GLY A 14 8.824 -9.445 21.320 1.00 21.85 O +ATOM 122 N GLY A 15 9.149 -8.199 19.455 1.00 23.41 N +ATOM 123 CA GLY A 15 8.880 -6.917 20.103 1.00 25.09 C +ATOM 124 C GLY A 15 7.378 -6.717 20.320 1.00 23.56 C +ATOM 125 O GLY A 15 6.968 -6.064 21.278 1.00 23.45 O +ATOM 131 N GLY A 16 6.569 -7.318 19.442 1.00 21.80 N +ATOM 132 CA GLY A 16 5.106 -7.272 19.532 1.00 20.39 C +ATOM 133 C GLY A 16 4.711 -8.157 20.718 1.00 20.37 C +ATOM 134 O GLY A 16 3.856 -7.788 21.511 1.00 18.06 O +ATOM 136 N GLY A 17 5.429 -9.273 20.876 1.00 20.11 N +ATOM 137 CA GLY A 17 5.215 -10.213 21.983 1.00 21.59 C +ATOM 138 C GLY A 17 5.492 -9.561 23.332 1.00 22.42 C +ATOM 139 O GLY A 17 4.665 -9.622 24.238 1.00 23.01 O +ATOM 145 N GLY A 18 6.639 -8.890 23.414 1.00 24.69 N +ATOM 146 CA GLY A 18 7.114 -8.182 24.603 1.00 26.91 C +ATOM 147 C GLY A 18 6.147 -7.077 25.056 1.00 26.71 C +ATOM 148 O GLY A 18 5.800 -7.000 26.231 1.00 27.59 O +ATOM 154 N GLY A 19 5.683 -6.273 24.099 1.00 25.69 N +ATOM 155 CA GLY A 19 4.764 -5.161 24.348 1.00 25.99 C +ATOM 156 C GLY A 19 3.375 -5.643 24.772 1.00 23.81 C +ATOM 157 O GLY A 19 2.828 -5.155 25.769 1.00 24.09 O +ATOM 162 N GLY A 20 2.830 -6.601 24.019 1.00 19.41 N +ATOM 163 CA GLY A 20 1.496 -7.148 24.282 1.00 21.16 C +ATOM 164 C GLY A 20 1.366 -8.006 25.540 1.00 20.66 C +ATOM 165 O GLY A 20 0.301 -8.035 26.151 1.00 20.51 O +END diff --git a/modelling/tests/test_modelling.py b/modelling/tests/test_modelling.py index 7e1bebee4221149467c1cb435103ab598968bdc2..5ca41eabe0b8fa0467bc609e9acd60d1d6061658 100644 --- a/modelling/tests/test_modelling.py +++ b/modelling/tests/test_modelling.py @@ -51,6 +51,7 @@ class ModellingTests(unittest.TestCase): aln.AttachView(1, tpl.CreateFullView()) result = modelling.BuildRawModel(aln) seq1 = seq.SequenceFromChain('MODEL', result.model.chains[0]) + self.assertEqual(len(result.gaps), 0) self.assertEqual(seq1.string, aln.sequences[0].string) def testDeletion(self): @@ -77,6 +78,19 @@ class ModellingTests(unittest.TestCase): self.assertEqual(result.gaps[0].after, residues[2]) self.assertEqual(result.gaps[0].seq, 'AV') + def testNonFeasiblePeptideBond(self): + # test if the result contains a gap when two residues cannot be + # connected with a feasible peptide bond + tpl = io.LoadPDB('data/gly_shifted_nter.pdb') + aln = io.LoadAlignment('data/seq.fasta') + aln.AttachView(1, tpl.CreateFullView()) + result = modelling.BuildRawModel(aln) + residues = result.model.residues + self.assertEqual(len(result.gaps), 1) + self.assertEqual(result.gaps[0].before, residues[1]) + self.assertEqual(result.gaps[0].after, residues[2]) + self.assertEqual(result.gaps[0].seq, '') + def testTer(self): # test if the result contains two terminal gaps, one at the beginning, # one at the end