Commit 7460007b by Maarten L. Hekkelman

New strand calculations

parent 2f352826
......@@ -172,6 +172,7 @@ class dssp
std::tuple<residue_info, int, bool> bridge_partner(int i) const;
int sheet() const;
int strand() const;
/// \brief return resinfo and the energy of the bond
std::tuple<residue_info, double> acceptor(int i) const;
......
......@@ -322,8 +322,9 @@ void writeBridgePairs(cif::datablock &db, const dssp &dssp)
void writeSheets(cif::datablock &db, const dssp &dssp)
{
using namespace cif::literals;
using res_list = std::vector<dssp::residue_info>;
using ss_type = dssp::structure_type;
// clean up old info first
......@@ -334,448 +335,411 @@ void writeSheets(cif::datablock &db, const dssp &dssp)
// create a list of strands, based on the SS info in DSSP. Store sheet number along with the strand.
std::vector<std::tuple<int, res_list>> strands;
std::map<std::tuple<std::string, int>, int> sheetMap; // mapping from bridge number (=info.sheet()) in DSSP to sheet ID
ss_type ss = ss_type::Loop;
std::map<std::tuple<int,int>, res_list> strands;
std::set<int> sheetNrs;
for (auto &res : dssp)
{
std::tuple<std::string, int> sheetID{ res.asym_id(), res.sheet() };
ss_type iss = res.type();
if (iss == ss and ss == ss_type::Strand and
sheetMap.count(sheetID) > 0 and sheetMap[sheetID] == std::get<0>(strands.back()))
{
std::get<1>(strands.back()).emplace_back(res);
continue;
}
ss = iss;
if (ss != ss_type::Strand)
if (res.type() != dssp::structure_type::Strand)
continue;
if (not sheetMap.count(sheetID))
sheetMap[sheetID] = static_cast<int>(sheetMap.size());
strands.emplace_back(sheetMap[sheetID], res_list{ res });
strands[{res.sheet(), res.strand()}].emplace_back(res);
sheetNrs.insert(res.sheet());
}
// sort the strands vector
std::sort(strands.begin(), strands.end(), [](auto &a, auto &b)
{
const auto &[sheetA, strandsA] = a;
const auto &[sheetB, strandsB] = b;
int d = sheetA - sheetB;
if (d == 0)
d = strandsA.front().nr() - strandsB.front().nr();
return d < 0; });
// write out the struct_sheet, since all info is available now
auto &struct_sheet = db["struct_sheet"];
auto &struct_sheet_range = db["struct_sheet_range"];
auto &struct_sheet_order = db["struct_sheet_order"];
auto &struct_sheet_hbond = db["struct_sheet_hbond"];
// auto &pdbx_struct_sheet_hbond = db["pdbx_struct_sheet_hbond"];
// auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"];
int lastSheet = -1;
for (const auto &[sheetNr, strand] : strands)
{
if (sheetNr != lastSheet)
{
struct_sheet.emplace({
{ "id", cif::cif_id_for_number(sheetNr) },
{ "number_strands",
std::count_if(strands.begin(), strands.end(), [nr = sheetNr](std::tuple<int, res_list> const &s)
{ return std::get<0>(s) == nr; })
}
});
lastSheet = sheetNr;
}
}
// Each residue resides in a single strand which is part of a single sheet
// this function returns the sequence number inside the sheet for the strand
// containing res
std::map<int,int> strandMap;
int strandNr = 0;
for (auto &&[sheet, strand] : strands)
for (int sheetNr : sheetNrs)
{
for (auto &r : strand)
{
if (r.type() != ss_type::Strand)
continue;
strandMap[r.nr()] = strandNr;
}
++strandNr;
}
auto sheetID = cif::cif_id_for_number(sheetNr - 1);
// This map is used to record the sense of a ladder, and can be used
// to detect ladders already seen.
std::map<std::tuple<int, int, int>, std::tuple<int, bool>> ladderSense;
std::map<std::tuple<int,int>,int> sheetOrder;
for (auto &res : dssp)
{
if (res.type() != ss_type::Strand)
continue;
int s1 = strandMap[res.nr()];
struct_sheet.emplace({
{ "id", sheetID },
{ "number_strands",
std::count_if(strands.begin(), strands.end(), [nr = sheetNr](std::tuple<std::tuple<int,int>, res_list> const &s)
{
const auto &[strandID, strand] = s;
return strand.front().sheet() == nr;
})
}
});
for (int i : { 0, 1 })
for (auto &&[strandTuple, strand] : strands)
{
const auto &[p, ladder, parallel] = res.bridge_partner(i);
if (not p or p.asym_id() != res.asym_id() or p.sheet() != res.sheet() or p.type() != ss_type::Strand)
if (strand.front().sheet() != sheetNr)
continue;
std::string strandID = "strand_" + cif::cif_id_for_number(strand.front().strand() - 1);
int s2 = strandMap[p.nr()];
// assert(s1 != s2);
if (s2 == s1)
continue;
std::sort(strand.begin(), strand.end(), [](dssp::residue_info const &a, dssp::residue_info const &b)
{ return a.nr() < b.nr(); });
std::tuple<std::string, int> sheetID{ res.asym_id(), res.sheet() };
int sheet = sheetMap[sheetID];
auto &beg = strand.front();
auto &end = strand.back();
auto k = s1 > s2 ? std::make_tuple(sheet, s2, s1) : std::make_tuple(sheet, s1, s2);
if (ladderSense.count(k))
struct_sheet_range.emplace({
{ "sheet_id", sheetID },
{ "id", strandID },
{ "beg_label_comp_id", beg.compound_id() },
{ "beg_label_asym_id", beg.asym_id() },
{ "beg_label_seq_id", beg.seq_id() },
{ "pdbx_beg_PDB_ins_code", beg.pdb_ins_code() },
{ "end_label_comp_id", end.compound_id() },
{ "end_label_asym_id", end.asym_id() },
{ "end_label_seq_id", end.seq_id() },
{ "pdbx_end_PDB_ins_code", end.pdb_ins_code() },
{ "beg_auth_comp_id", beg.compound_id() },
{ "beg_auth_asym_id", beg.auth_asym_id() },
{ "beg_auth_seq_id", beg.auth_seq_id() },
{ "end_auth_comp_id", end.compound_id() },
{ "end_auth_asym_id", end.auth_asym_id() },
{ "end_auth_seq_id", end.auth_seq_id() } });
// loop over the ladders for this strand and write out the struct_sheet_order
for (auto &res : strand)
{
// assert(ladderSense[k] == std::make_tuple(ladder, parallel));
assert(std::get<1>(ladderSense[k]) == parallel);
continue;
for (int i : { 0, 1 })
{
const auto &[bp, ladder, parallel] = res.bridge_partner(i);
if (not bp or bp.type() != dssp::structure_type::Strand)
continue;
auto s1 = res.strand();
auto s2 = bp.strand();
if (s1 > s2)
std::swap(s1, s2);
sheetOrder[{ s1, s2 }] += parallel ? 1 : -1;
}
}
ladderSense.emplace(k, std::make_tuple(ladder, parallel));
}
}
auto &struct_sheet_order = db["struct_sheet_order"];
auto &struct_sheet_hbond = db["struct_sheet_hbond"];
auto &pdbx_struct_sheet_hbond = db["pdbx_struct_sheet_hbond"];
auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"];
for (const auto &[k, parallel_test] : sheetOrder)
{
const auto &[s1, s2] = k;
for (const auto &[key, value] : ladderSense)
{
const auto &[sheet, s1, s2] = key;
const auto &[ladder, parallel] = value;
if (parallel_test == 0)
continue;
bool parallel = parallel_test > 0;
struct_sheet_order.emplace({ { "sheet_id", cif::cif_id_for_number(sheet) },
// { "dssp_struct_ladder_id", cif::cifIdForNumber(ladder) },
{ "range_id_1", s1 + 1 },
{ "range_id_2", s2 + 1 },
{ "sense", parallel ? "parallel" : "anti-parallel" } });
std::string strandID_1 = "strand_" + cif::cif_id_for_number(s1 - 1);
std::string strandID_2 = "strand_" + cif::cif_id_for_number(s2 - 1);
res_list strand1, strand2;
struct_sheet_order.emplace({
{ "sheet_id", sheetID },
{ "range_id_1", "strand_" + strandID_1 },
{ "range_id_2", "strand_" + strandID_2 },
{ "sense", parallel > 0 ? "parallel" : "anti-parallel" }
});
for (int strandIx = 0; static_cast<size_t>(strandIx) < strands.size(); ++strandIx)
{
const auto &[sSheet, strand] = strands[strandIx];
if (sSheet != sheet)
continue;
res_list strand1, strand2;
if (strandIx == s1)
strand1 = strand;
else if (strandIx == s2)
for (auto &&[strandTuple, strand] : strands)
{
strand2 = strand;
break;
}
}
const auto &[sheet_nr, strand_nr] = strandTuple;
if (sheet_nr != sheetNr)
continue;
assert(not(strand1.empty() or strand2.empty()));
if (strand_nr == s1)
strand1 = strand;
else if (strand_nr == s2)
{
strand2 = strand;
break;
}
}
int beg1SeqID = 0, beg2SeqID = 0, end1SeqID = 0, end2SeqID = 0;
std::string beg1AtomID, beg2AtomID, end1AtomID, end2AtomID;
assert(not(strand1.empty() or strand2.empty()));
if (parallel)
{
// I. a d II. a d parallel
// \ /
// b e b e <= the residues forming the bridge
// / \ ..
// c f c f
int beg1SeqID = 0, beg2SeqID = 0, end1SeqID = 0, end2SeqID = 0;
std::string beg1AtomID, beg2AtomID, end1AtomID, end2AtomID;
for (auto b : strand1)
if (parallel)
{
for (int i : { 0, 1 })
// I. a d II. a d parallel
// \ /
// b e b e <= the residues forming the bridge
// / \ ..
// c f c f
for (auto b : strand1)
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
for (int i : { 0, 1 })
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
if (esi == strand2.end())
continue;
if (esi == strand2.end())
continue;
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto a = *std::prev(bi);
auto c = *std::next(bi);
auto a = *std::prev(bi);
auto c = *std::next(bi);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::prev(ei);
auto f = *std::next(ei);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::prev(ei);
auto f = *std::next(ei);
if (test_bond(e, a) and test_bond(c, e)) // case I.
{
beg1SeqID = a.seq_id();
beg2SeqID = e.seq_id();
if (test_bond(e, a) and test_bond(c, e)) // case I.
{
beg1SeqID = a.seq_id();
beg2SeqID = e.seq_id();
beg1AtomID = "O";
beg2AtomID = "N";
}
else if (test_bond(b, d) and test_bond(f, b)) // case II.
{
beg1SeqID = b.seq_id();
beg2SeqID = d.seq_id();
beg1AtomID = "O";
beg2AtomID = "N";
}
else if (test_bond(b, d) and test_bond(f, b)) // case II.
{
beg1SeqID = b.seq_id();
beg2SeqID = d.seq_id();
beg1AtomID = "N";
beg2AtomID = "O";
beg1AtomID = "N";
beg2AtomID = "O";
}
break;
}
break;
if (beg1SeqID)
break;
}
if (beg1SeqID)
break;
}
std::reverse(strand1.begin(), strand1.end());
std::reverse(strand2.begin(), strand2.end());
std::reverse(strand1.begin(), strand1.end());
std::reverse(strand2.begin(), strand2.end());
for (auto b : strand1)
{
for (int i : { 0, 1 })
for (auto b : strand1)
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
for (int i : { 0, 1 })
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
if (esi == strand2.end())
continue;
if (esi == strand2.end())
continue;
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto a = *std::next(bi);
auto c = *std::prev(bi);
auto a = *std::next(bi);
auto c = *std::prev(bi);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::next(ei);
auto f = *std::prev(ei);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::next(ei);
auto f = *std::prev(ei);
if (test_bond(a, e) and test_bond(e, c)) // case I.
{
end1SeqID = a.seq_id();
end2SeqID = e.seq_id();
if (test_bond(a, e) and test_bond(e, c)) // case I.
{
end1SeqID = a.seq_id();
end2SeqID = e.seq_id();
end1AtomID = "N";
end2AtomID = "O";
}
else if (test_bond(d, b) and test_bond(b, f)) // case II.
{
end1SeqID = b.seq_id();
end2SeqID = d.seq_id();
end1AtomID = "N";
end2AtomID = "O";
}
else if (test_bond(d, b) and test_bond(b, f)) // case II.
{
end1SeqID = b.seq_id();
end2SeqID = d.seq_id();
end1AtomID = "O";
end2AtomID = "N";
}
end1AtomID = "O";
end2AtomID = "N";
break;
}
break;
if (end1SeqID)
break;
}
if (end1SeqID)
break;
}
}
else
{
// III. a <- f IV. a f antiparallel
//
// b e b <-> e <= the residues forming the bridge
//
// c -> d c d
else
{
// III. a <- f IV. a f antiparallel
//
// b e b <-> e <= the residues forming the bridge
//
// c -> d c d
std::reverse(strand2.begin(), strand2.end());
std::reverse(strand2.begin(), strand2.end());
for (auto b : strand1)
{
for (int i : { 0, 1 })
for (auto b : strand1)
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
for (int i : { 0, 1 })
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
if (esi == strand2.end())
continue;
if (esi == strand2.end())
continue;
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto a = *std::prev(bi);
auto c = *std::next(bi);
auto a = *std::prev(bi);
auto c = *std::next(bi);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::prev(ei);
auto f = *std::next(ei);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::prev(ei);
auto f = *std::next(ei);
if (test_bond(f, a) and test_bond(c, d)) // case III.
{
beg1SeqID = a.seq_id();
beg2SeqID = f.seq_id();
if (test_bond(f, a) and test_bond(c, d)) // case III.
{
beg1SeqID = a.seq_id();
beg2SeqID = f.seq_id();
beg1AtomID = "O";
beg2AtomID = "N";
}
else if (test_bond(b, e) and test_bond(e, b)) // case IV.
{
beg1SeqID = b.seq_id();
beg2SeqID = e.seq_id();
beg1AtomID = "O";
beg2AtomID = "N";
}
else if (test_bond(b, e) and test_bond(e, b)) // case IV.
{
beg1SeqID = b.seq_id();
beg2SeqID = e.seq_id();
beg1AtomID = "N";
beg2AtomID = "O";
}
beg1AtomID = "N";
beg2AtomID = "O";
break;
}
break;
if (beg1SeqID)
break;
}
if (beg1SeqID)
break;
}
std::reverse(strand1.begin(), strand1.end());
std::reverse(strand2.begin(), strand2.end());
std::reverse(strand1.begin(), strand1.end());
std::reverse(strand2.begin(), strand2.end());
for (auto b : strand1)
{
for (int i : { 0, 1 })
for (auto b : strand1)
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
for (int i : { 0, 1 })
{
const auto &[e, ladder1, parallel1] = b.bridge_partner(i);
auto esi = std::find(strand2.begin(), strand2.end(), e);
if (esi == strand2.end())
continue;
if (esi == strand2.end())
continue;
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto bi = std::find(dssp.begin(), dssp.end(), b);
assert(bi != dssp.end() and bi != dssp.begin());
auto a = *std::next(bi);
auto c = *std::prev(bi);
auto a = *std::next(bi);
auto c = *std::prev(bi);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::next(ei);
auto f = *std::prev(ei);
auto ei = std::find(dssp.begin(), dssp.end(), e);
assert(ei != dssp.end() and ei != dssp.begin());
auto d = *std::next(ei);
auto f = *std::prev(ei);
if (test_bond(a, f) and test_bond(d, c)) // case III.
{
end1SeqID = a.seq_id();
end2SeqID = f.seq_id();
if (test_bond(a, f) and test_bond(d, c)) // case III.
{
end1SeqID = a.seq_id();
end2SeqID = f.seq_id();
end1AtomID = "N";
end2AtomID = "O";
}
else if (test_bond(b, e) and test_bond(e, b)) // case IV.
{
end1SeqID = b.seq_id();
end2SeqID = e.seq_id();
end1AtomID = "N";
end2AtomID = "O";
}
else if (test_bond(b, e) and test_bond(e, b)) // case IV.
{
end1SeqID = b.seq_id();
end2SeqID = e.seq_id();
end1AtomID = "N";
end2AtomID = "O";
end1AtomID = "N";
end2AtomID = "O";
}
break;
}
break;
if (end1SeqID)
break;
}
if (end1SeqID)
break;
}
}
struct_sheet_hbond.emplace({ { "sheet_id", cif::cif_id_for_number(sheet) },
{ "range_id_1", s1 + 1 },
{ "range_id_2", s2 + 1 },
{ "range_1_beg_label_seq_id", beg1SeqID },
{ "range_1_beg_label_atom_id", beg1AtomID },
{ "range_2_beg_label_seq_id", beg2SeqID },
{ "range_2_beg_label_atom_id", beg2AtomID },
{ "range_1_end_label_seq_id", end1SeqID },
{ "range_1_end_label_atom_id", end1AtomID },
{ "range_2_end_label_seq_id", end2SeqID },
{ "range_2_end_label_atom_id", end2AtomID } });
using namespace cif::literals;
auto b1 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand1.front().asym_id() and "seq_id"_key == beg1SeqID);
auto e1 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand1.front().asym_id() and "seq_id"_key == end1SeqID);
auto b2 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand2.front().asym_id() and "seq_id"_key == beg2SeqID);
auto e2 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand2.front().asym_id() and "seq_id"_key == end2SeqID);
if (not(b1 and e1 and b2 and e2))
{
if (cif::VERBOSE > 0)
std::cerr << "error looking up strand ends" << std::endl;
continue;
struct_sheet_hbond.emplace({
{ "sheet_id", sheetID },
{ "range_id_1", strandID_1 },
{ "range_id_2", strandID_2 },
{ "range_1_beg_label_seq_id", beg1SeqID },
{ "range_1_beg_label_atom_id", beg1AtomID },
{ "range_2_beg_label_seq_id", beg2SeqID },
{ "range_2_beg_label_atom_id", beg2AtomID },
{ "range_1_end_label_seq_id", end1SeqID },
{ "range_1_end_label_atom_id", end1AtomID },
{ "range_2_end_label_seq_id", end2SeqID },
{ "range_2_end_label_atom_id", end2AtomID } });
}
pdbx_struct_sheet_hbond.emplace({
{ "sheet_id", cif::cif_id_for_number(sheet) },
{ "range_id_1", s1 + 1 },
{ "range_id_2", s2 + 1 },
{ "range_1_label_atom_id", beg1AtomID },
{ "range_1_label_comp_id", b1["mon_id"].as<std::string>() },
{ "range_1_label_asym_id", b1["asym_id"].as<std::string>() },
{ "range_1_label_seq_id", b1["seq_id"].as<std::string>() },
{ "range_1_PDB_ins_code", b1["pdb_ins_code"].as<std::string>() },
{ "range_1_auth_atom_id", beg1AtomID },
{ "range_1_auth_comp_id", b1["auth_mon_id"].as<std::string>() },
{ "range_1_auth_asym_id", b1["pdb_strand_id"].as<std::string>() },
{ "range_1_auth_seq_id", b1["auth_seq_num"].as<std::string>() },
{ "range_2_label_atom_id", beg2AtomID },
{ "range_2_label_comp_id", b2["mon_id"].as<std::string>() },
{ "range_2_label_asym_id", b2["asym_id"].as<std::string>() },
{ "range_2_label_seq_id", b2["seq_id"].as<std::string>() },
{ "range_2_PDB_ins_code", b2["pdb_ins_code"].as<std::string>() },
{ "range_2_auth_atom_id", beg2AtomID },
{ "range_2_auth_comp_id", b2["auth_mon_id"].as<std::string>() },
{ "range_2_auth_asym_id", b2["pdb_strand_id"].as<std::string>() },
{ "range_2_auth_seq_id", b2["auth_seq_num"].as<std::string>() },
});
}
// Data items in the PDBX_STRUCT_SHEET_HBOND category record details
// about the hydrogen bonding between residue ranges in a beta sheet.
// This category is provided for cases where only a single hydrogen
// bond is used to register the two residue ranges. Category
// STRUCT_SHEET_HBOND should be used when the initial and terminal
// hydrogen bonds for strand pair are known.
auto &struct_sheet_range = db["struct_sheet_range"];
// // Okay, so that means we should write entries in that category only
// // when the ladder is size 1. Right? But those are called BetaBridges
// // in
for (const auto &[key, iSheet] : sheetMap)
{
for (auto &&[sheet, strand] : strands)
{
if (sheet != iSheet)
continue;
std::sort(strand.begin(), strand.end(), [](dssp::residue_info const &a, dssp::residue_info const &b)
{ return a.nr() < b.nr(); });
auto &beg = strand.front();
auto &end = strand.back();
struct_sheet_range.emplace({
{ "sheet_id", cif::cif_id_for_number(sheet) },
{ "id", strandMap[strand.front().nr()] + 1 },
{ "beg_label_comp_id", beg.compound_id() },
{ "beg_label_asym_id", beg.asym_id() },
{ "beg_label_seq_id", beg.seq_id() },
{ "pdbx_beg_PDB_ins_code", beg.pdb_ins_code() },
{ "end_label_comp_id", end.compound_id() },
{ "end_label_asym_id", end.asym_id() },
{ "end_label_seq_id", end.seq_id() },
{ "pdbx_end_PDB_ins_code", end.pdb_ins_code() },
{ "beg_auth_comp_id", beg.compound_id() },
{ "beg_auth_asym_id", beg.auth_asym_id() },
{ "beg_auth_seq_id", beg.auth_seq_id() },
{ "end_auth_comp_id", end.compound_id() },
{ "end_auth_asym_id", end.auth_asym_id() },
{ "end_auth_seq_id", end.auth_seq_id() } });
}
// {
// auto b1 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand1.front().asym_id() and "seq_id"_key == beg1SeqID);
// auto e1 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand1.front().asym_id() and "seq_id"_key == end1SeqID);
// auto b2 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand2.front().asym_id() and "seq_id"_key == beg2SeqID);
// auto e2 = pdbx_poly_seq_scheme.find_first("asym_id"_key == strand2.front().asym_id() and "seq_id"_key == end2SeqID);
// if (not(b1 and e1 and b2 and e2))
// {
// if (cif::VERBOSE > 0)
// std::cerr << "error looking up strand ends" << std::endl;
// continue;
// }
// pdbx_struct_sheet_hbond.emplace({
// { "sheet_id", sheetID },
// { "range_id_1", strandID_1 },
// { "range_id_2", strandID_2 },
// { "range_1_label_atom_id", beg1AtomID },
// { "range_1_label_comp_id", b1["mon_id"].as<std::string>() },
// { "range_1_label_asym_id", b1["asym_id"].as<std::string>() },
// { "range_1_label_seq_id", b1["seq_id"].as<std::string>() },
// { "range_1_PDB_ins_code", b1["pdb_ins_code"].as<std::string>() },
// { "range_1_auth_atom_id", beg1AtomID },
// { "range_1_auth_comp_id", b1["auth_mon_id"].as<std::string>() },
// { "range_1_auth_asym_id", b1["pdb_strand_id"].as<std::string>() },
// { "range_1_auth_seq_id", b1["auth_seq_num"].as<std::string>() },
// { "range_2_label_atom_id", beg2AtomID },
// { "range_2_label_comp_id", b2["mon_id"].as<std::string>() },
// { "range_2_label_asym_id", b2["asym_id"].as<std::string>() },
// { "range_2_label_seq_id", b2["seq_id"].as<std::string>() },
// { "range_2_PDB_ins_code", b2["pdb_ins_code"].as<std::string>() },
// { "range_2_auth_atom_id", beg2AtomID },
// { "range_2_auth_comp_id", b2["auth_mon_id"].as<std::string>() },
// { "range_2_auth_asym_id", b2["pdb_strand_id"].as<std::string>() },
// { "range_2_auth_seq_id", b2["auth_seq_num"].as<std::string>() },
// });
// }
}
}
......
......@@ -421,6 +421,9 @@ struct dssp::residue
void SetSheet(uint32_t inSheet) { mSheet = inSheet; }
uint32_t GetSheet() const { return mSheet; }
void SetStrand(uint32_t inStrand) { mStrand = inStrand; }
uint32_t GetStrand() const { return mStrand; }
bool IsBend() const { return mBend; }
void SetBend(bool inBend) { mBend = inBend; }
......@@ -548,6 +551,7 @@ struct dssp::residue
HBond mHBondDonor[2] = {}, mHBondAcceptor[2] = {};
bridge_partner mBetaPartner[2] = {};
uint32_t mSheet = 0;
uint32_t mStrand = 0; // Added to ease the writing of mmCIF's struct_sheet and friends
helix_position_type mHelixFlags[4] = { helix_position_type::None, helix_position_type::None, helix_position_type::None, helix_position_type::None }; //
bool mBend = false;
chain_break_type mChainBreak = chain_break_type::None;
......@@ -1099,6 +1103,86 @@ void CalculateBetaSheets(std::vector<residue> &inResidues, statistics &stats, st
inResidues[i].SetSheet(bridge.sheet);
}
}
// Construct the 'strands'
// For mmCIF output, this is needed and since we now have the information available
// it is best to do the calculation here.
// strands are ranges of residues of length > 1 that form beta bridges in a sheet.
for (uint32_t iSheet = 1; iSheet < sheet; ++iSheet)
{
std::vector<std::tuple<uint32_t,uint32_t>> strands;
for (auto &bridge : bridges)
{
if (bridge.sheet != iSheet)
continue;
for (auto &range : { bridge.i, bridge.j})
{
auto imin = range.front();
auto imax = range.back();
if (imin == imax)
continue;
if (imin > imax)
std::swap(imin, imax);
auto ii = find_if(strands.begin(), strands.end(), [a = imin, b = imax] (std::tuple<uint32_t,uint32_t> &t)
{
auto &&[start, end] = t;
bool result = false;
if (start <= b and end >= a)
{
result = true;
if (start > a)
start = a;
if (end < b)
end = b;
}
return result;
});
if (ii == strands.end())
strands.emplace_back(imin, imax);
}
}
std::sort(strands.begin(), strands.end());
// collapse ranges that overlap
if (strands.size() > 1)
{
auto si = strands.begin();
while (std::next(si) != strands.end())
{
auto &&[afirst, alast] = *si;
auto &&[bfirst, blast] = *(std::next(si));
if (alast >= bfirst)
{
bfirst = afirst;
si = strands.erase(si);
continue;
}
++si;
}
}
for (size_t i = 0; i < strands.size(); ++i)
{
const auto &[first, last] = strands[i];
for (auto nr = first; nr <= last; ++nr)
{
assert(inResidues[nr].mStrand == 0);
inResidues[nr].SetStrand(i + 1);
}
}
}
}
// --------------------------------------------------------------------
......@@ -2138,6 +2222,11 @@ int dssp::residue_info::sheet() const
return m_impl->GetSheet();
}
int dssp::residue_info::strand() const
{
return m_impl->GetStrand();
}
std::tuple<dssp::residue_info, double> dssp::residue_info::acceptor(int i) const
{
auto &a = m_impl->mHBondAcceptor[i];
......
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