/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "cif++.hpp" #include #include #include #include #include #include namespace cif::pdb { using namespace std::literals; // -------------------------------------------------------------------- // conversion routines between cif and pdb format std::string cif2pdbDate(const std::string &d) { const std::regex rx(R"((\d{4})-(\d{2})(?:-(\d{2}))?)"); const char *kMonths[12] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; std::smatch m; std::string result; if (std::regex_match(d, m, rx)) { int year = std::stoi(m[1].str()); int month = std::stoi(m[2].str()); if (m[3].matched) result = cif::format("%02.2d-%3.3s-%02.2d", stoi(m[3].str()), kMonths[month - 1], (year % 100)).str(); else result = cif::format("%3.3s-%02.2d", kMonths[month - 1], (year % 100)).str(); } return result; } std::string cif2pdbAuth(std::string name) { const std::regex rx(R"(([^,]+), (\S+))"); std::smatch m; if (std::regex_match(name, m, rx)) name = m[2].str() + m[1].str(); return name; } std::string cif2pdbSymmetry(std::string s) { auto i = s.rfind('_'); if (i != std::string::npos) s.erase(i, 1); return s; } std::string cif2pdbAtomName(std::string name, std::string resName, const datablock &db) { if (name.length() < 4) { for (auto r : db["atom_site"].find(key("label_atom_id") == name and key("label_comp_id") == resName)) { std::string element = r["type_symbol"].as(); if (element.length() == 1 or not iequals(name, element)) name.insert(name.begin(), ' '); break; } } return name; } enum SoftwareType { eRefinement, eDataScaling, eDataExtraction, eDataReduction, ePhasing }; std::string cifSoftware(const datablock &db, SoftwareType sw) { std::string result = "NULL"; try { switch (sw) { case eRefinement: result = db["computing"].find_first(key("entry_id") == db.name(), "structure_refinement"); break; case eDataScaling: result = db["computing"].find_first(key("entry_id") == db.name(), "pdbx_data_reduction_ds"); break; case eDataReduction: result = db["computing"].find_first(key("entry_id") == db.name(), "pdbx_data_reduction_ii"); break; default: break; } if (result.empty() or result == "NULL") { auto &software = db["software"]; row_handle r; switch (sw) { case eRefinement: r = software.find_first(key("classification") == "refinement"); break; case eDataScaling: r = software.find_first(key("classification") == "data scaling"); break; case eDataExtraction: r = software.find_first(key("classification") == "data extraction"); break; case eDataReduction: r = software.find_first(key("classification") == "data reduction"); break; case ePhasing: r = software.find_first(key("classification") == "phasing"); break; } if (not r.empty()) result = r["name"].as() + " " + r["version"].as(); } trim(result); to_upper(result); if (result.empty()) result = "NULL"; } catch (...) { } return result; } // Map asym ID's back to PDB Chain ID's std::vector MapAsymIDs2ChainIDs(const std::vector &asymIDs, const datablock &db) { std::set result; for (auto asym : asymIDs) { for (auto r : db["pdbx_poly_seq_scheme"].find(key("asym_id") == asym)) { result.insert(r["pdb_strand_id"].as()); break; } for (auto r : db["pdbx_nonpoly_scheme"].find(key("asym_id") == asym)) { result.insert(r["pdb_strand_id"].as()); break; } } return { result.begin(), result.end() }; } // support for wrapping text using a 'continuation marker' size_t WriteContinuedLine(std::ostream &pdbFile, std::string header, int &count, int cLen, std::string text, std::string::size_type lStart = 0) { if (lStart == 0) { if (cLen == 0) lStart = header.length() + 1; else lStart = header.length() + cLen; } std::string::size_type maxLength = 80 - lStart - 1; std::vector lines = word_wrap(text, maxLength); for (auto &line : lines) { // to_upper(line); pdbFile << header; if (++count <= 1 or cLen == 0) { pdbFile << std::string(lStart - header.length(), ' '); if (count == 1) lStart = header.length() + cLen + 1; } else pdbFile << std::fixed << std::setw(cLen) << std::right << count << ' '; pdbFile << line << '\n'; } return lines.size(); } size_t WriteOneContinuedLine(std::ostream &pdbFile, std::string header, int cLen, std::string line, int lStart = 0) { int count = 0; return WriteContinuedLine(pdbFile, header, count, cLen, line, lStart); } size_t WriteCitation(std::ostream &pdbFile, const datablock &db, row_handle r, int reference) { size_t result = 0; std::string s1; if (reference > 0) { pdbFile << "REMARK 1 REFERENCE " << std::to_string(reference) << '\n'; result = 1; s1 = "REMARK 1 "; } else s1 = "JRNL "; std::string id, title, pubname, volume, astm, country, issn, csd, publ, pmid, doi, pageFirst, pageLast, year; cif::tie(id, title, pubname, volume, astm, country, issn, csd, publ, pmid, doi, pageFirst, pageLast, year) = r.get("id", "title", "journal_abbrev", "journal_volume", "journal_id_ASTM", "country", "journal_id_ISSN", "journal_id_CSD", "book_publisher", "pdbx_database_id_PubMed", "pdbx_database_id_DOI", "page_first", "page_last", "year"); std::vector authors; for (auto r1 : db["citation_author"].find(key("citation_id") == id)) authors.push_back(cif2pdbAuth(r1["name"].as())); if (not authors.empty()) result += WriteOneContinuedLine(pdbFile, s1 + "AUTH", 2, join(authors, ","), 19); result += WriteOneContinuedLine(pdbFile, s1 + "TITL", 2, title, 19); if (not pubname.empty()) { to_upper(pubname); const std::string kRefHeader = s1 + "REF %2.2s %-28.28s %2.2s%4.4s %5.5s %4.4s"; pdbFile << cif::format(kRefHeader, "" /* continuation */, pubname, (volume.empty() ? "" : "V."), volume, pageFirst, year) << '\n'; ++result; } if (not issn.empty()) { const std::string kRefHeader = s1 + "REFN ISSN %-25.25s"; pdbFile << cif::format(kRefHeader, issn) << '\n'; ++result; } // if (not issn.empty() or astm.empty()) // { //// 0 1 2 3 4 5 6 7 8 //// HEADER xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDDDDDDDDD IIII // const char kRefHeader[] = // "REMARK 1 REFN %4.4s %-6.6s %2.2s %-25.25s"; // // pdbFile << (boost::cif::format(kRefHeader) // % (astm.empty() ? "" : "ASTN") // % astm // % country // % issn).str() // << '\n'; // } if (not pmid.empty()) { const std::string kPMID = s1 + "PMID %-60.60s "; pdbFile << cif::format(kPMID, pmid) << '\n'; ++result; } if (not doi.empty()) { const std::string kDOI = s1 + "DOI %-60.60s "; pdbFile << cif::format(kDOI, doi) << '\n'; ++result; } return result; } void write_header_lines(std::ostream &pdbFile, const datablock &db) { // 0 1 2 3 4 5 6 7 8 // HEADER xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDDDDDDDDD IIII const char kHeader[] = "HEADER %-40.40s" "%-9.9s" " %-4.4s"; // HEADER std::string keywords; auto &cat1 = db["struct_keywords"]; for (auto r : cat1) { keywords = r["pdbx_keywords"].as(); break; } std::string date; for (auto r : db["pdbx_database_status"]) { date = r["recvd_initial_deposition_date"].as(); if (date.empty()) continue; date = cif2pdbDate(date); break; } if (date.empty()) { for (auto r : db["database_PDB_rev"]) { date = r["date_original"].as(); if (date.empty()) continue; date = cif2pdbDate(date); break; } } pdbFile << cif::format(kHeader, keywords, date, db.name()) << '\n'; // TODO: implement // OBSLTE (skip for now) // TITLE for (auto r : db["struct"]) { std::string title = r["title"].as(); trim(title); WriteOneContinuedLine(pdbFile, "TITLE ", 2, title); break; } // COMPND using namespace std::placeholders; int molID = 0; std::vector cmpnd; for (auto r : db["entity"]) { if (r["type"] != "polymer") continue; std::string entityID = r["id"].as(); ++molID; cmpnd.push_back("MOL_ID: " + std::to_string(molID)); std::string molecule = r["pdbx_description"].as(); cmpnd.push_back("MOLECULE: " + molecule); auto poly = db["entity_poly"].find(key("entity_id") == entityID); if (not poly.empty()) { std::string chains = poly.front()["pdbx_strand_id"].as(); replace_all(chains, ",", ", "); cmpnd.push_back("CHAIN: " + chains); } std::string fragment = r["pdbx_fragment"].as(); if (not fragment.empty()) cmpnd.push_back("FRAGMENT: " + fragment); for (auto sr : db["entity_name_com"].find(key("entity_id") == entityID)) { std::string syn = sr["name"].as(); if (not syn.empty()) cmpnd.push_back("SYNONYM: " + syn); } std::string mutation = r["pdbx_mutation"].as(); if (not mutation.empty()) cmpnd.push_back("MUTATION: " + mutation); std::string ec = r["pdbx_ec"].as(); if (not ec.empty()) cmpnd.push_back("EC: " + ec); if (r["src_method"] == "man" or r["src_method"] == "syn") cmpnd.push_back("ENGINEERED: YES"); std::string details = r["details"].as(); if (not details.empty()) cmpnd.push_back("OTHER_DETAILS: " + details); } WriteOneContinuedLine(pdbFile, "COMPND ", 3, join(cmpnd, ";\n")); // SOURCE molID = 0; std::vector source; for (auto r : db["entity"]) { if (r["type"] != "polymer") continue; std::string entityID = r["id"].as(); ++molID; source.push_back("MOL_ID: " + std::to_string(molID)); if (r["src_method"] == "syn") source.push_back("SYNTHETIC: YES"); auto &gen = db["entity_src_gen"]; const std::pair kGenSourceMapping[] = { { "gene_src_common_name", "ORGANISM_COMMON" }, { "pdbx_gene_src_gene", "GENE" }, { "gene_src_strain", "STRAIN" }, { "pdbx_gene_src_cell_line", "CELL_LINE" }, { "pdbx_gene_src_organelle", "ORGANELLE" }, { "pdbx_gene_src_cellular_location", "CELLULAR_LOCATION" }, { "pdbx_gene_src_scientific_name", "ORGANISM_SCIENTIFIC" }, { "pdbx_gene_src_ncbi_taxonomy_id", "ORGANISM_TAXID" }, { "pdbx_host_org_scientific_name", "EXPRESSION_SYSTEM" }, { "pdbx_host_org_ncbi_taxonomy_id", "EXPRESSION_SYSTEM_TAXID" }, { "pdbx_host_org_strain", "EXPRESSION_SYSTEM_STRAIN" }, { "pdbx_host_org_variant", "EXPRESSION_SYSTEM_VARIANT" }, { "pdbx_host_org_cellular_location", "EXPRESSION_SYSTEM_CELLULAR_LOCATION" }, { "pdbx_host_org_vector_type", "EXPRESSION_SYSTEM_VECTOR_TYPE" }, { "pdbx_host_org_vector", "EXPRESSION_SYSTEM_VECTOR" }, { "pdbx_host_org_gene", "EXPRESSION_SYSTEM_GENE" }, { "plasmid_name", "EXPRESSION_SYSTEM_PLASMID" }, { "details", "OTHER_DETAILS" } }; for (auto gr : gen.find(key("entity_id") == entityID)) { for (const auto &[cname, sname] : kGenSourceMapping) { std::string s = gr[cname].as(); if (not s.empty()) source.push_back(sname + ": "s + s); } } auto &nat = db["entity_src_nat"]; const std::pair kNatSourceMapping[] = { { "common_name", "ORGANISM_COMMON" }, { "strain", "STRAIN" }, { "pdbx_organism_scientific", "ORGANISM_SCIENTIFIC" }, { "pdbx_ncbi_taxonomy_id", "ORGANISM_TAXID" }, { "pdbx_cellular_location", "CELLULAR_LOCATION" }, { "pdbx_plasmid_name", "PLASMID" }, { "pdbx_organ", "ORGAN" }, { "details", "OTHER_DETAILS" } }; for (auto nr : nat.find(key("entity_id") == entityID)) { for (const auto &[cname, sname] : kNatSourceMapping) { std::string s = nr[cname].as(); if (not s.empty()) source.push_back(sname + ": "s + s); } } } WriteOneContinuedLine(pdbFile, "SOURCE ", 3, join(source, ";\n")); // KEYWDS keywords.clear(); for (auto r : cat1) { if (not r["text"].empty()) keywords += r["text"].as(); else keywords += r["pdbx_keywords"].as(); } if (not keywords.empty()) WriteOneContinuedLine(pdbFile, "KEYWDS ", 2, keywords); // EXPDTA auto &dbexpt = db["exptl"]; if (not dbexpt.empty()) { std::vector method; for (auto r : dbexpt) method.push_back(r["method"].as()); if (not method.empty()) WriteOneContinuedLine(pdbFile, "EXPDTA ", 2, join(method, "; ")); } // NUMMDL // TODO... // MDLTYP // TODO... // AUTHOR std::vector authors; for (auto r : db["audit_author"]) authors.push_back(cif2pdbAuth(r["name"].as())); if (not authors.empty()) WriteOneContinuedLine(pdbFile, "AUTHOR ", 2, join(authors, ",")); } void WriteTitle(std::ostream &pdbFile, const datablock &db) { write_header_lines(pdbFile, db); // REVDAT const char kRevDatFmt[] = "REVDAT %3d%2.2s %9.9s %4.4s %1d "; auto &cat2 = db["database_PDB_rev"]; std::vector rev(cat2.begin(), cat2.end()); sort(rev.begin(), rev.end(), [](row_handle a, row_handle b) -> bool { return a["num"].as() > b["num"].as(); }); for (auto r : rev) { int revNum, modType; std::string date, replaces; cif::tie(revNum, modType, date, replaces) = r.get("num", "mod_type", "date", "replaces"); date = cif2pdbDate(date); std::vector types; for (auto r1 : db["database_PDB_rev_record"].find(key("rev_num") == revNum)) types.push_back(r1["type"].as()); int continuation = 0; do { std::string cs = ++continuation > 1 ? std::to_string(continuation) : std::string(); pdbFile << cif::format(kRevDatFmt, revNum, cs, date, db.name(), modType); for (size_t i = 0; i < 4; ++i) pdbFile << cif::format(" %-6.6s", (i < types.size() ? types[i] : std::string())); pdbFile << '\n'; if (types.size() > 4) types.erase(types.begin(), types.begin() + 4); else types.clear(); } while (types.empty() == false); } // SPRSDE // TODO... // JRNL for (auto r : db["citation"]) { WriteCitation(pdbFile, db, r, 0); break; } } void WriteRemark1(std::ostream &pdbFile, const datablock &db) { int reference = 0; for (auto r : db["citation"]) { if (reference > 0) { if (reference == 1) pdbFile << "REMARK 1\n"; WriteCitation(pdbFile, db, r, reference); } ++reference; } } void WriteRemark2(std::ostream &pdbFile, const datablock &db) { auto &refine = db["refine"]; if (refine.empty()) { pdbFile << "REMARK 2\n" << "REMARK 2 RESOLUTION. NOT APPLICABLE.\n"; } else { try { float resHigh = refine.front()["ls_d_res_high"].as(); pdbFile << "REMARK 2\n" << cif::format("REMARK 2 RESOLUTION. %7.2f ANGSTROMS.", resHigh) << '\n'; } catch (...) { /* skip it */ } } } // -------------------------------------------------------------------- // Code to help format RERMARK 3 data class FBase { public: virtual ~FBase() {} virtual void out(std::ostream &os) = 0; protected: FBase(row_handle r, const char *f) : mRow(r) , mField(f) { } FBase(const category &cat, condition &&cond, const char *f) : mField(f) { auto r = cat.find(std::move(cond)); if (not r.empty()) mRow = r.front(); } std::string_view text() const { return mRow.empty() or mRow[mField].empty() ? "" : mRow[mField].text(); } row_handle mRow; const char *mField; }; class Fi : public FBase { public: Fi(row_handle r, const char *f) : FBase(r, f) { } Fi(const category &cat, condition &&cond, const char *f) : FBase(cat, std::move(cond), f) { } virtual void out(std::ostream &os) { std::string s{ text() }; if (s.empty()) { os << "NULL"; if (os.width() > 4) os << std::string(os.width() - 4, ' '); } else { long l = 0; auto r = std::from_chars(s.data(), s.data() + s.length(), l); if ((bool)r.ec) { if (VERBOSE > 0) std::cerr << "Failed to write '" << s << "' as a long from field " << mField << ", this indicates an error in the code for writing PDB files\n"; os << s; } else os << l; } } }; class Ff : public FBase { public: Ff(row_handle r, const char *f) : FBase(r, f) { } Ff(const category &cat, condition &&cond, const char *f) : FBase(cat, std::move(cond), f) { } virtual void out(std::ostream &os) { if (mRow.empty() or mRow[mField].empty()) { os << "NULL"; if (os.width() > 4) os << std::string(os.width() - 4, ' '); } else { std::string s{ text() }; double d = 0; auto r = cif::from_chars(s.data(), s.data() + s.length(), d); if ((bool)r.ec) { if (VERBOSE > 0) std::cerr << "Failed to write '" << s << "' as a double from field " << mField << ", this indicates an error in the code for writing PDB files\n"; os << s; } else os << d; } } }; class Fs : public FBase { public: Fs(row_handle r, const char *f, int remarkNr = 3) : FBase(r, f) , mNr(remarkNr) { } Fs(const category &cat, condition &&cond, const char *f, int remarkNr = 3) : FBase(cat, std::move(cond), f) , mNr(remarkNr) { } virtual void out(std::ostream &os) { std::string s{ text() }; size_t width = os.width(); if (s.empty()) { os << "NULL"; if (os.width() > 4) os << std::string(width - 4, ' '); } else if (width == 0 or s.length() <= width) os << s; else { os << '\n'; std::stringstream ss; ss << "REMARK " << std::setw(3) << std::right << mNr << ' '; WriteOneContinuedLine(os, ss.str(), 0, s); } } int mNr = 3; }; std::ostream &operator<<(std::ostream &os, FBase &&fld) { fld.out(os); return os; } template struct RM { RM(const char *desc, int width = 0, int precision = 6) : mDesc(desc) , mWidth(width) , mPrecision(precision) { } const char *mDesc; int mWidth, mPrecision; }; typedef RM<3> RM3; template std::ostream &operator<<(std::ostream &os, RM &&rm) { os << "REMARK " << std::setw(3) << std::right << N << " " << rm.mDesc << (rm.mWidth > 0 ? std::left : std::right) << std::fixed << std::setw(std::abs(rm.mWidth)) << std::setprecision(rm.mPrecision); return os; } struct SEP { SEP(const char *txt, int width, int precision = 6) : mText(txt) , mWidth(width) , mPrecision(precision) { } const char *mText; int mWidth, mPrecision; }; std::ostream &operator<<(std::ostream &os, SEP &&sep) { os << sep.mText << (sep.mWidth > 0 ? std::left : std::right) << std::fixed << std::setw(std::abs(sep.mWidth)) << std::setprecision(sep.mPrecision); return os; } // -------------------------------------------------------------------- void WriteRemark3BusterTNT(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); auto ls_shell = db["refine_ls_shell"].front(); auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; // auto ls_restr_ncs = db["refine_ls_restr_ncs"].front(); // auto pdbx_xplor_file = db["pdbx_xplor_file"].front(); // auto pdbx_refine = db["pdbx_refine"].front(); pdbFile << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" COMPLETENESS FOR RANGE (%) : ", 6, 1) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' << RM3(" R VALUE (WORKING + TEST SET) : ", 7, 3) << Ff(refine, "ls_R_factor_obs") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 3) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 3) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free_error") << '\n' << RM3("") << '\n' << RM3(" FIT IN THE HIGHEST RESOLUTION BIN.") << '\n' << RM3(" TOTAL NUMBER OF BINS USED : ", 12, 6) << Fi(ls_shell, "pdbx_total_number_of_bins_used") << '\n' << RM3(" BIN RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(ls_shell, "d_res_high") << '\n' << RM3(" BIN RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(ls_shell, "d_res_low") << '\n' << RM3(" BIN COMPLETENESS (WORKING+TEST) (%) : ", 6, 2) << Ff(ls_shell, "percent_reflns_obs") << '\n' << RM3(" REFLECTIONS IN BIN (WORKING + TEST SET) : ", 12, 6) << Fi(ls_shell, "number_reflns_all") << '\n' << RM3(" BIN R VALUE (WORKING + TEST SET) : ", 8, 4) << Ff(ls_shell, "R_factor_all") << '\n' << RM3(" REFLECTIONS IN BIN (WORKING SET) : ", 12, 6) << Fi(ls_shell, "number_reflns_R_work") << '\n' << RM3(" BIN R VALUE (WORKING SET) : ", 8, 4) << Ff(ls_shell, "R_factor_R_work") << '\n' << RM3(" BIN FREE R VALUE : ", 8, 4) << Ff(ls_shell, "R_factor_R_free") << '\n' << RM3(" BIN FREE R VALUE TEST SET SIZE (%) : ", 6, 2) << Ff(ls_shell, "percent_reflns_R_free") << '\n' << RM3(" BIN FREE R VALUE TEST SET COUNT : ", 12, 7) << Fi(ls_shell, "number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF BIN FREE R VALUE : ", 7, 3) << Ff(ls_shell, "R_factor_R_free_error") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ", 12, 6) << Fi(hist, "number_atoms_solvent") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' // << RM3(" B VALUE TYPE : ") << Fs(refine, "pdbx_TLS_residual_ADP_flag") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 7, 2) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 7, 2) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM LUZZATI PLOT (A) : ", 7, 3) << Ff(analyze, "Luzzati_coordinate_error_obs") << '\n' << RM3(" DPI (BLOW EQ-10) BASED ON R VALUE (A) : ", 5, 3) << Ff(refine, "pdbx_overall_SU_R_Blow_DPI") << '\n' << RM3(" DPI (BLOW EQ-9) BASED ON FREE R VALUE (A) : ", 5, 3) << Ff(refine, "pdbx_overall_SU_R_free_Blow_DPI") << '\n' << RM3(" DPI (CRUICKSHANK) BASED ON R VALUE (A) : ", 5, 3) << Ff(refine, "overall_SU_R_Cruickshank_DPI") << '\n' << RM3(" DPI (CRUICKSHANK) BASED ON FREE R VALUE (A) : ", 5, 3) << Ff(refine, "pdbx_overall_SU_R_free_Cruickshank_DPI") << '\n' << RM3("") << '\n' << RM3(" REFERENCES: BLOW, D. (2002) ACTA CRYST D58, 792-797") << '\n' << RM3(" CRUICKSHANK, D.W.J. (1999) ACTA CRYST D55, 583-601") << '\n' << RM3("") << '\n' << RM3(" CORRELATION COEFFICIENTS.") << '\n' << RM3(" CORRELATION COEFFICIENT FO-FC : ", 5, 3) << Ff(refine, "correlation_coeff_Fo_to_Fc") << '\n' << RM3(" CORRELATION COEFFICIENT FO-FC FREE : ", 5, 3) << Ff(refine, "correlation_coeff_Fo_to_Fc_free") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF GEOMETRIC FUNCTION TERMS DEFINED : 15") << '\n' << RM3(" TERM COUNT WEIGHT FUNCTION.") << '\n' << RM3(" BOND LENGTHS : ", 7, 0) << Ff(ls_restr, key("type") == "t_bond_d", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_bond_d", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_bond_d", "pdbx_restraint_function") << '\n' << RM3(" BOND ANGLES : ", 7, 0) << Ff(ls_restr, key("type") == "t_angle_deg", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_angle_deg", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_angle_deg", "pdbx_restraint_function") << '\n' << RM3(" TORSION ANGLES : ", 7, 0) << Ff(ls_restr, key("type") == "t_dihedral_angle_d", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_dihedral_angle_d", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_dihedral_angle_d", "pdbx_restraint_function") << '\n' << RM3(" TRIGONAL CARBON PLANES : ", 7, 0) << Ff(ls_restr, key("type") == "t_trig_c_planes", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_trig_c_planes", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_trig_c_planes", "pdbx_restraint_function") << '\n' << RM3(" GENERAL PLANES : ", 7, 0) << Ff(ls_restr, key("type") == "t_gen_planes", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_gen_planes", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_gen_planes", "pdbx_restraint_function") << '\n' << RM3(" ISOTROPIC THERMAL FACTORS : ", 7, 0) << Ff(ls_restr, key("type") == "t_it", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_it", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_it", "pdbx_restraint_function") << '\n' << RM3(" BAD NON-BONDED CONTACTS : ", 7, 0) << Ff(ls_restr, key("type") == "t_nbd", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_nbd", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_nbd", "pdbx_restraint_function") << '\n' << RM3(" IMPROPER TORSIONS : ", 7, 0) << Ff(ls_restr, key("type") == "t_improper_torsion", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_improper_torsion", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_improper_torsion", "pdbx_restraint_function") << '\n' << RM3(" PSEUDOROTATION ANGLES : ", 7, 0) << Ff(ls_restr, key("type") == "t_pseud_angle", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_pseud_angle", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_pseud_angle", "pdbx_restraint_function") << '\n' << RM3(" CHIRAL IMPROPER TORSION : ", 7, 0) << Ff(ls_restr, key("type") == "t_chiral_improper_torsion", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_chiral_improper_torsion", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_chiral_improper_torsion", "pdbx_restraint_function") << '\n' << RM3(" SUM OF OCCUPANCIES : ", 7, 0) << Ff(ls_restr, key("type") == "t_sum_occupancies", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_sum_occupancies", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_sum_occupancies", "pdbx_restraint_function") << '\n' << RM3(" UTILITY DISTANCES : ", 7, 0) << Ff(ls_restr, key("type") == "t_utility_distance", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_utility_distance", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_utility_distance", "pdbx_restraint_function") << '\n' << RM3(" UTILITY ANGLES : ", 7, 0) << Ff(ls_restr, key("type") == "t_utility_angle", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_utility_angle", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_utility_angle", "pdbx_restraint_function") << '\n' << RM3(" UTILITY TORSION : ", 7, 0) << Ff(ls_restr, key("type") == "t_utility_torsion", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_utility_torsion", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_utility_torsion", "pdbx_restraint_function") << '\n' << RM3(" IDEAL-DIST CONTACT TERM : ", 7, 0) << Ff(ls_restr, key("type") == "t_ideal_dist_contact", "number") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "t_ideal_dist_contact", "weight") << SEP("; ", 12) << Fs(ls_restr, key("type") == "t_ideal_dist_contact", "pdbx_restraint_function") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM IDEAL VALUES.") << '\n' << RM3(" BOND LENGTHS (A) : ", 7, 3) << Ff(ls_restr, key("type") == "t_bond_d", "dev_ideal") << '\n' << RM3(" BOND ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "t_angle_deg", "dev_ideal") << '\n' << RM3(" PEPTIDE OMEGA TORSION ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "t_omega_torsion", "dev_ideal") << '\n' << RM3(" OTHER TORSION ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "t_other_torsion", "dev_ideal") << '\n'; auto &tls = db["pdbx_refine_tls"]; pdbFile << RM3("") << '\n' << RM3(" TLS DETAILS") << '\n' << RM3(" NUMBER OF TLS GROUPS : ") << (tls.size() ? std::to_string(tls.size()) : "NULL") << '\n'; for (auto t : tls) { std::string id = t["id"].as(); auto g = db["pdbx_refine_tls_group"].find_first(key("refine_tls_id") == id); pdbFile << RM3("") << '\n' << RM3(" TLS GROUP : ") << id << '\n' << RM3(" SELECTION: ") << Fs(g, "selection_details") << '\n'; pdbFile << RM3(" ORIGIN FOR THE GROUP (A):", -9, 4) << Ff(t, "origin_x") << SEP("", -9, 4) << Ff(t, "origin_y") << SEP("", -9, 4) << Ff(t, "origin_z") << '\n' << RM3(" T TENSOR") << '\n' << RM3(" T11:", -9, 4) << Ff(t, "T[1][1]") << SEP(" T22:", -9, 4) << Ff(t, "T[2][2]") << '\n' << RM3(" T33:", -9, 4) << Ff(t, "T[3][3]") << SEP(" T12:", -9, 4) << Ff(t, "T[1][2]") << '\n' << RM3(" T13:", -9, 4) << Ff(t, "T[1][3]") << SEP(" T23:", -9, 4) << Ff(t, "T[2][3]") << '\n' << RM3(" L TENSOR") << '\n' << RM3(" L11:", -9, 4) << Ff(t, "L[1][1]") << SEP(" L22:", -9, 4) << Ff(t, "L[2][2]") << '\n' << RM3(" L33:", -9, 4) << Ff(t, "L[3][3]") << SEP(" L12:", -9, 4) << Ff(t, "L[1][2]") << '\n' << RM3(" L13:", -9, 4) << Ff(t, "L[1][3]") << SEP(" L23:", -9, 4) << Ff(t, "L[2][3]") << '\n' << RM3(" S TENSOR") << '\n' << RM3(" S11:", -9, 4) << Ff(t, "S[1][1]") << SEP(" S12:", -9, 4) << Ff(t, "S[1][2]") << SEP(" S13:", -9, 4) << Ff(t, "S[1][3]") << '\n' << RM3(" S21:", -9, 4) << Ff(t, "S[2][1]") << SEP(" S22:", -9, 4) << Ff(t, "S[2][2]") << SEP(" S23:", -9, 4) << Ff(t, "S[2][3]") << '\n' << RM3(" S31:", -9, 4) << Ff(t, "S[3][1]") << SEP(" S32:", -9, 4) << Ff(t, "S[3][2]") << SEP(" S33:", -9, 4) << Ff(t, "S[3][3]") << '\n'; } pdbFile << RM3("") << '\n'; } // -------------------------------------------------------------------- void WriteRemark3CNS(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); auto ls_shell = db["refine_ls_shell"].front(); auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; auto ls_restr_ncs = db["refine_ls_restr_ncs"].front(); // auto pdbx_xplor_file = db["pdbx_xplor_file"].front(); // auto pdbx_refine = db["pdbx_refine"].front(); pdbFile << RM3("") << '\n' << RM3("REFINEMENT TARGET : ") << Fs(refine, "pdbx_stereochemistry_target_values") << '\n' << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" DATA CUTOFF HIGH (ABS(F)) : ", 6, 3) << Ff(refine, "pdbx_data_cutoff_high_absF") << '\n' << RM3(" DATA CUTOFF LOW (ABS(F)) : ", 7, 4) << Ff(refine, "pdbx_data_cutoff_low_absF") << '\n' << RM3(" COMPLETENESS (WORKING+TEST) (%) : ", 4, 1) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' // << RM3(" R VALUE (WORKING + TEST SET) : ", 7, 5) << Ff(refine, "ls_R_factor_obs") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 3) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 3) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free_error") << '\n' // << RM3("") << '\n' // << RM3(" FIT/AGREEMENT OF MODEL WITH ALL DATA.") << '\n' // << RM3(" R VALUE (WORKING + TEST SET, NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "R_factor_all_no_cutoff") << '\n' // << RM3(" R VALUE (WORKING SET, NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "R_factor_obs_no_cutoff") << '\n' // << RM3(" FREE R VALUE (NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "free_R_factor_no_cutoff") << '\n' // << RM3(" FREE R VALUE TEST SET SIZE (%, NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "free_R_val_test_set_size_perc_no_cutoff") << '\n' // << RM3(" FREE R VALUE TEST SET COUNT (NO CUTOFF) : ", 12, 6) << Fi(pdbx_refine, "free_R_val_test_set_ct_no_cutoff") << '\n' // << RM3(" TOTAL NUMBER OF REFLECTIONS (NO CUTOFF) : ", 12, 6) << Fi(refine, "ls_number_reflns_all") << '\n' << RM3("") << '\n' << RM3(" FIT IN THE HIGHEST RESOLUTION BIN.") << '\n' << RM3(" TOTAL NUMBER OF BINS USED : ", 12, 6) << Fi(ls_shell, "pdbx_total_number_of_bins_used") << '\n' << RM3(" BIN RESOLUTION RANGE HIGH (A) : ", 5, 2) << Ff(ls_shell, "d_res_high") << '\n' << RM3(" BIN RESOLUTION RANGE LOW (A) : ", 5, 2) << Ff(ls_shell, "d_res_low") << '\n' << RM3(" BIN COMPLETENESS (WORKING+TEST) (%) : ", 6, 2) << Ff(ls_shell, "percent_reflns_obs") << '\n' << RM3(" REFLECTIONS IN BIN (WORKING SET) : ", 12, 6) << Fi(ls_shell, "number_reflns_R_work") << '\n' << RM3(" BIN R VALUE (WORKING SET) : ", 8, 4) << Ff(ls_shell, "R_factor_R_work") << '\n' << RM3(" BIN FREE R VALUE : ", 8, 4) << Ff(ls_shell, "R_factor_R_free") << '\n' << RM3(" BIN FREE R VALUE TEST SET SIZE (%) : ", 6, 2) << Ff(ls_shell, "percent_reflns_R_free") << '\n' << RM3(" BIN FREE R VALUE TEST SET COUNT : ", 12, 7) << Fi(ls_shell, "number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF BIN FREE R VALUE : ", 7, 3) << Ff(ls_shell, "R_factor_R_free_error") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ", 12, 6) << Fi(hist, "number_atoms_solvent") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' << RM3(" B VALUE TYPE : ") << Fs(refine, "pdbx_TLS_residual_ADP_flag") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 7, 2) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 7, 2) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -8, 5) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM LUZZATI PLOT (A) : ", 7, 2) << Ff(analyze, "Luzzati_coordinate_error_obs") << '\n' << RM3(" ESD FROM SIGMAA (A) : ", 7, 2) << Ff(analyze, "Luzzati_sigma_a_obs") << '\n' << RM3(" LOW RESOLUTION CUTOFF (A) : ", 7, 2) << Ff(analyze, "Luzzati_d_res_low_obs") << '\n' << RM3("") << '\n' << RM3(" CROSS-VALIDATED ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM C-V LUZZATI PLOT (A) : ", 7, 2) << Ff(analyze, "Luzzati_coordinate_error_free") << '\n' << RM3(" ESD FROM C-V SIGMAA (A) : ", 7, 2) << Ff(analyze, "Luzzati_sigma_a_free") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM IDEAL VALUES.") << '\n' << RM3(" BOND LENGTHS (A) : ", 7, 3) << Ff(ls_restr, key("type") == "c_bond_d", "dev_ideal") << '\n' << RM3(" BOND ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "c_angle_deg", "dev_ideal") << '\n' << RM3(" DIHEDRAL ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "c_dihedral_angle_d", "dev_ideal") << '\n' << RM3(" IMPROPER ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "c_improper_angle_d", "dev_ideal") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL MODEL : ") << Fs(refine, "pdbx_isotropic_thermal_model") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL FACTOR RESTRAINTS. RMS SIGMA") << '\n' << RM3(" MAIN-CHAIN BOND (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "c_mcbond_it", "dev_ideal") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "c_mcbond_it", "dev_ideal_target") << '\n' << RM3(" MAIN-CHAIN ANGLE (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "c_mcangle_it", "dev_ideal") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "c_mcangle_it", "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN BOND (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "c_scbond_it", "dev_ideal") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "c_scbond_it", "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN ANGLE (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "c_scangle_it", "dev_ideal") << SEP("; ", 7, 3) << Ff(ls_restr, key("type") == "c_scangle_it", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" BULK SOLVENT MODELING.") << '\n' << RM3(" METHOD USED : ") << Fs(refine, "solvent_model_details") << '\n' << RM3(" KSOL : ", 5, 2) << Ff(refine, "solvent_model_param_ksol") << '\n' << RM3(" BSOL : ", 5, 2) << Ff(refine, "solvent_model_param_bsol") << '\n' << RM3("") << '\n' << RM3(" NCS MODEL : ") << Fs(ls_restr_ncs, "ncs_model_details") << '\n' << RM3("") << '\n' << RM3(" NCS RESTRAINTS. RMS SIGMA/WEIGHT") << '\n' // TODO: using only group 1 here, should this be fixed??? << RM3(" GROUP 1 POSITIONAL (A) : ", 4, 2) << Ff(ls_restr_ncs, "rms_dev_position") << SEP("; ", 6, 2) << Ff(ls_restr_ncs, "weight_position") << SEP("; ", 6, 2) << '\n' << RM3(" GROUP 1 B-FACTOR (A**2) : ", 4, 2) << Ff(ls_restr_ncs, "rms_dev_B_iso") << SEP("; ", 6, 2) << Ff(ls_restr_ncs, "weight_B_iso") << SEP("; ", 6, 2) << '\n' // TODO: using only files from serial_no 1 here // << RM3("") << '\n' // << RM3(" PARAMETER FILE 1 : ") << Fs(pdbx_xplor_file, "param_file") << '\n' // << RM3(" TOPOLOGY FILE 1 : ") << Fs(pdbx_xplor_file, "topol_file") << '\n' << RM3("") << '\n'; } // -------------------------------------------------------------------- void WriteRemark3Refmac(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); auto ls_shell = db["refine_ls_shell"].front(); auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); // auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; // auto pdbx_xplor_file = db["pdbx_xplor_file"].front(); auto c = [](const char *t) -> condition { return key("type") == t; }; pdbFile << RM3("") << '\n' << RM3("REFINEMENT TARGET : ") << Fs(refine, "pdbx_stereochemistry_target_values") << '\n' << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" COMPLETENESS FOR RANGE (%) : ", 5, 2) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' << RM3(" R VALUE (WORKING + TEST SET) : ", 7, 5) << Ff(refine, "ls_R_factor_obs") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 5) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 5) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 1) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free_error") << '\n' << RM3("") << '\n' << RM3(" FIT IN THE HIGHEST RESOLUTION BIN.") << '\n' << RM3(" TOTAL NUMBER OF BINS USED : ") << Fi(ls_shell, "pdbx_total_number_of_bins_used") << '\n' << RM3(" BIN RESOLUTION RANGE HIGH (A) : ", 5, 3) << Ff(ls_shell, "d_res_high") << '\n' << RM3(" BIN RESOLUTION RANGE LOW (A) : ", 5, 3) << Ff(ls_shell, "d_res_low") << '\n' << RM3(" REFLECTION IN BIN (WORKING SET) : ") << Fi(ls_shell, "number_reflns_R_work") << '\n' << RM3(" BIN COMPLETENESS (WORKING+TEST) (%) : ", 5, 2) << Ff(ls_shell, "percent_reflns_obs") << '\n' << RM3(" BIN R VALUE (WORKING SET) : ", 7, 3) << Ff(ls_shell, "R_factor_R_work") << '\n' << RM3(" BIN FREE R VALUE SET COUNT : ") << Fi(ls_shell, "number_reflns_R_free") << '\n' << RM3(" BIN FREE R VALUE : ", 7, 3) << Ff(ls_shell, "R_factor_R_free") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ") << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ") << Fi(hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ") << Fi(hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ") << Fi(hist, "number_atoms_solvent") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' << RM3(" B VALUE TYPE : ") << Fs(refine, "pdbx_TLS_residual_ADP_flag") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 8, 3) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 8, 3) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" ESTIMATED OVERALL COORDINATE ERROR.") << '\n' << RM3(" ESU BASED ON R VALUE (A): ", 6, 3) << Ff(refine, "pdbx_overall_ESU_R") << '\n' << RM3(" ESU BASED ON FREE R VALUE (A): ", 6, 3) << Ff(refine, "pdbx_overall_ESU_R_Free") << '\n' << RM3(" ESU BASED ON MAXIMUM LIKELIHOOD (A): ", 6, 3) << Ff(refine, "overall_SU_ML") << '\n' << RM3(" ESU FOR B VALUES BASED ON MAXIMUM LIKELIHOOD (A**2): ", 6, 3) << Ff(refine, "overall_SU_B") << '\n' << RM3("") << '\n' << RM3(" CORRELATION COEFFICIENTS.") << '\n' << RM3(" CORRELATION COEFFICIENT FO-FC : ", 6, 3) << Ff(refine, "correlation_coeff_Fo_to_Fc") << '\n' << RM3(" CORRELATION COEFFICIENT FO-FC FREE : ", 6, 3) << Ff(refine, "correlation_coeff_Fo_to_Fc_free") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM IDEAL VALUES COUNT RMS WEIGHT") << '\n' << RM3(" BOND LENGTHS REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_bond_refined_d"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_bond_refined_d"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_bond_refined_d"), "dev_ideal_target") << '\n' << RM3(" BOND LENGTHS OTHERS (A): ", -5) << Fi(ls_restr, c("r_bond_other_d"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_bond_other_d"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_bond_other_d"), "dev_ideal_target") << '\n' << RM3(" BOND ANGLES REFINED ATOMS (DEGREES): ", -5) << Fi(ls_restr, c("r_angle_refined_deg"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_angle_refined_deg"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_angle_refined_deg"), "dev_ideal_target") << '\n' << RM3(" BOND ANGLES OTHERS (DEGREES): ", -5) << Fi(ls_restr, c("r_angle_other_deg"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_angle_other_deg"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_angle_other_deg"), "dev_ideal_target") << '\n' << RM3(" TORSION ANGLES, PERIOD 1 (DEGREES): ", -5) << Fi(ls_restr, c("r_dihedral_angle_1_deg"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_1_deg"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_1_deg"), "dev_ideal_target") << '\n' << RM3(" TORSION ANGLES, PERIOD 2 (DEGREES): ", -5) << Fi(ls_restr, c("r_dihedral_angle_2_deg"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_2_deg"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_2_deg"), "dev_ideal_target") << '\n' << RM3(" TORSION ANGLES, PERIOD 3 (DEGREES): ", -5) << Fi(ls_restr, c("r_dihedral_angle_3_deg"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_3_deg"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_3_deg"), "dev_ideal_target") << '\n' << RM3(" TORSION ANGLES, PERIOD 4 (DEGREES): ", -5) << Fi(ls_restr, c("r_dihedral_angle_4_deg"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_4_deg"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_dihedral_angle_4_deg"), "dev_ideal_target") << '\n' << RM3(" CHIRAL-CENTER RESTRAINTS (A**3): ", -5) << Fi(ls_restr, c("r_chiral_restr"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_chiral_restr"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_chiral_restr"), "dev_ideal_target") << '\n' << RM3(" GENERAL PLANES REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_gen_planes_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_gen_planes_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_gen_planes_refined"), "dev_ideal_target") << '\n' << RM3(" GENERAL PLANES OTHERS (A): ", -5) << Fi(ls_restr, c("r_gen_planes_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_gen_planes_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_gen_planes_other"), "dev_ideal_target") << '\n' << RM3(" NON-BONDED CONTACTS REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_nbd_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbd_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbd_refined"), "dev_ideal_target") << '\n' << RM3(" NON-BONDED CONTACTS OTHERS (A): ", -5) << Fi(ls_restr, c("r_nbd_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbd_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbd_other"), "dev_ideal_target") << '\n' << RM3(" NON-BONDED TORSION REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_nbtor_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbtor_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbtor_refined"), "dev_ideal_target") << '\n' << RM3(" NON-BONDED TORSION OTHERS (A): ", -5) << Fi(ls_restr, c("r_nbtor_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbtor_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_nbtor_other"), "dev_ideal_target") << '\n' << RM3(" H-BOND (X...Y) REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_xyhbond_nbd_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_xyhbond_nbd_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_xyhbond_nbd_refined"), "dev_ideal_target") << '\n' << RM3(" H-BOND (X...Y) OTHERS (A): ", -5) << Fi(ls_restr, c("r_xyhbond_nbd_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_xyhbond_nbd_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_xyhbond_nbd_other"), "dev_ideal_target") << '\n' << RM3(" POTENTIAL METAL-ION REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_metal_ion_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_metal_ion_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_metal_ion_refined"), "dev_ideal_target") << '\n' << RM3(" POTENTIAL METAL-ION OTHERS (A): ", -5) << Fi(ls_restr, c("r_metal_ion_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_metal_ion_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_metal_ion_other"), "dev_ideal_target") << '\n' << RM3(" SYMMETRY VDW REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_symmetry_vdw_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_vdw_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_vdw_refined"), "dev_ideal_target") << '\n' << RM3(" SYMMETRY VDW OTHERS (A): ", -5) << Fi(ls_restr, c("r_symmetry_vdw_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_vdw_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_vdw_other"), "dev_ideal_target") << '\n' << RM3(" SYMMETRY H-BOND REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_symmetry_hbond_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_hbond_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_hbond_refined"), "dev_ideal_target") << '\n' << RM3(" SYMMETRY H-BOND OTHERS (A): ", -5) << Fi(ls_restr, c("r_symmetry_hbond_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_hbond_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_hbond_other"), "dev_ideal_target") << '\n' << RM3(" SYMMETRY METAL-ION REFINED ATOMS (A): ", -5) << Fi(ls_restr, c("r_symmetry_metal_ion_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_metal_ion_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_metal_ion_refined"), "dev_ideal_target") << '\n' << RM3(" SYMMETRY METAL-ION OTHERS (A): ", -5) << Fi(ls_restr, c("r_symmetry_metal_ion_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_metal_ion_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_symmetry_metal_ion_other"), "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL FACTOR RESTRAINTS. COUNT RMS WEIGHT") << '\n' << RM3(" MAIN-CHAIN BOND REFINED ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_mcbond_it"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcbond_it"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcbond_it"), "dev_ideal_target") << '\n' << RM3(" MAIN-CHAIN BOND OTHER ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_mcbond_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcbond_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcbond_other"), "dev_ideal_target") << '\n' << RM3(" MAIN-CHAIN ANGLE REFINED ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_mcangle_it"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcangle_it"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcangle_it"), "dev_ideal_target") << '\n' << RM3(" MAIN-CHAIN ANGLE OTHER ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_mcangle_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcangle_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_mcangle_other"), "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN BOND REFINED ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_scbond_it"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scbond_it"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scbond_it"), "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN BOND OTHER ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_scbond_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scbond_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scbond_other"), "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN ANGLE REFINED ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_scangle_it"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scangle_it"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scangle_it"), "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN ANGLE OTHER ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_scangle_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scangle_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_scangle_other"), "dev_ideal_target") << '\n' << RM3(" LONG RANGE B REFINED ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_long_range_B_refined"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_long_range_B_refined"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_long_range_B_refined"), "dev_ideal_target") << '\n' << RM3(" LONG RANGE B OTHER ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_long_range_B_other"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_long_range_B_other"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_long_range_B_other"), "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" ANISOTROPIC THERMAL FACTOR RESTRAINTS. COUNT RMS WEIGHT") << '\n' << RM3(" RIGID-BOND RESTRAINTS (A**2): ", -5) << Fi(ls_restr, c("r_rigid_bond_restr"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_rigid_bond_restr"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_rigid_bond_restr"), "dev_ideal_target") << '\n' << RM3(" SPHERICITY; FREE ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_sphericity_free"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_sphericity_free"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_sphericity_free"), "dev_ideal_target") << '\n' << RM3(" SPHERICITY; BONDED ATOMS (A**2): ", -5) << Fi(ls_restr, c("r_sphericity_bonded"), "number") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_sphericity_bonded"), "dev_ideal") << SEP(" ;", -6, 3) << Ff(ls_restr, c("r_sphericity_bonded"), "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" NCS RESTRAINTS STATISTICS") << '\n'; auto &ncs_dom = db["struct_ncs_dom"]; if (ncs_dom.empty()) pdbFile << RM3(" NUMBER OF DIFFERENT NCS GROUPS : NULL") << '\n'; else { std::set ncs_groups; for (auto i : ncs_dom) ncs_groups.insert(i["pdbx_ens_id"].as()); pdbFile << RM3(" NUMBER OF DIFFERENT NCS GROUPS : ") << ncs_groups.size() << '\n'; for (auto ens_id : ncs_groups) { auto lim = db["struct_ncs_dom_lim"].find(key("pdbx_ens_id") == ens_id); std::set chains; std::set component_ids; for (auto l : lim) { chains.insert(l["beg_auth_asym_id"].as()); component_ids.insert(l["pdbx_component_id"].as()); } pdbFile << RM3("") << '\n' << RM3(" NCS GROUP NUMBER : ") << ens_id << '\n' << RM3(" CHAIN NAMES : ") << join(chains, " ") << '\n' << RM3(" NUMBER OF COMPONENTS NCS GROUP : ") << component_ids.size() << '\n' << RM3(" COMPONENT C SSSEQI TO C SSSEQI CODE") << '\n'; for (auto l : lim) { pdbFile << RM3(" ", -2) << Fi(l, "pdbx_component_id") << SEP(" ", -5) << Fs(l, "beg_auth_asym_id") << SEP(" ", -5) << Fi(l, "beg_auth_seq_id") << SEP(" ", -5) << Fs(l, "end_auth_asym_id") << SEP(" ", -5) << Fi(l, "end_auth_seq_id") << SEP(" ", -5) << Fs(l, "pdbx_refine_code") << '\n'; } pdbFile << RM3(" GROUP CHAIN COUNT RMS WEIGHT") << '\n'; for (auto l : db["refine_ls_restr_ncs"].find(key("pdbx_ens_id") == ens_id)) { std::string type = l["pdbx_type"].as(); to_upper(type); std::string unit; if (ends_with(type, "POSITIONAL")) unit = " (A): "; else if (ends_with(type, "THERMAL")) unit = " (A**2): "; else unit = " : "; pdbFile << RM3(" ", 18) << type << SEP("", -2) << Fs(l, "pdbx_ens_id") << SEP(" ", 1) << Fs(l, "pdbx_auth_asym_id") << SEP(unit.c_str(), -6) << Fi(l, "pdbx_number") << SEP(" ;", -6, 3) << Ff(l, "rms_dev_position") << SEP(" ;", -6, 3) << Ff(l, "weight_position") << '\n'; } } } pdbFile << RM3("") << '\n' << RM3(" TWIN DETAILS") << '\n'; auto &twins = db["pdbx_reflns_twin"]; if (twins.empty()) pdbFile << RM3(" NUMBER OF TWIN DOMAINS : NULL") << '\n'; else { pdbFile << RM3(" NUMBER OF TWIN DOMAINS : ") << twins.size() << '\n'; int nr = 1; for (auto twin : twins) { pdbFile << RM3(" TWIN DOMAIN : ") << nr++ << '\n' << RM3(" TWIN OPERATOR : ") << Fs(twin, "operator") << '\n' << RM3(" TWIN FRACTION : ") << SEP("", -6, 3) << Ff(twin, "fraction") << '\n'; } } auto &tls = db["pdbx_refine_tls"]; pdbFile << RM3("") << '\n' << RM3(" TLS DETAILS") << '\n' << RM3(" NUMBER OF TLS GROUPS : ") << (tls.size() ? std::to_string(tls.size()) : "NULL") << '\n'; for (auto t : tls) { std::string id = t["id"].as(); auto g = db["pdbx_refine_tls_group"].find(key("refine_tls_id") == id); pdbFile << RM3("") << '\n' << RM3(" TLS GROUP : ") << id << '\n' << RM3(" NUMBER OF COMPONENTS GROUP : ") << g.size() << '\n' << RM3(" COMPONENTS C SSSEQI TO C SSSEQI") << '\n'; for (auto gi : g) { pdbFile << RM3(" RESIDUE RANGE : ") << Fs(gi, "beg_auth_asym_id") << SEP("", -6) << Fi(gi, "beg_auth_seq_id") << SEP("", -9) << Fs(gi, "end_auth_asym_id") << SEP("", -6) << Fi(gi, "end_auth_seq_id") << '\n'; } pdbFile << RM3(" ORIGIN FOR THE GROUP (A):", -9, 4) << Ff(t, "origin_x") << SEP("", -9, 4) << Ff(t, "origin_y") << SEP("", -9, 4) << Ff(t, "origin_z") << '\n' << RM3(" T TENSOR") << '\n' << RM3(" T11:", -9, 4) << Ff(t, "T[1][1]") << SEP(" T22:", -9, 4) << Ff(t, "T[2][2]") << '\n' << RM3(" T33:", -9, 4) << Ff(t, "T[3][3]") << SEP(" T12:", -9, 4) << Ff(t, "T[1][2]") << '\n' << RM3(" T13:", -9, 4) << Ff(t, "T[1][3]") << SEP(" T23:", -9, 4) << Ff(t, "T[2][3]") << '\n' << RM3(" L TENSOR") << '\n' << RM3(" L11:", -9, 4) << Ff(t, "L[1][1]") << SEP(" L22:", -9, 4) << Ff(t, "L[2][2]") << '\n' << RM3(" L33:", -9, 4) << Ff(t, "L[3][3]") << SEP(" L12:", -9, 4) << Ff(t, "L[1][2]") << '\n' << RM3(" L13:", -9, 4) << Ff(t, "L[1][3]") << SEP(" L23:", -9, 4) << Ff(t, "L[2][3]") << '\n' << RM3(" S TENSOR") << '\n' << RM3(" S11:", -9, 4) << Ff(t, "S[1][1]") << SEP(" S12:", -9, 4) << Ff(t, "S[1][2]") << SEP(" S13:", -9, 4) << Ff(t, "S[1][3]") << '\n' << RM3(" S21:", -9, 4) << Ff(t, "S[2][1]") << SEP(" S22:", -9, 4) << Ff(t, "S[2][2]") << SEP(" S23:", -9, 4) << Ff(t, "S[2][3]") << '\n' << RM3(" S31:", -9, 4) << Ff(t, "S[3][1]") << SEP(" S32:", -9, 4) << Ff(t, "S[3][2]") << SEP(" S33:", -9, 4) << Ff(t, "S[3][3]") << '\n'; } pdbFile << RM3("") << '\n' << RM3(" BULK SOLVENT MODELLING.") << '\n' << RM3(" METHOD USED : ") << Fs(refine, "solvent_model_details") << '\n' << RM3(" PARAMETERS FOR MASK CALCULATION") << '\n' << RM3(" VDW PROBE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_vdw_probe_radii") << '\n' << RM3(" ION PROBE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_ion_probe_radii") << '\n' << RM3(" SHRINKAGE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_shrinkage_radii") << '\n' << RM3("") << '\n'; } void WriteRemark3Shelxl(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); // auto ls_shell = db["refine_ls_shell"].front(); auto refine_hist = db["refine_hist"].front(); // auto reflns = db["reflns"].front(); auto refine_analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; // auto pdbx_xplor_file = db["pdbx_xplor_file"].front(); auto pdbx_refine = db["pdbx_refine"].front(); auto c = [](const char *t) -> condition { return key("type") == t; }; pdbFile << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" COMPLETENESS FOR RANGE (%) : ", 5, 2) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT (NO CUTOFF).") << '\n' << RM3(" R VALUE (WORKING + TEST SET, NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "R_factor_all_no_cutoff") << '\n' << RM3(" R VALUE (WORKING SET, NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "R_factor_obs_no_cutoff") << '\n' << RM3(" FREE R VALUE (NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "free_R_factor_no_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%, NO CUTOFF) : ", 7, 3) << Ff(pdbx_refine, "free_R_val_test_set_size_perc_no_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET COUNT (NO CUTOFF) : ", 12, 6) << Fi(pdbx_refine, "free_R_val_test_set_ct_no_cutoff") << '\n' << RM3(" TOTAL NUMBER OF REFLECTIONS (NO CUTOFF) : ", 12, 6) << Fi(refine, "ls_number_reflns_all") << '\n' << RM3("") << '\n' << RM3(" FIT/AGREEMENT OF MODEL FOR DATA WITH F>4SIG(F).") << '\n' << RM3(" R VALUE (WORKING + TEST SET, F>4SIG(F)) : ", 7, 3) << Ff(pdbx_refine, "R_factor_all_4sig_cutoff") << '\n' << RM3(" R VALUE (WORKING SET, F>4SIG(F)) : ", 7, 3) << Ff(pdbx_refine, "R_factor_obs_4sig_cutoff") << '\n' << RM3(" FREE R VALUE (F>4SIG(F)) : ", 7, 3) << Ff(pdbx_refine, "free_R_factor_4sig_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%, F>4SIG(F)) : ", 7, 3) << Ff(pdbx_refine, "free_R_val_test_set_size_perc_4sig_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET COUNT (F>4SIG(F)) : ") << Fi(pdbx_refine, "free_R_val_test_set_ct_4sig_cutoff") << '\n' << RM3(" TOTAL NUMBER OF REFLECTIONS (F>4SIG(F)) : ") << Fi(pdbx_refine, "number_reflns_obs_4sig_cutoff") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ") << Fi(refine_hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ") << Fi(refine_hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ") << Fi(refine_hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ") << Fi(refine_hist, "number_atoms_solvent") << '\n' << RM3("") << '\n' << RM3(" MODEL REFINEMENT.") << '\n' << RM3(" OCCUPANCY SUM OF NON-HYDROGEN ATOMS : ", 7, 3) << Ff(refine_analyze, "occupancy_sum_non_hydrogen") << '\n' << RM3(" OCCUPANCY SUM OF HYDROGEN ATOMS : ", 7, 3) << Ff(refine_analyze, "occupancy_sum_hydrogen") << '\n' << RM3(" NUMBER OF DISCRETELY DISORDERED RESIDUES : ") << Fi(refine_analyze, "number_disordered_residues") << '\n' << RM3(" NUMBER OF LEAST-SQUARES PARAMETERS : ") << Fi(refine, "ls_number_parameters") << '\n' << RM3(" NUMBER OF RESTRAINTS : ") << Fi(refine, "ls_number_restraints") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM RESTRAINT TARGET VALUES.") << '\n' << RM3(" BOND LENGTHS (A) : ", 7, 3) << Ff(ls_restr, c("s_bond_d"), "dev_ideal") << '\n' << RM3(" ANGLE DISTANCES (A) : ", 7, 3) << Ff(ls_restr, c("s_angle_d"), "dev_ideal") << '\n' << RM3(" SIMILAR DISTANCES (NO TARGET VALUES) (A) : ", 7, 3) << Ff(ls_restr, c("s_similar_dist"), "dev_ideal") << '\n' << RM3(" DISTANCES FROM RESTRAINT PLANES (A) : ", 7, 3) << Ff(ls_restr, c("s_from_restr_planes"), "dev_ideal") << '\n' << RM3(" ZERO CHIRAL VOLUMES (A**3) : ", 7, 3) << Ff(ls_restr, c("s_zero_chiral_vol"), "dev_ideal") << '\n' << RM3(" NON-ZERO CHIRAL VOLUMES (A**3) : ", 7, 3) << Ff(ls_restr, c("s_non_zero_chiral_vol"), "dev_ideal") << '\n' << RM3(" ANTI-BUMPING DISTANCE RESTRAINTS (A) : ", 7, 3) << Ff(ls_restr, c("s_anti_bump_dis_restr"), "dev_ideal") << '\n' << RM3(" RIGID-BOND ADP COMPONENTS (A**2) : ", 7, 3) << Ff(ls_restr, c("s_rigid_bond_adp_cmpnt"), "dev_ideal") << '\n' << RM3(" SIMILAR ADP COMPONENTS (A**2) : ", 7, 3) << Ff(ls_restr, c("s_similar_adp_cmpnt"), "dev_ideal") << '\n' << RM3(" APPROXIMATELY ISOTROPIC ADPS (A**2) : ", 7, 3) << Ff(ls_restr, c("s_approx_iso_adps"), "dev_ideal") << '\n' << RM3("") << '\n' << RM3(" BULK SOLVENT MODELING.") << '\n' << RM3(" METHOD USED: ") << Fs(refine, "solvent_model_details") << '\n' << RM3("") << '\n' << RM3(" STEREOCHEMISTRY TARGET VALUES : ") << Fs(refine, "pdbx_stereochemistry_target_values") << '\n' << RM3(" SPECIAL CASE: ") << Fs(refine, "pdbx_stereochem_target_val_spec_case") << '\n' << RM3("") << '\n'; } void WriteRemark3Phenix(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); // auto ls_shell = db["refine_ls_shell"].front(); // auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); // auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; // auto pdbx_xplor_file = db["pdbx_xplor_file"].front(); auto pdbx_reflns_twin = db["pdbx_reflns_twin"].front(); auto c = [](const char *t) -> condition { return key("type") == t; }; pdbFile << RM3("") << '\n' << RM3(" REFINEMENT TARGET : ") << Fs(refine, "pdbx_stereochemistry_target_values") << '\n' << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" MIN(FOBS/SIGMA_FOBS) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" COMPLETENESS FOR RANGE (%) : ", 5, 2) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" R VALUE (WORKING + TEST SET) : ", 7, 5) << Ff(refine, "ls_R_factor_obs") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 5) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 5) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 3) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT (IN BINS).") << '\n' << RM3(" BIN RESOLUTION RANGE COMPL. NWORK NFREE RWORK RFREE") << '\n'; int bin = 1; std::vector bins; for (auto r : db["refine_ls_shell"]) bins.push_back(r); // reverse(bins.begin(), bins.end()); try { sort(bins.begin(), bins.end(), [](row_handle a, row_handle b) -> bool { return a["d_res_high"].as() > b["d_res_high"].as(); }); } catch (...) { } for (auto r : bins) { float d_res_low, d_res_high, percent_reflns_obs, R_factor_R_work, R_factor_R_free; int number_reflns_R_work, number_reflns_R_free; tie(d_res_low, d_res_high, percent_reflns_obs, number_reflns_R_work, number_reflns_R_free, R_factor_R_work, R_factor_R_free) = r.get("d_res_low", "d_res_high", "percent_reflns_obs", "number_reflns_R_work", "number_reflns_R_free", "R_factor_R_work", "R_factor_R_free"); percent_reflns_obs /= 100; pdbFile << RM3(" ") << cif::format("%3d %7.4f - %7.4f %4.2f %8d %5d %6.4f %6.4f", bin++, d_res_low, d_res_high, percent_reflns_obs, number_reflns_R_work, number_reflns_R_free, R_factor_R_work, R_factor_R_free) << '\n'; } pdbFile << RM3("") << '\n' << RM3(" BULK SOLVENT MODELLING.") << '\n' << RM3(" METHOD USED : ") << Fs(refine, "solvent_model_details") << '\n' << RM3(" SOLVENT RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_vdw_probe_radii") << '\n' << RM3(" SHRINKAGE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_shrinkage_radii") << '\n' << RM3(" K_SOL : ", 5, 2) << Ff(refine, "solvent_model_param_ksol") << '\n' << RM3(" B_SOL : ", 5, 2) << Ff(refine, "solvent_model_param_bsol") << '\n' << RM3("") << '\n' << RM3(" ERROR ESTIMATES.") << '\n' << RM3(" COORDINATE ERROR (MAXIMUM-LIKELIHOOD BASED) : ", 6, 3) << Ff(refine, "overall_SU_ML") << '\n' << RM3(" PHASE ERROR (DEGREES, MAXIMUM-LIKELIHOOD BASED) : ", 6, 3) << Ff(refine, "pdbx_overall_phase_error") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' << RM3(" B VALUE TYPE : ") << Fs(refine, "pdbx_TLS_residual_ADP_flag") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 7, 4) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 7, 4) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" TWINNING INFORMATION.") << '\n' << RM3(" FRACTION: ") << Fs(pdbx_reflns_twin, "fraction") << '\n' << RM3(" OPERATOR: ") << Fs(pdbx_reflns_twin, "operator") << '\n' << RM3("") << '\n' << RM3(" DEVIATIONS FROM IDEAL VALUES.") << '\n' << RM3(" RMSD COUNT") << '\n' << RM3(" BOND : ", -6, 3) << Ff(ls_restr, c("f_bond_d"), "dev_ideal") << SEP(" ", -7) << Fi(ls_restr, c("f_bond_d"), "number") << '\n' << RM3(" ANGLE : ", -6, 3) << Ff(ls_restr, c("f_angle_d"), "dev_ideal") << SEP(" ", -7) << Fi(ls_restr, c("f_angle_d"), "number") << '\n' << RM3(" CHIRALITY : ", -6, 3) << Ff(ls_restr, c("f_chiral_restr"), "dev_ideal") << SEP(" ", -7) << Fi(ls_restr, c("f_chiral_restr"), "number") << '\n' << RM3(" PLANARITY : ", -6, 3) << Ff(ls_restr, c("f_plane_restr"), "dev_ideal") << SEP(" ", -7) << Fi(ls_restr, c("f_plane_restr"), "number") << '\n' << RM3(" DIHEDRAL : ", -6, 3) << Ff(ls_restr, c("f_dihedral_angle_d"), "dev_ideal") << SEP(" ", -7) << Fi(ls_restr, c("f_dihedral_angle_d"), "number") << '\n'; auto &tls = db["pdbx_refine_tls"]; pdbFile << RM3("") << '\n' << RM3(" TLS DETAILS") << '\n' << RM3(" NUMBER OF TLS GROUPS : ") << (tls.size() ? std::to_string(tls.size()) : "NULL") << '\n'; for (auto t : tls) { std::string id = t["id"].as(); auto pdbx_refine_tls_group = db["pdbx_refine_tls_group"].find_first(key("refine_tls_id") == id); pdbFile << RM3(" TLS GROUP : ") << id << '\n' << RM3(" SELECTION: ") << Fs(pdbx_refine_tls_group, "selection_details") << '\n' << RM3(" ORIGIN FOR THE GROUP (A):", -9, 4) << Ff(t, "origin_x") << SEP("", -9, 4) << Ff(t, "origin_y") << SEP("", -9, 4) << Ff(t, "origin_z") << '\n' << RM3(" T TENSOR") << '\n' << RM3(" T11:", -9, 4) << Ff(t, "T[1][1]") << SEP(" T22:", -9, 4) << Ff(t, "T[2][2]") << '\n' << RM3(" T33:", -9, 4) << Ff(t, "T[3][3]") << SEP(" T12:", -9, 4) << Ff(t, "T[1][2]") << '\n' << RM3(" T13:", -9, 4) << Ff(t, "T[1][3]") << SEP(" T23:", -9, 4) << Ff(t, "T[2][3]") << '\n' << RM3(" L TENSOR") << '\n' << RM3(" L11:", -9, 4) << Ff(t, "L[1][1]") << SEP(" L22:", -9, 4) << Ff(t, "L[2][2]") << '\n' << RM3(" L33:", -9, 4) << Ff(t, "L[3][3]") << SEP(" L12:", -9, 4) << Ff(t, "L[1][2]") << '\n' << RM3(" L13:", -9, 4) << Ff(t, "L[1][3]") << SEP(" L23:", -9, 4) << Ff(t, "L[2][3]") << '\n' << RM3(" S TENSOR") << '\n' << RM3(" S11:", -9, 4) << Ff(t, "S[1][1]") << SEP(" S12:", -9, 4) << Ff(t, "S[1][2]") << SEP(" S13:", -9, 4) << Ff(t, "S[1][3]") << '\n' << RM3(" S21:", -9, 4) << Ff(t, "S[2][1]") << SEP(" S22:", -9, 4) << Ff(t, "S[2][2]") << SEP(" S23:", -9, 4) << Ff(t, "S[2][3]") << '\n' << RM3(" S31:", -9, 4) << Ff(t, "S[3][1]") << SEP(" S32:", -9, 4) << Ff(t, "S[3][2]") << SEP(" S33:", -9, 4) << Ff(t, "S[3][3]") << '\n'; } pdbFile << RM3("") << '\n' << RM3(" NCS DETAILS") << '\n'; auto &ncs_dom = db["struct_ncs_dom"]; if (ncs_dom.empty()) pdbFile << RM3(" NUMBER OF NCS GROUPS : NULL") << '\n'; else { std::set ncs_groups; for (auto i : ncs_dom) ncs_groups.insert(i["pdbx_ens_id"].as()); pdbFile << RM3(" NUMBER OF NCS GROUPS : ") << ncs_groups.size() << '\n'; // // for (auto ens_id: ncs_groups) // { // auto lim = db["struct_ncs_dom_lim"].find(key("pdbx_ens_id") == ens_id); // // set chains; // set component_ids; // // for (auto l: lim) // { // chains.insert(l["beg_auth_asym_id"]); // component_ids.insert(l["pdbx_component_id"].as()); // } // // pdbFile << RM3("") << '\n' // << RM3(" NCS GROUP NUMBER : ") << ens_id << '\n' // << RM3(" CHAIN NAMES : ") << join(chains, " ") << '\n' // << RM3(" NUMBER OF COMPONENTS NCS GROUP : ") << component_ids.size() << '\n' // << RM3(" COMPONENT C SSSEQI TO C SSSEQI CODE") << '\n'; // // for (auto l: lim) // { // pdbFile << RM3(" ", -2) << Fi(l, "pdbx_component_id") // << SEP(" ", -5) << Fs(l, "beg_auth_asym_id") // << SEP(" ", -5) << Fi(l, "beg_auth_seq_id") // << SEP(" ", -5) << Fs(l, "end_auth_asym_id") // << SEP(" ", -5) << Fi(l, "end_auth_seq_id") // << SEP(" ", -5) << Fs(l, "pdbx_refine_code") // << '\n'; // } // // pdbFile << RM3(" GROUP CHAIN COUNT RMS WEIGHT") << '\n'; // for (auto l: db["refine_ls_restr_ncs"].find(key("pdbx_ens_id") == ens_id)) // { // std::string type = l["pdbx_type"]; // to_upper(type); // // std::string unit; // if (ends_with(type, "POSITIONAL")) // unit = " (A): "; // else if (ends_with(type, "THERMAL")) // unit = " (A**2): "; // else // unit = " : "; // // pdbFile << RM3(" ", 18) << type // << SEP("", -2) << Fi(l, "pdbx_ens_id") // << SEP(" ", 1) << Fs(l, "pdbx_auth_asym_id") // << SEP(unit.c_str(), -6) << Fi(l, "pdbx_number") // << SEP(" ;", -6, 3) << Ff(l, "rms_dev_position") // << SEP(" ;", -6, 3) << Ff(l, "weight_position") // << '\n'; // } // } } // pdbFile << RM3("") << '\n' // << RM3(" BULK SOLVENT MODELLING.") << '\n' // << RM3(" METHOD USED : ") << Fs(refine, "solvent_model_details") << '\n' // << RM3(" PARAMETERS FOR MASK CALCULATION") << '\n' // << RM3(" VDW PROBE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_vdw_probe_radii") << '\n' // << RM3(" ION PROBE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_ion_probe_radii") << '\n' // << RM3(" SHRINKAGE RADIUS : ", 5, 2) << Ff(refine, "pdbx_solvent_shrinkage_radii") << '\n' // // << RM3("") << '\n'; pdbFile << RM3("") << '\n'; } void WriteRemark3XPlor(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); auto ls_shell = db["refine_ls_shell"].front(); auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; auto ls_restr_ncs = db["refine_ls_restr_ncs"].front(); auto pdbx_xplor_file = db["pdbx_xplor_file"].front(); pdbFile << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" DATA CUTOFF HIGH (ABS(F)) : ", 6, 3) << Ff(refine, "pdbx_data_cutoff_high_absF") << '\n' << RM3(" DATA CUTOFF LOW (ABS(F)) : ", 6, 3) << Ff(refine, "pdbx_data_cutoff_low_absF") << '\n' << RM3(" COMPLETENESS (WORKING+TEST) (%) : ", 5, 2) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 3) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 3) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free_error") << '\n' << RM3("") << '\n' << RM3(" FIT IN THE HIGHEST RESOLUTION BIN.") << '\n' << RM3(" TOTAL NUMBER OF BINS USED : ", 12, 6) << Fi(ls_shell, "pdbx_total_number_of_bins_used") << '\n' << RM3(" BIN RESOLUTION RANGE HIGH (A) : ", 5, 2) << Ff(ls_shell, "d_res_high") << '\n' << RM3(" BIN RESOLUTION RANGE LOW (A) : ", 5, 2) << Ff(ls_shell, "d_res_low") << '\n' << RM3(" BIN COMPLETENESS (WORKING+TEST) (%) : ", 5, 1) << Ff(ls_shell, "percent_reflns_obs") << '\n' << RM3(" REFLECTIONS IN BIN (WORKING SET) : ", 12, 6) << Fi(ls_shell, "number_reflns_R_work") << '\n' << RM3(" BIN R VALUE (WORKING SET) : ", 7, 3) << Ff(ls_shell, "R_factor_R_work") << '\n' << RM3(" BIN FREE R VALUE : ", 7, 3) << Ff(ls_shell, "R_factor_R_free") << '\n' << RM3(" BIN FREE R VALUE TEST SET SIZE (%) : ", 5, 1) << Ff(ls_shell, "percent_reflns_R_free") << '\n' << RM3(" BIN FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(ls_shell, "number_reflns_R_free") << '\n' << RM3(" ESTIMATED ERROR OF BIN FREE R VALUE : ", 7, 3) << Ff(ls_shell, "R_factor_R_free_error") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ", 12, 6) << Fi(hist, "number_atoms_solvent") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 7, 2) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 7, 2) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM LUZZATI PLOT (A) : ", 7, 2) << Ff(analyze, "Luzzati_coordinate_error_obs") << '\n' << RM3(" ESD FROM SIGMAA (A) : ", 7, 2) << Ff(analyze, "Luzzati_sigma_a_obs") << '\n' << RM3(" LOW RESOLUTION CUTOFF (A) : ", 7, 2) << Ff(analyze, "Luzzati_d_res_low_obs") << '\n' << RM3("") << '\n' << RM3(" CROSS-VALIDATED ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM C-V LUZZATI PLOT (A) : ", 7, 2) << Ff(analyze, "Luzzati_coordinate_error_free") << '\n' << RM3(" ESD FROM C-V SIGMAA (A) : ", 7, 2) << Ff(analyze, "Luzzati_sigma_a_free") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM IDEAL VALUES.") << '\n' << RM3(" BOND LENGTHS (A) : ", 7, 3) << Ff(ls_restr, key("type") == "x_bond_d", "dev_ideal") << '\n' << RM3(" BOND ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "x_angle_deg", "dev_ideal") << '\n' << RM3(" DIHEDRAL ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "x_dihedral_angle_d", "dev_ideal") << '\n' << RM3(" IMPROPER ANGLES (DEGREES) : ", 7, 2) << Ff(ls_restr, key("type") == "x_improper_angle_d", "dev_ideal") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL MODEL : ") << Fs(refine, "pdbx_isotropic_thermal_model") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL FACTOR RESTRAINTS. RMS SIGMA") << '\n' << RM3(" MAIN-CHAIN BOND (A**2) : ", 6, 2) << Ff(ls_restr, key("type") == "x_mcbond_it", "dev_ideal") << SEP("; ", 6, 2) << Ff(ls_restr, key("type") == "x_mcbond_it", "dev_ideal_target") << '\n' << RM3(" MAIN-CHAIN ANGLE (A**2) : ", 6, 2) << Ff(ls_restr, key("type") == "x_mcangle_it", "dev_ideal") << SEP("; ", 6, 2) << Ff(ls_restr, key("type") == "x_mcangle_it", "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN BOND (A**2) : ", 6, 2) << Ff(ls_restr, key("type") == "x_scbond_it", "dev_ideal") << SEP("; ", 6, 2) << Ff(ls_restr, key("type") == "x_scbond_it", "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN ANGLE (A**2) : ", 6, 2) << Ff(ls_restr, key("type") == "x_scangle_it", "dev_ideal") << SEP("; ", 6, 2) << Ff(ls_restr, key("type") == "x_scangle_it", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" NCS MODEL : ") << Fs(ls_restr_ncs, "ncs_model_details") << '\n' << RM3("") << '\n' << RM3(" NCS RESTRAINTS. RMS SIGMA/WEIGHT") << '\n' // TODO: using only group 1 here, should this be fixed??? << RM3(" GROUP 1 POSITIONAL (A) : ", 4, 2) << Ff(ls_restr_ncs, "rms_dev_position") << SEP("; ", 6, 2) << Ff(ls_restr_ncs, "weight_position") << SEP("; ", 6, 2) << '\n' << RM3(" GROUP 1 B-FACTOR (A**2) : ", 4, 2) << Ff(ls_restr_ncs, "rms_dev_B_iso") << SEP("; ", 6, 2) << Ff(ls_restr_ncs, "weight_B_iso") << SEP("; ", 6, 2) << '\n' // TODO: using only files from serial_no 1 here << RM3("") << '\n' << RM3(" PARAMETER FILE 1 : ") << Fs(pdbx_xplor_file, "param_file") << '\n' << RM3(" TOPOLOGY FILE 1 : ") << Fs(pdbx_xplor_file, "topol_file") << '\n' << RM3("") << '\n'; } void WriteRemark3NuclSQ(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); auto pdbx_refine = db["pdbx_refine"].front(); auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; pdbFile << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" COMPLETENESS FOR RANGE (%) : ", 5, 2) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' << RM3(" R VALUE (WORKING + TEST SET) : ", 7, 3) << Ff(refine, "ls_R_factor_obs") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 3) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 3) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3("") << '\n' << RM3(" FIT/AGREEMENT OF MODEL WITH ALL DATA.") << '\n' << RM3(" R VALUE (WORKING + TEST SET, NO CUTOFF) : ") << Fs(refine, "ls_R_factor_all") << '\n' << RM3(" R VALUE (WORKING SET, NO CUTOFF) : ") << Fs(pdbx_refine, "R_factor_obs_no_cutoff") << '\n' << RM3(" FREE R VALUE (NO CUTOFF) : ") << Fs(pdbx_refine, "free_R_factor_no_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%, NO CUTOFF) : ") << Fs(pdbx_refine, "free_R_val_test_set_size_perc_no_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET COUNT (NO CUTOFF) : ") << Fs(pdbx_refine, "free_R_val_test_set_ct_no_cutoff") << '\n' << RM3(" TOTAL NUMBER OF REFLECTIONS (NO CUTOFF) : ") << Fs(refine, "ls_number_reflns_all") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ", 12, 6) << Fi(hist, "number_atoms_solvent") << '\n' // << RM3(" ALL ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' // << RM3(" B VALUE TYPE : ", 7, 2) << Fs(refine, "pdbx_TLS_residual_ADP_flag") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 7, 2) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 7, 2) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM LUZZATI PLOT (A) : ", 7, 2) << Ff(analyze, "Luzzati_coordinate_error_obs") << '\n' << RM3(" ESD FROM SIGMAA (A) : ", 7, 2) << Ff(analyze, "Luzzati_sigma_a_obs") << '\n' << RM3(" LOW RESOLUTION CUTOFF (A) : ", 7, 2) << Ff(analyze, "Luzzati_d_res_low_obs") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM IDEAL VALUES.") << '\n' << RM3(" DISTANCE RESTRAINTS. RMS SIGMA") << '\n' << RM3(" SUGAR-BASE BOND DISTANCE (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_sugar_bond_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_sugar_bond_d", "dev_ideal_target") << '\n' << RM3(" SUGAR-BASE BOND ANGLE DISTANCE (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_sugar_bond_angle_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_sugar_bond_angle_d", "dev_ideal_target") << '\n' << RM3(" PHOSPHATE BONDS DISTANCE (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_phos_bond_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_phos_bond_d", "dev_ideal_target") << '\n' << RM3(" PHOSPHATE BOND ANGLE, H-BOND (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_phos_bond_angle_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_phos_bond_angle_d", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" PLANE RESTRAINT (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_plane_restr", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_plane_restr", "dev_ideal_target") << '\n' << RM3(" CHIRAL-CENTER RESTRAINT (A**3) : ", 7, 3) << Ff(ls_restr, key("type") == "n_chiral_restr", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_chiral_restr", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" NON-BONDED CONTACT RESTRAINTS.") << '\n' << RM3(" SINGLE TORSION CONTACT (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_singtor_nbd", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_singtor_nbd", "dev_ideal_target") << '\n' << RM3(" MULTIPLE TORSION CONTACT (A) : ", 7, 3) << Ff(ls_restr, key("type") == "n_multtor_nbd", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_multtor_nbd", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL FACTOR RESTRAINTS. RMS SIGMA") << '\n' << RM3(" SUGAR-BASE BONDS (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "n_sugar_bond_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_sugar_bond_it", "dev_ideal_target") << '\n' << RM3(" SUGAR-BASE ANGLES (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "n_sugar_angle_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_sugar_angle_it", "dev_ideal_target") << '\n' << RM3(" PHOSPHATE BONDS (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "n_phos_bond_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_phos_bond_it", "dev_ideal_target") << '\n' << RM3(" PHOSPHATE BOND ANGLE, H-BOND (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "n_phos_angle_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "n_phos_angle_it", "dev_ideal_target") << '\n' << RM3("") << '\n'; } void WriteRemark3ProlSQ(std::ostream &pdbFile, const datablock &db) { auto refine = db["refine"].front(); auto pdbx_refine = db["pdbx_refine"].front(); auto hist = db["refine_hist"].front(); auto reflns = db["reflns"].front(); auto analyze = db["refine_analyze"].front(); auto &ls_restr = db["refine_ls_restr"]; pdbFile << RM3("") << '\n' << RM3(" DATA USED IN REFINEMENT.") << '\n' << RM3(" RESOLUTION RANGE HIGH (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_high") << '\n' << RM3(" RESOLUTION RANGE LOW (ANGSTROMS) : ", 5, 2) << Ff(refine, "ls_d_res_low") << '\n' << RM3(" DATA CUTOFF (SIGMA(F)) : ", 6, 3) << Ff(refine, "pdbx_ls_sigma_F") << '\n' << RM3(" COMPLETENESS FOR RANGE (%) : ", 5, 2) << Ff(refine, "ls_percent_reflns_obs") << '\n' << RM3(" NUMBER OF REFLECTIONS : ", 12, 6) << Fi(refine, "ls_number_reflns_obs") << '\n' << RM3("") << '\n' << RM3(" FIT TO DATA USED IN REFINEMENT.") << '\n' << RM3(" CROSS-VALIDATION METHOD : ") << Fs(refine, "pdbx_ls_cross_valid_method") << '\n' << RM3(" FREE R VALUE TEST SET SELECTION : ") << Fs(refine, "pdbx_R_Free_selection_details") << '\n' << RM3(" R VALUE (WORKING + TEST SET) : ", 7, 3) << Ff(refine, "ls_R_factor_obs") << '\n' << RM3(" R VALUE (WORKING SET) : ", 7, 3) << Ff(refine, "ls_R_factor_R_work") << '\n' << RM3(" FREE R VALUE : ", 7, 3) << Ff(refine, "ls_R_factor_R_free") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%) : ", 7, 3) << Ff(refine, "ls_percent_reflns_R_free") << '\n' << RM3(" FREE R VALUE TEST SET COUNT : ", 12, 6) << Fi(refine, "ls_number_reflns_R_free") << '\n' << RM3("") << '\n' << RM3(" FIT/AGREEMENT OF MODEL WITH ALL DATA.") << '\n' << RM3(" R VALUE (WORKING + TEST SET, NO CUTOFF) : ") << Fs(refine, "ls_R_factor_all") << '\n' << RM3(" R VALUE (WORKING SET, NO CUTOFF) : ") << Fs(pdbx_refine, "R_factor_obs_no_cutoff") << '\n' << RM3(" FREE R VALUE (NO CUTOFF) : ") << Fs(pdbx_refine, "free_R_factor_no_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET SIZE (%, NO CUTOFF) : ") << Fs(pdbx_refine, "free_R_val_test_set_size_perc_no_cutoff") << '\n' << RM3(" FREE R VALUE TEST SET COUNT (NO CUTOFF) : ") << Fs(pdbx_refine, "free_R_val_test_set_ct_no_cutoff") << '\n' << RM3(" TOTAL NUMBER OF REFLECTIONS (NO CUTOFF) : ") << Fs(refine, "ls_number_reflns_all") << '\n' << RM3("") << '\n' << RM3(" NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.") << '\n' << RM3(" PROTEIN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3(" NUCLEIC ACID ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_nucleic_acid") << '\n' << RM3(" HETEROGEN ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_ligand") << '\n' << RM3(" SOLVENT ATOMS : ", 12, 6) << Fi(hist, "number_atoms_solvent") << '\n' // << RM3(" ALL ATOMS : ", 12, 6) << Fi(hist, "pdbx_number_atoms_protein") << '\n' << RM3("") << '\n' << RM3(" B VALUES.") << '\n' // << RM3(" B VALUE TYPE : ", 7, 2) << Fs(refine, "pdbx_TLS_residual_ADP_flag") << '\n' << RM3(" FROM WILSON PLOT (A**2) : ", 7, 2) << Ff(reflns, "B_iso_Wilson_estimate") << '\n' << RM3(" MEAN B VALUE (OVERALL, A**2) : ", 7, 2) << Ff(refine, "B_iso_mean") << '\n' << RM3(" OVERALL ANISOTROPIC B VALUE.") << '\n' << RM3(" B11 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][1]") << '\n' << RM3(" B22 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][2]") << '\n' << RM3(" B33 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[3][3]") << '\n' << RM3(" B12 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][2]") << '\n' << RM3(" B13 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[1][3]") << '\n' << RM3(" B23 (A**2) : ", -7, 2) << Ff(refine, "aniso_B[2][3]") << '\n' << RM3("") << '\n' << RM3(" ESTIMATED COORDINATE ERROR.") << '\n' << RM3(" ESD FROM LUZZATI PLOT (A) : ", 7, 2) << Ff(analyze, "Luzzati_coordinate_error_obs") << '\n' << RM3(" ESD FROM SIGMAA (A) : ", 7, 2) << Ff(analyze, "Luzzati_sigma_a_obs") << '\n' << RM3(" LOW RESOLUTION CUTOFF (A) : ", 7, 2) << Ff(analyze, "Luzzati_d_res_low_obs") << '\n' << RM3("") << '\n' << RM3(" RMS DEVIATIONS FROM IDEAL VALUES.") << '\n' << RM3(" DISTANCE RESTRAINTS. RMS SIGMA") << '\n' << RM3(" BOND LENGTH (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_bond_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_bond_d", "dev_ideal_target") << '\n' << RM3(" ANGLE DISTANCE (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_angle_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_angle_d", "dev_ideal_target") << '\n' << RM3(" INTRAPLANAR 1-4 DISTANCE (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_planar_d", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_planar_d", "dev_ideal_target") << '\n' << RM3(" H-BOND OR METAL COORDINATION (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_hb_or_metal_coord", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_hb_or_metal_coord", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" PLANE RESTRAINT (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_plane_restr", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_plane_restr", "dev_ideal_target") << '\n' << RM3(" CHIRAL-CENTER RESTRAINT (A**3) : ", 7, 3) << Ff(ls_restr, key("type") == "p_chiral_restr", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_chiral_restr", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" NON-BONDED CONTACT RESTRAINTS.") << '\n' << RM3(" SINGLE TORSION (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_singtor_nbd", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_singtor_nbd", "dev_ideal_target") << '\n' << RM3(" MULTIPLE TORSION (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_multtor_nbd", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_multtor_nbd", "dev_ideal_target") << '\n' << RM3(" H-BOND (X...Y) (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_xyhbond_nbd", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_xyhbond_nbd", "dev_ideal_target") << '\n' << RM3(" H-BOND (X-H...Y) (A) : ", 7, 3) << Ff(ls_restr, key("type") == "p_xhyhbond_nbd", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_xhyhbond_nbd", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" CONFORMATIONAL TORSION ANGLE RESTRAINTS.") << '\n' << RM3(" SPECIFIED (DEGREES) : ", 7, 3) << Ff(ls_restr, key("type") == "p_special_tor", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_special_tor", "dev_ideal_target") << '\n' << RM3(" PLANAR (DEGREES) : ", 7, 3) << Ff(ls_restr, key("type") == "p_planar_tor", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_planar_tor", "dev_ideal_target") << '\n' << RM3(" STAGGERED (DEGREES) : ", 7, 3) << Ff(ls_restr, key("type") == "p_staggered_tor", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_staggered_tor", "dev_ideal_target") << '\n' << RM3(" TRANSVERSE (DEGREES) : ", 7, 3) << Ff(ls_restr, key("type") == "p_transverse_tor", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_transverse_tor", "dev_ideal_target") << '\n' << RM3("") << '\n' << RM3(" ISOTROPIC THERMAL FACTOR RESTRAINTS. RMS SIGMA") << '\n' << RM3(" MAIN-CHAIN BOND (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "p_mcbond_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_mcbond_it", "dev_ideal_target") << '\n' << RM3(" MAIN-CHAIN ANGLE (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "p_mcangle_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_mcangle_it", "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN BOND (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "p_scbond_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_scbond_it", "dev_ideal_target") << '\n' << RM3(" SIDE-CHAIN ANGLE (A**2) : ", 7, 3) << Ff(ls_restr, key("type") == "p_scangle_it", "dev_ideal") << " ; " << Ff(ls_restr, key("type") == "p_scangle_it", "dev_ideal_target") << '\n' << RM3("") << '\n'; } void WriteRemark3(std::ostream &pdbFile, const datablock &db) { std::string program, authors; if (not db["pdbx_nmr_software"].empty()) { auto software = db["pdbx_nmr_software"].find(key("classification") == "refinement"); if (software.size() == 1) cif::tie(program, authors) = software.front().get("name", "authors"); else if (software.size() > 1) { for (auto r : software) { if (program.empty() == false) { program += ", "; authors += ", "; } program += r["name"].as(); authors += r["authors"].as() + " (" + r["name"].as() + ")"; } } } if (program.empty()) program = cifSoftware(db, eRefinement); if (authors.empty()) authors = "NULL"; if (not program.empty()) { pdbFile << RM3("") << '\n' << RM3("REFINEMENT.") << '\n'; int l = 0; for (auto s : word_wrap(program, 52)) pdbFile << RM3(++l == 1 ? " PROGRAM : " : " ") << s << '\n'; l = 0; for (auto s : word_wrap(authors, 52)) pdbFile << RM3(++l == 1 ? " AUTHORS : " : " ") << s << '\n'; } if (not db["refine"].empty()) { auto s = program.find(' '); if (s != std::string::npos) program.erase(s, std::string::npos); if (iequals(program, "BUSTER") or iequals(program, "BUSTER-TNT") or iequals(program, "TNT")) WriteRemark3BusterTNT(pdbFile, db); else if (iequals(program, "CNS") or iequals(program, "CNX")) WriteRemark3CNS(pdbFile, db); else if (iequals(program, "X-PLOR")) WriteRemark3XPlor(pdbFile, db); else if (iequals(program, "REFMAC")) WriteRemark3Refmac(pdbFile, db); else if (iequals(program, "SHELXL")) WriteRemark3Shelxl(pdbFile, db); else if (iequals(program, "PHENIX")) WriteRemark3Phenix(pdbFile, db); else if (iequals(program, "NUCLSQ")) WriteRemark3NuclSQ(pdbFile, db); else if (iequals(program, "PROLSQ")) WriteRemark3ProlSQ(pdbFile, db); } for (auto r : db["refine"]) { std::string remarks = r["details"].as(); if (remarks.empty()) remarks = "NULL"; WriteOneContinuedLine(pdbFile, "REMARK 3 ", 0, "OTHER REFINEMENT REMARKS: " + remarks); break; } } void WriteRemark200(std::ostream &pdbFile, const datablock &db) { typedef RM<200> RM; try { for (auto diffrn : db["diffrn"]) { std::string diffrn_id = diffrn["id"].as(); std::string crystal_id = diffrn["crystal_id"].as(); auto diffrn_radiation = db["diffrn_radiation"].find_first(key("diffrn_id") == diffrn_id); auto diffrn_radiation_wavelength = db["diffrn_radiation_wavelength"].find_first(key("id") == diffrn_radiation["wavelength_id"].as()); auto diffrn_source = db["diffrn_source"].find_first(key("diffrn_id") == diffrn_id); auto diffrn_detector = db["diffrn_detector"].find_first(key("diffrn_id") == diffrn_id); auto exptl = db["exptl"].find_first(key("entry_id") == db.name()); auto exptl_crystal = db["exptl_crystal"].find_first(key("id") == crystal_id); auto exptl_crystal_grow = db["exptl_crystal_grow"].find_first(key("crystal_id") == crystal_id); auto computing = db["computing"].find_first(key("entry_id") == db.name()); auto reflns = db["reflns"].find_first(key("entry_id") == db.name()); std::string pdbx_diffrn_id = reflns["pdbx_diffrn_id"].as(); auto reflns_shell = db["reflns_shell"].find_first(key("pdbx_diffrn_id") == pdbx_diffrn_id); auto refine = db["refine"].find_first(key("pdbx_diffrn_id") == pdbx_diffrn_id); std::string date = diffrn_detector.empty() ? "NULL" : cif2pdbDate(diffrn_detector["pdbx_collection_date"].as()); std::string iis = cifSoftware(db, eDataReduction); std::string dss = cifSoftware(db, eDataScaling); std::string source = diffrn_source["source"].as(); std::string synchrotron, type; if (source.empty()) synchrotron = "NULL"; else if (iequals(source, "SYNCHROTRON")) { synchrotron = "Y"; source = diffrn_source["pdbx_synchrotron_site"].as(); if (source.empty()) source = "NULL"; type = "NULL"; } else { synchrotron = "N"; type = diffrn_source["type"].as(); if (type.empty()) type = "NULL"; } if (source.empty()) source = "NULL"; if (type.empty()) type = "NULL"; pdbFile << RM("") << '\n' << RM("EXPERIMENTAL DETAILS") << '\n' << RM(" EXPERIMENT TYPE : ") << Fs(exptl, "method") << '\n' << RM(" DATE OF DATA COLLECTION : ") << date << '\n' << RM(" TEMPERATURE (KELVIN) : ", 5, 1) << Ff(diffrn, "ambient_temp") << '\n' << RM(" PH : ", 4, 1) << Ff(exptl_crystal_grow, "ph") << '\n' << RM(" NUMBER OF CRYSTALS USED : ") << Fi(exptl, "crystals_number") << '\n' << RM("") << '\n' << RM(" SYNCHROTRON (Y/N) : ") << synchrotron << '\n' << RM(" RADIATION SOURCE : ") << source << '\n' << RM(" BEAMLINE : ") << Fs(diffrn_source, "pdbx_synchrotron_beamline") << '\n' << RM(" X-RAY GENERATOR MODEL : ") << type << '\n' << RM(" MONOCHROMATIC OR LAUE (M/L) : ") << Fs(diffrn_radiation, "pdbx_monochromatic_or_laue_m_l") << '\n' << RM(" WAVELENGTH OR RANGE (A) : ", 7, 4) << Ff(diffrn_radiation_wavelength, "wavelength") << '\n' << RM(" MONOCHROMATOR : ") << Fs(diffrn_radiation, "monochromator") << '\n' << RM(" OPTICS : ") << Fs(diffrn_detector, "details") << '\n' << RM("") << '\n' << RM(" DETECTOR TYPE : ") << Fs(diffrn_detector, "detector") << '\n' << RM(" DETECTOR MANUFACTURER : ") << Fs(diffrn_detector, "type") << '\n' << RM(" INTENSITY-INTEGRATION SOFTWARE : ") << iis << '\n' << RM(" DATA SCALING SOFTWARE : ") << dss << '\n' << RM(" ") << '\n' << RM(" NUMBER OF UNIQUE REFLECTIONS : ") << Fi(reflns, "number_obs") << '\n' << RM(" RESOLUTION RANGE HIGH (A) : ", 7, 3) << Ff(reflns, "d_resolution_high") << '\n' << RM(" RESOLUTION RANGE LOW (A) : ", 7, 3) << Ff(reflns, "d_resolution_low") << '\n' << RM(" REJECTION CRITERIA (SIGMA(I)) : ", 7, 3) << Ff(reflns, "observed_criterion_sigma_I") << '\n' << RM("") << '\n' << RM("OVERALL.") << '\n' << RM(" COMPLETENESS FOR RANGE (%) : ", 7, 1) << Ff(reflns, "percent_possible_obs") << '\n' << RM(" DATA REDUNDANCY : ", 7, 3) << Ff(reflns, "pdbx_redundancy") << '\n' << RM(" R MERGE (I) : ", 7, 5) << Ff(reflns, "pdbx_Rmerge_I_obs") << '\n' << RM(" R SYM (I) : ", 7, 5) << Ff(reflns, "pdbx_Rsym_value") << '\n' << RM(" FOR THE DATA SET : ", 7, 4) << Ff(reflns, "pdbx_netI_over_sigmaI") << '\n' << RM("") << '\n' << RM("IN THE HIGHEST RESOLUTION SHELL.") << '\n' << RM(" HIGHEST RESOLUTION SHELL, RANGE HIGH (A) : ", 7, 2) << Ff(reflns_shell, "d_res_high") << '\n' << RM(" HIGHEST RESOLUTION SHELL, RANGE LOW (A) : ", 7, 2) << Ff(reflns_shell, "d_res_low") << '\n' << RM(" COMPLETENESS FOR SHELL (%) : ", 7, 1) << Ff(reflns_shell, "percent_possible_all") << '\n' << RM(" DATA REDUNDANCY IN SHELL : ", 7, 2) << Ff(reflns_shell, "pdbx_redundancy") << '\n' << RM(" R MERGE FOR SHELL (I) : ", 7, 5) << Ff(reflns_shell, "Rmerge_I_obs") << '\n' << RM(" R SYM FOR SHELL (I) : ", 7, 5) << Ff(reflns_shell, "pdbx_Rsym_value") << '\n' << RM(" FOR SHELL : ", 7, 3) << Ff(reflns_shell, "meanI_over_sigI_obs") << '\n' << RM("") << '\n'; struct { row_handle r; const char *field; const char *dst; } kTail[] = { { diffrn_radiation, "pdbx_diffrn_protocol", "DIFFRACTION PROTOCOL: " }, { refine, "pdbx_method_to_determine_struct", "METHOD USED TO DETERMINE THE STRUCTURE: " }, { computing, "structure_solution", "SOFTWARE USED: " }, { refine, "pdbx_starting_model", "STARTING MODEL: " }, { exptl_crystal, "description", "\nREMARK: " } }; for (auto &t : kTail) { std::string s = t.r[t.field].as(); if (s.empty()) { if (strcmp(t.field, "structure_solution") == 0) s = cifSoftware(db, ePhasing); else s = "NULL"; } WriteOneContinuedLine(pdbFile, "REMARK 200", 0, t.dst + s); } break; } } catch (const std::exception &ex) { if (VERBOSE >= 0) std::cerr << ex.what() << '\n'; } } void WriteRemark280(std::ostream &pdbFile, const datablock &db) { typedef RM<280> RM; try { for (auto exptl_crystal : db["exptl_crystal"]) { std::string crystal_id = exptl_crystal["id"].as(); auto exptl_crystal_grow = db["exptl_crystal_grow"].find_first(key("crystal_id") == crystal_id); pdbFile << RM("") << '\n' << RM("CRYSTAL") << '\n' << RM("SOLVENT CONTENT, VS (%): ", 6, 2) << Ff(exptl_crystal, "density_percent_sol") << '\n' << RM("MATTHEWS COEFFICIENT, VM (ANGSTROMS**3/DA): ", 6, 2) << Ff(exptl_crystal, "density_Matthews") << '\n' << RM("") << '\n'; std::vector conditions; auto add = [&conditions](const std::string c) { if (find(conditions.begin(), conditions.end(), c) == conditions.end()) conditions.push_back(c); }; const char *keys[] = { "pdbx_details", "ph", "method", "temp" }; for (size_t i = 0; i < (sizeof(keys) / sizeof(const char *)); ++i) { const char *c = keys[i]; std::string v = exptl_crystal_grow[c].as(); if (not v.empty()) { to_upper(v); switch (i) { case 1: add("PH " + v); break; case 3: add("TEMPERATURE " + v + "K"); break; default: for (std::string::size_type b = 0, e = v.find(", "); b != std::string::npos; b = (e == std::string::npos ? e : e + 2), e = v.find(", ", b)) add(v.substr(b, e - b)); break; } } } WriteOneContinuedLine(pdbFile, "REMARK 280", 0, "CRYSTALLIZATION CONDITIONS: " + (conditions.empty() ? "NULL" : join(conditions, ", "))); break; } } catch (const std::exception &ex) { if (VERBOSE >= 0) std::cerr << ex.what() << '\n'; } } void WriteRemark350(std::ostream &pdbFile, const datablock &db) { auto &c1 = db["pdbx_struct_assembly"]; if (c1.empty()) return; std::vector biomolecules, details; for (auto bm : c1) { std::string id = bm["id"].as(); biomolecules.push_back(id); for (auto r : db["struct_biol"].find(key("id") == id)) { std::string s = r["details"].as(); if (not s.empty()) details.push_back(s); } } // write out the mandatory REMARK 300 first pdbFile << RM<300>("") << '\n' << RM<300>("BIOMOLECULE: ") << join(biomolecules, ", ") << '\n' << RM<300>("SEE REMARK 350 FOR THE AUTHOR PROVIDED AND/OR PROGRAM") << '\n' << RM<300>("GENERATED ASSEMBLY INFORMATION FOR THE STRUCTURE IN") << '\n' << RM<300>("THIS ENTRY. THE REMARK MAY ALSO PROVIDE INFORMATION ON") << '\n' << RM<300>("BURIED SURFACE AREA.") << '\n'; if (not details.empty()) { pdbFile << RM<300>("REMARK:") << '\n'; for (auto detail : details) WriteOneContinuedLine(pdbFile, "REMARK 300", 0, detail); } typedef RM<350> RM; pdbFile << RM("") << '\n' << RM("COORDINATES FOR A COMPLETE MULTIMER REPRESENTING THE KNOWN") << '\n' << RM("BIOLOGICALLY SIGNIFICANT OLIGOMERIZATION STATE OF THE") << '\n' << RM("MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS") << '\n' << RM("GIVEN BELOW. BOTH NON-CRYSTALLOGRAPHIC AND") << '\n' << RM("CRYSTALLOGRAPHIC OPERATIONS ARE GIVEN.") << '\n'; for (auto bm : c1) { std::string id, detail, method, oligomer; cif::tie(id, detail, method, oligomer) = bm.get("id", "details", "method_details", "oligomeric_details"); pdbFile << RM("") << '\n' << RM("BIOMOLECULE: ") << id << '\n'; to_upper(oligomer); if (detail == "author_defined_assembly" or detail == "author_and_software_defined_assembly") pdbFile << RM("AUTHOR DETERMINED BIOLOGICAL UNIT: ") << oligomer << '\n'; if (detail == "software_defined_assembly" or detail == "author_and_software_defined_assembly") pdbFile << RM("SOFTWARE DETERMINED QUATERNARY STRUCTURE: ") << oligomer << '\n'; if (not method.empty()) pdbFile << RM("SOFTWARE USED: ") << method << '\n'; for (std::string type : { "ABSA (A^2)", "SSA (A^2)", "MORE" }) { for (auto prop : db["pdbx_struct_assembly_prop"].find(key("biol_id") == id and key("type") == type)) { std::string value = prop["value"].as(); if (iequals(type, "ABSA (A^2)")) pdbFile << RM("TOTAL BURIED SURFACE AREA: ") << value << " ANGSTROM**2\n"; else if (iequals(type, "SSA (A^2)")) pdbFile << RM("SURFACE AREA OF THE COMPLEX: ") << value << " ANGSTROM**2\n"; else if (iequals(type, "MORE")) pdbFile << RM("CHANGE IN SOLVENT FREE ENERGY: ") << value << " KCAL/MOL\n"; } } auto gen = db["pdbx_struct_assembly_gen"].find_first(key("assembly_id") == id); if (gen) { std::string asym_id_list, oper_id_list; cif::tie(asym_id_list, oper_id_list) = gen.get("asym_id_list", "oper_expression"); auto asyms = split(asym_id_list, ","); std::vector chains = MapAsymIDs2ChainIDs(asyms, db); pdbFile << RM("APPLY THE FOLLOWING TO CHAINS: ") << join(chains, ", ") << '\n'; for (auto oper_id : split(oper_id_list, ",", true)) { auto r = db["pdbx_struct_oper_list"].find_first(key("id") == oper_id); pdbFile << RM(" BIOMT1 ", -3) << Fs(r, "id") << SEP(" ", -9, 6) << Ff(r, "matrix[1][1]") << SEP(" ", -9, 6) << Ff(r, "matrix[1][2]") << SEP(" ", -9, 6) << Ff(r, "matrix[1][3]") << SEP(" ", -14, 5) << Ff(r, "vector[1]") << '\n' << RM(" BIOMT2 ", -3) << Fs(r, "id") << SEP(" ", -9, 6) << Ff(r, "matrix[2][1]") << SEP(" ", -9, 6) << Ff(r, "matrix[2][2]") << SEP(" ", -9, 6) << Ff(r, "matrix[2][3]") << SEP(" ", -14, 5) << Ff(r, "vector[2]") << '\n' << RM(" BIOMT3 ", -3) << Fs(r, "id") << SEP(" ", -9, 6) << Ff(r, "matrix[3][1]") << SEP(" ", -9, 6) << Ff(r, "matrix[3][2]") << SEP(" ", -9, 6) << Ff(r, "matrix[3][3]") << SEP(" ", -14, 5) << Ff(r, "vector[3]") << '\n'; } } } } void WriteRemark400(std::ostream &pdbFile, const datablock &db) { for (auto r : db["pdbx_entry_details"]) { std::string compound_details = r["compound_details"].as(); if (not compound_details.empty()) WriteOneContinuedLine(pdbFile, "REMARK 400", 0, "\nCOMPOUND\n" + compound_details); } } void WriteRemark450(std::ostream &pdbFile, const datablock &db) { for (auto r : db["pdbx_entry_details"]) { std::string source_details = r["source_details"].as(); if (not source_details.empty()) WriteOneContinuedLine(pdbFile, "REMARK 450", 0, "\nSOURCE\n" + source_details, 11); break; } } void WriteRemark465(std::ostream &pdbFile, const datablock &db) { bool first = true; typedef RM<465> RM; auto &c = db["pdbx_unobs_or_zero_occ_residues"]; std::vector missing(c.begin(), c.end()); stable_sort(missing.begin(), missing.end(), [](row_handle a, row_handle b) -> bool { int modelNrA, seqIDA, modelNrB, seqIDB; std::string asymIDA, asymIDB; cif::tie(modelNrA, asymIDA, seqIDA) = a.get("PDB_model_num", "auth_asym_id", "auth_seq_id"); cif::tie(modelNrB, asymIDB, seqIDB) = b.get("PDB_model_num", "auth_asym_id", "auth_seq_id"); int d = modelNrA - modelNrB; if (d == 0) d = asymIDA.compare(asymIDB); if (d == 0) d = seqIDA - seqIDB; return d < 0; }); for (auto r : missing) { if (first) { pdbFile << RM("") << '\n' << RM("MISSING RESIDUES") << '\n' << RM("THE FOLLOWING RESIDUES WERE NOT LOCATED IN THE") << '\n' << RM("EXPERIMENT. (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN") << '\n' << RM("IDENTIFIER; SSSEQ=SEQUENCE NUMBER; I=INSERTION CODE.)") << '\n' << RM("") << '\n' << RM(" M RES C SSSEQI") << '\n'; first = false; } std::string modelNr, resName, chainID, iCode; int seqNr; cif::tie(modelNr, resName, chainID, iCode, seqNr) = r.get("PDB_model_num", "auth_comp_id", "auth_asym_id", "PDB_ins_code", "auth_seq_id"); pdbFile << cif::format("REMARK 465 %3.3s %3.3s %1.1s %5d%1.1s", modelNr, resName, chainID, seqNr, iCode) << '\n'; } } void WriteRemark470(std::ostream &pdbFile, const datablock &db) { typedef RM<470> RM; // wow... typedef std::tuple key_type; std::map> data; for (auto r : db["pdbx_unobs_or_zero_occ_atoms"]) { std::string modelNr, resName, chainID, iCode, atomID; int seqNr; cif::tie(modelNr, resName, chainID, iCode, seqNr, atomID) = r.get("PDB_model_num", "auth_comp_id", "auth_asym_id", "PDB_ins_code", "auth_seq_id", "auth_atom_id"); key_type k{ modelNr, chainID, seqNr, iCode, resName }; auto i = data.find(k); if (i == data.end()) data[k] = std::deque{ atomID }; else i->second.push_back(atomID); } if (not data.empty()) { pdbFile << RM("") << '\n' << RM("MISSING ATOM") << '\n' << RM("THE FOLLOWING RESIDUES HAVE MISSING ATOMS (M=MODEL NUMBER;") << '\n' << RM("RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE NUMBER;") << '\n' << RM("I=INSERTION CODE):") << '\n' << RM(" M RES CSSEQI ATOMS") << '\n'; for (auto &a : data) { std::string modelNr, resName, chainID, iCode; int seqNr; std::tie(modelNr, chainID, seqNr, iCode, resName) = a.first; while (not a.second.empty()) { pdbFile << cif::format("REMARK 470 %3.3s %3.3s %1.1s%4d%1.1s ", modelNr, resName, chainID, seqNr, iCode) << " "; for (size_t i = 0; i < 6 and not a.second.empty(); ++i) { pdbFile << cif2pdbAtomName(a.second.front(), resName, db) << ' '; a.second.pop_front(); } pdbFile << '\n'; } } } } void WriteRemark610(std::ostream &pdbFile, const datablock &db) { // #warning("unimplemented!"); } void WriteRemark800(std::ostream &pdbFile, const datablock &db) { int nr = 0; for (auto r : db["struct_site"]) { pdbFile << "REMARK 800\n"; if (++nr == 1) { pdbFile << "REMARK 800 SITE\n"; ++nr; } std::string ident, code, desc; cif::tie(ident, code, desc) = r.get("id", "pdbx_evidence_code", "details"); to_upper(code); for (auto l : { "SITE_IDENTIFIER: " + ident, "EVIDENCE_CODE: " + code, "SITE_DESCRIPTION: " + desc }) { for (auto s : word_wrap(l, 69)) pdbFile << "REMARK 800 " << s << '\n'; }; } } void WriteRemark999(std::ostream &pdbFile, const datablock &db) { for (auto r : db["pdbx_entry_details"]) { std::string sequence_details = r["sequence_details"].as(); if (not sequence_details.empty()) WriteOneContinuedLine(pdbFile, "REMARK 999", 0, "\nSEQUENCE\n" + sequence_details, 11); break; } } void WriteRemarks(std::ostream &pdbFile, const datablock &db) { WriteRemark1(pdbFile, db); WriteRemark2(pdbFile, db); WriteRemark3(pdbFile, db); WriteRemark200(pdbFile, db); WriteRemark280(pdbFile, db); WriteRemark350(pdbFile, db); WriteRemark400(pdbFile, db); WriteRemark465(pdbFile, db); WriteRemark470(pdbFile, db); WriteRemark610(pdbFile, db); WriteRemark800(pdbFile, db); WriteRemark999(pdbFile, db); } int WritePrimaryStructure(std::ostream &pdbFile, const datablock &db) { int numSeq = 0; // DBREF for (auto r : db["struct_ref"]) { std::string id, db_name, db_code; cif::tie(id, db_name, db_code) = r.get("id", "db_name", "db_code"); for (auto r1 : db["struct_ref_seq"].find(key("ref_id") == id)) { std::string idCode, chainID, insertBegin, insertEnd, dbAccession, dbinsBeg, dbinsEnd; std::string seqBegin, seqEnd, dbseqBegin, dbseqEnd; cif::tie(idCode, chainID, seqBegin, insertBegin, seqEnd, insertEnd, dbAccession, dbseqBegin, dbinsBeg, dbseqEnd, dbinsEnd) = r1.get("pdbx_PDB_id_code", "pdbx_strand_id", "pdbx_auth_seq_align_beg", "pdbx_seq_align_beg_ins_code", "pdbx_auth_seq_align_end", "pdbx_seq_align_end_ins_code", "pdbx_db_accession", "db_align_beg", "pdbx_db_align_beg_ins_code", "db_align_end", "pdbx_db_align_end_ins_code"); if (dbAccession.length() > 8 or db_code.length() > 12 or atoi(dbseqEnd.c_str()) >= 100000) pdbFile << cif::format( "DBREF1 %4.4s %1.1s %4.4s%1.1s %4.4s%1.1s %-6.6s %-20.20s", idCode, chainID, seqBegin, insertBegin, seqEnd, insertEnd, db_name, db_code) << '\n' << cif::format( "DBREF2 %4.4s %1.1s %-22.22s %10.10s %10.10s", idCode, chainID, dbAccession, dbseqBegin, dbseqEnd) << '\n'; else pdbFile << cif::format( "DBREF %4.4s %1.1s %4.4s%1.1s %4.4s%1.1s %-6.6s %-8.8s %-12.12s %5.5s%1.1s %5.5s%1.1s", idCode, chainID, seqBegin, insertBegin, seqEnd, insertEnd, db_name, dbAccession, db_code, dbseqBegin, dbinsBeg, dbseqEnd, dbinsEnd) << '\n'; } } // SEQADV for (auto r : db["struct_ref_seq_dif"]) { std::string idCode, resName, chainID, seqNum, iCode, database, dbAccession, dbRes, dbSeq, conflict; cif::tie(idCode, resName, chainID, seqNum, iCode, database, dbAccession, dbRes, dbSeq, conflict) = r.get("pdbx_PDB_id_code", "mon_id", "pdbx_pdb_strand_id", "pdbx_auth_seq_num", "pdbx_pdb_ins_code", "pdbx_seq_db_name", "pdbx_seq_db_accession_code", "db_mon_id", "pdbx_seq_db_seq_num", "details"); to_upper(conflict); pdbFile << cif::format( "SEQADV %4.4s %3.3s %1.1s %4.4s%1.1s %-4.4s %-9.9s %3.3s %5.5s %-21.21s", idCode, resName, chainID, seqNum, iCode, database, dbAccession, dbRes, dbSeq, conflict) .str() << '\n'; } // SEQRES std::map> seqres; std::map seqresl; for (auto r : db["pdbx_poly_seq_scheme"]) { std::string chainID, res; cif::tie(chainID, res) = r.get("pdb_strand_id", "mon_id"); if (chainID.empty() or res.length() > 3 or res.length() < 1) throw std::runtime_error("invalid pdbx_poly_seq_scheme record, chain: " + chainID + " res: " + res); seqres[chainID[0]].push_back(std::string(3 - res.length(), ' ') + res); ++seqresl[chainID[0]]; } for (auto &&[chainID, seq] : seqres) { int n = 1; while (seq.empty() == false) { auto t = seq.size(); if (t > 13) t = 13; pdbFile << cif::format( "SEQRES %3d %1.1s %4d %-51.51s ", n++, std::string{ chainID }, seqresl[chainID], join(seq.begin(), seq.begin() + t, " ")) << '\n'; ++numSeq; seq.erase(seq.begin(), seq.begin() + t); } } // MODRES for (auto r : db["pdbx_struct_mod_residue"]) { std::string chainID, seqNum, resName, iCode, stdRes, comment; cif::tie(chainID, seqNum, resName, iCode, stdRes, comment) = r.get("auth_asym_id", "auth_seq_id", "auth_comp_id", "PDB_ins_code", "parent_comp_id", "details"); pdbFile << cif::format( "MODRES %4.4s %3.3s %1.1s %4.4s%1.1s %3.3s %-41.41s", db.name(), resName, chainID, seqNum, iCode, stdRes, comment) .str() << '\n'; } return numSeq; } int WriteHeterogen(std::ostream &pdbFile, const datablock &db) { int numHet = 0; std::string water_entity_id, water_comp_id; for (auto r : db["entity"].find(key("type") == std::string("water"))) { water_entity_id = r["id"].as(); break; } std::map het; for (auto r : db["chem_comp"]) { std::string id, name, mon_nstd_flag; cif::tie(id, name, mon_nstd_flag) = r.get("id", "name", "mon_nstd_flag"); if (mon_nstd_flag == "y") continue; het[id] = name; } for (auto r : db["pdbx_entity_nonpoly"]) { std::string entity_id, name, comp_id; cif::tie(entity_id, name, comp_id) = r.get("entity_id", "name", "comp_id"); if (entity_id == water_entity_id) water_comp_id = comp_id; if (het.count(comp_id) == 0) het[comp_id] = name; } struct HET { bool water; std::string hetID; char chainID; int seqNum; char iCode; int numHetAtoms; std::string text; // ignored }; std::vector hets; // // construct component number map // map component_nr; // std::string lChainID, lCompID, lICode; // int lSeqNum; // // for (auto r: db["atom_site"]) // { // std::string chainID, compID, iCode; // int seqNum; // // tie(seqNum, comp_id, chain_id, iCode) = // r.get("auth_seq_id", "auth_comp_id", "auth_asym_id", "pdbx_PDB_ins_code"); // // if (chainID != lChainID or compID != lCompID or seqNum != lSeqNum or iCode != lICode) // // } // count the HETATM's // for (auto r: db["atom_site"].find(key("group_PDB") == std::string("HETATM"))) std::set missingHetNames; for (auto r : db["atom_site"]) { int seqNum; std::string entity_id, comp_id, chain_id, iCode, modelNr; cif::tie(entity_id, seqNum, comp_id, chain_id, iCode, modelNr) = r.get("label_entity_id", "auth_seq_id", "auth_comp_id", "auth_asym_id", "pdbx_PDB_ins_code", "pdbx_PDB_model_num"); if (compound_factory::kAAMap.count(comp_id) or compound_factory::kBaseMap.count(comp_id)) continue; if (chain_id.length() != 1) throw std::runtime_error("Cannot produce PDB file, auth_asym_id not valid"); if (entity_id != water_entity_id and het.count(comp_id) == 0) missingHetNames.insert(comp_id); auto h = find_if(hets.begin(), hets.end(), [=](const HET &het) -> bool { return het.hetID == comp_id and het.chainID == chain_id[0] and het.seqNum == seqNum; }); if (h == hets.end()) { hets.push_back({ entity_id == water_entity_id, comp_id, chain_id[0], seqNum, (iCode.empty() ? ' ' : iCode[0]), 1 }); } else h->numHetAtoms += 1; } if (VERBOSE > 1 and not missingHetNames.empty()) std::cerr << "Missing het name(s) for " << join(missingHetNames, ", ") << '\n'; for (auto h : hets) { if (h.water) continue; pdbFile << cif::format("HET %3.3s %c%4d%c %5d", h.hetID, h.chainID, h.seqNum, h.iCode, h.numHetAtoms) << '\n'; ++numHet; } for (auto &&[id, name] : het) { if (id == water_comp_id) continue; to_upper(name); int c = 1; for (;;) { pdbFile << cif::format("HETNAM %2.2s %3.3s ", (c > 1 ? std::to_string(c) : std::string()), id); ++c; if (name.length() > 55) { bool done = false; for (auto e = name.begin() + 54; e != name.begin(); --e) { if (ispunct(*e)) { pdbFile << std::string(name.begin(), e) << '\n'; name.erase(name.begin(), e); done = true; break; } } if (not done) { pdbFile << std::string(name.begin(), name.begin() + 55) << '\n'; name.erase(name.begin(), name.begin() + 55); } continue; } pdbFile << name << '\n'; break; } } for (auto &&[id, name] : het) { if (id == water_comp_id) continue; std::string syn = db["chem_comp"].find_first(key("id") == id, "pdbx_synonyms"); if (syn.empty()) continue; WriteOneContinuedLine(pdbFile, "HETSYN", 4, id + ' ' + syn, 11); } // FORMUL std::vector formulas; for (auto h : het) { std::string hetID = h.first; int componentNr = 0; std::string first_het_asym_id; for (auto p : db["pdbx_poly_seq_scheme"].find(key("mon_id") == hetID)) { first_het_asym_id = p["asym_id"].as(); break; } if (first_het_asym_id.empty()) { for (auto p : db["pdbx_nonpoly_scheme"].find(key("mon_id") == hetID)) { first_het_asym_id = p["asym_id"].as(); break; } } if (not first_het_asym_id.empty()) { for (auto a : db["struct_asym"]) { ++componentNr; if (a["id"] == first_het_asym_id) break; } } auto nr = count_if(hets.begin(), hets.end(), [hetID](auto &h) -> bool { return h.hetID == hetID; }); for (auto r : db["chem_comp"].find(key("id") == hetID)) { std::string formula = r["formula"].as(); if (nr > 1) formula = std::to_string(nr) + '(' + formula + ')'; int c = 1; for (;;) { std::stringstream fs; fs << cif::format("FORMUL %2d %3.3s %2.2s%c", componentNr, hetID, (c > 1 ? std::to_string(c) : std::string()), (hetID == water_comp_id ? '*' : ' ')); ++c; if (formula.length() > 51) { bool done = false; for (auto e = formula.begin() + 50; e != formula.begin(); --e) { if (ispunct(*e)) { pdbFile << std::string(formula.begin(), e) << '\n'; formula.erase(formula.begin(), e); done = true; break; } } if (not done) { pdbFile << std::string(formula.begin(), formula.begin() + 55) << '\n'; formula.erase(formula.begin(), formula.begin() + 55); } continue; } fs << formula << '\n'; formulas.push_back(fs.str()); break; } break; } } sort(formulas.begin(), formulas.end(), [](const std::string &a, const std::string &b) -> bool { return stoi(a.substr(8, 2)) < stoi(b.substr(8, 2)); }); for (auto &f : formulas) pdbFile << f; return numHet; } std::tuple WriteSecondaryStructure(std::ostream &pdbFile, const datablock &db) { int numHelix = 0, numSheet = 0; // HELIX for (auto r : db["struct_conf"].find(key("conf_type_id") == "HELX_P")) { std::string pdbx_PDB_helix_id, beg_label_comp_id, pdbx_beg_PDB_ins_code, end_label_comp_id, pdbx_end_PDB_ins_code, beg_auth_comp_id, beg_auth_asym_id, end_auth_comp_id, end_auth_asym_id, details; int pdbx_PDB_helix_class, pdbx_PDB_helix_length, beg_auth_seq_id, end_auth_seq_id; cif::tie(pdbx_PDB_helix_id, beg_label_comp_id, pdbx_beg_PDB_ins_code, end_label_comp_id, pdbx_end_PDB_ins_code, beg_auth_comp_id, beg_auth_asym_id, end_auth_comp_id, end_auth_asym_id, details, pdbx_PDB_helix_class, pdbx_PDB_helix_length, beg_auth_seq_id, end_auth_seq_id) = r.get("pdbx_PDB_helix_id", "beg_label_comp_id", "pdbx_beg_PDB_ins_code", "end_label_comp_id", "pdbx_end_PDB_ins_code", "beg_auth_comp_id", "beg_auth_asym_id", "end_auth_comp_id", "end_auth_asym_id", "details", "pdbx_PDB_helix_class", "pdbx_PDB_helix_length", "beg_auth_seq_id", "end_auth_seq_id"); ++numHelix; pdbFile << cif::format("HELIX %3d %3.3s %3.3s %1.1s %4d%1.1s %3.3s %1.1s %4d%1.1s%2d%-30.30s %5d", numHelix, pdbx_PDB_helix_id, beg_label_comp_id, beg_auth_asym_id, beg_auth_seq_id, pdbx_beg_PDB_ins_code, end_label_comp_id, end_auth_asym_id, end_auth_seq_id, pdbx_end_PDB_ins_code, pdbx_PDB_helix_class, details, pdbx_PDB_helix_length) << '\n'; } for (auto r : db["struct_sheet"]) { std::string sheetID; int numStrands = 0; cif::tie(sheetID, numStrands) = r.get("id", "number_strands"); bool first = true; for (auto o : db["struct_sheet_order"].find(key("sheet_id") == sheetID)) { int sense = 0; std::string s, rangeID1, rangeID2; cif::tie(s, rangeID1, rangeID2) = o.get("sense", "range_id_1", "range_id_2"); if (s == "anti-parallel") sense = -1; else if (s == "parallel") sense = 1; if (first) { std::string initResName, initChainID, initICode, endResName, endChainID, endICode; int initSeqNum, endSeqNum; auto r1 = db["struct_sheet_range"].find_first(key("sheet_id") == sheetID and key("id") == rangeID1); cif::tie(initResName, initICode, endResName, endICode, initResName, initChainID, initSeqNum, endResName, endChainID, endSeqNum) = r1.get("beg_label_comp_id", "pdbx_beg_PDB_ins_code", "end_label_comp_id", "pdbx_end_PDB_ins_code", "beg_auth_comp_id", "beg_auth_asym_id", "beg_auth_seq_id", "end_auth_comp_id", "end_auth_asym_id", "end_auth_seq_id"); pdbFile << cif::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d", rangeID1, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, 0) << '\n'; first = false; } std::string initResName, initChainID, initICode, endResName, endChainID, endICode, curAtom, curResName, curChainID, curICode, prevAtom, prevResName, prevChainID, prevICode; int initSeqNum, endSeqNum, curResSeq, prevResSeq; auto r2 = db["struct_sheet_range"].find_first(key("sheet_id") == sheetID and key("id") == rangeID2); cif::tie(initResName, initICode, endResName, endICode, initResName, initChainID, initSeqNum, endResName, endChainID, endSeqNum) = r2.get("beg_label_comp_id", "pdbx_beg_PDB_ins_code", "end_label_comp_id", "pdbx_end_PDB_ins_code", "beg_auth_comp_id", "beg_auth_asym_id", "beg_auth_seq_id", "end_auth_comp_id", "end_auth_asym_id", "end_auth_seq_id"); auto h = db["pdbx_struct_sheet_hbond"].find(key("sheet_id") == sheetID and key("range_id_1") == rangeID1 and key("range_id_2") == rangeID2); if (h.empty()) { pdbFile << cif::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d", rangeID2, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, sense) << '\n'; } else { std::string compID[2]; cif::tie(compID[0], compID[1]) = h.front().get("range_2_label_comp_id", "range_1_label_comp_id"); cif::tie(curAtom, curResName, curResSeq, curChainID, curICode, prevAtom, prevResName, prevResSeq, prevChainID, prevICode) = h.front().get("range_2_auth_atom_id", "range_2_auth_comp_id", "range_2_auth_seq_id", "range_2_auth_asym_id", "range_2_PDB_ins_code", "range_1_auth_atom_id", "range_1_auth_comp_id", "range_1_auth_seq_id", "range_1_auth_asym_id", "range_1_PDB_ins_code"); curAtom = cif2pdbAtomName(curAtom, compID[0], db); prevAtom = cif2pdbAtomName(prevAtom, compID[1], db); pdbFile << cif::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d " "%-4.4s%3.3s %1.1s%4d%1.1s %-4.4s%3.3s %1.1s%4d%1.1s", rangeID2, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, sense, curAtom, curResName, curChainID, curResSeq, curICode, prevAtom, prevResName, prevChainID, prevResSeq, prevICode) << '\n'; } ++numSheet; } } return std::make_tuple(numHelix, numSheet); } void WriteConnectivity(std::ostream &pdbFile, const datablock &db) { // SSBOND // have to filter out alts std::set> ssSeen; int nr = 1; for (auto r : db["struct_conn"].find(key("conn_type_id") == "disulf")) { std::string chainID1, icode1, chainID2, icode2, sym1, sym2; float Length; int seqNum1, seqNum2; cif::tie( chainID1, seqNum1, icode1, chainID2, seqNum2, icode2, sym1, sym2, Length) = r.get("ptnr1_auth_asym_id", "ptnr1_auth_seq_id", "pdbx_ptnr1_PDB_ins_code", "ptnr2_auth_asym_id", "ptnr2_auth_seq_id", "pdbx_ptnr2_PDB_ins_code", "ptnr1_symmetry", "ptnr2_symmetry", "pdbx_dist_value"); auto n = ssSeen.emplace(chainID1[0], seqNum1, icode1[0], chainID2[0], seqNum2, icode2[0]); if (n.second == false) continue; sym1 = cif2pdbSymmetry(sym1); sym2 = cif2pdbSymmetry(sym2); pdbFile << cif::format("SSBOND %3d CYS %1.1s %4d%1.1s CYS %1.1s %4d%1.1s %6.6s %6.6s %5.2f", nr, chainID1, seqNum1, icode1, chainID2, seqNum2, icode2, sym1, sym2, Length) << '\n'; ++nr; } // LINK for (auto r : db["struct_conn"].find(key("conn_type_id") == "metalc" or key("conn_type_id") == "covale")) { std::string name1, altLoc1, resName1, chainID1, iCode1, name2, altLoc2, resName2, chainID2, iCode2, sym1, sym2, Length; int resSeq1, resSeq2; cif::tie(name1, altLoc1, resName1, chainID1, resSeq1, iCode1, name2, altLoc2, resName2, chainID2, resSeq2, iCode2, sym1, sym2, Length) = r.get("ptnr1_label_atom_id", "pdbx_ptnr1_label_alt_id", "ptnr1_label_comp_id", "ptnr1_auth_asym_id", "ptnr1_auth_seq_id", "pdbx_ptnr1_PDB_ins_code", "ptnr2_label_atom_id", "pdbx_ptnr2_label_alt_id", "ptnr2_label_comp_id", "ptnr2_auth_asym_id", "ptnr2_auth_seq_id", "pdbx_ptnr2_PDB_ins_code", "ptnr1_symmetry", "ptnr2_symmetry", "pdbx_dist_value"); std::string compID[2]; cif::tie(compID[0], compID[1]) = r.get("ptnr1_label_comp_id", "ptnr2_label_comp_id"); name1 = cif2pdbAtomName(name1, compID[0], db); name2 = cif2pdbAtomName(name2, compID[1], db); sym1 = cif2pdbSymmetry(sym1); sym2 = cif2pdbSymmetry(sym2); pdbFile << cif::format("LINK %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %6.6s %6.6s", name1, altLoc1, resName1, chainID1, resSeq1, iCode1, name2, altLoc2, resName2, chainID2, resSeq2, iCode2, sym1, sym2); if (not Length.empty()) pdbFile << cif::format(" %5.2f", stod(Length)); pdbFile << '\n'; } // CISPEP for (auto r : db["struct_mon_prot_cis"]) { std::string serNum, pep1, chainID1, icode1, pep2, chainID2, icode2, modNum; int seqNum1, seqNum2; float measure; cif::tie(serNum, pep1, chainID1, seqNum1, icode1, pep2, chainID2, seqNum2, icode2, modNum, measure) = r.get("pdbx_id", "label_comp_id", "auth_asym_id", "auth_seq_id", "pdbx_PDB_ins_code", "pdbx_label_comp_id_2", "pdbx_auth_asym_id_2", "pdbx_auth_seq_id_2", "pdbx_PDB_ins_code_2", "pdbx_PDB_model_num", "pdbx_omega_angle"); pdbFile << cif::format("CISPEP %3.3s %3.3s %1.1s %4d%1.1s %3.3s %1.1s %4d%1.1s %3.3s %6.2f", serNum, pep1, chainID1, seqNum1, icode1, pep2, chainID2, seqNum2, icode2, modNum, measure) << '\n'; } } int WriteMiscellaneousFeatures(std::ostream &pdbFile, const datablock &db) { int numSite = 0; // SITE std::map> sites; for (auto r : db["struct_site_gen"]) { std::string siteID, resName, chainID, iCode; int seq; cif::tie(siteID, resName, chainID, seq, iCode) = r.get("site_id", "auth_comp_id", "auth_asym_id", "auth_seq_id", "pdbx_auth_ins_code"); sites[siteID].push_back(cif::format("%3.3s %1.1s%4d%1.1s ", resName, chainID, seq, iCode).str()); } for (auto s : sites) { std::string siteID = std::get<0>(s); std::deque &res = std::get<1>(s); size_t numRes = res.size(); int nr = 1; while (res.empty() == false) { pdbFile << cif::format("SITE %3d %3.3s %2d ", nr, siteID, numRes); for (int i = 0; i < 4; ++i) { if (not res.empty()) { pdbFile << res.front(); res.pop_front(); } else pdbFile << std::string(11, ' '); } pdbFile << '\n'; ++nr; ++numSite; } } return numSite; } void WriteCrystallographic(std::ostream &pdbFile, const datablock &db) { auto r = db["symmetry"].find_first(key("entry_id") == db.name()); std::string symmetry = r["space_group_name_H-M"].as(); r = db["cell"].find_first(key("entry_id") == db.name()); pdbFile << cif::format("CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11.11s%4d", r["length_a"].as(), r["length_b"].as(), r["length_c"].as(), r["angle_alpha"].as(), r["angle_beta"].as(), r["angle_gamma"].as(), symmetry, r["Z_PDB"].as()) << '\n'; } int WriteCoordinateTransformation(std::ostream &pdbFile, const datablock &db) { int result = 0; for (auto r : db["database_PDB_matrix"]) { pdbFile << cif::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 1, r["origx[1][1]"].as(), r["origx[1][2]"].as(), r["origx[1][3]"].as(), r["origx_vector[1]"].as()) << '\n'; pdbFile << cif::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 2, r["origx[2][1]"].as(), r["origx[2][2]"].as(), r["origx[2][3]"].as(), r["origx_vector[2]"].as()) << '\n'; pdbFile << cif::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 3, r["origx[3][1]"].as(), r["origx[3][2]"].as(), r["origx[3][3]"].as(), r["origx_vector[3]"].as()) << '\n'; result += 3; break; } for (auto r : db["atom_sites"]) { pdbFile << cif::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 1, r["fract_transf_matrix[1][1]"].as(), r["fract_transf_matrix[1][2]"].as(), r["fract_transf_matrix[1][3]"].as(), r["fract_transf_vector[1]"].as()) << '\n'; pdbFile << cif::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 2, r["fract_transf_matrix[2][1]"].as(), r["fract_transf_matrix[2][2]"].as(), r["fract_transf_matrix[2][3]"].as(), r["fract_transf_vector[2]"].as()) << '\n'; pdbFile << cif::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 3, r["fract_transf_matrix[3][1]"].as(), r["fract_transf_matrix[3][2]"].as(), r["fract_transf_matrix[3][3]"].as(), r["fract_transf_vector[3]"].as()) << '\n'; result += 3; break; } int nr = 1; for (auto r : db["struct_ncs_oper"]) { std::string given = r["code"] == "given" ? "1" : ""; pdbFile << cif::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 1, nr, r["matrix[1][1]"].as(), r["matrix[1][2]"].as(), r["matrix[1][3]"].as(), r["vector[1]"].as(), given) << '\n'; pdbFile << cif::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 2, nr, r["matrix[2][1]"].as(), r["matrix[2][2]"].as(), r["matrix[2][3]"].as(), r["vector[2]"].as(), given) << '\n'; pdbFile << cif::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 3, nr, r["matrix[3][1]"].as(), r["matrix[3][2]"].as(), r["matrix[3][3]"].as(), r["vector[3]"].as(), given) << '\n'; ++nr; result += 3; } return result; } std::tuple WriteCoordinatesForModel(std::ostream &pdbFile, const datablock &db, const std::map> &last_resseq_for_chain_map, std::set &terminatedChains, int model_nr) { using namespace cif::literals; int numCoord = 0, numTer = 0; auto &atom_site = db["atom_site"]; auto &atom_site_anisotrop = db["atom_site_anisotrop"]; auto &entity = db["entity"]; // auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"]; // auto &pdbx_nonpoly_scheme = db["pdbx_nonpoly_scheme"]; auto &pdbx_branch_scheme = db["pdbx_branch_scheme"]; int serial = 1; auto ri = atom_site.begin(); std::string id, group, name, altLoc, resName, chainID, iCode, element; int resSeq = 0, charge; for (;;) { std::string nextResName, nextChainID, nextICode, modelNum; int nextResSeq = 0; if (ri != atom_site.end()) cif::tie(nextResName, nextChainID, nextICode, nextResSeq, modelNum) = (*ri).get("label_comp_id", "auth_asym_id", "pdbx_PDB_ins_code", "auth_seq_id", "pdbx_PDB_model_num"); if (modelNum.empty() == false) { int nr = 0; auto r = std::from_chars(modelNum.data(), modelNum.data() + modelNum.length(), nr); if ((bool)r.ec) { if (VERBOSE > 0) std::cerr << "Model number '" << modelNum << "' is not a valid integer\n"; } if (nr != model_nr) { ++ri; continue; } } if (chainID.empty() == false and terminatedChains.count(chainID) == 0) { bool terminate = nextChainID != chainID; if (not terminate) terminate = (nextResSeq != resSeq or iCode != nextICode) and (last_resseq_for_chain_map.count(chainID) == false or last_resseq_for_chain_map.at(chainID) == make_tuple(resName, resSeq, iCode)); if (terminate) { pdbFile << cif::format("TER %5d %3.3s %1.1s%4d%1.1s", serial, resName, chainID, resSeq, iCode) << '\n'; ++serial; terminatedChains.insert(chainID); ++numTer; } } if (ri == atom_site.end()) break; auto r = *ri++; try { if (r["pdbx_PDB_model_num"].as() != model_nr) continue; } catch (...) { /* perhaps no model number here */ } float x, y, z, occupancy, tempFactor; cif::tie(id, group, name, altLoc, resName, chainID, resSeq, iCode, x, y, z, occupancy, tempFactor, element, charge) = r.get("id", "group_PDB", "label_atom_id", "label_alt_id", "auth_comp_id", "auth_asym_id", "auth_seq_id", "pdbx_PDB_ins_code", "Cartn_x", "Cartn_y", "Cartn_z", "occupancy", "B_iso_or_equiv", "type_symbol", "pdbx_formal_charge"); if (resName != "HOH") { int entity_id = r.get("label_entity_id"); try { auto type = entity.find1("id"_key == entity_id, "type"); if (type == "branched") // find the real auth_seq_num, since sugars have their auth_seq_num reused as sugar number... sigh. resSeq = pdbx_branch_scheme.find1("asym_id"_key == r.get("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num"); // else if (type == "non-polymer") // same for non-polymers // resSeq = pdbx_nonpoly_scheme.find1("asym_id"_key == r.get("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num"); // else if (type == "polymer") // resSeq = pdbx_poly_seq_scheme.find1("asym_id"_key == r.get("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num"); } catch (const std::exception &ex) { std::cerr << "Oops, there was not exactly one entity with id " << entity_id << '\n'; } } if (chainID.length() > 1) throw std::runtime_error("Chain ID " + chainID + " won't fit into a PDB file"); if (name.length() < 4 and (element.length() == 1 or std::toupper(name[0]) != std::toupper(element[0]) or std::toupper(name[1]) != std::toupper(element[1]))) name.insert(name.begin(), ' '); std::string sCharge; if (charge != 0) sCharge = std::to_string(charge) + (charge > 0 ? '+' : '-'); pdbFile << cif::format("%-6.6s%5d %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %8.3f%8.3f%8.3f%6.2f%6.2f %2.2s%2.2s", group, serial, name, altLoc, resName, chainID, resSeq, iCode, x, y, z, occupancy, tempFactor, element, sCharge) << '\n'; ++numCoord; auto ai = atom_site_anisotrop.find_first(key("id") == id); if (not ai.empty()) // // auto ai = find_if(atom_site_anisotrop.begin(), atom_site_anisotrop.end(), [id](row_handle r) -> bool { return r["id"] == id; }); // if (ai != atom_site_anisotrop.end()) { float u11, u22, u33, u12, u13, u23; tie(u11, u22, u33, u12, u13, u23) = ai.get("U[1][1]", "U[2][2]", "U[3][3]", "U[1][2]", "U[1][3]", "U[2][3]"); pdbFile << cif::format("ANISOU%5d %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %7d%7d%7d%7d%7d%7d %2.2s%2.2s", serial, name, altLoc, resName, chainID, resSeq, iCode, std::lrintf(u11 * 10000), std::lrintf(u22 * 10000), std::lrintf(u33 * 10000), std::lrintf(u12 * 10000), std::lrintf(u13 * 10000), std::lrintf(u23 * 10000), element, sCharge) << '\n'; } ++serial; } return std::make_tuple(numCoord, numTer); } std::tuple WriteCoordinate(std::ostream &pdbFile, const datablock &db) { // residues known from seqres // map,std::string> res2chain_map; std::map> last_resseq_for_chain_map; for (auto r : db["pdbx_poly_seq_scheme"]) { std::string chainID, resName, iCode; int resSeq; if (r["auth_seq_num"].empty()) continue; cif::tie(chainID, resName, resSeq, iCode) = r.get("pdb_strand_id", "pdb_mon_id", "auth_seq_num", "pdb_ins_code"); last_resseq_for_chain_map[chainID] = make_tuple(resName, resSeq, iCode); // res2chain_map[make_tuple(resName, resSeq, iCode)] = chainID; } // collect known model numbers std::set models; try { for (auto r : db["atom_site"]) models.insert(r["pdbx_PDB_model_num"].as()); } catch (...) { } std::tuple result; if (models.empty() or models == std::set{ 0 }) { std::set TERminatedChains; result = WriteCoordinatesForModel(pdbFile, db, last_resseq_for_chain_map, TERminatedChains, 0); } else { for (int model_nr : models) { if (models.size() > 1) pdbFile << cif::format("MODEL %4d", model_nr) << '\n'; std::set TERminatedChains; auto n = WriteCoordinatesForModel(pdbFile, db, last_resseq_for_chain_map, TERminatedChains, model_nr); if (model_nr == 1) result = n; if (models.size() > 1) pdbFile << "ENDMDL\n"; } } return result; } void WritePDBHeaderLines(std::ostream &os, const datablock &db) { fill_out_streambuf fb(os); write_header_lines(os, db); } std::string FixStringLength(const std::string &s, std::string::size_type l) { auto result = s; if (result.length() > l) result = result.substr(0, l - 4) + "... "; else if (result.length() < l) result.append(l - result.length(), ' '); return result; } std::string get_HEADER_line(const datablock &db, std::string::size_type truncate_at) { // 0 1 2 3 4 5 6 7 8 // HEADER xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDDDDDDDDD IIII // HEADER std::string keywords; auto &cat1 = db["struct_keywords"]; for (auto r : cat1) { keywords = r["pdbx_keywords"].as(); if (keywords.length() > truncate_at - 40) keywords = keywords.substr(0, truncate_at - 44) + " ..."; } std::string date; for (auto r : db["pdbx_database_status"]) { date = r["recvd_initial_deposition_date"].as(); if (date.empty()) continue; date = cif2pdbDate(date); break; } if (date.empty()) { for (auto r : db["database_PDB_rev"]) { date = r["date_original"].as(); if (date.empty()) continue; date = cif2pdbDate(date); break; } } return FixStringLength(cif::format("HEADER %-40.40s%-9.9s %-4.4s", keywords, date, db.name()).str(), truncate_at); } std::string get_COMPND_line(const datablock &db, std::string::size_type truncate_at) { // COMPND using namespace std::placeholders; int molID = 0; std::vector cmpnd; for (auto r : db["entity"]) { if (r["type"] != "polymer") continue; std::string entityID = r["id"].as(); ++molID; cmpnd.push_back("MOL_ID: " + std::to_string(molID)); std::string molecule = r["pdbx_description"].as(); cmpnd.push_back("MOLECULE: " + molecule); auto poly = db["entity_poly"].find(key("entity_id") == entityID); if (not poly.empty()) { std::string chains = poly.front()["pdbx_strand_id"].as(); replace_all(chains, ",", ", "); cmpnd.push_back("CHAIN: " + chains); } std::string fragment = r["pdbx_fragment"].as(); if (not fragment.empty()) cmpnd.push_back("FRAGMENT: " + fragment); for (auto sr : db["entity_name_com"].find(key("entity_id") == entityID)) { std::string syn = sr["name"].as(); if (not syn.empty()) cmpnd.push_back("SYNONYM: " + syn); } std::string mutation = r["pdbx_mutation"].as(); if (not mutation.empty()) cmpnd.push_back("MUTATION: " + mutation); std::string ec = r["pdbx_ec"].as(); if (not ec.empty()) cmpnd.push_back("EC: " + ec); if (r["src_method"] == "man" or r["src_method"] == "syn") cmpnd.push_back("ENGINEERED: YES"); std::string details = r["details"].as(); if (not details.empty()) cmpnd.push_back("OTHER_DETAILS: " + details); } return FixStringLength("COMPND " + join(cmpnd, "; "), truncate_at); } std::string get_SOURCE_line(const datablock &db, std::string::size_type truncate_at) { // SOURCE int molID = 0; std::vector source; for (auto r : db["entity"]) { if (r["type"] != "polymer") continue; std::string entityID = r["id"].as(); ++molID; source.push_back("MOL_ID: " + std::to_string(molID)); if (r["src_method"] == "syn") source.push_back("SYNTHETIC: YES"); auto &gen = db["entity_src_gen"]; const std::pair kGenSourceMapping[] = { { "gene_src_common_name", "ORGANISM_COMMON" }, { "pdbx_gene_src_gene", "GENE" }, { "gene_src_strain", "STRAIN" }, { "pdbx_gene_src_cell_line", "CELL_LINE" }, { "pdbx_gene_src_organelle", "ORGANELLE" }, { "pdbx_gene_src_cellular_location", "CELLULAR_LOCATION" }, { "pdbx_gene_src_scientific_name", "ORGANISM_SCIENTIFIC" }, { "pdbx_gene_src_ncbi_taxonomy_id", "ORGANISM_TAXID" }, { "pdbx_host_org_scientific_name", "EXPRESSION_SYSTEM" }, { "pdbx_host_org_ncbi_taxonomy_id", "EXPRESSION_SYSTEM_TAXID" }, { "pdbx_host_org_strain", "EXPRESSION_SYSTEM_STRAIN" }, { "pdbx_host_org_variant", "EXPRESSION_SYSTEM_VARIANT" }, { "pdbx_host_org_cellular_location", "EXPRESSION_SYSTEM_CELLULAR_LOCATION" }, { "pdbx_host_org_vector_type", "EXPRESSION_SYSTEM_VECTOR_TYPE" }, { "pdbx_host_org_vector", "EXPRESSION_SYSTEM_VECTOR" }, { "pdbx_host_org_gene", "EXPRESSION_SYSTEM_GENE" }, { "plasmid_name", "EXPRESSION_SYSTEM_PLASMID" } }; for (auto gr : gen.find(key("entity_id") == entityID)) { for (const auto &[cname, sname] : kGenSourceMapping) { std::string s = gr[cname].as(); if (not s.empty()) source.push_back(sname + ": "s + s); } } auto &nat = db["entity_src_nat"]; const std::pair kNatSourceMapping[] = { { "common_name", "ORGANISM_COMMON" }, { "strain", "STRAIN" }, { "pdbx_organism_scientific", "ORGANISM_SCIENTIFIC" }, { "pdbx_ncbi_taxonomy_id", "ORGANISM_TAXID" }, { "pdbx_cellular_location", "CELLULAR_LOCATION" }, { "pdbx_plasmid_name", "PLASMID" }, { "pdbx_organ", "ORGAN" }, { "details", "OTHER_DETAILS" } }; for (auto nr : nat.find(key("entity_id") == entityID)) { for (const auto &[cname, sname] : kNatSourceMapping) { std::string s = nr[cname].as(); if (not s.empty()) source.push_back(sname + ": "s + s); } } } return FixStringLength("SOURCE " + join(source, "; "), truncate_at); } std::string get_AUTHOR_line(const datablock &db, std::string::size_type truncate_at) { // AUTHOR std::vector author; for (auto r : db["audit_author"]) author.push_back(cif2pdbAuth(r["name"].as())); return FixStringLength("AUTHOR " + join(author, "; "), truncate_at); } // -------------------------------------------------------------------- void write(std::ostream &os, const datablock &db) { fill_out_streambuf fb(os); int numRemark = 0, numHet = 0, numHelix = 0, numSheet = 0, numTurn = 0, numSite = 0, numXform = 0, numCoord = 0, numTer = 0, numConect = 0, numSeq = 0; WriteTitle(os, db); int savedLineCount = fb.get_line_count(); // numRemark = WriteRemarks(pdbFile, db); WriteRemarks(os, db); numRemark = fb.get_line_count() - savedLineCount; numSeq = WritePrimaryStructure(os, db); numHet = WriteHeterogen(os, db); std::tie(numHelix, numSheet) = WriteSecondaryStructure(os, db); WriteConnectivity(os, db); numSite = WriteMiscellaneousFeatures(os, db); WriteCrystallographic(os, db); numXform = WriteCoordinateTransformation(os, db); std::tie(numCoord, numTer) = WriteCoordinate(os, db); os << cif::format("MASTER %5d 0%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", numRemark, numHet, numHelix, numSheet, numTurn, numSite, numXform, numCoord, numTer, numConect, numSeq) << '\n' << "END\n"; } void write(const std::filesystem::path &p, const datablock &db) { gzio::ofstream out(p); bool writePDB = false; if (p.extension() == ".gz") writePDB = iequals(p.stem().extension().string(), ".pdb"); else writePDB = iequals(p.extension().string(), ".pdb"); if (writePDB) write(out, db); else db.write(out); } } // namespace cif::pdb