| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "dssp-io.hpp" |
| #include "revision.hpp" |
|
|
| #include <cif++.hpp> |
| #include <cif++/dictionary_parser.hpp> |
|
|
| #include <exception> |
| #include <filesystem> |
| #include <fstream> |
| #include <iostream> |
|
|
| |
|
|
| std::string ResidueToDSSPLine(const dssp::residue_info &info) |
| { |
| |
| |
| |
| |
| |
|
|
| |
| auto &residue = info; |
|
|
| if (residue.pdb_strand_id().length() > 1) |
| throw std::runtime_error("This file contains data that won't fit in the original DSSP format"); |
|
|
| char code = residue.compound_letter(); |
|
|
| if (code == 'C') |
| { |
| auto ssbridgenr = info.ssBridgeNr(); |
| if (ssbridgenr) |
| code = 'a' + ((ssbridgenr - 1) % 26); |
| } |
|
|
| char ss = ' '; |
| switch (info.type()) |
| { |
| case dssp::structure_type::Alphahelix: ss = 'H'; break; |
| case dssp::structure_type::Betabridge: ss = 'B'; break; |
| case dssp::structure_type::Strand: ss = 'E'; break; |
| case dssp::structure_type::Helix_3: ss = 'G'; break; |
| case dssp::structure_type::Helix_5: ss = 'I'; break; |
| case dssp::structure_type::Helix_PPII: ss = 'P'; break; |
| case dssp::structure_type::Turn: ss = 'T'; break; |
| case dssp::structure_type::Bend: ss = 'S'; break; |
| case dssp::structure_type::Loop: ss = ' '; break; |
| } |
|
|
| char helix[4] = { ' ', ' ', ' ', ' ' }; |
| for (dssp::helix_type helixType : { dssp::helix_type::_3_10, dssp::helix_type::alpha, dssp::helix_type::pi, dssp::helix_type::pp }) |
| { |
| switch (info.helix(helixType)) |
| { |
| case dssp::helix_position_type::None: helix[static_cast<int>(helixType)] = ' '; break; |
| case dssp::helix_position_type::Start: helix[static_cast<int>(helixType)] = '>'; break; |
| case dssp::helix_position_type::End: helix[static_cast<int>(helixType)] = '<'; break; |
| case dssp::helix_position_type::StartAndEnd: helix[static_cast<int>(helixType)] = 'X'; break; |
| case dssp::helix_position_type::Middle: helix[static_cast<int>(helixType)] = (helixType == dssp::helix_type::pp ? 'P' : static_cast<char>('3' + static_cast<int>(helixType))); break; |
| } |
| } |
|
|
| char bend = ' '; |
| if (info.bend()) |
| bend = 'S'; |
|
|
| double alpha = residue.alpha().value_or(360); |
| char chirality = alpha == 360 ? ' ' : (alpha < 0 ? '-' : '+'); |
|
|
| uint32_t bp[2] = {}; |
| char bridgelabel[2] = { ' ', ' ' }; |
| for (uint32_t i : { 0, 1 }) |
| { |
| const auto &[p, ladder, parallel] = info.bridge_partner(i); |
| if (not p) |
| continue; |
|
|
| bp[i] = p.nr() % 10000; |
| bridgelabel[i] = (parallel ? 'a' : 'A') + ladder % 26; |
| } |
|
|
| char sheet = ' '; |
| if (info.sheet() != 0) |
| sheet = 'A' + (info.sheet() - 1) % 26; |
|
|
| std::string NHO[2], ONH[2]; |
| for (int i : { 0, 1 }) |
| { |
| const auto &[donor, donorE] = info.donor(i); |
| const auto &[acceptor, acceptorE] = info.acceptor(i); |
|
|
| NHO[i] = ONH[i] = "0, 0.0"; |
|
|
| if (acceptor) |
| { |
| auto d = acceptor.nr() - info.nr(); |
| NHO[i] = cif::format("%d,%3.1f", d, acceptorE).str(); |
| } |
|
|
| if (donor) |
| { |
| auto d = donor.nr() - info.nr(); |
| ONH[i] = cif::format("%d,%3.1f", d, donorE).str(); |
| } |
| } |
|
|
| |
| auto const &[cax, cay, caz] = residue.ca_location(); |
|
|
| return cif::format("%5d%5d%1.1s%1.1s %c %c%c%c%c%c%c%c%c%c%4d%4d%c%4.0f %11s%11s%11s%11s %6.3f%6.1f%6.1f%6.1f%6.1f %6.1f %6.1f %6.1f", |
| info.nr(), residue.pdb_seq_num(), residue.pdb_ins_code(), residue.pdb_strand_id(), code, |
| ss, helix[3], helix[0], helix[1], helix[2], bend, chirality, bridgelabel[0], bridgelabel[1], |
| bp[0], bp[1], sheet, floor(info.accessibility() + 0.5), |
| NHO[0], ONH[0], NHO[1], ONH[1], |
| residue.tco().value_or(0), |
| residue.kappa().value_or(360), |
| residue.alpha().value_or(360), |
| residue.phi().value_or(360), |
| residue.psi().value_or(360), |
| cax, cay, caz) |
| .str(); |
| } |
|
|
| void writeDSSP(const dssp &dssp, std::ostream &os) |
| { |
| using namespace std::chrono; |
|
|
| auto stats = dssp.get_statistics(); |
|
|
| std::time_t today = system_clock::to_time_t(system_clock::now()); |
| std::tm *tm = std::gmtime(&today); |
|
|
| std::string version = kVersionNumber; |
| if (version.length() < 10) |
| version.insert(version.end(), 10 - version.length(), ' '); |
|
|
| os << "==== Secondary Structure Definition by the program DSSP, NKI version " << version << " ==== DATE=" << std::put_time(tm, "%F") << " ." << std::endl |
| << "REFERENCE W. KABSCH AND C.SANDER, BIOPOLYMERS 22 (1983) 2577-2637 ." << std::endl |
| << dssp.get_pdb_header_line(dssp::pdb_record_type::HEADER) << '.' << std::endl |
| << dssp.get_pdb_header_line(dssp::pdb_record_type::COMPND) << '.' << std::endl |
| << dssp.get_pdb_header_line(dssp::pdb_record_type::SOURCE) << '.' << std::endl |
| << dssp.get_pdb_header_line(dssp::pdb_record_type::AUTHOR) << '.' << std::endl; |
|
|
| os << cif::format("%5d%3d%3d%3d%3d TOTAL NUMBER OF RESIDUES, NUMBER OF CHAINS, NUMBER OF SS-BRIDGES(TOTAL,INTRACHAIN,INTERCHAIN) .", |
| stats.count.residues, stats.count.chains, stats.count.SS_bridges, stats.count.intra_chain_SS_bridges, (stats.count.SS_bridges - stats.count.intra_chain_SS_bridges)) |
| << std::endl; |
|
|
| os << cif::format("%8.1f ACCESSIBLE SURFACE OF PROTEIN (ANGSTROM**2) .", stats.accessible_surface) << std::endl; |
|
|
| |
|
|
| os << cif::format("%5d%5.1f TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(J) , SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds, (stats.count.H_bonds * 100.0 / stats.count.residues)) << std::endl; |
|
|
| os << cif::format("%5d%5.1f TOTAL NUMBER OF HYDROGEN BONDS IN PARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds_in_parallel_bridges, (stats.count.H_bonds_in_parallel_bridges * 100.0 / stats.count.residues)) << std::endl; |
|
|
| os << cif::format("%5d%5.1f TOTAL NUMBER OF HYDROGEN BONDS IN ANTIPARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds_in_antiparallel_bridges, (stats.count.H_bonds_in_antiparallel_bridges * 100.0 / stats.count.residues)) << std::endl; |
|
|
| for (int k = 0; k < 11; ++k) |
| os << cif::format("%5d%5.1f TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(I%c%1d), SAME NUMBER PER 100 RESIDUES .", stats.count.H_Bonds_per_distance[k], (stats.count.H_Bonds_per_distance[k] * 100.0 / stats.count.residues), (k - 5 < 0 ? '-' : '+'), abs(k - 5)) << std::endl; |
|
|
| |
| os << " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 *** HISTOGRAMS OF *** ." << std::endl; |
|
|
| for (auto hi : stats.histogram.residues_per_alpha_helix) |
| os << cif::format("%3d", hi); |
| os << " RESIDUES PER ALPHA HELIX ." << std::endl; |
|
|
| for (auto hi : stats.histogram.parallel_bridges_per_ladder) |
| os << cif::format("%3d", hi); |
| os << " PARALLEL BRIDGES PER LADDER ." << std::endl; |
|
|
| for (auto hi : stats.histogram.antiparallel_bridges_per_ladder) |
| os << cif::format("%3d", hi); |
| os << " ANTIPARALLEL BRIDGES PER LADDER ." << std::endl; |
|
|
| for (auto hi : stats.histogram.ladders_per_sheet) |
| os << cif::format("%3d", hi); |
| os << " LADDERS PER SHEET ." << std::endl; |
|
|
| |
|
|
| os << " # RESIDUE AA STRUCTURE BP1 BP2 ACC N-H-->O O-->H-N N-H-->O O-->H-N TCO KAPPA ALPHA PHI PSI X-CA Y-CA Z-CA" << std::endl; |
|
|
| int last = 0; |
| for (auto ri : dssp) |
| { |
| |
| |
|
|
| if (ri.nr() != last + 1) |
| os << cif::format("%5d !%c 0 0 0 0, 0.0 0, 0.0 0, 0.0 0, 0.0 0.000 360.0 360.0 360.0 360.0 0.0 0.0 0.0", |
| (last + 1), (ri.chain_break() == dssp::chain_break_type::NewChain ? '*' : ' ')) |
| << std::endl; |
|
|
| os << ResidueToDSSPLine(ri) << std::endl; |
| last = ri.nr(); |
| } |
| } |
|
|
| |
|
|
| void writeBridgePairs(cif::datablock &db, const dssp &dssp) |
| { |
| auto &hb = db["dssp_struct_bridge_pairs"]; |
|
|
| hb.add_item("id"); |
| hb.add_item("label_comp_id"); |
| hb.add_item("label_seq_id"); |
| hb.add_item("label_asym_id"); |
| hb.add_item("auth_seq_id"); |
| hb.add_item("auth_asym_id"); |
| hb.add_item("pdbx_PDB_ins_code"); |
|
|
| |
| for (std::string da : { "acceptor_", "donor_" }) |
| { |
| for (std::string i : { "1_", "2_" }) |
| { |
| for (std::string n : { "label_comp_id", "label_seq_id", "label_asym_id", "auth_seq_id", "auth_asym_id", "pdbx_PDB_ins_code", "energy" }) |
| hb.add_item(da + i + n); |
| } |
| } |
|
|
| for (auto &res : dssp) |
| { |
| cif::row_initializer data({ |
| { "id", hb.get_unique_id("") }, |
| { "label_comp_id", res.compound_id() }, |
| { "label_seq_id", res.seq_id() }, |
| { "label_asym_id", res.asym_id() }, |
| |
| { "auth_seq_id", res.auth_seq_id() }, |
| { "auth_asym_id", res.auth_asym_id() }, |
| { "pdbx_PDB_ins_code", res.pdb_ins_code() } |
| }); |
|
|
| for (int i : { 0, 1 }) |
| { |
| const auto &&[acceptor, acceptorEnergy] = res.acceptor(i); |
| const auto &&[donor, donorEnergy] = res.donor(i); |
|
|
| if (acceptor) |
| { |
| if (i == 0) |
| { |
| data.emplace_back("acceptor_1_label_comp_id", acceptor.compound_id()); |
| data.emplace_back("acceptor_1_label_seq_id", acceptor.seq_id()); |
| data.emplace_back("acceptor_1_label_asym_id", acceptor.asym_id()); |
| |
| data.emplace_back("acceptor_1_auth_seq_id", acceptor.auth_seq_id()); |
| data.emplace_back("acceptor_1_auth_asym_id", acceptor.auth_asym_id()); |
| data.emplace_back("acceptor_1_pdbx_PDB_ins_code", acceptor.pdb_ins_code()); |
| data.emplace_back("acceptor_1_energy", acceptorEnergy, 1); |
| } |
| else |
| { |
| data.emplace_back("acceptor_2_label_comp_id", acceptor.compound_id()); |
| data.emplace_back("acceptor_2_label_seq_id", acceptor.seq_id()); |
| data.emplace_back("acceptor_2_label_asym_id", acceptor.asym_id()); |
| |
| data.emplace_back("acceptor_2_auth_seq_id", acceptor.auth_seq_id()); |
| data.emplace_back("acceptor_2_auth_asym_id", acceptor.auth_asym_id()); |
| data.emplace_back("acceptor_2_pdbx_PDB_ins_code", acceptor.pdb_ins_code()); |
| data.emplace_back("acceptor_2_energy", acceptorEnergy, 1); |
| } |
| } |
|
|
| if (donor) |
| { |
| if (i == 0) |
| { |
| data.emplace_back("donor_1_label_comp_id", donor.compound_id()); |
| data.emplace_back("donor_1_label_seq_id", donor.seq_id()); |
| data.emplace_back("donor_1_label_asym_id", donor.asym_id()); |
| |
| data.emplace_back("donor_1_auth_seq_id", donor.auth_seq_id()); |
| data.emplace_back("donor_1_auth_asym_id", donor.auth_asym_id()); |
| data.emplace_back("donor_1_pdbx_PDB_ins_code", donor.pdb_ins_code()); |
| data.emplace_back("donor_1_energy", donorEnergy, 1); |
| } |
| else |
| { |
| data.emplace_back("donor_2_label_comp_id", donor.compound_id()); |
| data.emplace_back("donor_2_label_seq_id", donor.seq_id()); |
| data.emplace_back("donor_2_label_asym_id", donor.asym_id()); |
| |
| data.emplace_back("donor_2_auth_seq_id", donor.auth_seq_id()); |
| data.emplace_back("donor_2_auth_asym_id", donor.auth_asym_id()); |
| data.emplace_back("donor_2_pdbx_PDB_ins_code", donor.pdb_ins_code()); |
| data.emplace_back("donor_2_energy", donorEnergy, 1); |
| } |
| } |
| } |
|
|
| hb.emplace(std::move(data)); |
| } |
| } |
|
|
| void writeSheets(cif::datablock &db, const dssp &dssp) |
| { |
| using namespace cif::literals; |
|
|
| using res_list = std::vector<dssp::residue_info>; |
|
|
| |
|
|
| for (auto sheet_cat : { "struct_sheet", "struct_sheet_order", "struct_sheet_range", "struct_sheet_hbond", "pdbx_struct_sheet_hbond" }) |
| db.erase(remove_if(db.begin(), db.end(), [sheet_cat](const cif::category &cat) |
| { return cat.name() == sheet_cat; }), |
| db.end()); |
|
|
| |
|
|
| std::map<std::tuple<int,int>, res_list> strands; |
| std::set<int> sheetNrs; |
|
|
| for (auto &res : dssp) |
| { |
| if (res.type() != dssp::structure_type::Strand and res.type() != dssp::structure_type::Betabridge) |
| continue; |
|
|
| strands[{res.sheet(), res.strand()}].emplace_back(res); |
| sheetNrs.insert(res.sheet()); |
| } |
|
|
| |
|
|
| auto &struct_sheet = db["struct_sheet"]; |
| auto &struct_sheet_range = db["struct_sheet_range"]; |
|
|
| for (int sheetNr : sheetNrs) |
| { |
| auto sheetID = cif::cif_id_for_number(sheetNr - 1); |
|
|
| 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 (auto &&[strandTuple, strand] : strands) |
| { |
| if (strand.front().sheet() != sheetNr) |
| continue; |
| |
| std::string strandID = cif::cif_id_for_number(strand.front().strand() - 1); |
|
|
| 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", 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() } }); |
| } |
| } |
| } |
|
|
| void writeLadders(cif::datablock &db, const dssp &dssp) |
| { |
| |
| struct ladder_info |
| { |
| ladder_info(int label, int sheet, bool parallel, const dssp::residue_info &a, const dssp::residue_info &b) |
| : ladder(label) |
| , sheet(sheet) |
| , parallel(parallel) |
| , pairs({ { a, b } }) |
| { |
| } |
|
|
| bool operator<(const ladder_info &rhs) const |
| { |
| return ladder < rhs.ladder; |
| } |
|
|
| int ladder; |
| int sheet; |
| bool parallel; |
| std::vector<std::pair<dssp::residue_info, dssp::residue_info>> pairs; |
| }; |
|
|
| std::vector<ladder_info> ladders; |
|
|
| for (auto res : dssp) |
| { |
| for (int i : { 0, 1 }) |
| { |
| const auto &[p, ladder, parallel] = res.bridge_partner(i); |
|
|
| if (not p) |
| continue; |
|
|
| bool is_new = true; |
| for (auto &l : ladders) |
| { |
| if (l.ladder != ladder) |
| continue; |
|
|
| assert(l.parallel == parallel); |
|
|
| if (find_if(l.pairs.begin(), l.pairs.end(), [na = p.nr(), nb = res.nr()](const auto &p) |
| { return p.first.nr() == na and p.second.nr() == nb; }) != l.pairs.end()) |
| { |
| is_new = false; |
| break; |
| } |
|
|
| l.pairs.emplace_back(res, p); |
| is_new = false; |
| break; |
| } |
|
|
| if (not is_new) |
| continue; |
|
|
| ladders.emplace_back(ladder, res.sheet() - 1, parallel, res, p); |
| } |
| } |
|
|
| std::sort(ladders.begin(), ladders.end()); |
|
|
| auto &dssp_struct_ladder = db["dssp_struct_ladder"]; |
|
|
| for (const auto &l : ladders) |
| { |
| const auto &[beg1, beg2] = l.pairs.front(); |
| const auto &[end1, end2] = l.pairs.back(); |
|
|
| dssp_struct_ladder.emplace({ |
| { "id", cif::cif_id_for_number(l.ladder) }, |
| { "sheet_id", cif::cif_id_for_number(l.sheet) }, |
| { "range_id_1", cif::cif_id_for_number(beg1.strand() - 1) }, |
| { "range_id_2", cif::cif_id_for_number(beg2.strand() - 1) }, |
| { "type", l.parallel ? "parallel" : "anti-parallel" }, |
|
|
| { "beg_1_label_comp_id", beg1.compound_id() }, |
| { "beg_1_label_asym_id", beg1.asym_id() }, |
| { "beg_1_label_seq_id", beg1.seq_id() }, |
| { "pdbx_beg_1_PDB_ins_code", beg1.pdb_ins_code() }, |
| { "end_1_label_comp_id", end1.compound_id() }, |
| { "end_1_label_asym_id", end1.asym_id() }, |
| { "end_1_label_seq_id", end1.seq_id() }, |
| { "pdbx_end_1_PDB_ins_code", end1.pdb_ins_code() }, |
| { "beg_1_auth_comp_id", beg1.compound_id() }, |
| { "beg_1_auth_asym_id", beg1.auth_asym_id() }, |
| { "beg_1_auth_seq_id", beg1.auth_seq_id() }, |
| { "end_1_auth_comp_id", end1.compound_id() }, |
| { "end_1_auth_asym_id", end1.auth_asym_id() }, |
| { "end_1_auth_seq_id", end1.auth_seq_id() }, |
|
|
| { "beg_2_label_comp_id", beg2.compound_id() }, |
| { "beg_2_label_asym_id", beg2.asym_id() }, |
| { "beg_2_label_seq_id", beg2.seq_id() }, |
| { "pdbx_beg_2_PDB_ins_code", beg2.pdb_ins_code() }, |
| { "end_2_label_comp_id", end2.compound_id() }, |
| { "end_2_label_asym_id", end2.asym_id() }, |
| { "end_2_label_seq_id", end2.seq_id() }, |
| { "pdbx_end_2_PDB_ins_code", end2.pdb_ins_code() }, |
| { "beg_2_auth_comp_id", beg2.compound_id() }, |
| { "beg_2_auth_asym_id", beg2.auth_asym_id() }, |
| { "beg_2_auth_seq_id", beg2.auth_seq_id() }, |
| { "end_2_auth_comp_id", end2.compound_id() }, |
| { "end_2_auth_asym_id", end2.auth_asym_id() }, |
| { "end_2_auth_seq_id", end2.auth_seq_id() } }); |
| } |
| } |
|
|
| void writeStatistics(cif::datablock &db, const dssp &dssp) |
| { |
| using namespace std::literals; |
|
|
| auto stats = dssp.get_statistics(); |
|
|
| auto &dssp_statistics = db["dssp_statistics"]; |
|
|
| auto stats_i = dssp_statistics.emplace({ { "entry_id", db.name() }, |
| { "nr_of_residues", stats.count.residues }, |
| { "nr_of_chains", stats.count.chains }, |
| { "nr_of_ss_bridges_total", stats.count.SS_bridges }, |
| { "nr_of_ss_bridges_intra_chain", stats.count.intra_chain_SS_bridges }, |
| { "nr_of_ss_bridges_inter_chain", stats.count.SS_bridges - stats.count.intra_chain_SS_bridges } }); |
| |
| if (stats.accessible_surface > 0) |
| (*stats_i)["accessible_surface_of_protein"] = stats.accessible_surface; |
|
|
| auto &dssp_struct_hbonds = db["dssp_statistics_hbond"]; |
|
|
| dssp_struct_hbonds.emplace({ { "entry_id", db.name() }, |
| { "type", "O(I)-->H-N(J)" }, |
| { "count", stats.count.H_bonds }, |
| { "count_per_100", stats.count.H_bonds * 100.0 / stats.count.residues, 1 } }); |
|
|
| dssp_struct_hbonds.emplace({ { "entry_id", db.name() }, |
| { "type", "PARALLEL BRIDGES" }, |
| { "count", stats.count.H_bonds_in_parallel_bridges }, |
| { "count_per_100", stats.count.H_bonds_in_parallel_bridges * 100.0 / stats.count.residues, 1 } }); |
|
|
| dssp_struct_hbonds.emplace({ { "entry_id", db.name() }, |
| { "type", "ANTIPARALLEL BRIDGES" }, |
| { "count", stats.count.H_bonds_in_antiparallel_bridges }, |
| { "count_per_100", stats.count.H_bonds_in_antiparallel_bridges * 100.0 / stats.count.residues, 1 } }); |
|
|
| for (int k = 0; k < 11; ++k) |
| dssp_struct_hbonds.emplace({ { "entry_id", db.name() }, |
| { "type", "O(I)-->H-N(I"s + char(k - 5 < 0 ? '-' : '+') + std::to_string(abs(k - 5)) + ")" }, |
| { "count", stats.count.H_Bonds_per_distance[k] }, |
| { "count_per_100", stats.count.H_Bonds_per_distance[k] * 100.0 / stats.count.residues, 1 } }); |
|
|
| auto &dssp_statistics_histogram = db["dssp_statistics_histogram"]; |
|
|
| using histogram_data_type = std::tuple<const char *, const uint32_t *>; |
| for (const auto &[type, values] : std::vector<histogram_data_type>{ |
| { "residues_per_alpha_helix", stats.histogram.residues_per_alpha_helix }, |
| { "parallel_bridges_per_ladder", stats.histogram.parallel_bridges_per_ladder }, |
| { "antiparallel_bridges_per_ladder", stats.histogram.antiparallel_bridges_per_ladder }, |
| { "ladders_per_sheet", stats.histogram.ladders_per_sheet } }) |
| { |
| auto hi = dssp_statistics_histogram.emplace({ |
| { "entry_id", db.name() }, |
| { "type", type }, |
| { "1", values[0] }, |
| { "2", values[1] }, |
| { "3", values[2] }, |
| { "4", values[3] }, |
| { "5", values[4] }, |
| { "6", values[5] }, |
| { "7", values[6] }, |
| { "8", values[7] }, |
| { "9", values[8] }, |
| { "10", values[9] }, |
| { "11", values[10] }, |
| { "12", values[11] }, |
| { "13", values[12] }, |
| { "14", values[13] }, |
| { "15", values[14] }, |
| { "16", values[15] }, |
| { "17", values[16] }, |
| { "18", values[17] }, |
| { "19", values[18] }, |
| { "20", values[19] }, |
| { "21", values[20] }, |
| { "22", values[21] }, |
| { "23", values[22] }, |
| { "24", values[23] }, |
| { "25", values[24] }, |
| { "26", values[25] }, |
| { "27", values[26] }, |
| { "28", values[27] }, |
| { "29", values[28] }, |
| { "30", values[29] }, |
| }); |
| } |
| } |
|
|
| void writeSummary(cif::datablock &db, const dssp &dssp) |
| { |
| bool writeAccessibility = dssp.get_statistics().accessible_surface > 0; |
|
|
| |
|
|
| auto &dssp_struct_summary = db["dssp_struct_summary"]; |
|
|
| |
|
|
| for (auto label : { "entry_id", "label_comp_id", "label_asym_id", "label_seq_id", "secondary_structure", |
| "ss_bridge", "helix_3_10", "helix_alpha", "helix_pi", "helix_pp", "bend", "chirality", "sheet", |
| "strand", "ladder_1", "ladder_2", "accessibility", "TCO", "kappa", "alpha", "phi", "psi", |
| "x_ca", "y_ca", "z_ca"}) |
| dssp_struct_summary.add_item(label); |
|
|
| for (auto res : dssp) |
| { |
|
|
| |
| |
| |
| |
| |
|
|
| std::string ss_bridge = "."; |
| if (res.ssBridgeNr() != 0) |
| ss_bridge = std::to_string(res.ssBridgeNr()); |
|
|
| std::string ss = { res.type() == dssp::structure_type::Loop ? '.' : static_cast<char>(res.type()) }; |
|
|
| std::string helix[4] = { ".", ".", ".", "." }; |
| for (dssp::helix_type helixType : { dssp::helix_type::_3_10, dssp::helix_type::alpha, dssp::helix_type::pi, dssp::helix_type::pp }) |
| { |
| switch (res.helix(helixType)) |
| { |
| |
| case dssp::helix_position_type::Start: |
| helix[static_cast<int>(helixType)] = { '>' }; |
| break; |
|
|
| case dssp::helix_position_type::End: |
| helix[static_cast<int>(helixType)] = { '<' }; |
| break; |
|
|
| case dssp::helix_position_type::StartAndEnd: |
| helix[static_cast<int>(helixType)] = { 'X' }; |
| break; |
|
|
| case dssp::helix_position_type::Middle: |
| if (helixType == dssp::helix_type::pp) |
| helix[static_cast<int>(helixType)] = { 'P' }; |
| else |
| helix[static_cast<int>(helixType)] = { static_cast<char>('3' + static_cast<int>(helixType)) }; |
| break; |
|
|
| default: |
| break; |
| } |
| } |
|
|
| std::string bend = "."; |
| if (res.bend()) |
| bend = "S"; |
|
|
| std::string chirality = "."; |
| if (res.alpha().has_value()) |
| chirality = *res.alpha() < 0 ? "-" : "+"; |
|
|
| std::string ladders[2] = { ".", "." }; |
|
|
| for (uint32_t i : { 0, 1 }) |
| { |
| const auto &[p, ladder, parallel] = res.bridge_partner(i); |
| if (not p) |
| continue; |
|
|
| ladders[i] = cif::cif_id_for_number(ladder); |
| } |
|
|
| auto const &[cax, cay, caz] = res.ca_location(); |
|
|
| cif::row_initializer data{ |
| { "entry_id", db.name() }, |
| { "label_comp_id", res.compound_id() }, |
| { "label_asym_id", res.asym_id() }, |
| { "label_seq_id", res.seq_id() }, |
|
|
| { "secondary_structure", ss }, |
|
|
| { "ss_bridge", ss_bridge }, |
|
|
| { "helix_3_10", helix[0] }, |
| { "helix_alpha", helix[1] }, |
| { "helix_pi", helix[2] }, |
| { "helix_pp", helix[3] }, |
|
|
| { "bend", bend }, |
| { "chirality", chirality }, |
|
|
| { "sheet", res.sheet() ? cif::cif_id_for_number(res.sheet() - 1) : "." }, |
| { "strand", res.strand() ? cif::cif_id_for_number(res.strand() - 1) : "." }, |
| { "ladder_1", ladders[0] }, |
| { "ladder_2", ladders[1] }, |
|
|
| { "x_ca", cax, 1 }, |
| { "y_ca", cay, 1 }, |
| { "z_ca", caz, 1 }, |
| }; |
|
|
| if (writeAccessibility) |
| data.emplace_back("accessibility", res.accessibility(), 1); |
|
|
| if (res.tco().has_value()) |
| data.emplace_back("TCO", *res.tco(), 3); |
| else |
| data.emplace_back("TCO", "."); |
|
|
| if (res.kappa().has_value()) |
| data.emplace_back("kappa", *res.kappa(), 1); |
| else |
| data.emplace_back("kappa", "."); |
|
|
| if (res.alpha().has_value()) |
| data.emplace_back("alpha", *res.alpha(), 1); |
| else |
| data.emplace_back("alpha", "."); |
|
|
| if (res.phi().has_value()) |
| data.emplace_back("phi", *res.phi(), 1); |
| else |
| data.emplace_back("phi", "."); |
|
|
| if (res.psi().has_value()) |
| data.emplace_back("psi", *res.psi(), 1); |
| else |
| data.emplace_back("psi", "."); |
| |
| dssp_struct_summary.emplace(std::move(data)); |
| } |
| } |
|
|
| void annotateDSSP(cif::datablock &db, const dssp &dssp, bool writeOther, bool writeExperimental) |
| { |
| using namespace std::literals; |
|
|
| auto &validator = const_cast<cif::validator &>(*db.get_validator()); |
| if (validator.get_validator_for_category("dssp_struct_summary") == nullptr) |
| { |
| auto dssp_extension = cif::load_resource("dssp-extension.dic"); |
| if (dssp_extension) |
| cif::extend_dictionary(validator, *dssp_extension); |
| } |
|
|
| if (dssp.empty()) |
| { |
| if (cif::VERBOSE > 0) |
| std::cout << "No secondary structure information found" << std::endl; |
| } |
| else |
| { |
| if (writeExperimental) |
| { |
| writeBridgePairs(db, dssp); |
| writeSheets(db, dssp); |
| writeLadders(db, dssp); |
| writeStatistics(db, dssp); |
| writeSummary(db, dssp); |
| } |
|
|
| |
| auto &structConfType = db["struct_conf_type"]; |
| structConfType.clear(); |
|
|
| auto &structConf = db["struct_conf"]; |
| structConf.clear(); |
|
|
| std::map<std::string, int> foundTypes; |
|
|
| auto st = dssp.begin(), lt = st; |
| auto lastSS = st->type(); |
|
|
| for (auto t = dssp.begin();; lt = t, ++t) |
| { |
| bool stop = t == dssp.end(); |
|
|
| bool flush = (stop or t->type() != lastSS); |
|
|
| if (flush and (writeOther or lastSS != dssp::structure_type::Loop)) |
| { |
| auto &rb = *st; |
| auto &re = *lt; |
|
|
| std::string id; |
| switch (lastSS) |
| { |
| case dssp::structure_type::Helix_3: |
| id = "HELX_RH_3T_P"; |
| break; |
|
|
| case dssp::structure_type::Alphahelix: |
| id = "HELX_RH_AL_P"; |
| break; |
|
|
| case dssp::structure_type::Helix_5: |
| id = "HELX_RH_PI_P"; |
| break; |
|
|
| case dssp::structure_type::Helix_PPII: |
| id = "HELX_LH_PP_P"; |
| break; |
|
|
| case dssp::structure_type::Turn: |
| id = "TURN_TY1_P"; |
| break; |
|
|
| case dssp::structure_type::Bend: |
| id = "BEND"; |
| break; |
|
|
| case dssp::structure_type::Betabridge: |
| case dssp::structure_type::Strand: |
| id = "STRN"; |
| break; |
|
|
| case dssp::structure_type::Loop: |
| id = "OTHER"; |
| break; |
| } |
|
|
| if (foundTypes.count(id) == 0) |
| { |
| structConfType.emplace({ { "id", id }, |
| { "criteria", "DSSP" } }); |
| foundTypes[id] = 1; |
| } |
|
|
| structConf.emplace({ |
| { "conf_type_id", id }, |
| { "id", id + std::to_string(foundTypes[id]++) }, |
| |
| { "beg_label_comp_id", rb.compound_id() }, |
| { "beg_label_asym_id", rb.asym_id() }, |
| { "beg_label_seq_id", rb.seq_id() }, |
| { "pdbx_beg_PDB_ins_code", rb.pdb_ins_code() }, |
| { "end_label_comp_id", re.compound_id() }, |
| { "end_label_asym_id", re.asym_id() }, |
| { "end_label_seq_id", re.seq_id() }, |
| { "pdbx_end_PDB_ins_code", re.pdb_ins_code() }, |
|
|
| { "beg_auth_comp_id", rb.compound_id() }, |
| { "beg_auth_asym_id", rb.auth_asym_id() }, |
| { "beg_auth_seq_id", rb.auth_seq_id() }, |
| { "end_auth_comp_id", re.compound_id() }, |
| { "end_auth_asym_id", re.auth_asym_id() }, |
| { "end_auth_seq_id", re.auth_seq_id() } |
| }); |
|
|
| st = t; |
| } |
|
|
| if (stop) |
| break; |
|
|
| if (lastSS != t->type()) |
| { |
| st = t; |
| lastSS = t->type(); |
| } |
| } |
| } |
|
|
| auto &software = db["software"]; |
| software.emplace({ |
| { "pdbx_ordinal", software.get_unique_id("") }, |
| { "name", "dssp" }, |
| { "version", kVersionNumber }, |
| { "date", kRevisionDate }, |
| { "classification", "model annotation" } |
| }); |
| } |
|
|