diff --git a/modules/io/pymod/export_pdb_io.cc b/modules/io/pymod/export_pdb_io.cc index 5f252d31897a86ac906566f55f91e552d80cfff5..6cc80b813ca1c95fca26604b91f93012684390e4 100644 --- a/modules/io/pymod/export_pdb_io.cc +++ b/modules/io/pymod/export_pdb_io.cc @@ -38,12 +38,14 @@ void export_pdb_io() .value("SKIP_FAULTY_RECORDS", PDB::SKIP_FAULTY_RECORDS) .value("WRITE_MULTIPLE_MODELS", PDB::WRITE_MULTIPLE_MODELS) .value("JOIN_SPREAD_ATOM_RECORDS", PDB::JOIN_SPREAD_ATOM_RECORDS) + .value("SEQUENTIAL_ATOM_IMPORT", PDB::SEQUENTIAL_ATOM_IMPORT) ; class_<PDBReader, boost::noncopyable>("PDBReader", init<String>()) .def("HasNext", &PDBReader::HasNext) .def("Import", &PDBReader::Import, X_import(args("entity", "restrict_chains"))) .def("SetFlags", &PDBReader::SetFlags) + .def("GetSequentialAtoms", &PDBReader::GetSequentialAtoms) ; class_<PDBWriter, boost::noncopyable>("PDBWriter", init<String>()) diff --git a/modules/io/src/mol/entity_io_crd_handler.cc b/modules/io/src/mol/entity_io_crd_handler.cc index 8cd61e3e9ee486ad7520b88c71db42d35eeef7f6..a7870b33ed239d98bee19519cdfbabb7a73fa7ca 100644 --- a/modules/io/src/mol/entity_io_crd_handler.cc +++ b/modules/io/src/mol/entity_io_crd_handler.cc @@ -259,7 +259,7 @@ mol::CoordGroupHandle LoadCHARMMTraj(const String& crd_fn, std::vector<mol::AtomHandle> alist; if(boost::filesystem::extension(crd_f)==".pdb") { PDBReader reader(crd_f); - reader.CollectSequentialAtoms(true); + reader.SetFlags(PDB::SEQUENTIAL_ATOM_IMPORT); LOGN_MESSAGE("importing coordinate data"); reader.Import(ent); alist = reader.GetSequentialAtoms(); diff --git a/modules/io/src/mol/pdb_io.hh b/modules/io/src/mol/pdb_io.hh index e14cfb2d44fa37f282f30cd802d3f9abeca39286..54edc8a1320cf57f697bb44b2d8ac4d2a13e603c 100644 --- a/modules/io/src/mol/pdb_io.hh +++ b/modules/io/src/mol/pdb_io.hh @@ -57,7 +57,14 @@ struct PDB { /// /// By default, the atom 550 will start a new residue instead of being /// joined with atoms 43-48 into one residue. - JOIN_SPREAD_ATOM_RECORDS=16 + JOIN_SPREAD_ATOM_RECORDS=16, + //// \brief keep track of the order of atom records + /// + /// This option is mostly useful in combination with + /// PDB::JOIN_SPREAD_ATOM_RECORDS and CoordGroups. + /// + /// The atoms are accessible via PDBReader::GetSequentialAtoms() + SEQUENTIAL_ATOM_IMPORT=32 } Type; }; diff --git a/modules/io/src/mol/pdb_reader.cc b/modules/io/src/mol/pdb_reader.cc index c59be53a623e88ad163a94086cfb486fe62b9c57..5ad97901e4ebc4da64db7b957177f0564ee9f8a4 100644 --- a/modules/io/src/mol/pdb_reader.cc +++ b/modules/io/src/mol/pdb_reader.cc @@ -146,8 +146,6 @@ void PDBReader::Init(const boost::filesystem::path& loc) in_.push(instream_); if(!infile_) throw IOException("could not open "+loc.string()); line_num_=0; - collect_sequential_atoms_=false; - if(boost::iequals(boost::filesystem::extension(loc), ".pqr")) { is_pqr_=true; } else { @@ -261,11 +259,6 @@ void PDBReader::ClearState() sequential_atom_list_.clear(); } -void PDBReader::CollectSequentialAtoms(bool f) -{ - collect_sequential_atoms_=f; -} - std::vector<mol::AtomHandle> PDBReader::GetSequentialAtoms() const { return sequential_atom_list_; @@ -501,14 +494,14 @@ void PDBReader::ParseAndAddAtom(const String& line, int line_num, } else { mol::AtomHandle ah=editor.InsertAltAtom(curr_residue_, aname, String(1, alt_loc), apos, aprop); - if (collect_sequential_atoms_) { + if (flags_ & PDB::SEQUENTIAL_ATOM_IMPORT) { sequential_atom_list_.push_back(ah); } ++atom_count_; } } else { mol::AtomHandle ah = editor.InsertAtom(curr_residue_, aname, apos, aprop); - if (collect_sequential_atoms_) { + if (flags_ & PDB::SEQUENTIAL_ATOM_IMPORT) { sequential_atom_list_.push_back(ah); } ++atom_count_; diff --git a/modules/io/src/mol/pdb_reader.hh b/modules/io/src/mol/pdb_reader.hh index a3581510f89996248c1084cb6a914a43d029d200..b41eef65a1444e07fa151201bab7ee790adaca8a 100644 --- a/modules/io/src/mol/pdb_reader.hh +++ b/modules/io/src/mol/pdb_reader.hh @@ -49,8 +49,14 @@ public: void Import(mol::EntityHandle& ent, const String& restrict_chains=""); void SetFlags(PDBFlags flags); - // these two are needed for synchronizing with a traj import - void CollectSequentialAtoms(bool f); + + /// \brief get list of atoms + /// + /// The atom handles reflect the order of atom records in the PDb files. This + /// is used to synchronize PDB and coordgroup io. + /// + /// By default, the atom list is empty, The PDB::SEQUENTIAL_ATOM_IMPORT flag + /// must be set. std::vector<mol::AtomHandle> GetSequentialAtoms() const; private: @@ -76,7 +82,6 @@ private: std::istream& instream_; boost::iostreams::filtering_stream<boost::iostreams::input> in_; String curr_line_; - bool collect_sequential_atoms_; std::vector<mol::AtomHandle> sequential_atom_list_; PDBFlags flags_; // this needs to be set to true for reading pqr diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc index 5bc9f8e4c7c9cae6968ed20359d32972b32e76ed..44b7f3db415e838848633ae7d656f5d7b59efaf7 100644 --- a/modules/io/tests/test_io_pdb.cc +++ b/modules/io/tests/test_io_pdb.cc @@ -18,6 +18,7 @@ //------------------------------------------------------------------------------ #include <ost/mol/mol.hh> #include <ost/io/mol/entity_io_pdb_handler.hh> +#include <ost/io/pdb_reader.hh> #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; @@ -29,7 +30,7 @@ BOOST_AUTO_TEST_SUITE( io ) BOOST_AUTO_TEST_CASE(test_io_pdb) { - const String fname("testfiles/test_in.pdb"); + String fname("testfiles/test_in.pdb"); mol::EntityHandle eh=mol::CreateEntity(); EntityIOPDBHandler pdbh; @@ -42,7 +43,44 @@ BOOST_AUTO_TEST_CASE(test_io_pdb) BOOST_CHECK(EntityIOPDBHandler::ProvidesExport(fname)); BOOST_CHECK(EntityIOPDBHandler::ProvidesExport("test_in.PDB")); - pdbh.Import(eh,"testfiles/test_in.pdb"); + pdbh.Import(eh,"testfiles/pdb/simple.pdb"); +} + +BOOST_AUTO_TEST_CASE(join_spread_records_on) +{ + String fname("testfiles/pdb/join-spread-records.pdb"); + PDBReader reader(fname); + reader.SetFlags(PDB::JOIN_SPREAD_ATOM_RECORDS); + + mol::EntityHandle ent=mol::CreateEntity(); + reader.Import(ent); + BOOST_CHECK_EQUAL(ent.GetResidueCount(), 2); + mol::ResidueHandle res1=ent.FindResidue("A", mol::ResNum(1)); + BOOST_CHECK(res1.IsValid()); + BOOST_CHECK_EQUAL(res1.GetAtomCount(), 2); + BOOST_CHECK(res1.FindAtom("N")); + BOOST_CHECK(res1.FindAtom("CE")); + mol::ResidueHandle res2=ent.FindResidue("A", mol::ResNum(2)); + BOOST_CHECK(res2.IsValid()); + BOOST_CHECK_EQUAL(res2.GetAtomCount(), 1); + BOOST_CHECK(res2.FindAtom("N")); +} + +BOOST_AUTO_TEST_CASE(join_spread_records_off) +{ + String fname("testfiles/pdb/join-spread-records.pdb"); + PDBReader reader(fname); + mol::EntityHandle ent=mol::CreateEntity(); + reader.Import(ent); + BOOST_CHECK_EQUAL(ent.GetResidueCount(), 2); + mol::ResidueHandle res1=ent.FindResidue("A", mol::ResNum(1)); + BOOST_CHECK(res1.IsValid()); + BOOST_CHECK_EQUAL(res1.GetAtomCount(), 1); + BOOST_CHECK(res1.FindAtom("N")); + mol::ResidueHandle res2=ent.FindResidue("A", mol::ResNum(2)); + BOOST_CHECK(res2.IsValid()); + BOOST_CHECK_EQUAL(res2.GetAtomCount(), 1); + BOOST_CHECK(res2.FindAtom("N")); } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/modules/io/tests/testfiles/pdb/join-spread-records.pdb b/modules/io/tests/testfiles/pdb/join-spread-records.pdb new file mode 100644 index 0000000000000000000000000000000000000000..e87adc9748fbd6446648b00f04a0b98a2e0f8166 --- /dev/null +++ b/modules/io/tests/testfiles/pdb/join-spread-records.pdb @@ -0,0 +1,3 @@ +ATOM 1 N MET A 1 21.609 35.384 56.705 1.00 41.48 N +ATOM 9 N ARG A 2 20.202 33.112 58.011 1.00 36.39 N +ATOM 8 CE MET A 1 23.233 37.697 58.529 1.00 54.59 C diff --git a/modules/io/tests/testfiles/test_in.pdb b/modules/io/tests/testfiles/pdb/simple.pdb similarity index 100% rename from modules/io/tests/testfiles/test_in.pdb rename to modules/io/tests/testfiles/pdb/simple.pdb