Require boost 1.84 or higher for numpy 2

Fix interface to be more compliant with standard concepts
This commit is contained in:
Maarten L. Hekkelman
2026-01-27 11:39:55 +01:00
parent ab92b66349
commit 171ca99ad3
9 changed files with 198 additions and 148 deletions

22
.clang-format Normal file
View File

@@ -0,0 +1,22 @@
BasedOnStyle: LLVM
UseTab: AlignWithSpaces
IndentWidth: 4
TabWidth: 4
BreakBeforeBraces: Allman
ColumnLimit: 0
NamespaceIndentation: Inner
FixNamespaceComments: true
AccessModifierOffset: -2
AllowShortCaseLabelsOnASingleLine: true
IndentCaseLabels: true
BreakConstructorInitializers: BeforeComma
BraceWrapping:
BeforeLambdaBody: false
AlignAfterOpenBracket: DontAlign
Cpp11BracedListStyle: false
IncludeBlocks: Regroup
LambdaBodyIndentation: Signature
AllowShortLambdasOnASingleLine: Inline
EmptyLineBeforeAccessModifier: LogicalBlock
IndentPPDirectives: AfterHash
PPIndentWidth: 1

18
.clang-tidy Normal file
View File

@@ -0,0 +1,18 @@
Checks: '-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
cert-*,
modernize*,
-modernize-use-trailing-return-type,
-modernize-avoid-c-arrays,
-modernize-use-designated-initializers,
performance
'
# HeaderFilterRegex: '.*'
ExcludeHeaderFilterRegex: 'Eigen|Eigen/Eigenvalues|eigen3/Eigen/Eigenvalues|sqlite3.h'
CheckOptions:
- key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
value: false
- key: bugprone-narrowing-conversions.WarnOnIntegerToFloatingPointNarrowingConversion
value: false

View File

@@ -39,7 +39,7 @@ jobs:
- name: Install Catch2 Ubuntu
if: matrix.os == 'ubuntu-latest'
run: >
sudo apt-get update && sudo apt-get install catch2 libpython3-all-dev libboost1.83-all-dev
sudo apt-get update && sudo apt-get install catch2 libpython3-all-dev libboost1.84-all-dev
- name: setup python
uses: actions/setup-python@v5

View File

