Files
dssp/libdssp/include/dssp.hpp
Maarten L. Hekkelman 171ca99ad3 Require boost 1.84 or higher for numpy 2
Fix interface to be more compliant with standard concepts
2026-01-27 11:39:55 +01:00

293 lines
7.9 KiB
C++

/*-
* 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.
*/
#pragma once
/// \file DSSP.hpp
/// Calculate DSSP-like secondary structure information.
#include <cif++.hpp>
#include <filesystem>
#include <iterator>
#include <ranges>
class dssp
{
public:
struct residue;
enum class structure_type : char
{
Loop = ' ',
Alphahelix = 'H',
Betabridge = 'B',
Strand = 'E',
Helix_3 = 'G',
Helix_5 = 'I',
Helix_PPII = 'P',
Turn = 'T',
Bend = 'S'
};
enum class helix_type
{
_3_10,
alpha,
pi,
pp
};
enum class helix_position_type
{
None,
Start,
End,
StartAndEnd,
Middle
};
static constexpr size_t kHistogramSize = 30;
struct statistics
{
struct
{
uint32_t residues, chains, SS_bridges, intra_chain_SS_bridges, H_bonds;
uint32_t H_bonds_in_antiparallel_bridges, H_bonds_in_parallel_bridges;
uint32_t H_Bonds_per_distance[11];
} count;
double accessible_surface;
struct
{
uint32_t residues_per_alpha_helix[kHistogramSize];
uint32_t parallel_bridges_per_ladder[kHistogramSize];
uint32_t antiparallel_bridges_per_ladder[kHistogramSize];
uint32_t ladders_per_sheet[kHistogramSize];
} histogram;
};
enum class chain_break_type
{
None,
NewChain,
Gap
};
dssp(const cif::datablock &db, int model_nr, int min_poly_proline_stretch_length, bool calculateSurfaceAccessibility);
dssp(const cif::mm::structure &s, int min_poly_proline_stretch_length, bool calculateSurfaceAccessibility);
~dssp();
dssp(const dssp &) = delete;
dssp &operator=(const dssp &) = delete;
[[nodiscard]] statistics get_statistics() const;
class iterator;
using res_iterator = typename std::vector<residue>::iterator;
class residue_info
{
public:
friend class iterator;
residue_info() = default;
residue_info(const residue_info &rhs) = default;
residue_info &operator=(const residue_info &rhs) = default;
explicit operator bool() const { return not empty(); }
[[nodiscard]] bool empty() const { return m_impl == nullptr; }
[[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
[[nodiscard]] std::string auth_asym_id() const;
[[nodiscard]] int auth_seq_id() const;
[[nodiscard]] std::string pdb_strand_id() const;
[[nodiscard]] int pdb_seq_num() const;
[[nodiscard]] std::string pdb_ins_code() 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;
[[nodiscard]] bool is_pre_pro() const;
[[nodiscard]] bool is_cis() const { return std::abs(omega().value_or(360)) < 30.0f; }
[[nodiscard]] float chiral_volume() const;
[[nodiscard]] std::size_t nr_of_chis() const;
[[nodiscard]] float chi(std::size_t index) const;
[[nodiscard]] std::vector<float> chis() const
{
std::vector<float> result;
for (size_t i = 0; i < nr_of_chis(); ++i)
result.push_back(chi(i));
return result;
}
[[nodiscard]] std::tuple<float, float, float> ca_location() const;
[[nodiscard]] chain_break_type chain_break() const;
/// \brief the internal number in DSSP
[[nodiscard]] int nr() const;
[[nodiscard]] structure_type type() const;
[[nodiscard]] int ssBridgeNr() const;
[[nodiscard]] helix_position_type helix(helix_type helixType) const;
[[nodiscard]] bool is_alpha_helix_end_before_start() const;
[[nodiscard]] bool bend() const;
[[nodiscard]] double accessibility() const;
/// \brief returns resinfo, ladder and parallel
[[nodiscard]] std::tuple<residue_info, int, bool> bridge_partner(int i) const;
[[nodiscard]] int sheet() const;
[[nodiscard]] int strand() const;
/// \brief return resinfo and the energy of the bond
[[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
{
return m_impl == rhs.m_impl;
}
/// \brief Returns \result true if there is a bond between two residues
friend bool test_bond(residue_info const &a, residue_info const &b);
[[nodiscard]] residue_info next() const;
private:
residue_info(residue *res)
: m_impl(res)
{
}
residue *m_impl = nullptr;
};
class iterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
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*() const { return m_current; }
pointer operator->() const { return &m_current; }
iterator &operator++();
iterator operator++(int)
{
auto tmp(*this);
this->operator++();
return tmp;
}
iterator &operator--();
iterator operator--(int)
{
auto tmp(*this);
this->operator--();
return tmp;
}
bool operator==(const iterator &rhs) const { return m_current.m_impl == rhs.m_current.m_impl; }
bool operator!=(const iterator &rhs) const { return m_current.m_impl != rhs.m_current.m_impl; }
private:
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>;
[[nodiscard]] iterator begin() const;
[[nodiscard]] iterator end() const;
[[nodiscard]] iterator cbegin() const;
[[nodiscard]] iterator cend() const;
residue_info operator[](const key_type &key) const;
[[nodiscard]] bool empty() const { return begin() == end(); }
// --------------------------------------------------------------------
// Writing out the data, either in legacy format...
void write_legacy_output(std::ostream &os) const;
// ... or as annotation in the cif::datablock
void annotate(cif::datablock &db, bool writeOther, bool writeDSSPCategories) const;
// convenience method, when creating old style DSSP files
enum class pdb_record_type
{
HEADER,
COMPND,
SOURCE,
AUTHOR
};
[[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>);