diff --git a/modules/mol/alg/src/nonstandard.cc b/modules/mol/alg/src/nonstandard.cc index ef878cbc80ea3d64d472a71d8f8234f11c2d2ceb..f675cc9746f15b0adbee11eaac817c72036f437c 100644 --- a/modules/mol/alg/src/nonstandard.cc +++ b/modules/mol/alg/src/nonstandard.cc @@ -21,6 +21,7 @@ Author: Marco Biasini, Juergen Haas */ +#include <ost/message.hh> #include <ost/log.hh> #include <ost/dyn_cast.hh> #include <ost/conop/conop.hh> @@ -58,8 +59,15 @@ bool CopyResidue(ResidueHandle src_res, ResidueHandle dst_res, } // insert Cbeta, unless dst residue is glycine. if (!has_cbeta && dst_res.GetName()!="GLY") { - geom::Vec3 cbeta_pos=mol::alg::CBetaPosition(dst_res); - edi.InsertAtom(dst_res, "CB", cbeta_pos, "C"); + try { + geom::Vec3 cbeta_pos = mol::alg::CBetaPosition(dst_res); + edi.InsertAtom(dst_res, "CB", cbeta_pos, "C"); + } catch (ost::Error& e) { + LOG_WARNING("Issue in CB reconstruction while copying residue " + << src_res.GetQualifiedName() << " to " + << dst_res.GetQualifiedName() << ": " << e.what() + << ". Skipped reconstruction."); + } } return ret; } diff --git a/modules/mol/alg/tests/test_nonstandard.py b/modules/mol/alg/tests/test_nonstandard.py index cbe8257a70576b5eb225ca3ba29293f95e362075..c7f49215eb79b559c1c43cd71659569de5e447fb 100644 --- a/modules/mol/alg/tests/test_nonstandard.py +++ b/modules/mol/alg/tests/test_nonstandard.py @@ -57,11 +57,56 @@ class TestNonStandard(unittest.TestCase): self.assertTrue(residues[3].FindAtom("CB").IsValid()) + def test_CBetaFail(self): + # make sure that we can handle cases where CB reconstruction fails + + # NOTES: + # - SNN is (since June 2011) labeled as a modified ASN but has a weird + # backbone structure without any overlap in atom names with ASN + # -> we hence expect it to a) always fall back to CopyNonConserved + # and b) fail to copy any atoms (and hence also fail to) + # - SNN also removes N of following residue which is expected to have an + # incomplete backbone which would make it impossible to create a CB pos. + + # source of file: residues A.198 and A.199 from PDB ID 2YHW + tpl = io.LoadPDB('testfiles/cbeta_fail.pdb') + new_hdl = mol.CreateEntity(); + ed = new_hdl.EditXCS() + c = ed.InsertChain('A') + ed.AppendResidue(c, 'GLY') + ed.AppendResidue(c, 'ALA') + ed.AppendResidue(c, 'ASN') + ed.AppendResidue(c, 'GLY') + ed.AppendResidue(c, 'ALA') + # SNN to GLY + err = mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[0], ed) + self.assertFalse(err) + self.assertEqual(new_hdl.residues[0].atom_count, 0) + # SNN to ALA + err = mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[1], ed) + self.assertFalse(err) + self.assertEqual(new_hdl.residues[1].atom_count, 0) + # SNN to ASN + err = mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[2], ed) + self.assertFalse(err) + self.assertEqual(new_hdl.residues[2].atom_count, 0) + # GLY to GLY + err = mol.alg.CopyResidue(tpl.residues[1], new_hdl.residues[3], ed) + self.assertTrue(err) + self.assertEqual(new_hdl.residues[3].atom_count, 3) + self.assertFalse(new_hdl.residues[3].FindAtom("CB").IsValid()) + # GLY to ALA + err = mol.alg.CopyResidue(tpl.residues[1], new_hdl.residues[4], ed) + self.assertFalse(err) + self.assertEqual(new_hdl.residues[4].atom_count, 3) + self.assertFalse(new_hdl.residues[4].FindAtom("CB").IsValid()) + + def test_CopyResidue(self): - tpl=io.LoadPDB('testfiles/cbeta.pdb') - new_hdl=mol.CreateEntity(); - ed=new_hdl.EditXCS() - c=ed.InsertChain('A') + tpl = io.LoadPDB('testfiles/cbeta.pdb') + new_hdl = mol.CreateEntity(); + ed = new_hdl.EditXCS() + c = ed.InsertChain('A') ed.AppendResidue(c, 'MET') ed.AppendResidue(c, 'GLY') ed.AppendResidue(c, 'GLY') @@ -72,31 +117,31 @@ class TestNonStandard(unittest.TestCase): ed.AppendResidue(c, 'MET') # MET to MET - err =mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[0], ed) + err = mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[0], ed) self.assertTrue(err) #GLY to GLY - err =mol.alg.CopyResidue(tpl.residues[1], new_hdl.residues[1], ed) + err = mol.alg.CopyResidue(tpl.residues[1], new_hdl.residues[1], ed) self.assertTrue(err) # GLY to GLY - err =mol.alg.CopyResidue(tpl.residues[2], new_hdl.residues[2], ed) + err = mol.alg.CopyResidue(tpl.residues[2], new_hdl.residues[2], ed) self.assertTrue(err) #now we copy a HIS to a HIS - err =mol.alg.CopyResidue(tpl.residues[3], new_hdl.residues[3], ed) + err = mol.alg.CopyResidue(tpl.residues[3], new_hdl.residues[3], ed) self.assertTrue(err) # copy a GLY to a HIS - err, has_cbeta=mol.alg.CopyNonConserved(tpl.residues[1], new_hdl.residues[4], ed) + err, has_cbeta = mol.alg.CopyNonConserved(tpl.residues[1], new_hdl.residues[4], ed) self.assertFalse(has_cbeta) - # copy a MET to a GLY - err =mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[5], ed) + # copy a MET to a GLY + err = mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[5], ed) self.assertFalse(err) - # copy a MET to a HIS - err =mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[6], ed) + # copy a MET to a HIS + err = mol.alg.CopyResidue(tpl.residues[0], new_hdl.residues[6], ed) self.assertFalse(err) # copy a GLY to a MET with adding CB - err=mol.alg.CopyResidue(tpl.residues[1], new_hdl.residues[7], ed) + err = mol.alg.CopyResidue(tpl.residues[1], new_hdl.residues[7], ed) self.assertFalse(err) - residues=new_hdl.residues + residues = new_hdl.residues self.assertEqual(len(residues), 8) # MET to MET self.assertTrue(residues[0].FindAtom("CB").IsValid()) diff --git a/modules/mol/alg/tests/testfiles/cbeta_fail.pdb b/modules/mol/alg/tests/testfiles/cbeta_fail.pdb new file mode 100644 index 0000000000000000000000000000000000000000..3c856297e848d7621a9d20414b336f2feec59c93 --- /dev/null +++ b/modules/mol/alg/tests/testfiles/cbeta_fail.pdb @@ -0,0 +1,13 @@ +ATOM 1 N1 SNN A 198 -29.170 34.390 20.593 1.00 19.36 N +ATOM 2 C2 SNN A 198 -29.098 33.236 19.935 1.00 22.44 C +ATOM 3 C3 SNN A 198 -30.445 32.723 19.591 1.00 22.60 C +ATOM 4 N3 SNN A 198 -30.638 31.540 20.497 1.00 19.05 N +ATOM 5 C4 SNN A 198 -31.361 33.870 20.080 1.00 24.77 C +ATOM 6 C5 SNN A 198 -30.421 34.922 20.754 1.00 31.46 C +ATOM 7 O2 SNN A 198 -28.057 32.598 19.660 1.00 21.86 O +ATOM 8 O5 SNN A 198 -30.731 36.074 21.349 1.00 31.34 O +ATOM 9 CA GLY A 199 -27.868 35.007 21.247 1.00 21.30 C +ATOM 10 C GLY A 199 -27.140 35.813 20.142 1.00 19.04 C +ATOM 11 O GLY A 199 -27.544 35.877 18.965 1.00 19.95 O +TER 12 GLY A 199 +END