@@ -32,6 +32,8 @@
#include <cif++.hpp>
#include <filesystem>
#include <iterator>
#include <ranges>
class dssp
{
@@ -105,7 +107,7 @@ class dssp
dssp(const dssp &) = delete;
dssp &operator=(const dssp &) = delete;
statistics get_statistics() const;
[[nodiscard]] statistics get_statistics() const;
class iterator;
using res_iterator = typename std::vector<residue>::iterator;
@@ -120,37 +122,37 @@ class dssp
residue_info &operator=(const residue_info &rhs) = default;
explicit operator bool() const { return not empty(); }
bool empty() const { return m_impl == nullptr; }
[[nodiscard]] bool empty() const { return m_impl == nullptr; }
std::string asym_id() const;
int seq_id() const;
std::string alt_id() const;
std::string compound_id() const;
char compound_letter() const; // Single letter for residue compound type, or 'X' in case it is not known
[[nodiscard]] std::string asym_id() const;
[[nodiscard]] int seq_id() const;
[[nodiscard]] std::string alt_id() const;
[[nodiscard]] std::string compound_id() const;
[[nodiscard]] char compound_letter() const; // Single letter for residue compound type, or 'X' in case it is not known
std::string auth_asym_id() const;
int auth_seq_id() const;
[[nodiscard]] std::string auth_asym_id() const;
[[nodiscard]] int auth_seq_id() const;
std::string pdb_strand_id() const;
int pdb_seq_num() const;
std::string pdb_ins_code() const;
[[nodiscard]] std::string pdb_strand_id() const;
[[nodiscard]] int pdb_seq_num() const;
[[nodiscard]] std::string pdb_ins_code() const;
std::optional<float> alpha() const;
std::optional<float> kappa() const;
std::optional<float> phi() const;
std::optional<float> psi() const;
std::optional<float> tco() const;
std::optional<float> omega() const;
[[nodiscard]] std::optional<float> alpha() const;
[[nodiscard]] std::optional<float> kappa() const;
[[nodiscard]] std::optional<float> phi() const;
[[nodiscard]] std::optional<float> psi() const;
[[nodiscard]] std::optional<float> tco() const;
[[nodiscard]] std::optional<float> omega() const;
bool is_pre_pro() const;
bool is_cis() const { return std::abs(omega().value_or(360)) < 30.0f; }
[[nodiscard]] bool is_pre_pro() const;
[[nodiscard]] bool is_cis() const { return std::abs(omega().value_or(360)) < 30.0f; }
float chiral_volume() const;
[[nodiscard]] float chiral_volume() const;
std::size_t nr_of_chis() const;
float chi(std::size_t index) const;
[[nodiscard]] std::size_t nr_of_chis() const;
[[nodiscard]] float chi(std::size_t index) const;
std::vector<float> chis() const
[[nodiscard]] std::vector<float> chis() const
{
std::vector<float> result;
for (size_t i = 0; i < nr_of_chis(); ++i)
@@ -158,34 +160,34 @@ class dssp
return result;
}
std::tuple<float, float, float> ca_location() const;
[[nodiscard]] std::tuple<float, float, float> ca_location() const;
chain_break_type chain_break() const;
[[nodiscard]] chain_break_type chain_break() const;
/// \brief the internal number in DSSP
int nr() const;
[[nodiscard]] int nr() const;
structure_type type() const;
[[nodiscard]] structure_type type() const;
int ssBridgeNr() const;
[[nodiscard]] int ssBridgeNr() const;
helix_position_type helix(helix_type helixType) const;
[[nodiscard]] helix_position_type helix(helix_type helixType) const;
bool is_alpha_helix_end_before_start() const;
[[nodiscard]] bool is_alpha_helix_end_before_start() const;
bool bend() const;
[[nodiscard]] bool bend() const;
double accessibility() const;
[[nodiscard]] double accessibility() const;
/// \brief returns resinfo, ladder and parallel
std::tuple<residue_info, int, bool> bridge_partner(int i) const;
[[nodiscard]] std::tuple<residue_info, int, bool> bridge_partner(int i) const;
int sheet() const;
int strand() const;
[[nodiscard]] int sheet() const;
[[nodiscard]] int strand() const;
/// \brief return resinfo and the energy of the bond
std::tuple<residue_info, double> acceptor(int i) const;
std::tuple<residue_info, double> donor(int i) const;
[[nodiscard]] std::tuple<residue_info, double> acceptor(int i) const;
[[nodiscard]] std::tuple<residue_info, double> donor(int i) const;
/// \brief Simple compare equals
bool operator==(const residue_info &rhs) const
@@ -196,7 +198,7 @@ class dssp
/// \brief Returns \result true if there is a bond between two residues
friend bool test_bond(residue_info const &a, residue_info const &b);
residue_info next() const;
[[nodiscard]] residue_info next() const;
private:
residue_info(residue *res)
@@ -211,17 +213,18 @@ class dssp
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = residue_info;
using value_type = const residue_info;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
iterator() = default;
iterator(const iterator &i) = default;
iterator(residue *res);
iterator &operator=(const iterator &i) = default;
reference operator*() { return m_current; }
pointer operator->() { return &m_current; }
reference operator*() const { return m_current; }
pointer operator->() const { return &m_current; }
iterator &operator++();
iterator operator++(int)
@@ -246,17 +249,22 @@ class dssp
residue_info m_current;
};
static_assert(std::input_iterator<iterator>);
using value_type = residue_info;
// To access residue info by key, i.e. LabelAsymID and LabelSeqID
using key_type = std::tuple<std::string, int>;
iterator begin() const;
iterator end() const;
[[nodiscard]] iterator begin() const;
[[nodiscard]] iterator end() const;
[[nodiscard]] iterator cbegin() const;
[[nodiscard]] iterator cend() const;
residue_info operator[](const key_type &key) const;
bool empty() const { return begin() == end(); }
[[nodiscard]] bool empty() const { return begin() == end(); }
// --------------------------------------------------------------------
// Writing out the data, either in legacy format...
@@ -276,8 +284,10 @@ class dssp
AUTHOR
};
std::string get_pdb_header_line(pdb_record_type pdb_record) const;
[[nodiscard]] std::string get_pdb_header_line(pdb_record_type pdb_record) const;
private:
struct DSSP_impl *m_impl;
};
static_assert(std::ranges::input_range<dssp>);

View File

