diff --git a/modules/io/src/mol/pdb_reader.cc b/modules/io/src/mol/pdb_reader.cc index c52e5cf3151e1fc1e2c59f39616e822a4b7dd90f..6f5ac46338c897c715bf8412019818d0639adcd9 100644 --- a/modules/io/src/mol/pdb_reader.cc +++ b/modules/io/src/mol/pdb_reader.cc @@ -808,12 +808,14 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num, return; } } + Real b=temp.first ? temp.second : 0.0; + Real o=occ.first ? occ.second : 1.0; if (!profile_.quack_mode && alt_loc!=' ') { // Check if there is already a atom with the same name. mol::AtomHandle me=curr_residue_.FindAtom(aname); if (me.IsValid()) { try { - editor.AddAltAtomPos(String(1, alt_loc), me, apos); + editor.AddAltAtomPos(String(1, alt_loc), me, apos, o, b); } catch (Error) { LOG_INFO("Ignoring atom alt location since there is already an atom " "with name " << aname << ", but without an alt loc"); @@ -822,7 +824,7 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num, return; } else { ah=editor.InsertAltAtom(curr_residue_, aname, - String(1, alt_loc), apos, s_ele); + String(1, alt_loc), apos, s_ele, o, b); ++atom_count_; } } else { @@ -844,12 +846,8 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num, ah.SetRadius(radius.second); } } - if (temp.first) { - ah.SetBFactor(temp.second); - } - if (occ.first) { - ah.SetOccupancy(occ.second); - } + ah.SetBFactor(b); + ah.SetOccupancy(o); if (charge.first) { ah.SetCharge(charge.second); } diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc index f3c863594c926c330426c5322f0638715cb676ce..fdae17a5110b741790e5c4c4c791b78cb67edbe6 100644 --- a/modules/io/src/mol/pdb_writer.cc +++ b/modules/io/src/mol/pdb_writer.cc @@ -172,8 +172,8 @@ void write_atom(std::ostream& ostr, FormattedLine& line, line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2); line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2); } else { - line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2); - Real bfac=atom.GetBFactor(); + line(54, 6)=fmt::LPaddedFloat(atom.GetAltOcc(*i), 2); + Real bfac=atom.GetAltBFactor(*i); if (bfac>999.99) { line(60, 6)=fmt::LPaddedFloat(999.99, 2); } else { diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc index 1e7ecde2f7aabbc31843870d0dc6f3260584a66b..cb40a2c04a0a737da86f6c83ab2e8a014e1d378c 100644 --- a/modules/io/tests/test_io_pdb.cc +++ b/modules/io/tests/test_io_pdb.cc @@ -424,6 +424,25 @@ BOOST_AUTO_TEST_CASE(deuterium_import) BOOST_CHECK(ent.FindResidue("A", 297).IsPeptideLinking()); } +BOOST_AUTO_TEST_CASE(bzdng_318) +{ + String fname("testfiles/pdb/bzdng-318.pdb"); + PDBReader reader(fname, IOProfile()); + mol::EntityHandle ent=mol::CreateEntity(); + reader.Import(ent); + // we use conopology to mark amino acids as peptide-linking. + conop::Conopology& conop_inst=conop::Conopology::Instance(); + conop_inst.ConnectAll(conop_inst.GetBuilder(), ent); + { + PDBWriter writer(std::string("testfiles/pdb/bzdng-318-out.pdb"), + IOProfile()); + writer.Write(ent); + } + + BOOST_CHECK(compare_files("testfiles/pdb/bzdng-318.pdb", + "testfiles/pdb/bzdng-318-out.pdb")); +} + BOOST_AUTO_TEST_CASE(faulty_lines) { String fname("testfiles/pdb/faulty.pdb"); diff --git a/modules/io/tests/testfiles/pdb/bzdng-318.pdb b/modules/io/tests/testfiles/pdb/bzdng-318.pdb new file mode 100644 index 0000000000000000000000000000000000000000..8008e84b1abbeeeed341e7e91745c5327923b633 --- /dev/null +++ b/modules/io/tests/testfiles/pdb/bzdng-318.pdb @@ -0,0 +1,4 @@ +ATOM 1 CA ALYS A 9 31.209 -9.896 12.154 0.62 22.96 C +ATOM 1 CA BLYS A 9 31.213 -9.902 12.145 0.38 24.64 C +TER 2 LYS A 9 +END \ No newline at end of file diff --git a/modules/mol/base/src/atom_base.cc b/modules/mol/base/src/atom_base.cc index 642ea5aa93baad015633ab13caedbb2f7e3f704d..c818fbc1cec5ee0c0fa1be6fbb51eb59750133f0 100644 --- a/modules/mol/base/src/atom_base.cc +++ b/modules/mol/base/src/atom_base.cc @@ -69,6 +69,17 @@ geom::Vec3 AtomBase::GetAltPos(const String& alt_group) const return impl_->GetResidue()->GetAltAtomPos(Impl(), alt_group); } +Real AtomBase::GetAltBFactor(const String& alt_group) const +{ + this->CheckValidity(); + return impl_->GetResidue()->GetAltAtomBFactor(Impl(), alt_group); +} +Real AtomBase::GetAltOcc(const String& alt_group) const +{ + this->CheckValidity(); + return impl_->GetResidue()->GetAltAtomOcc(Impl(), alt_group); +} + std::vector<String> AtomBase::GetAltGroupNames() const { this->CheckValidity(); diff --git a/modules/mol/base/src/atom_base.hh b/modules/mol/base/src/atom_base.hh index 8d19514af07c9e58536cf505ee7f51f11098dd52..13795311560e4c81d46063156c75aa6459359131 100644 --- a/modules/mol/base/src/atom_base.hh +++ b/modules/mol/base/src/atom_base.hh @@ -87,6 +87,8 @@ public: const geom::Vec3& GetOriginalPos() const; /// \brief get alternative atom position geom::Vec3 GetAltPos(const String& alt_group) const; + Real GetAltBFactor(const String& alt_group) const; + Real GetAltOcc(const String& alt_group) const; std::vector<String> GetAltGroupNames() const; diff --git a/modules/mol/base/src/editor_base.cc b/modules/mol/base/src/editor_base.cc index ba822f0f5e3f57535d1ae59ab9837819f447221d..d75827806359c8dc5036fa7cf819abb0ce7ffcc6 100644 --- a/modules/mol/base/src/editor_base.cc +++ b/modules/mol/base/src/editor_base.cc @@ -119,21 +119,26 @@ AtomHandle EditorBase::InsertAtom(ResidueHandle res, const String& name, AtomHandle EditorBase::InsertAltAtom(ResidueHandle res, const String& name, const String& alt_group, const geom::Vec3& pos, - const String& ele) + const String& ele, Real occ, + Real b_factor) { CheckHandleValidity(res); ent_.Impl()->MarkTraceDirty(); - AtomHandle atom(res.Impl()->InsertAltAtom(name, alt_group, pos, ele)); + AtomHandle atom(res.Impl()->InsertAltAtom(name, alt_group, pos, + ele, occ, b_factor)); this->UpdateTrace(); return atom; } void EditorBase::AddAltAtomPos(const String& group, const AtomHandle& atom, - const geom::Vec3& position) + const geom::Vec3& position, Real occ, + Real b_factor) { CheckHandleValidity(atom); - atom.GetResidue().Impl()->AddAltAtomPos(group, atom.Impl(), position); + atom.GetResidue().Impl()->AddAltAtomPos(group, atom.Impl(), + position, occ, b_factor); + } void EditorBase::DeleteChain(const ChainHandle& chain) diff --git a/modules/mol/base/src/editor_base.hh b/modules/mol/base/src/editor_base.hh index c6309cce3ee22f5c792b6240487d16b15c6ed48c..504311d547cf00f43e11fb5b1c49925a16564e34 100644 --- a/modules/mol/base/src/editor_base.hh +++ b/modules/mol/base/src/editor_base.hh @@ -124,7 +124,8 @@ public: /// \sa EditorBase::AddAltAtomPos(), ResidueHandle AtomHandle InsertAltAtom(ResidueHandle residue, const String& name, const String& alt_group, const geom::Vec3& pos, - const String& ele=""); + const String& ele="", Real occ=1.0, + Real b_factor=0.0); /// \brief Add alternative atom position /// \param group is the name of the alternative atom position group. If no /// group of that name exists, it will be created. @@ -136,7 +137,8 @@ public: /// is the alternative position /// \sa EditorBase::InsertAltAtom(), ResidueHandle void AddAltAtomPos(const String& group, const AtomHandle& atom, - const geom::Vec3& position); + const geom::Vec3& position, Real occ=1.0, + Real b_factor=0.0); //\} /// \brief connect two atoms with bond diff --git a/modules/mol/base/src/impl/atom_group.hh b/modules/mol/base/src/impl/atom_group.hh index 934fda241c3c614185a2fe32a77ccdad6b0582e3..50a7c6338972313b36f41bed8072f60d42cdf21a 100644 --- a/modules/mol/base/src/impl/atom_group.hh +++ b/modules/mol/base/src/impl/atom_group.hh @@ -29,10 +29,13 @@ namespace ost { namespace mol {namespace impl { struct AtomGroupEntry { AtomGroupEntry() {} - AtomGroupEntry(const AtomImplPtr& a, const geom::Vec3& p) - : atom(a), pos(p) {} + AtomGroupEntry(const AtomImplPtr& a, const geom::Vec3& p, + Real o, Real b) + : atom(a), pos(p), occ(o), b_factor(b) {} impl::AtomImplW atom; geom::Vec3 pos; + Real occ; + Real b_factor; }; typedef std::vector<AtomGroupEntry> AtomGroupEntryList; diff --git a/modules/mol/base/src/impl/residue_impl.cc b/modules/mol/base/src/impl/residue_impl.cc index eb633c5be612603ae304975dfd24335c53aa92ec..1e0fa1d461662e1895f6d8dd5bbeb7d8a58479f6 100644 --- a/modules/mol/base/src/impl/residue_impl.cc +++ b/modules/mol/base/src/impl/residue_impl.cc @@ -91,7 +91,8 @@ Real ResidueImpl::GetAverageBFactor() const } void ResidueImpl::AddAltAtom(const String& group, const AtomImplPtr& atom, - const geom::Vec3& position) { + const geom::Vec3& position, + Real occ, Real b_factor) { if (group.length()==0) throw Error("alt atom group name can't be empty String"); @@ -106,7 +107,7 @@ void ResidueImpl::AddAltAtom(const String& group, const AtomImplPtr& atom, curr_group_=group; } } - i->second.atoms.push_back(AtomGroupEntry(atom, position)); + i->second.atoms.push_back(AtomGroupEntry(atom, position, occ, b_factor)); } geom::Vec3 ResidueImpl::GetAltAtomPos(const AtomImplPtr& atom, @@ -127,12 +128,47 @@ geom::Vec3 ResidueImpl::GetAltAtomPos(const AtomImplPtr& atom, " does not have alternative atom position '"+group+"'"); } +Real ResidueImpl::GetAltAtomOcc(const AtomImplPtr& atom, + const String& group) const +{ + AtomEntryGroups::const_iterator i=alt_groups_.find(group); + if (i==alt_groups_.end()) { + throw Error("No alt atom group '"+group+"'"); + } + const AtomGroup& g=i->second; + for (AtomGroupEntryList::const_iterator j=g.atoms.begin(), + e=g.atoms.end(); j!=e; ++j) { + if (atom==j->atom.lock()) { + return j->occ; + } + } + throw Error(atom->GetQualifiedName()+ + " does not have alternative atom position '"+group+"'"); +} +Real ResidueImpl::GetAltAtomBFactor(const AtomImplPtr& atom, + const String& group) const +{ + AtomEntryGroups::const_iterator i=alt_groups_.find(group); + if (i==alt_groups_.end()) { + throw Error("No alt atom group '"+group+"'"); + } + const AtomGroup& g=i->second; + for (AtomGroupEntryList::const_iterator j=g.atoms.begin(), + e=g.atoms.end(); j!=e; ++j) { + if (atom==j->atom.lock()) { + return j->b_factor; + } + } + throw Error(atom->GetQualifiedName()+ + " does not have alternative atom position '"+group+"'"); +} AtomImplPtr ResidueImpl::InsertAltAtom(const String& name, const String& alt_group, const geom::Vec3& pos, - const String& ele) { + const String& ele, + Real occupancy, Real b_factor) { AtomImplPtr atom=this->InsertAtom(name, pos, ele); - this->AddAltAtom(alt_group, atom, pos); + this->AddAltAtom(alt_group, atom, pos, occupancy, b_factor); return atom; } @@ -506,7 +542,8 @@ geom::Vec3 ResidueImpl::GetCenterOfMass() const void ResidueImpl::AddAltAtomPos(const String& group, const AtomImplPtr& atom, - const geom::Vec3& position) { + const geom::Vec3& position, + Real occ, Real b_factor) { // Make sure atom is already registered for having an alternative position. // Bail out, if this is not the case. AtomEntryGroups::iterator i=alt_groups_.begin(); @@ -522,7 +559,7 @@ void ResidueImpl::AddAltAtomPos(const String& group, } } if (found) - this->AddAltAtom(group, atom, position); + this->AddAltAtom(group, atom, position, occ, b_factor); else { String m="Definition of alternative position without prior call to " "InsertAltAtom is not allowed"; @@ -582,6 +619,8 @@ bool ResidueImpl::SwitchAtomPos(const String& group) { AtomGroupEntry& entry=*k; assert(!entry.atom.expired()); entry.pos=entry.atom.lock()->OriginalPos(); + entry.occ=entry.atom.lock()->GetOccupancy(); + entry.b_factor=entry.atom.lock()->GetBFactor(); } } AtomGroup& agr=i->second; @@ -595,6 +634,8 @@ bool ResidueImpl::SwitchAtomPos(const String& group) { geom::Mat4 transf_matrix = ent.GetTransformationMatrix(); geom::Vec3 transf_pos = geom::Vec3(transf_matrix*geom::Vec4(entry.pos)); entry.atom.lock()->TransformedPos()=transf_pos; + entry.atom.lock()->SetBFactor(j->b_factor); + entry.atom.lock()->SetOccupancy(j->occ); } curr_group_=group; return true; diff --git a/modules/mol/base/src/impl/residue_impl.hh b/modules/mol/base/src/impl/residue_impl.hh index b52d26fc7a9449bf84f1a39bbf2cf592be362b37..24f829c6922bdbfdcc0ee8645cbec80e4ff49f88 100644 --- a/modules/mol/base/src/impl/residue_impl.hh +++ b/modules/mol/base/src/impl/residue_impl.hh @@ -58,7 +58,8 @@ public: /// no bonds AtomImplPtr InsertAtom(const AtomImplPtr& atom); AtomImplPtr InsertAltAtom(const String& name, const String& alt_group, - const geom::Vec3& pos, const String& ele); + const geom::Vec3& pos, const String& ele, + Real occ, Real b_factor); const ResNum& GetNumber() const {return num_;} void SetNumber(const ResNum& num) {num_=num;} @@ -167,8 +168,11 @@ public: void AddAltAtomPos(const String& group, const AtomImplPtr& atom, - const geom::Vec3& position); + const geom::Vec3& position, + Real occ, Real b_factor); geom::Vec3 GetAltAtomPos(const AtomImplPtr& atom, const String& group) const; + Real GetAltAtomOcc(const AtomImplPtr& atom, const String& group) const; + Real GetAltAtomBFactor(const AtomImplPtr& atom, const String& group) const; const String& GetCurrentAltGroupName() const { @@ -221,7 +225,7 @@ public: void SetIsLigand(bool flag) { ligand_=flag; } private: void AddAltAtom(const String& group, const AtomImplPtr& atom, - const geom::Vec3& position); + const geom::Vec3& position, Real occ, Real b_factor); void RemoveAltPositionsForAtom(const AtomImplPtr& atom); String curr_group_;