diff --git a/modules/io/doc/mmcif.rst b/modules/io/doc/mmcif.rst index c5a0a164587a328253cf8a970a5bf557084daf38..8136df7aa4d6f2bf9643ee582b7a2c036af64755 100644 --- a/modules/io/doc/mmcif.rst +++ b/modules/io/doc/mmcif.rst @@ -41,6 +41,13 @@ of the annotation available. Also available as :meth:`GetMethod`. May also be modified by :meth:`SetMethod`. + .. attribute:: resolution + + Stores the resolution of the crystal structure. + + Also available as :meth:`GetResolution`. May also be modified by + :meth:`SetResolution`. + .. method:: AddCitation(citation) Add a citation to the citation list of an info object. @@ -69,6 +76,14 @@ of the annotation available. See :attr:`method` + .. method:: SetResolution(resolution) + + See :attr:`resolution` + + .. method:: GetResolution() + + See :attr:`resolution` + .. class:: MMCifInfoCitation This stores citation information from an input file. diff --git a/modules/io/pymod/export_mmcif_io.cc b/modules/io/pymod/export_mmcif_io.cc index 06cba8423ca595ae9c6e7f5889704eca888c33ab..dac09bcbf5cfa11c1ecac58c2b71851d58c2bc52 100644 --- a/modules/io/pymod/export_mmcif_io.cc +++ b/modules/io/pymod/export_mmcif_io.cc @@ -108,9 +108,13 @@ void export_mmcif_io() return_value_policy<copy_const_reference>())) .def("SetMethod", &MMCifInfo::SetMethod) .def("GetMethod", &MMCifInfo::GetMethod) + .def("SetResolution", &MMCifInfo::SetResolution) + .def("GetResolution", &MMCifInfo::GetResolution) .def("AddAuthorsToCitation", &MMCifInfo::AddAuthorsToCitation) .add_property("citations", make_function(&MMCifInfo::GetCitations, return_value_policy<copy_const_reference>())) .add_property("method", &MMCifInfo::GetMethod, &MMCifInfo::SetMethod) + .add_property("resolution", &MMCifInfo::GetResolution, + &MMCifInfo::SetResolution) ; } diff --git a/modules/io/src/mol/mmcif_info.hh b/modules/io/src/mol/mmcif_info.hh index 37e8969754d1e31d6d6559669e8ea195cb562f3b..5b257bebbdfbd9fec7ac4897074cc3e20a37df9b 100644 --- a/modules/io/src/mol/mmcif_info.hh +++ b/modules/io/src/mol/mmcif_info.hh @@ -245,7 +245,7 @@ private: class DLLEXPORT_OST_IO MMCifInfo { public: /// \brief Create an info object. - MMCifInfo(): exptl_method_("") {}; + MMCifInfo(): exptl_method_(""), resolution_(0.0f) {}; /// \brief Add an item to the list of citations /// @@ -282,11 +282,22 @@ public: return StringRef(exptl_method_.c_str(), exptl_method_.length()); } + /// \brief Set resolution. + /// + /// \param res experiment resolution + void SetResolution(Real res) { resolution_ = res; } + + /// \brief Get resolution. + /// + /// \return experiment resolution + Real GetResolution() const { return resolution_; } + //protected: private: // members String exptl_method_; + Real resolution_; std::vector<MMCifInfoCitation> citations_; ///< list of citations }; diff --git a/modules/io/src/mol/mmcif_reader.cc b/modules/io/src/mol/mmcif_reader.cc index 9f99c0b6e625fba1d24fb5a0b3ab58948aaff8b2..595ae05d2da1192c34502e99ef856e13eb4d99ad 100644 --- a/modules/io/src/mol/mmcif_reader.cc +++ b/modules/io/src/mol/mmcif_reader.cc @@ -193,17 +193,23 @@ bool MMCifParser::OnBeginLoop(const StarLoopDesc& header) category_ = CITATION_AUTHOR; // mandatory items this->TryStoreIdx(AUTHOR_CITATION_ID, "citation_id", header); - this->TryStoreIdx(AUTHOR_NAME, "name", header); - this->TryStoreIdx(ORDINAL, "ordinal", header); + this->TryStoreIdx(AUTHOR_NAME, "name", header); + this->TryStoreIdx(ORDINAL, "ordinal", header); cat_available = true; } else if (header.GetCategory() == "exptl") { category_ = EXPTL; // mandatory items this->TryStoreIdx(CITATION_ID, "entry_id", header); - this->TryStoreIdx(METHOD, "method", header); + this->TryStoreIdx(METHOD, "method", header); cat_available = true; - } /* else if (header.GetCategory()=="struct_conf") { - }*/ + } else if (header.GetCategory() == "refine") { + category_ = REFINE; + // mandatory items + this->TryStoreIdx(REFINE_ENTRY_ID, "entry_id", header); + this->TryStoreIdx(LS_D_RES_HIGH, "ls_d_res_high", header); + this->TryStoreIdx(LS_D_RES_LOW, "ls_d_res_low", header); + cat_available = true; + } category_counts_[category_]++; return cat_available; } @@ -713,6 +719,12 @@ void MMCifParser::ParseExptl(const std::vector<StringRef>& columns) info_.SetMethod(columns[indices_[METHOD]].str()); } +void MMCifParser::ParseRefine(const std::vector<StringRef>& columns) +{ + info_.SetResolution(this->TryGetReal(columns[indices_[LS_D_RES_HIGH]], + "refine.ls_d_res_high")); +} + void MMCifParser::OnDataRow(const StarLoopDesc& header, const std::vector<StringRef>& columns) { @@ -741,6 +753,10 @@ void MMCifParser::OnDataRow(const StarLoopDesc& header, LOG_TRACE("processing exptl entry") this->ParseExptl(columns); break; + case REFINE: + LOG_TRACE("processing refine entry") + this->ParseRefine(columns); + break; default: throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR, "Uncatched category '"+ header.GetCategory() +"' found.", diff --git a/modules/io/src/mol/mmcif_reader.hh b/modules/io/src/mol/mmcif_reader.hh index 1376abee23cfafc16e7eb0ad33685263a282fd36..e8094ab77bdd588bc3488a25561777dcecd2d09e 100644 --- a/modules/io/src/mol/mmcif_reader.hh +++ b/modules/io/src/mol/mmcif_reader.hh @@ -231,6 +231,11 @@ protected: /// \param columns data row void ParseExptl(const std::vector<StringRef>& columns); + /// \brief Fetch MMCif refine information + /// + /// \param columns data row + void ParseRefine(const std::vector<StringRef>& columns); + private: /// \enum magic numbers of this class typedef enum { @@ -304,6 +309,13 @@ private: METHOD ///< method of the experiment } ExptlItems; + /// \enum items of the refine category + typedef enum { + REFINE_ENTRY_ID, + LS_D_RES_HIGH, + LS_D_RES_LOW + } RefineItems; + /// \enum categories of the mmcif format typedef enum { ATOM_SITE, @@ -312,6 +324,7 @@ private: CITATION, CITATION_AUTHOR, EXPTL, + REFINE, DONT_KNOW } MMCifCategory; diff --git a/modules/io/tests/test_io_mmcif.py b/modules/io/tests/test_io_mmcif.py index fd5671262c892b25029cbc49790d0f6977c7a93c..ba37343ebd9cdce201455f06fee820f7a3f9c1bc 100644 --- a/modules/io/tests/test_io_mmcif.py +++ b/modules/io/tests/test_io_mmcif.py @@ -48,6 +48,7 @@ class TestPDB(unittest.TestCase): i = io.MMCifInfo() i.SetMethod('Deep-Fry') + i.SetResolution(2.0) i.AddCitation(c) s.append('Bar') i.AddAuthorsToCitation('ID', s) @@ -60,6 +61,7 @@ class TestPDB(unittest.TestCase): self.assertEquals(al[1], 'Bar') self.assertEquals(i.GetMethod(), 'Deep-Fry') + self.assertEquals(i.GetResolution(), 2.0) if __name__== '__main__': unittest.main() diff --git a/modules/io/tests/test_mmcif_info.cc b/modules/io/tests/test_mmcif_info.cc index d5e1aa3d4c5f405de7a98e8c6f0a9fbeb338d5de..72a33dbbec09a19f509ed8d7a5b0c959b9396852 100644 --- a/modules/io/tests/test_mmcif_info.cc +++ b/modules/io/tests/test_mmcif_info.cc @@ -86,7 +86,10 @@ BOOST_AUTO_TEST_CASE(mmcif_info) MMCifInfo info = MMCifInfo(); info.SetMethod("Cooking."); + info.SetResolution(1.9f); + BOOST_CHECK(info.GetMethod() == StringRef("Cooking.", 8)); + BOOST_CHECK_CLOSE(info.GetResolution(), 1.9f, 0.001f); BOOST_MESSAGE(" done."); } diff --git a/modules/io/tests/test_mmcif_reader.cc b/modules/io/tests/test_mmcif_reader.cc index 42b44d38ff547f45227e9218021fd97f3d59acae..a424553fc5c0facaa4b974f2558757245374db9a 100644 --- a/modules/io/tests/test_mmcif_reader.cc +++ b/modules/io/tests/test_mmcif_reader.cc @@ -54,6 +54,7 @@ public: using MMCifParser::ParseEntity; using MMCifParser::ParseEntityPoly; using MMCifParser::ParseCitation; + using MMCifParser::ParseRefine; using MMCifParser::TryStoreIdx; using MMCifParser::SetReadSeqRes; using MMCifParser::SetReadCanonicalSeqRes; @@ -567,6 +568,42 @@ BOOST_AUTO_TEST_CASE(mmcif_citation_author_tests) BOOST_MESSAGE(" done."); } +BOOST_AUTO_TEST_CASE(mmcif_refine_tests) +{ + BOOST_MESSAGE(" Running mmcif_refine_tests..."); + BOOST_MESSAGE(" positive test..."); + { + mol::EntityHandle eh = mol::CreateEntity(); + std::ifstream s("testfiles/mmcif/atom_site.mmcif"); + IOProfile profile; + MMCifParser mmcif_p(s, eh, profile); + BOOST_CHECK_NO_THROW(mmcif_p.Parse()); + BOOST_CHECK_CLOSE(mmcif_p.GetInfo().GetResolution(), 2.0f, 0.001f); + } + BOOST_MESSAGE(" done."); + BOOST_MESSAGE(" capturing fishy data lines..."); + { + mol::EntityHandle eh; + TestMMCifParserProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh); + StarLoopDesc tmmcif_h; + std::vector<StringRef> columns; + + tmmcif_h.SetCategory(StringRef("refine", 6)); + tmmcif_h.Add(StringRef("entry_id", 8)); + tmmcif_h.Add(StringRef("ls_d_res_high", 13)); + tmmcif_h.Add(StringRef("ls_d_res_low", 12)); + tmmcif_p.OnBeginLoop(tmmcif_h); + + columns.push_back(StringRef("1Foo", 4)); + columns.push_back(StringRef("Foo", 3)); + columns.push_back(StringRef("1", 1)); + + BOOST_CHECK_THROW(tmmcif_p.ParseRefine(columns), IOException); + } + BOOST_MESSAGE(" done."); + BOOST_MESSAGE(" done."); +} + BOOST_AUTO_TEST_CASE(mmcif_parseatomident) { BOOST_MESSAGE(" Running mmcif_parseatomident tests..."); @@ -585,7 +622,7 @@ BOOST_AUTO_TEST_CASE(mmcif_parseatomident) //StringRef atom_name; BOOST_MESSAGE(" testing valid line"); - //tmmcif_p.ParseAtomIdent(columns, chain_name, res_name); + //tmmcif_p.ParseAtomIdent(); BOOST_MESSAGE(" done."); // negative //cols.push_back(StringRef("ATOM", 4)); diff --git a/modules/io/tests/testfiles/mmcif/atom_site.mmcif b/modules/io/tests/testfiles/mmcif/atom_site.mmcif index 6ada7db03d34b2131f5afc4e824780679235eb73..f6a1b63d4a3095a861a9f85fbd31bf6193578a8e 100644 --- a/modules/io/tests/testfiles/mmcif/atom_site.mmcif +++ b/modules/io/tests/testfiles/mmcif/atom_site.mmcif @@ -46,6 +46,10 @@ _citation_author.name _exptl.entry_id experiment1 _exptl.method 'Deep-fry' +_refine.entry_id '1BAR' +_refine.ls_d_res_high 2.0 +_refine.ls_d_res_low 1.5 + loop_ _atom_site.group_PDB _atom_site.type_symbol