@@ -25,14 +25,13 @@
*/
#include "dssp-io.hpp"
#include "revision.hpp"
#include <algorithm>
#include <cif++.hpp>
#include <cif++/dictionary_parser.hpp>
#include <exception>
#include <filesystem>
#include <fstream>
#include <format>
#include <iostream>
// --------------------------------------------------------------------
@@ -121,20 +120,20 @@ std::string ResidueToDSSPLine(const dssp::residue_info &info)
if (acceptor)
{
auto d = acceptor.nr() - info.nr();
NHO[i] = cif::format("{:d},{:3.1f}", d, acceptorE);
NHO[i] = std::format("{:d},{:3.1f}", d, acceptorE);
}
if (donor)
{
auto d = donor.nr() - info.nr();
ONH[i] = cif::format("{:d},{:3.1f}", d, donorE);
ONH[i] = std::format("{:d},{:3.1f}", d, donorE);
}
}
// auto ca = residue.atomByID("CA");
auto const &[cax, cay, caz] = residue.ca_location();
return cif::format("{:5d}{:5d}{:1.1s}{:1.1s} {:1c} {:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:4d}{:4d}{:1c}{:4.0f} {:>11s}{:>11s}{:>11s}{:>11s} {:6.3f}{:6.1f}{:6.1f}{:6.1f}{:6.1f} {:6.1f} {:6.1f} {:6.1f}",
return std::format("{:5d}{:5d}{:1.1s}{:1.1s} {:1c} {:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:1c}{:4d}{:4d}{:1c}{:4.0f} {:>11s}{:>11s}{:>11s}{:>11s} {:6.3f}{:6.1f}{:6.1f}{:6.1f}{:6.1f} {:6.1f} {:6.1f} {:6.1f}",
info.nr(), residue.pdb_seq_num(), residue.pdb_ins_code(), residue.pdb_strand_id(), code,
ss, helix[3], helix[0], helix[1], helix[2], bend, chirality, bridgelabel[0], bridgelabel[1],
bp[0], bp[1], sheet, floor(info.accessibility() + 0.5),
@@ -167,40 +166,40 @@ void writeDSSP(const dssp &dssp, std::ostream &os)
<< dssp.get_pdb_header_line(dssp::pdb_record_type::SOURCE) << '.' << std::endl
<< dssp.get_pdb_header_line(dssp::pdb_record_type::AUTHOR) << '.' << std::endl;
os << cif::format("{:5d}{:3d}{:3d}{:3d}{:3d} TOTAL NUMBER OF RESIDUES, NUMBER OF CHAINS, NUMBER OF SS-BRIDGES(TOTAL,INTRACHAIN,INTERCHAIN) .",
os << std::format("{:5d}{:3d}{:3d}{:3d}{:3d} TOTAL NUMBER OF RESIDUES, NUMBER OF CHAINS, NUMBER OF SS-BRIDGES(TOTAL,INTRACHAIN,INTERCHAIN) .",
stats.count.residues, stats.count.chains, stats.count.SS_bridges, stats.count.intra_chain_SS_bridges, (stats.count.SS_bridges - stats.count.intra_chain_SS_bridges))
<< std::endl;
os << cif::format("{:8.1f} ACCESSIBLE SURFACE OF PROTEIN (ANGSTROM**2) .", stats.accessible_surface) << std::endl;
os << std::format("{:8.1f} ACCESSIBLE SURFACE OF PROTEIN (ANGSTROM**2) .", stats.accessible_surface) << std::endl;
// hydrogenbond summary
os << cif::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(J) , SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds, (stats.count.H_bonds * 100.0 / stats.count.residues)) << std::endl;
os << std::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(J) , SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds, (stats.count.H_bonds * 100.0 / stats.count.residues)) << std::endl;
os << cif::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS IN PARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds_in_parallel_bridges, (stats.count.H_bonds_in_parallel_bridges * 100.0 / stats.count.residues)) << std::endl;
os << std::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS IN PARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds_in_parallel_bridges, (stats.count.H_bonds_in_parallel_bridges * 100.0 / stats.count.residues)) << std::endl;
os << cif::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS IN ANTIPARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds_in_antiparallel_bridges, (stats.count.H_bonds_in_antiparallel_bridges * 100.0 / stats.count.residues)) << std::endl;
os << std::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS IN ANTIPARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES .", stats.count.H_bonds_in_antiparallel_bridges, (stats.count.H_bonds_in_antiparallel_bridges * 100.0 / stats.count.residues)) << std::endl;
for (int k = 0; k < 11; ++k)
os << cif::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(I{:1c}{:1d}), SAME NUMBER PER 100 RESIDUES .", stats.count.H_Bonds_per_distance[k], (stats.count.H_Bonds_per_distance[k] * 100.0 / stats.count.residues), (k - 5 < 0 ? '-' : '+'), abs(k - 5)) << std::endl;
os << std::format("{:5d}{:5.1f} TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(I{:1c}{:1d}), SAME NUMBER PER 100 RESIDUES .", stats.count.H_Bonds_per_distance[k], (stats.count.H_Bonds_per_distance[k] * 100.0 / stats.count.residues), (k - 5 < 0 ? '-' : '+'), abs(k - 5)) << std::endl;
// histograms...
os << " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 *** HISTOGRAMS OF *** ." << std::endl;
for (auto hi : stats.histogram.residues_per_alpha_helix)
os << cif::format("{:3d}", hi);
os << std::format("{:3d}", hi);
os << " RESIDUES PER ALPHA HELIX ." << std::endl;
for (auto hi : stats.histogram.parallel_bridges_per_ladder)
os << cif::format("{:3d}", hi);
os << std::format("{:3d}", hi);
os << " PARALLEL BRIDGES PER LADDER ." << std::endl;
for (auto hi : stats.histogram.antiparallel_bridges_per_ladder)
os << cif::format("{:3d}", hi);
os << std::format("{:3d}", hi);
os << " ANTIPARALLEL BRIDGES PER LADDER ." << std::endl;
for (auto hi : stats.histogram.ladders_per_sheet)
os << cif::format("{:3d}", hi);
os << std::format("{:3d}", hi);
os << " LADDERS PER SHEET ." << std::endl;
// per residue information
@@ -214,7 +213,7 @@ void writeDSSP(const dssp &dssp, std::ostream &os)
// can be the transition to a different chain, or missing residues in the current chain
if (ri.nr() != last + 1)
os << cif::format("{:5d} !{:1c} 0 0 0 0, 0.0 0, 0.0 0, 0.0 0, 0.0 0.000 360.0 360.0 360.0 360.0 0.0 0.0 0.0",
os << std::format("{:5d} !{:1c} 0 0 0 0, 0.0 0, 0.0 0, 0.0 0, 0.0 0.000 360.0 360.0 360.0 360.0 0.0 0.0 0.0",
(last + 1), (ri.chain_break() == dssp::chain_break_type::NewChain ? '*' : ' '))
<< std::endl;
@@ -329,9 +328,8 @@ void writeSheets(cif::datablock &db, const dssp &dssp)
// clean up old info first
for (auto sheet_cat : { "struct_sheet", "struct_sheet_order", "struct_sheet_range", "struct_sheet_hbond", "pdbx_struct_sheet_hbond" })
db.erase(remove_if(db.begin(), db.end(), [sheet_cat](const cif::category &cat)
{ return cat.name() == sheet_cat; }),
db.end());
std::erase_if(db, [sheet_cat](const cif::category &cat)
{ return cat.name() == sheet_cat; });
// create a list of strands, based on the SS info in DSSP. Store sheet number along with the strand.
@@ -370,7 +368,7 @@ void writeSheets(cif::datablock &db, const dssp &dssp)
std::string strandID = cif::cif_id_for_number(strand.front().strand() - 1);
std::sort(strand.begin(), strand.end(), [](dssp::residue_info const &a, dssp::residue_info const &b)
std::ranges::sort(strand, [](dssp::residue_info const &a, dssp::residue_info const &b)
{ return a.nr() < b.nr(); });
auto &beg = strand.front();
@@ -458,7 +456,7 @@ void writeLadders(cif::datablock &db, const dssp &dssp)
}
}
std::sort(ladders.begin(), ladders.end());
std::ranges::sort(ladders, std::less<>());
auto &dssp_struct_ladder = db["dssp_struct_ladder"];
@@ -746,7 +744,7 @@ void annotateDSSP(cif::datablock &db, const dssp &dssp, bool writeOther, bool wr
if (audit_conform.empty())
{
auto &cf = cif::validator_factory::instance();
cf.get("mmcif_pdbx.dic").fill_audit_conform(audit_conform);
cf.get("mmcif_pdbx.dic")->fill_audit_conform(audit_conform);
}
audit_conform.erase(cif::key("dict_name") == "dssp-extension.dic");
@@ -771,10 +769,10 @@ void annotateDSSP(cif::datablock &db, const dssp &dssp, bool writeOther, bool wr
"dssp_statistics",
"dssp_statistics_hbond",
"dssp_statistics_histogram",
"dssp_struct_summary"
})
"dssp_struct_summary" })
{
db.erase(std::remove_if(db.begin(), db.end(), [cat] (cif::category &c) { return c.name() == cat; }), db.end());
std::erase_if(db, [cat](cif::category &c)
{ return c.name() == cat; });
}
if (writeNewFormat)

View File

@@ -30,8 +30,11 @@
#include "dssp-io.hpp"
#include <algorithm>
#include <deque>
#include <iomanip>
#include <memory>
#include <numbers>
#include <numeric>
#include <thread>
@@ -49,7 +52,7 @@ using chain_break_type = dssp::chain_break_type;
// --------------------------------------------------------------------
const double
kPI = 3.141592653589793238462643383279502884;
kPI = std::numbers::pi;
struct point
{
@@ -263,7 +266,6 @@ struct dssp::residue
: mPDBStrandID(pdb_strand_id)
, mPDBSeqNum(pdb_seq_num)
, mPDBInsCode(pdb_ins_code)
, mChainBreak(chain_break_type::None)
, m_model_nr(model_nr)
{
// update the box containing all atoms
@@ -393,7 +395,7 @@ struct dssp::residue
auto pc = mPrev->mC;
auto po = mPrev->mO;
float CODistance = static_cast<float>(distance(pc, po));
auto CODistance = static_cast<float>(distance(pc, po));
mH.mX += (pc.mX - po.mX) / CODistance;
mH.mY += (pc.mY - po.mY) / CODistance;
@@ -402,7 +404,7 @@ struct dssp::residue
}
void SetSecondaryStructure(structure_type inSS) { mSecondaryStructure = inSS; }
structure_type GetSecondaryStructure() const { return mSecondaryStructure; }
[[nodiscard]] structure_type GetSecondaryStructure() const { return mSecondaryStructure; }
void SetBetaPartner(uint32_t n, residue &inResidue, uint32_t inLadder, bool inParallel)
{
@@ -413,38 +415,38 @@ struct dssp::residue
mBetaPartner[n].parallel = inParallel;
}
bridge_partner GetBetaPartner(uint32_t n) const
[[nodiscard]] bridge_partner GetBetaPartner(uint32_t n) const
{
assert(n == 0 or n == 1);
return mBetaPartner[n];
}
void SetSheet(uint32_t inSheet) { mSheet = inSheet; }
uint32_t GetSheet() const { return mSheet; }
[[nodiscard]] uint32_t GetSheet() const { return mSheet; }
void SetStrand(uint32_t inStrand) { mStrand = inStrand; }
uint32_t GetStrand() const { return mStrand; }
[[nodiscard]] uint32_t GetStrand() const { return mStrand; }
bool IsBend() const { return mBend; }
[[nodiscard]] bool IsBend() const { return mBend; }
void SetBend(bool inBend) { mBend = inBend; }
helix_position_type GetHelixFlag(helix_type helixType) const
[[nodiscard]] helix_position_type GetHelixFlag(helix_type helixType) const
{
size_t stride = static_cast<size_t>(helixType);
auto stride = static_cast<size_t>(helixType);
assert(stride < 4);
return mHelixFlags[stride];
}
bool IsHelixStart(helix_type helixType) const
[[nodiscard]] bool IsHelixStart(helix_type helixType) const
{
size_t stride = static_cast<size_t>(helixType);
auto stride = static_cast<size_t>(helixType);
assert(stride < 4);
return mHelixFlags[stride] == helix_position_type::Start or mHelixFlags[stride] == helix_position_type::StartAndEnd;
}
void SetHelixFlag(helix_type helixType, helix_position_type inHelixFlag)
{
size_t stride = static_cast<size_t>(helixType);
auto stride = static_cast<size_t>(helixType);
assert(stride < 4);
mHelixFlags[stride] = inHelixFlag;
}
@@ -456,7 +458,7 @@ struct dssp::residue
mSSBridgeNr = inBridgeNr;
}
uint8_t GetSSBridgeNr() const
[[nodiscard]] uint8_t GetSSBridgeNr() const
{
if (mType != kCysteine)
throw std::runtime_error("Only cysteine residues can form sulphur bridges");
@@ -466,7 +468,7 @@ struct dssp::residue
float CalculateSurface(const std::vector<residue> &inResidues);
float CalculateSurface(const point &inAtom, float inRadius, const std::vector<residue *> &inNeighbours);
bool AtomIntersectsBox(const point &atom, float inRadius) const
[[nodiscard]] bool AtomIntersectsBox(const point &atom, float inRadius) const
{
return atom.mX + inRadius >= mBox[0].mX and
atom.mX - inRadius <= mBox[1].mX and
@@ -572,9 +574,9 @@ class accumulator
double radius;
double distance;
bool operator<(const candidate &rhs) const
auto operator<=>(const candidate &rhs) const
{
return distance < rhs.distance;
return distance <=> rhs.distance;
}
};
@@ -593,13 +595,13 @@ class accumulator
candidate c = { b - a, r * r, distance };
m_x.push_back(c);
push_heap(m_x.begin(), m_x.end());
std::ranges::push_heap(m_x, std::less<>());
}
}
void sort()
{
sort_heap(m_x.begin(), m_x.end());
std::ranges::sort_heap(m_x, std::less<>());
}
std::vector<candidate> m_x;
@@ -611,9 +613,9 @@ class MSurfaceDots
public:
static MSurfaceDots &Instance();
size_t size() const { return mPoints.size(); }
[[nodiscard]] size_t size() const { return mPoints.size(); }
const point &operator[](size_t inIx) const { return mPoints[inIx]; }
double weight() const { return mWeight; }
[[nodiscard]] double weight() const { return mWeight; }
private:
MSurfaceDots(int32_t inN);
@@ -634,14 +636,14 @@ MSurfaceDots::MSurfaceDots(int32_t N)
{
auto P = 2 * N + 1;
const float kGoldenRatio = (1 + std::sqrt(5.0f)) / 2;
const float kGoldenRatio = std::numbers::phi_v<float>;
mWeight = (4 * kPI) / P;
for (auto i = -N; i <= N; ++i)
{
float lat = std::asin((2.0f * i) / P);
float lon = static_cast<float>(std::fmod(i, kGoldenRatio) * 2 * kPI / kGoldenRatio);
auto lon = static_cast<float>(std::fmod(i, kGoldenRatio) * 2 * kPI / kGoldenRatio);
mPoints.emplace_back(point{ std::sin(lon) * std::cos(lat), std::cos(lon) * std::cos(lat), std::sin(lat) });
}
@@ -778,8 +780,8 @@ double CalculateHBondEnergy(residue &inDonor, residue &inAcceptor)
void CalculateHBondEnergies(std::vector<residue> &inResidues, std::vector<std::tuple<uint32_t, uint32_t>> &q)
{
std::unique_ptr<cif::progress_bar> progress;
if (cif::VERBOSE == 0 or cif::VERBOSE == 1)
progress.reset(new cif::progress_bar(q.size(), "calculate hbond energies"));
if (cif::VERBOSE >= 0)
progress = std::make_unique<cif::progress_bar>(q.size(), "calculate hbond energies");
for (const auto &[i, j] : q)
{
@@ -873,8 +875,8 @@ void CalculateBetaSheets(std::vector<residue> &inResidues, statistics &stats, st
// std::cerr << "calculating beta sheets" << std::endl;
std::unique_ptr<cif::progress_bar> progress;
if (cif::VERBOSE == 0 or cif::VERBOSE == 1)
progress.reset(new cif::progress_bar(q.size(), "calculate beta sheets"));
if (cif::VERBOSE >= 0)
progress = std::make_unique<cif::progress_bar>(q.size(), "calculate beta sheets");
// Calculate Bridges
std::vector<bridge> bridges;
@@ -929,7 +931,7 @@ void CalculateBetaSheets(std::vector<residue> &inResidues, statistics &stats, st
}
// extend ladders
std::sort(bridges.begin(), bridges.end());
std::ranges::sort(bridges, std::less<>());
for (uint32_t i = 0; i < bridges.size(); ++i)
{
@@ -1069,7 +1071,7 @@ void CalculateBetaSheets(std::vector<residue> &inResidues, statistics &stats, st
{
stats.count.H_bonds_in_parallel_bridges += bridge.i.back() - bridge.i.front() + 2;
std::deque<uint32_t>::iterator j = bridge.j.begin();
auto j = bridge.j.begin();
for (uint32_t i : bridge.i)
inResidues[i].SetBetaPartner(betai, inResidues[*j++], bridge.ladder, true);
@@ -1081,7 +1083,7 @@ void CalculateBetaSheets(std::vector<residue> &inResidues, statistics &stats, st
{
stats.count.H_bonds_in_antiparallel_bridges += bridge.i.back() - bridge.i.front() + 2;
std::deque<uint32_t>::reverse_iterator j = bridge.j.rbegin();
auto j = bridge.j.rbegin();
for (uint32_t i : bridge.i)
inResidues[i].SetBetaPartner(betai, inResidues[*j++], bridge.ladder, false);
@@ -1390,7 +1392,7 @@ struct DSSP_impl
auto findRes(const std::string &asymID, int seqID)
{
return std::find_if(mResidues.begin(), mResidues.end(), [&](auto &r)
return std::ranges::find_if(mResidues, [&](auto &r)
{ return r.mAsymID == asymID and r.mSeqID == seqID; });
}
@@ -1454,9 +1456,8 @@ DSSP_impl::DSSP_impl(const cif::datablock &db, int model_nr, int min_poly_prolin
for (auto &residue : mResidues)
residue.finish();
mResidues.erase(std::remove_if(mResidues.begin(), mResidues.end(), [](const dssp::residue &r)
{ return not r.mComplete; }),
mResidues.end());
std::erase_if(mResidues, [](const dssp::residue &r)
{ return not r.mComplete; });
mStats.count.chains = 1;
chain_break_type brk = chain_break_type::NewChain;
@@ -1592,8 +1593,8 @@ void DSSP_impl::calculateSecondaryStructure()
cAlphas.emplace_back(r.mCAlpha);
std::unique_ptr<cif::progress_bar> progress;
if (cif::VERBOSE == 0 or cif::VERBOSE == 1)
progress.reset(new cif::progress_bar((mResidues.size() * (mResidues.size() - 1)) / 2, "calculate distances"));
if (cif::VERBOSE >= 0)
progress = std::make_unique<cif::progress_bar>((mResidues.size() * (mResidues.size() - 1)) / 2, "calculate distances");
// Calculate the HBond energies
std::vector<std::tuple<uint32_t, uint32_t>> near;
@@ -1646,7 +1647,7 @@ void DSSP_impl::calculateSecondaryStructure()
auto id = r.mAsymID + ':' + std::to_string(r.mSeqID) + '/' + r.mCompoundID;
std::cerr << id << std::string(12 - id.length(), ' ')
<< char(r.mSecondaryStructure) << ' '
<< static_cast<char>(r.mSecondaryStructure) << ' '
<< helix
<< std::endl;
}
@@ -1784,8 +1785,8 @@ std::string DSSP_impl::GetPDBHEADERLine()
char header[] =
"HEADER xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDDDDDDDDD IIII";
std::copy(keywords.begin(), keywords.end(), header + 10);
std::copy(date.begin(), date.end(), header + 50);
std::ranges::copy(keywords, header + 10);
std::ranges::copy(date, header + 50);
std::string id = mDB.name();
if (id.length() < 4)
@@ -1793,7 +1794,7 @@ std::string DSSP_impl::GetPDBHEADERLine()
else if (id.length() > 4)
id.erase(id.begin() + 4, id.end());
std::copy(id.begin(), id.end(), header + 62);
std::ranges::copy(id, header + 62);
return FixStringLength(header);
}
@@ -1809,45 +1810,45 @@ std::string DSSP_impl::GetPDBCOMPNDLine()
for (auto r : mDB["entity"].find("type"_key == "polymer"))
{
std::string entityID = r["id"].as<std::string>();
auto entityID = r["id"].as<std::string>();
++molID;
cmpnd.push_back("MOL_ID: " + std::to_string(molID));
std::string molecule = r["pdbx_description"].as<std::string>();
auto molecule = r["pdbx_description"].as<std::string>();
cmpnd.push_back("MOLECULE: " + molecule);
auto poly = mDB["entity_poly"].find("entity_id"_key == entityID);
if (not poly.empty())
{
std::string chains = poly.front()["pdbx_strand_id"].as<std::string>();
auto chains = poly.front()["pdbx_strand_id"].as<std::string>();
cif::replace_all(chains, ",", ", ");
cmpnd.push_back("CHAIN: " + chains);
}
std::string fragment = r["pdbx_fragment"].as<std::string>();
auto fragment = r["pdbx_fragment"].as<std::string>();
if (not fragment.empty())
cmpnd.push_back("FRAGMENT: " + fragment);
for (auto sr : mDB["entity_name_com"].find("entity_id"_key == entityID))
{
std::string syn = sr["name"].as<std::string>();
auto syn = sr["name"].as<std::string>();
if (not syn.empty())
cmpnd.push_back("SYNONYM: " + syn);
}
std::string mutation = r["pdbx_mutation"].as<std::string>();
auto mutation = r["pdbx_mutation"].as<std::string>();
if (not mutation.empty())
cmpnd.push_back("MUTATION: " + mutation);
std::string ec = r["pdbx_ec"].as<std::string>();
auto ec = r["pdbx_ec"].as<std::string>();
if (not ec.empty())
cmpnd.push_back("EC: " + ec);
if (r["src_method"] == "man" or r["src_method"] == "syn")
cmpnd.push_back("ENGINEERED: YES");
cmpnd.emplace_back("ENGINEERED: YES");
std::string details = r["details"].as<std::string>();
auto details = r["details"].as<std::string>();
if (not details.empty())
cmpnd.push_back("OTHER_DETAILS: " + details);
}
@@ -1869,13 +1870,13 @@ std::string DSSP_impl::GetPDBSOURCELine()
if (r["type"] != "polymer")
continue;
std::string entityID = r["id"].as<std::string>();
auto entityID = r["id"].as<std::string>();
++molID;
source.push_back("MOL_ID: " + std::to_string(molID));
if (r["src_method"] == "syn")
source.push_back("SYNTHETIC: YES");
source.emplace_back("SYNTHETIC: YES");
auto &gen = mDB["entity_src_gen"];
const std::pair<const char *, const char *> kGenSourceMapping[] = {
@@ -1905,7 +1906,7 @@ std::string DSSP_impl::GetPDBSOURCELine()
std::string cname, sname;
tie(cname, sname) = m;
std::string s = gr[cname].as<std::string>();
auto s = gr[cname].as<std::string>();
if (not s.empty())
source.push_back(sname + ": " + s);
}
@@ -1930,7 +1931,7 @@ std::string DSSP_impl::GetPDBSOURCELine()
std::string cname, sname;
tie(cname, sname) = m;
std::string s = nr[cname].as<std::string>();
auto s = nr[cname].as<std::string>();
if (not s.empty())
source.push_back(sname + ": " + s);
}
@@ -2186,7 +2187,7 @@ std::tuple<dssp::residue_info, double> dssp::residue_info::donor(int i) const
dssp::residue_info dssp::residue_info::next() const
{
return residue_info(m_impl ? m_impl->mNext : nullptr);
return { m_impl ? m_impl->mNext : nullptr };
}
// --------------------------------------------------------------------
@@ -2220,7 +2221,8 @@ dssp::dssp(const cif::datablock &db, int model_nr, int min_poly_proline_stretch,
{
if (calculateSurfaceAccessibility)
{
std::thread t(std::bind(&DSSP_impl::calculateSurface, m_impl));
std::thread t([this]
{ m_impl->calculateSurface(); });
m_impl->calculateSecondaryStructure();
t.join();
}
@@ -2235,7 +2237,7 @@ dssp::~dssp()
dssp::iterator dssp::begin() const
{
return iterator(m_impl->mResidues.empty() ? nullptr : m_impl->mResidues.data());
return { m_impl->mResidues.empty() ? nullptr : m_impl->mResidues.data() };
}
dssp::iterator dssp::end() const
@@ -2248,12 +2250,12 @@ dssp::iterator dssp::end() const
res += m_impl->mResidues.size();
}
return iterator(res);
return { res };
}
dssp::residue_info dssp::operator[](const key_type &key) const
{
auto i = std::find_if(begin(), end(),
auto i = std::ranges::find_if(*this,
[key](const residue_info &res)
{ return res.asym_id() == std::get<0>(key) and res.seq_id() == std::get<1>(key); });

View File

@@ -29,7 +29,9 @@ if(CMAKE_VERSION GREATER_EQUAL 3.30)
endif()
find_package(Python REQUIRED COMPONENTS Interpreter Development)
find_package(Boost 1.83 QUIET COMPONENTS python)
# Boost 1.84 is required since it contains code required to use numpy 2.x
find_package(Boost 1.84 QUIET COMPONENTS python)
if(NOT Boost_FOUND)
# boost is a huge project and directly downloading the 'alternate release'

View File

@@ -2,6 +2,7 @@
#include <Python.h>
#include <dssp.hpp>
#include <memory>
struct statistics_wrapper
{
@@ -42,7 +43,7 @@ class dssp_wrapper
std::istream is(&buffer);
auto f = cif::pdb::read(is);
m_dssp.reset(new dssp(f.front(), model_nr, min_poly_proline_stretch_length, calculateSurfaceAccessibility));
m_dssp = std::make_shared<dssp>(f.front(), model_nr, min_poly_proline_stretch_length, calculateSurfaceAccessibility);
}
dssp_wrapper(const dssp_wrapper &) = default;
@@ -83,7 +84,7 @@ class dssp_wrapper
iterator(const iterator &i) = default;
iterator &operator=(const iterator &i) = default;
reference operator*() { return residue_info_handle(m_current); }
reference operator*() { return {m_current}; }
pointer operator->() { return &m_current; }
iterator &operator++()
@@ -126,12 +127,12 @@ class dssp_wrapper
// Custom exceptions
struct AttributeError : std::exception
{
const char *what() const throw() { return "AttributeError exception"; }
[[nodiscard]] const char *what() const noexcept override { return "AttributeError exception"; }
};
struct TypeError : std::exception
{
const char *what() const throw() { return "TypeError exception"; }
[[nodiscard]] const char *what() const noexcept override { return "TypeError exception"; }
};
// Set python exceptions

View File

@@ -24,16 +24,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdexcept>
#define CATCH_CONFIG_RUNNER
#include <catch2/catch_all.hpp>
#include "../libdssp/src/dssp-io.hpp"
#include "../src/revision.hpp"
#include "dssp.hpp"
#include <catch2/catch_all.hpp>
#include <cif++/dictionary_parser.hpp>
namespace fs = std::filesystem;
@@ -56,10 +53,12 @@ cif::file operator""_cf(const char *text, size_t length)
// --------------------------------------------------------------------
std::filesystem::path gTestDir = std::filesystem::current_path();
std::filesystem::path gTestDir;
int main(int argc, char *argv[])
{
gTestDir = std::filesystem::current_path();
Catch::Session session; // There must be exactly one instance
// Build a new parser on top of Catch2's
@@ -156,8 +155,6 @@ TEST_CASE("ut_mmcif_2")
dssp dssp(f.front(), 1, 3, true);
std::stringstream test;
dssp.annotate(f.front(), true, true);
cif::file rf(gTestDir / "1cbs-dssp.cif");
@@ -166,12 +163,12 @@ TEST_CASE("ut_mmcif_2")
auto &db2 = rf.front();
db1["software"].erase("name"_key == "dssp");
db1.erase(find_if(db1.begin(), db1.end(), [](cif::category &cat)
{ return cat.name() == "audit_conform"; }));
std::erase_if(db1, [](cif::category &cat)
{ return cat.name() == "audit_conform"; });
db2["software"].erase("name"_key == "dssp");
db2.erase(find_if(db2.begin(), db2.end(), [](cif::category &cat)
{ return cat.name() == "audit_conform"; }));
std::erase_if(db2, [](cif::category &cat)
{ return cat.name() == "audit_conform"; });
// generate some output on different files:
// cif::VERBOSE = 2;