Commit e1b240b2 by Maarten L. Hekkelman

sugar work

parent 3d79278e
...@@ -13,4 +13,4 @@ msvc/ ...@@ -13,4 +13,4 @@ msvc/
Testing/ Testing/
rsrc/feature-request.txt rsrc/feature-request.txt
test/1cbs.cif test/1cbs.cif
test/test-create_sugar_2.cif test/test-create_sugar_?.cif
...@@ -527,6 +527,9 @@ class Sugar : public Residue ...@@ -527,6 +527,9 @@ class Sugar : public Residue
Sugar(const Branch &branch, const std::string &compoundID, Sugar(const Branch &branch, const std::string &compoundID,
const std::string &asymID, int authSeqID); const std::string &asymID, int authSeqID);
Sugar(Sugar &&rhs);
Sugar &operator=(Sugar &&rhs);
int num() const { return std::stoi(mAuthSeqID); } int num() const { return std::stoi(mAuthSeqID); }
std::string name() const; std::string name() const;
...@@ -534,9 +537,14 @@ class Sugar : public Residue ...@@ -534,9 +537,14 @@ class Sugar : public Residue
Atom getLink() const { return mLink; } Atom getLink() const { return mLink; }
void setLink(Atom link) { mLink = link; } void setLink(Atom link) { mLink = link; }
size_t getLinkNr() const
{
return mLink ? std::stoi(mLink.authSeqID()) : 0;
}
private: private:
const Branch &mBranch; const Branch *mBranch;
Atom mLink; Atom mLink;
}; };
...@@ -710,7 +718,11 @@ class Structure ...@@ -710,7 +718,11 @@ class Structure
} }
// Actions // Actions
void removeAtom(Atom &a); void removeAtom(Atom &a)
{
removeAtom(a, true);
}
void swapAtoms(Atom a1, Atom a2); // swap the labels for these atoms void swapAtoms(Atom a1, Atom a2); // swap the labels for these atoms
void moveAtom(Atom a, Point p); // move atom to a new location void moveAtom(Atom a, Point p); // move atom to a new location
void changeResidue(Residue &res, const std::string &newCompound, void changeResidue(Residue &res, const std::string &newCompound,
...@@ -815,6 +827,9 @@ class Structure ...@@ -815,6 +827,9 @@ class Structure
Atom &emplace_atom(Atom &&atom); Atom &emplace_atom(Atom &&atom);
void removeAtom(Atom &a, bool removeFromResidue);
void removeSugar(Sugar &sugar);
cif::Datablock &mDb; cif::Datablock &mDb;
size_t mModelNr; size_t mModelNr;
AtomView mAtoms; AtomView mAtoms;
......
...@@ -1128,10 +1128,28 @@ int Polymer::Distance(const Monomer &a, const Monomer &b) const ...@@ -1128,10 +1128,28 @@ int Polymer::Distance(const Monomer &a, const Monomer &b) const
Sugar::Sugar(const Branch &branch, const std::string &compoundID, Sugar::Sugar(const Branch &branch, const std::string &compoundID,
const std::string &asymID, int authSeqID) const std::string &asymID, int authSeqID)
: Residue(branch.structure(), compoundID, asymID, 0, std::to_string(authSeqID)) : Residue(branch.structure(), compoundID, asymID, 0, std::to_string(authSeqID))
, mBranch(branch) , mBranch(&branch)
{ {
} }
Sugar::Sugar(Sugar &&rhs)
: Residue(std::forward<Residue>(rhs))
, mBranch(rhs.mBranch)
{
}
Sugar &Sugar::operator=(Sugar &&rhs)
{
if (this != &rhs)
{
Residue::operator=(std::forward<Residue>(rhs));
mBranch = rhs.mBranch;
}
return *this;
}
// bool Sugar::hasLinkedSugarAtLeavingO(int leavingO) const // bool Sugar::hasLinkedSugarAtLeavingO(int leavingO) const
// { // {
// return false; // return false;
...@@ -1874,7 +1892,7 @@ Atom &Structure::emplace_atom(Atom &&atom) ...@@ -1874,7 +1892,7 @@ Atom &Structure::emplace_atom(Atom &&atom)
return mAtoms.emplace_back(std::move(atom)); return mAtoms.emplace_back(std::move(atom));
} }
void Structure::removeAtom(Atom &a) void Structure::removeAtom(Atom &a, bool removeFromResidue)
{ {
using namespace cif::literals; using namespace cif::literals;
...@@ -1883,15 +1901,18 @@ void Structure::removeAtom(Atom &a) ...@@ -1883,15 +1901,18 @@ void Structure::removeAtom(Atom &a)
auto &atomSites = db["atom_site"]; auto &atomSites = db["atom_site"];
atomSites.erase("id"_key == a.id()); atomSites.erase("id"_key == a.id());
try if (removeFromResidue)
{
auto &res = getResidue(a);
res.mAtoms.erase(std::remove(res.mAtoms.begin(), res.mAtoms.end(), a), res.mAtoms.end());
}
catch (const std::exception &ex)
{ {
if (cif::VERBOSE > 0) try
std::cerr << "Error removing atom from residue: " << ex.what() << std::endl; {
auto &res = getResidue(a);
res.mAtoms.erase(std::remove(res.mAtoms.begin(), res.mAtoms.end(), a), res.mAtoms.end());
}
catch (const std::exception &ex)
{
if (cif::VERBOSE > 0)
std::cerr << "Error removing atom from residue: " << ex.what() << std::endl;
}
} }
assert(mAtomIndex.size() == mAtoms.size()); assert(mAtomIndex.size() == mAtoms.size());
...@@ -2078,8 +2099,6 @@ void Structure::removeResidue(Residue &res) ...@@ -2078,8 +2099,6 @@ void Structure::removeResidue(Residue &res)
cif::Datablock &db = datablock(); cif::Datablock &db = datablock();
auto atoms = res.atoms(); auto atoms = res.atoms();
for (auto atom : atoms)
removeAtom(atom);
switch (res.entityType()) switch (res.entityType())
{ {
...@@ -2108,12 +2127,104 @@ void Structure::removeResidue(Residue &res) ...@@ -2108,12 +2127,104 @@ void Structure::removeResidue(Residue &res)
break; break;
case EntityType::Branched: case EntityType::Branched:
throw std::runtime_error("Don't remove a sugar using removeResidue..."); {
Sugar &sugar = dynamic_cast<Sugar&>(res);
removeSugar(sugar);
atoms.clear();
break;
}
case EntityType::Macrolide: case EntityType::Macrolide:
// TODO: Fix this? // TODO: Fix this?
throw std::runtime_error("no support for macrolides yet"); throw std::runtime_error("no support for macrolides yet");
} }
for (auto atom : atoms)
removeAtom(atom, false);
}
void Structure::removeSugar(Sugar &sugar)
{
using namespace cif::literals;
std::string asym_id = sugar.asymID();
Branch &branch = getBranchByAsymID(asym_id);
auto si = std::find(branch.begin(), branch.end(), sugar);
if (si == branch.end())
throw std::runtime_error("Sugar not part of branch");
size_t six = si - branch.begin();
if (six == 0) // first sugar, means the death of this branch
removeBranch(branch);
else
{
std::set<size_t> dix;
std::stack<size_t> test;
test.push(sugar.num());
while (not test.empty())
{
auto tix = test.top();
test.pop();
if (dix.count(tix))
continue;
dix.insert(tix);
for (auto atom : branch[tix - 1].atoms())
removeAtom(atom, false);
for (auto &s : branch)
{
if (s.getLinkNr() == tix)
test.push(s.num());
}
}
branch.erase(remove_if(branch.begin(), branch.end(), [dix](const Sugar &s) { return dix.count(s.num()); }), branch.end());
cif::Datablock &db = datablock();
auto entity_id = createEntityForBranch(branch);
// Update the entity id of the asym
auto &struct_asym = db["struct_asym"];
auto r = struct_asym.find1("id"_key == asym_id);
r["entity_id"] = entity_id;
for (auto &sugar : branch)
{
for (auto atom : sugar.atoms())
atom.set_property("label_entity_id", entity_id);
}
auto &pdbx_branch_scheme = db["pdbx_branch_scheme"];
pdbx_branch_scheme.erase("asym_id"_key == asym_id);
for (auto &sugar : branch)
{
pdbx_branch_scheme.emplace({
{"asym_id", asym_id},
{"entity_id", entity_id},
{"num", sugar.num()},
{"mon_id", sugar.compoundID()},
{"pdb_asym_id", asym_id},
{"pdb_seq_num", sugar.num()},
{"pdb_mon_id", sugar.compoundID()},
// TODO: need fix, collect from nag_atoms?
{"auth_asym_id", asym_id},
{"auth_mon_id", sugar.compoundID()},
{"auth_seq_num", sugar.num()},
{"hetero", "n"}
});
}
}
} }
void Structure::removeBranch(Branch &branch) void Structure::removeBranch(Branch &branch)
...@@ -2331,16 +2442,19 @@ Branch &Structure::createBranch(std::vector<std::vector<cif::Item>> &nag_atoms) ...@@ -2331,16 +2442,19 @@ Branch &Structure::createBranch(std::vector<std::vector<cif::Item>> &nag_atoms)
// now we can create the entity and get the real ID // now we can create the entity and get the real ID
auto entity_id = createEntityForBranch(branch); auto entity_id = createEntityForBranch(branch);
struct_asym.emplace({{"id", asym_id}, struct_asym.emplace({
{"id", asym_id},
{"pdbx_blank_PDB_chainid_flag", "N"}, {"pdbx_blank_PDB_chainid_flag", "N"},
{"pdbx_modified", "N"}, {"pdbx_modified", "N"},
{"entity_id", entity_id}, {"entity_id", entity_id},
{"details", "?"}}); {"details", "?"}
});
for (auto &a : sugar.atoms()) for (auto &a : sugar.atoms())
a.set_property("label_entity_id", entity_id); a.set_property("label_entity_id", entity_id);
db["pdbx_branch_scheme"].emplace({{"asym_id", asym_id}, db["pdbx_branch_scheme"].emplace({
{"asym_id", asym_id},
{"entity_id", entity_id}, {"entity_id", entity_id},
{"num", 1}, {"num", 1},
{"mon_id", "NAG"}, {"mon_id", "NAG"},
...@@ -2354,7 +2468,8 @@ Branch &Structure::createBranch(std::vector<std::vector<cif::Item>> &nag_atoms) ...@@ -2354,7 +2468,8 @@ Branch &Structure::createBranch(std::vector<std::vector<cif::Item>> &nag_atoms)
{"auth_mon_id", "NAG"}, {"auth_mon_id", "NAG"},
{"auth_seq_num", 1}, {"auth_seq_num", 1},
{"hetero", "n"}}); {"hetero", "n"}
});
return branch; return branch;
} }
...@@ -2412,6 +2527,7 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec ...@@ -2412,6 +2527,7 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec
appendUnlessSet(atom, {"group_PDB", "HETATM"}); appendUnlessSet(atom, {"group_PDB", "HETATM"});
appendUnlessSet(atom, {"id", atom_id}); appendUnlessSet(atom, {"id", atom_id});
appendUnlessSet(atom, {"label_asym_id", asym_id});
appendUnlessSet(atom, {"label_comp_id", compoundID}); appendUnlessSet(atom, {"label_comp_id", compoundID});
appendUnlessSet(atom, {"label_entity_id", tmp_entity_id}); appendUnlessSet(atom, {"label_entity_id", tmp_entity_id});
appendUnlessSet(atom, {"auth_comp_id", compoundID}); appendUnlessSet(atom, {"auth_comp_id", compoundID});
...@@ -2429,6 +2545,11 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec ...@@ -2429,6 +2545,11 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec
auto entity_id = createEntityForBranch(branch); auto entity_id = createEntityForBranch(branch);
// Update the entity id of the asym
auto &struct_asym = db["struct_asym"];
auto r = struct_asym.find1("id"_key == asym_id);
r["entity_id"] = entity_id;
for (auto &sugar : branch) for (auto &sugar : branch)
{ {
for (auto atom : sugar.atoms()) for (auto atom : sugar.atoms())
...@@ -2440,7 +2561,8 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec ...@@ -2440,7 +2561,8 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec
for (auto &sugar : branch) for (auto &sugar : branch)
{ {
pdbx_branch_scheme.emplace({{"asym_id", asym_id}, pdbx_branch_scheme.emplace({
{"asym_id", asym_id},
{"entity_id", entity_id}, {"entity_id", entity_id},
{"num", sugar.num()}, {"num", sugar.num()},
{"mon_id", sugar.compoundID()}, {"mon_id", sugar.compoundID()},
...@@ -2454,7 +2576,8 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec ...@@ -2454,7 +2576,8 @@ Branch &Structure::extendBranch(const std::string &asym_id, std::vector<std::vec
{"auth_mon_id", sugar.compoundID()}, {"auth_mon_id", sugar.compoundID()},
{"auth_seq_num", sugar.num()}, {"auth_seq_num", sugar.num()},
{"hetero", "n"}}); {"hetero", "n"}
});
} }
return branch; return branch;
...@@ -2484,43 +2607,42 @@ std::string Structure::createEntityForBranch(Branch &branch) ...@@ -2484,43 +2607,42 @@ std::string Structure::createEntityForBranch(Branch &branch)
{"src_method", "man"}, {"src_method", "man"},
{"pdbx_description", entityName}, {"pdbx_description", entityName},
{"formula_weight", branch.weight()}}); {"formula_weight", branch.weight()}});
} auto &pdbx_entity_branch_list = mDb["pdbx_entity_branch_list"];
for (auto &sugar : branch)
auto &pdbx_entity_branch_list = mDb["pdbx_entity_branch_list"]; {
pdbx_entity_branch_list.erase("entity_id"_key == entityID); pdbx_entity_branch_list.emplace({
{"entity_id", entityID},
for (auto &sugar : branch) {"comp_id", sugar.compoundID()},
{ {"num", sugar.num()},
pdbx_entity_branch_list.emplace({{"entity_id", entityID}, {"hetero", "n"}
{"comp_id", sugar.compoundID()}, });
{"num", sugar.num()}, }
{"hetero", "n"}});
}
auto &pdbx_entity_branch_link = mDb["pdbx_entity_branch_link"];
pdbx_entity_branch_link.erase("entity_id"_key == entityID);
for (auto &s1 : branch) auto &pdbx_entity_branch_link = mDb["pdbx_entity_branch_link"];
{ for (auto &s1 : branch)
auto l2 = s1.getLink(); {
auto l2 = s1.getLink();
if (not l2) if (not l2)
continue; continue;
auto &s2 = branch.at(std::stoi(l2.authSeqID()) - 1); auto &s2 = branch.at(std::stoi(l2.authSeqID()) - 1);
auto l1 = s2.atomByID("C1"); auto l1 = s2.atomByID("C1");
pdbx_entity_branch_link.emplace({{"link_id", pdbx_entity_branch_link.getUniqueID("")}, pdbx_entity_branch_link.emplace({
{"entity_id", entityID}, {"link_id", pdbx_entity_branch_link.getUniqueID("")},
{"entity_branch_list_num_1", s1.authSeqID()}, {"entity_id", entityID},
{"comp_id_1", s1.compoundID()}, {"entity_branch_list_num_1", s1.authSeqID()},
{"atom_id_1", l1.labelAtomID()}, {"comp_id_1", s1.compoundID()},
{"leaving_atom_id_1", "O1"}, {"atom_id_1", l1.labelAtomID()},
{"entity_branch_list_num_2", s2.authSeqID()}, {"leaving_atom_id_1", "O1"},
{"comp_id_2", s2.compoundID()}, {"entity_branch_list_num_2", s2.authSeqID()},
{"atom_id_2", l2.labelAtomID()}, {"comp_id_2", s2.compoundID()},
{"leaving_atom_id_2", "H" + l2.labelAtomID()}, {"atom_id_2", l2.labelAtomID()},
{"value_order", "sing"}}); {"leaving_atom_id_2", "H" + l2.labelAtomID()},
{"value_order", "sing"}
});
}
} }
return entityID; return entityID;
......
...@@ -165,4 +165,35 @@ BOOST_AUTO_TEST_CASE(create_sugar_2) ...@@ -165,4 +165,35 @@ BOOST_AUTO_TEST_CASE(create_sugar_2)
BOOST_CHECK_EQUAL(bN.size(), 2); BOOST_CHECK_EQUAL(bN.size(), 2);
file.save(gTestDir / "test-create_sugar_2.cif"); file.save(gTestDir / "test-create_sugar_2.cif");
BOOST_CHECK_NO_THROW(mmcif::Structure s2(file));
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(delete_sugar_1)
{
using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
mmcif::File file(example.string());
mmcif::Structure s(file);
// Get branch for H
auto &bG = s.getBranchByAsymID("G");
BOOST_CHECK_EQUAL(bG.size(), 4);
s.removeResidue(bG[1]);
BOOST_CHECK_EQUAL(bG.size(), 1);
auto &bN = s.getBranchByAsymID("G");
BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose");
BOOST_CHECK_EQUAL(bN.size(), 1);
file.save(gTestDir / "test-create_sugar_3.cif");
BOOST_CHECK_NO_THROW(mmcif::Structure s2(file));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment