Compare commits

...

63 Commits

Author SHA1 Message Date
Maarten L. Hekkelman
24aa7a70e5 Fix writing pdbx_ens_id 2023-02-07 11:38:15 +01:00
Maarten L. Hekkelman
5ade3d6cdd Fixes in update data script 2023-02-06 16:10:41 +01:00
Maarten L. Hekkelman
0d8e548ffc pdb2cif and vv 2023-02-06 14:19:56 +01:00
Maarten L. Hekkelman
b09650812f oops 2023-02-06 06:48:57 +01:00
Maarten L. Hekkelman
acc9ad5c08 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-02-05 11:28:03 +01:00
Maarten L. Hekkelman
67b6c4bd27 update downloaded files only when needed and clean up afterwards 2023-02-05 11:27:54 +01:00
Maarten L. Hekkelman
7a1d3dbdfa Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-02-03 19:21:08 +01:00
Maarten L. Hekkelman
4bf10df0c5 include <array> 2023-02-03 19:20:40 +01:00
Maarten L. Hekkelman
d84faad109 Accept X as alias for atom symbol Nn 2023-02-02 11:23:40 +01:00
Maarten L. Hekkelman
e01ace7ea4 write auth_seq_num as well as pdb_seq_num for nonpolies 2023-02-02 09:49:21 +01:00
Maarten L. Hekkelman
e004e1591e fix cron script 2023-02-02 09:35:44 +01:00
Maarten L. Hekkelman
4613084e1b find_first, find_min, find_max, count added
PDB writing changed for auth_seq_num
version bump
2023-02-01 13:46:08 +01:00
Maarten L. Hekkelman
637b795a8f Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-02-01 09:00:51 +01:00
Maarten L. Hekkelman
4de981a3c0 better handling of missing residues in pdb2cif 2023-01-31 20:32:57 +01:00
Maarten L. Hekkelman
15db026e27 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-01-31 19:10:44 +01:00
Maarten L. Hekkelman
d88d520553 Use std::experimental::is_detected from libzeep, if needed
version bump
2023-01-25 17:06:47 +01:00
Maarten L. Hekkelman
46cd98ea1d Dependencies and share location in Win 2023-01-25 17:01:39 +01:00
Maarten L. Hekkelman
d10328d891 Use the zeep implementation of std::experimental::is_detected 2023-01-25 16:31:13 +01:00
Maarten L. Hekkelman
e418a17256 Version bump 2023-01-25 15:01:28 +01:00
Maarten L. Hekkelman
627d3b9df2 export by default, fixes for MSVC 2023-01-25 11:23:08 +01:00
Maarten L. Hekkelman
ba28ade414 clean up 2023-01-25 10:45:08 +01:00
Maarten L. Hekkelman
7c11130357 explicitly export what needs to be exported 2023-01-25 10:07:54 +01:00
Maarten L. Hekkelman
151915beea Merge branch 'exports' into develop 2023-01-25 09:44:04 +01:00
Maarten L. Hekkelman
4f9aacb338 Merge branch 'trunk' into develop 2023-01-25 09:41:59 +01:00
Maarten L. Hekkelman
1f8e491ddc generate exports header 2023-01-25 09:41:43 +01:00
Maarten L. Hekkelman
05cfa92182 revert version number 2023-01-17 14:16:36 +01:00
Maarten L. Hekkelman
e8031aeb49 Fix is_cis 2023-01-17 14:12:33 +01:00
Maarten L. Hekkelman
85885406aa Fix sugar test 2023-01-17 14:10:50 +01:00
Maarten L. Hekkelman
636f17d78d Update changelog 2023-01-17 14:10:38 +01:00
Maarten L. Hekkelman
29559a5339 Fix is_cis 2023-01-17 13:51:46 +01:00
Maarten L. Hekkelman
19f2fd75c9 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-01-04 17:14:33 +01:00
Maarten L. Hekkelman
8a60bae335 non-throwing remove_residue
add chem_comp for sugars
2023-01-04 17:05:48 +01:00
Maarten L. Hekkelman
fa5ff60550 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-01-03 21:31:09 +01:00
Maarten L. Hekkelman
f6e0568964 start reconstructing 2023-01-03 21:30:17 +01:00
Maarten L. Hekkelman
fa27a11fea some quaternion additions 2023-01-03 16:45:53 +01:00
Maarten L. Hekkelman
19706559cb Merge branch 'trunk' of github.com:PDB-REDO/libcifpp into trunk 2023-01-02 14:06:16 +01:00
Maarten L. Hekkelman
0a06a0a51d Fix cron script 2023-01-02 14:06:09 +01:00
Maarten L. Hekkelman
b045177734 less nervous progress bar 2023-01-02 14:05:47 +01:00
Maarten L. Hekkelman
7ee5fa8765 some quaternion tests added 2023-01-02 14:05:31 +01:00
Maarten L. Hekkelman
3e690048a6 sugar work 2023-01-02 14:04:56 +01:00
Maarten L. Hekkelman
7ec3bfea9f 3d work 2023-01-02 14:04:41 +01:00
Maarten L. Hekkelman
098f3fd496 FIx compound factory stacking 2022-12-21 21:14:41 +01:00
Maarten L. Hekkelman
5476eef049 some extensions for sugar tree building 2022-12-21 16:33:33 +01:00
Maarten L. Hekkelman
33c1eea9a1 Fix copy construction, do not copy the links 2022-12-19 17:40:43 +01:00
Maarten L. Hekkelman
d3432ed87c merging in fixes from develop branch 2022-12-15 09:05:51 +01:00
Maarten L. Hekkelman
f05363ea93 duh 2022-12-15 08:51:05 +01:00
Maarten L. Hekkelman
77389c20a4 Fix equals in condition_impl, columns might be unknown 2022-12-15 08:49:49 +01:00
Maarten L. Hekkelman
7c5f1ba85e Merge branch 'trunk' into develop 2022-12-14 10:49:56 +01:00
Maarten L. Hekkelman
e7c34cc15c Merge changes 2022-12-14 10:47:20 +01:00
Maarten L. Hekkelman
72fd03a6b2 formatting, fix in is_unquoted test 2022-12-13 16:48:09 +01:00
Maarten L. Hekkelman
61f464ae4d Merge branch 'trunk' of github.com:PDB-REDO/libcifpp into trunk 2022-12-13 16:08:16 +01:00
Maarten L. Hekkelman
19cdf66f10 fix operator or for conditions (equals or empty) 2022-12-13 16:05:23 +01:00
Maarten L. Hekkelman
0c036df6a8 fix operator or for conditions (equals or empty) 2022-12-13 16:02:55 +01:00
Maarten L. Hekkelman
4c1b9d83d1 Fix memory leak 2022-12-13 15:49:11 +01:00
Maarten L. Hekkelman
b976b4657b Optimised erase III 2022-12-13 15:41:57 +01:00
Maarten L. Hekkelman
eba04950d5 Optimised erase II 2022-12-13 11:31:56 +01:00
Maarten L. Hekkelman
0c70df27ec Optimised erase 2022-12-13 10:38:33 +01:00
Maarten L. Hekkelman
d83f34722b Accept and fix incorrect SEQRES 2022-12-13 09:50:40 +01:00
Maarten L. Hekkelman
652b6021d3 improved parser. is_non_quoted string 2022-12-07 16:58:54 +01:00
Maarten L. Hekkelman
7fe9c87b6e Some small fixes for windows 2022-12-07 15:39:26 +01:00
Maarten L. Hekkelman
9b2ae6d7fd Fix update script, order is important 2022-11-28 08:48:13 +01:00
Maarten L. Hekkelman
8fd5b9a34b Remove PATH_MAX to enable compilation on Debian/hurd 2022-11-20 13:30:44 +01:00
Maarten L. Hekkelman
dffbf52d04 removed erronous static-assert 2022-11-19 11:17:50 +01:00
47 changed files with 1684 additions and 925 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ CMakeSettings.json
msvc/
src/revision.hpp
test/test-create_sugar_?.cif
Testing/

View File

@@ -25,7 +25,7 @@
cmake_minimum_required(VERSION 3.16)
# set the project name
project(cifpp VERSION 5.0.5 LANGUAGES CXX)
project(cifpp VERSION 5.0.8 LANGUAGES CXX)
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -35,10 +35,13 @@ include(CheckIncludeFiles)
include(CheckLibraryExists)
include(CMakePackageConfigHelpers)
include(CheckCXXSourceCompiles)
include(GenerateExportHeader)
set(CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# set(CMAKE_CXX_VISIBILITY_PRESET hidden)
# set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
@@ -86,6 +89,7 @@ if(BUILD_FOR_CCP4)
list(APPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
list(APPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
set(CMAKE_INSTALL_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/share/libcifpp")
if(WIN32)
set(BUILD_SHARED_LIBS ON)
@@ -170,6 +174,12 @@ list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
include(FindAtomic)
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPATOMIC_LIBRARY})
if(MSVC)
# this dependency can go once MSVC supports std::experimental::is_detected
find_package(zeep 5.1.8 REQUIRED)
list(APPEND CIFPP_REQUIRED_LIBRARIES zeep::zeep)
endif()
# Create a revision file, containing the current git version info
include(VersionString)
write_version_header(${PROJECT_SOURCE_DIR}/src/ "LibCIFPP")
@@ -224,7 +234,6 @@ set(project_headers
${PROJECT_SOURCE_DIR}/include/cif++/datablock.hpp
${PROJECT_SOURCE_DIR}/include/cif++/file.hpp
${PROJECT_SOURCE_DIR}/include/cif++/validate.hpp
${PROJECT_SOURCE_DIR}/include/cif++/list.hpp
${PROJECT_SOURCE_DIR}/include/cif++/iterator.hpp
${PROJECT_SOURCE_DIR}/include/cif++/parser.hpp
${PROJECT_SOURCE_DIR}/include/cif++/forward_decl.hpp
@@ -249,6 +258,7 @@ set(project_headers
add_library(cifpp ${project_sources} ${project_headers} ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
add_library(cifpp::cifpp ALIAS cifpp)
generate_export_header(cifpp EXPORT_FILE_NAME cif++/exports.hpp)
if(BOOST_REGEX)
target_compile_definitions(cifpp PRIVATE USE_BOOST_REGEX=1 BOOST_REGEX_STANDALONE=1)
@@ -263,7 +273,7 @@ set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_include_directories(cifpp
PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include;${PROJECT_BINARY_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
@@ -343,6 +353,12 @@ install(
COMPONENT Devel
)
install(
FILES ${PROJECT_BINARY_DIR}/cif++/exports.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cif++
COMPONENT Devel
)
install(FILES
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic

View File

@@ -1,3 +1,20 @@
Version 5.0.8
- implemented find_first, find_min, find_max and count in category
- find1 now throws an exception if condition does not not exactly match one row
- Change in writing out PDB files, now looking up the original auth_seq_num
via the pdbx_xxx_scheme categories based on the atom_site.auth_seq_num ->
pdbx_xxx_scheme.pdb_seq_num relationship.
Version 5.0.7.1
- Use the implementation from zeep for std::experimental::is_detected
Version 5.0.7
- Reintroduce exports file. For DLL's
Version 5.0.6
- Fix file::contains, using iequals
- Fix is_cis
Version 5.0.5
- Fix code to work on 32 bit machines

View File

@@ -5,6 +5,10 @@ find_dependency(Threads)
find_dependency(ZLIB REQUIRED)
if(MSVC)
find_dependency(zeep REQUIRED)
endif()
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")

View File

@@ -204,7 +204,7 @@ struct atom_type_info
float radii[kRadiusTypeCount];
};
extern const atom_type_info kKnownAtoms[];
extern CIFPP_EXPORT const atom_type_info kKnownAtoms[];
// --------------------------------------------------------------------
// AtomTypeTraits

View File

@@ -26,8 +26,6 @@
#pragma once
#include <array>
#include <cif++/forward_decl.hpp>
#include <cif++/condition.hpp>
@@ -35,6 +33,8 @@
#include <cif++/row.hpp>
#include <cif++/validate.hpp>
#include <array>
// TODO: implement all of:
// https://en.cppreference.com/w/cpp/named_req/Container
// https://en.cppreference.com/w/cpp/named_req/SequenceContainer
@@ -49,7 +49,18 @@ class duplicate_key_error : public std::runtime_error
{
public:
duplicate_key_error(const std::string &msg)
: std::runtime_error(msg) {}
: std::runtime_error(msg)
{
}
};
class multiple_results_error : public std::runtime_error
{
public:
multiple_results_error()
: std::runtime_error("query should have returned exactly one row")
{
}
};
// --------------------------------------------------------------------
@@ -109,52 +120,52 @@ class category
reference front()
{
return {*this, *m_head};
return { *this, *m_head };
}
const_reference front() const
{
return {const_cast<category &>(*this), const_cast<row &>(*m_head)};
return { const_cast<category &>(*this), const_cast<row &>(*m_head) };
}
reference back()
{
return {*this, *m_tail};
return { *this, *m_tail };
}
const_reference back() const
{
return {const_cast<category &>(*this), const_cast<row &>(*m_tail)};
return { const_cast<category &>(*this), const_cast<row &>(*m_tail) };
}
iterator begin()
{
return {*this, m_head};
return { *this, m_head };
}
iterator end()
{
return {*this, nullptr};
return { *this, nullptr };
}
const_iterator begin() const
{
return {*this, m_head};
return { *this, m_head };
}
const_iterator end() const
{
return {*this, nullptr};
return { *this, nullptr };
}
const_iterator cbegin() const
{
return {*this, m_head};
return { *this, m_head };
}
const_iterator cend() const
{
return {*this, nullptr};
return { *this, nullptr };
}
size_t size() const
@@ -189,64 +200,64 @@ class category
iterator_proxy<const category, Ts...> rows(Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<const category, Ts...>(*this, begin(), {names...});
return iterator_proxy<const category, Ts...>(*this, begin(), { names... });
}
template <typename... Ts, typename... Ns>
iterator_proxy<category, Ts...> rows(Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<category, Ts...>(*this, begin(), {names...});
return iterator_proxy<category, Ts...>(*this, begin(), { names... });
}
// --------------------------------------------------------------------
conditional_iterator_proxy<category> find(condition &&cond)
{
return find(begin(), std::forward<condition>(cond));
return find(begin(), std::move(cond));
}
conditional_iterator_proxy<category> find(iterator pos, condition &&cond)
{
return {*this, pos, std::forward<condition>(cond)};
return { *this, pos, std::move(cond) };
}
conditional_iterator_proxy<const category> find(condition &&cond) const
{
return find(cbegin(), std::forward<condition>(cond));
return find(cbegin(), std::move(cond));
}
conditional_iterator_proxy<const category> find(const_iterator pos, condition &&cond) const
{
return conditional_iterator_proxy<const category>{*this, pos, std::forward<condition>(cond)};
return conditional_iterator_proxy<const category>{ *this, pos, std::move(cond) };
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<category, Ts...> find(condition &&cond, Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return find<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Ns>(names)...);
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<const category, Ts...> find(condition &&cond, Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return find<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Ns>(names)...);
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<category, Ts...> find(const_iterator pos, condition &&cond, Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return {*this, pos, std::forward<condition>(cond), std::forward<Ns>(names)...};
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<const category, Ts...> find(const_iterator pos, condition &&cond, Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return {*this, pos, std::forward<condition>(cond), std::forward<Ns>(names)...};
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
}
// --------------------------------------------------------------------
@@ -254,40 +265,49 @@ class category
row_handle find1(condition &&cond)
{
return find1(begin(), std::forward<condition>(cond));
return find1(begin(), std::move(cond));
}
row_handle find1(iterator pos, condition &&cond)
{
auto h = find(pos, std::forward<condition>(cond));
auto h = find(pos, std::move(cond));
return h.size() != 1 ? row_handle{} : *h.begin();
if (h.size() != 1)
throw multiple_results_error();
return *h.begin();
}
const row_handle find1(condition &&cond) const
{
return find1(cbegin(), std::forward<condition>(cond));
return find1(cbegin(), std::move(cond));
}
const row_handle find1(const_iterator pos, condition &&cond) const
{
auto h = find(pos, std::forward<condition>(cond));
auto h = find(pos, std::move(cond));
return h.size() != 1 ? row_handle{} : *h.begin();
if (h.size() != 1)
throw multiple_results_error();
return *h.begin();
}
template <typename T>
T find1(condition &&cond, const char *column) const
{
return find1<T>(cbegin(), std::forward<condition>(cond), column);
return find1<T>(cbegin(), std::move(cond), column);
}
template <typename T>
T find1(const_iterator pos, condition &&cond, const char *column) const
{
auto h = find<T>(pos, std::forward<condition>(cond), column);
auto h = find<T>(pos, std::move(cond), column);
return h.size() == 1 ? *h.begin() : T{};
if (h.size() != 1)
throw multiple_results_error();
return *h.begin();
}
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
@@ -295,16 +315,119 @@ class category
{
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
return find1<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Cs>(columns)...);
return find1<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(columns)...);
}
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
std::tuple<Ts...> find1(const_iterator pos, condition &&cond, Cs... columns) const
{
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
auto h = find<Ts...>(pos, std::forward<condition>(cond), std::forward<Cs>(columns)...);
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(columns)...);
return h.size() == 1 ? *h.begin() : std::tuple<Ts...>{};
if (h.size() != 1)
throw multiple_results_error();
return *h.begin();
}
// --------------------------------------------------------------------
// if you want only a first hit
row_handle find_first(condition &&cond)
{
return find_first(begin(), std::move(cond));
}
row_handle find_first(iterator pos, condition &&cond)
{
auto h = find(pos, std::move(cond));
return h.empty() ? row_handle{} : *h.begin();
}
const row_handle find_first(condition &&cond) const
{
return find_first(cbegin(), std::move(cond));
}
const row_handle find_first(const_iterator pos, condition &&cond) const
{
auto h = find(pos, std::move(cond));
return h.empty() ? row_handle{} : *h.begin();
}
template <typename T>
T find_first(condition &&cond, const char *column) const
{
return find_first<T>(cbegin(), std::move(cond), column);
}
template <typename T>
T find_first(const_iterator pos, condition &&cond, const char *column) const
{
auto h = find<T>(pos, std::move(cond), column);
return h.empty() ? T{} : *h.begin();
}
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
std::tuple<Ts...> find_first(condition &&cond, Cs... columns) const
{
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
return find_first<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(columns)...);
}
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
std::tuple<Ts...> find_first(const_iterator pos, condition &&cond, Cs... columns) const
{
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(columns)...);
return h.empty() ? std::tuple<Ts...>{} : *h.begin();
}
// --------------------------------------------------------------------
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
T find_max(const char *column, condition &&cond) const
{
T result = std::numeric_limits<T>::min();
for (auto v : find<T>(std::move(cond), column))
{
if (result < v)
result = v;
}
return result;
}
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
T find_max(const char *column) const
{
return find_max<T>(column, all());
}
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
T find_min(const char *column, condition &&cond) const
{
T result = std::numeric_limits<T>::max();
for (auto v : find<T>(std::move(cond), column))
{
if (result > v)
result = v;
}
return result;
}
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
T find_min(const char *column) const
{
return find_min<T>(column, all());
}
bool exists(condition &&cond) const
@@ -335,6 +458,31 @@ class category
return result;
}
size_t count(condition &&cond) const
{
size_t result = 0;
if (cond)
{
cond.prepare(*this);
auto sh = cond.single();
if (sh.has_value() and *sh)
result = 1;
else
{
for (auto r : *this)
{
if (cond(r))
++result;
}
}
}
return result;
}
// --------------------------------------------------------------------
bool has_children(row_handle r) const;
@@ -486,7 +634,7 @@ class category
// --------------------------------------------------------------------
void sort(std::function<int(row_handle,row_handle)> f);
void sort(std::function<int(row_handle, row_handle)> f);
void reorder_by_index();
// --------------------------------------------------------------------
@@ -583,7 +731,7 @@ class category
void swap_item(uint16_t column_ix, row_handle &a, row_handle &b);
// --------------------------------------------------------------------
std::string m_name;
std::vector<item_column> m_columns;
const validator *m_validator = nullptr;

View File

@@ -29,14 +29,15 @@
/// \file This file contains the definition for the class compound, encapsulating
/// the information found for compounds in the CCD.
#include <cif++.hpp>
#include <cif++/atom_type.hpp>
#include <cif++/point.hpp>
#include <map>
#include <set>
#include <tuple>
#include <vector>
#include <cif++.hpp>
#include <cif++/atom_type.hpp>
namespace cif
{
@@ -75,6 +76,11 @@ struct compound_atom
bool leaving_atom = false;
bool stereo_config = false;
float x, y, z;
point get_location() const
{
return { x, y, z };
}
};
/// --------------------------------------------------------------------
@@ -114,6 +120,7 @@ class compound
compound_atom get_atom_by_atom_id(const std::string &atom_id) const;
bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const;
float bond_length(const std::string &atomId_1, const std::string &atomId_2) const;
bool is_water() const
{
@@ -173,7 +180,7 @@ class compound_factory
~compound_factory();
static const std::map<std::string, char> kAAMap, kBaseMap;
static CIFPP_EXPORT const std::map<std::string, char> kAAMap, kBaseMap;
private:
compound_factory();
@@ -188,4 +195,4 @@ class compound_factory
std::shared_ptr<compound_factory_impl> m_impl;
};
} // namespace pdbx
} // namespace cif

View File

@@ -26,14 +26,14 @@
#pragma once
#include <cif++/row.hpp>
#include <cassert>
#include <functional>
#include <iostream>
#include <regex>
#include <utility>
#include <cif++/row.hpp>
namespace cif
{
@@ -57,6 +57,8 @@ namespace detail
virtual bool test(row_handle) const = 0;
virtual void str(std::ostream &) const = 0;
virtual std::optional<row_handle> single() const { return {}; };
virtual bool equals(const condition_impl *rhs) const { return false; }
};
struct all_condition_impl : public condition_impl
@@ -145,7 +147,6 @@ class condition
}
private:
void optimise(condition_impl *&impl);
condition_impl *m_impl;
@@ -181,6 +182,33 @@ namespace detail
uint16_t m_item_ix = 0;
};
struct key_is_not_empty_condition_impl : public condition_impl
{
key_is_not_empty_condition_impl(const std::string &item_tag)
: m_item_tag(item_tag)
{
}
condition_impl *prepare(const category &c) override
{
m_item_ix = get_column_ix(c, m_item_tag);
return this;
}
bool test(row_handle r) const override
{
return not r[m_item_ix].empty();
}
void str(std::ostream &os) const override
{
os << m_item_tag << " IS NOT NULL";
}
std::string m_item_tag;
uint16_t m_item_ix = 0;
};
struct key_equals_condition_impl : public condition_impl
{
key_equals_condition_impl(item &&i)
@@ -193,9 +221,7 @@ namespace detail
bool test(row_handle r) const override
{
return m_single_hit.has_value() ?
*m_single_hit == r :
r[m_item_ix].compare(m_value, m_icase) == 0;
return m_single_hit.has_value() ? *m_single_hit == r : r[m_item_ix].compare(m_value, m_icase) == 0;
}
void str(std::ostream &os) const override
@@ -208,6 +234,20 @@ namespace detail
return m_single_hit;
}
virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_condition_impl))
{
auto ri = static_cast<const key_equals_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
// watch out, both m_item_ix might be the same while tags might be diffent (in case they both do not exist in the category)
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_tag == ri->m_item_tag;
}
return this == rhs;
}
std::string m_item_tag;
uint16_t m_item_ix = 0;
bool m_icase = false;
@@ -244,7 +284,7 @@ namespace detail
void str(std::ostream &os) const override
{
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL";
os << '(' << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL)";
}
virtual std::optional<row_handle> single() const override
@@ -252,12 +292,26 @@ namespace detail
return m_single_hit;
}
virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_or_empty_condition_impl))
{
auto ri = static_cast<const key_equals_or_empty_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
// watch out, both m_item_ix might be the same while tags might be diffent (in case they both do not exist in the category)
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_tag == ri->m_item_tag;
}
return this == rhs;
}
std::string m_item_tag;
uint16_t m_item_ix = 0;
std::string m_value;
bool m_icase = false;
std::optional<row_handle> m_single_hit;
};
};
struct key_compare_condition_impl : public condition_impl
{
@@ -409,29 +463,53 @@ namespace detail
// case they make up an indexed tuple.
struct and_condition_impl : public condition_impl
{
and_condition_impl() = default;
and_condition_impl(condition &&a, condition &&b)
{
mSub.emplace_back(std::exchange(a.m_impl, nullptr));
mSub.emplace_back(std::exchange(b.m_impl, nullptr));
if (typeid(*a.m_impl) == typeid(*this))
{
and_condition_impl *ai = static_cast<and_condition_impl *>(a.m_impl);
std::swap(m_sub, ai->m_sub);
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
else if (typeid(*b.m_impl) == typeid(*this))
{
and_condition_impl *bi = static_cast<and_condition_impl *>(b.m_impl);
std::swap(m_sub, bi->m_sub);
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
}
else
{
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
}
~and_condition_impl()
{
for (auto sub : mSub)
for (auto sub : m_sub)
delete sub;
}
condition_impl *prepare(const category &c) override;
condition_impl *prepare(const category &c) override
{
for (auto &sub : m_sub)
sub = sub->prepare(c);
return this;
}
bool test(row_handle r) const override
{
bool result = true;
for (auto sub : mSub)
for (auto sub : m_sub)
{
if (sub->test(r))
continue;
result = false;
break;
}
@@ -444,7 +522,7 @@ namespace detail
os << '(';
bool first = true;
for (auto sub : mSub)
for (auto sub : m_sub)
{
if (first)
first = false;
@@ -461,7 +539,7 @@ namespace detail
{
std::optional<row_handle> result;
for (auto sub : mSub)
for (auto sub : m_sub)
{
auto s = sub->single();
@@ -470,7 +548,7 @@ namespace detail
result = s;
continue;
}
if (s == result)
continue;
@@ -481,56 +559,100 @@ namespace detail
return result;
}
std::vector<condition_impl *> mSub;
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
std::vector<condition_impl *> m_sub;
};
struct or_condition_impl : public condition_impl
{
or_condition_impl(condition &&a, condition &&b)
: mA(nullptr)
, mB(nullptr)
{
std::swap(mA, a.m_impl);
std::swap(mB, b.m_impl);
if (typeid(*a.m_impl) == typeid(*this))
{
or_condition_impl *ai = static_cast<or_condition_impl *>(a.m_impl);
std::swap(m_sub, ai->m_sub);
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
else if (typeid(*b.m_impl) == typeid(*this))
{
or_condition_impl *bi = static_cast<or_condition_impl *>(b.m_impl);
std::swap(m_sub, bi->m_sub);
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
}
else
{
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
}
~or_condition_impl()
{
delete mA;
delete mB;
for (auto sub : m_sub)
delete sub;
}
condition_impl *prepare(const category &c) override;
bool test(row_handle r) const override
{
return mA->test(r) or mB->test(r);
bool result = false;
for (auto sub : m_sub)
{
if (not sub->test(r))
continue;
result = true;
break;
}
return result;
}
void str(std::ostream &os) const override
{
bool first = true;
os << '(';
mA->str(os);
os << ") OR (";
mB->str(os);
for (auto sub : m_sub)
{
if (first)
first = false;
else
os << " OR ";
sub->str(os);
}
os << ')';
}
virtual std::optional<row_handle> single() const override
{
auto sa = mA->single();
auto sb = mB->single();
if (sa.has_value() and sb.has_value() and sa != sb)
sa.reset();
else if (not sa.has_value())
sa = sb;
std::optional<row_handle> result;
return sa;
for (auto sub : m_sub)
{
auto s = sub->single();
if (not result.has_value())
{
result = s;
continue;
}
if (s == result)
continue;
result.reset();
break;
}
return result;
}
condition_impl *mA;
condition_impl *mB;
std::vector<condition_impl *> m_sub;
};
struct not_condition_impl : public condition_impl
@@ -569,7 +691,7 @@ namespace detail
} // namespace detail
inline condition operator&&(condition &&a, condition &&b)
inline condition operator and(condition &&a, condition &&b)
{
if (a.m_impl and b.m_impl)
return condition(new detail::and_condition_impl(std::move(a), std::move(b)));
@@ -578,12 +700,35 @@ inline condition operator&&(condition &&a, condition &&b)
return condition(std::move(b));
}
inline condition operator||(condition &&a, condition &&b)
inline condition operator or(condition &&a, condition &&b)
{
if (a.m_impl and b.m_impl)
{
if (typeid(*a.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*b.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
auto ci = static_cast<detail::key_equals_condition_impl *>(a.m_impl);
auto ce = static_cast<detail::key_is_empty_condition_impl *>(b.m_impl);
if (ci->m_item_tag == ce->m_item_tag)
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
else if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
auto ci = static_cast<detail::key_equals_condition_impl *>(b.m_impl);
auto ce = static_cast<detail::key_is_empty_condition_impl *>(a.m_impl);
if (ci->m_item_tag == ce->m_item_tag)
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
}
if (a.m_impl)
return condition(std::move(a));
return condition(std::move(b));
}
@@ -706,7 +851,12 @@ inline condition operator==(const key &key, const empty_type &)
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
}
inline condition operator !(condition &&rhs)
inline condition operator!=(const key &key, const empty_type &)
{
return condition(new detail::key_is_not_empty_condition_impl(key.m_item_tag));
}
inline condition operator not(condition &&rhs)
{
return condition(new detail::not_condition_impl(std::move(rhs)));
}
@@ -741,4 +891,4 @@ namespace literals
}
} // namespace literals
} // namespace cif
} // namespace cif

View File

@@ -26,9 +26,8 @@
#pragma once
#include <cif++/forward_decl.hpp>
#include <cif++/category.hpp>
#include <cif++/forward_decl.hpp>
namespace cif
{
@@ -45,11 +44,10 @@ class datablock : public std::list<category>
{
}
datablock(const datablock &) = default;
datablock(const datablock &);
datablock(datablock &&) = default;
datablock &operator=(const datablock &) = default;
datablock &operator=(const datablock &);
datablock &operator=(datablock &&) = default;
// --------------------------------------------------------------------
@@ -89,7 +87,7 @@ class datablock : public std::list<category>
}
// --------------------------------------------------------------------
bool operator==(const datablock &rhs) const;
private:

View File

@@ -28,6 +28,7 @@
#include <list>
#include <cif++/exports.hpp>
#include <cif++/datablock.hpp>
#include <cif++/parser.hpp>

View File

@@ -26,6 +26,8 @@
#pragma once
#include <cif++/exports.hpp>
#include <string>
#include <vector>

View File

@@ -26,6 +26,12 @@
#pragma once
#include <cif++/exports.hpp>
#include <cif++/forward_decl.hpp>
#include <cif++/text.hpp>
#include <cif++/utilities.hpp>
#include <cassert>
#include <charconv>
#include <cstring>
#include <iomanip>
@@ -35,9 +41,6 @@
#include <optional>
#include <utility>
#include <cif++/forward_decl.hpp>
#include <cif++/text.hpp>
/// \file item.hpp
/// This file contains the declaration of item but also the item_value and item_handle
/// These handle the storage of and access to the data for a single data field.
@@ -45,8 +48,6 @@
namespace cif
{
extern int VERBOSE;
// --------------------------------------------------------------------
/// \brief item is a transient class that is used to pass data into rows
/// but it also takes care of formatting data.
@@ -259,8 +260,6 @@ struct item_value
}
};
static_assert(sizeof(item_value) == sizeof(void*) + 8, "sizeof(item_value) should be correct");
// --------------------------------------------------------------------
// Transient object to access stored data
@@ -355,7 +354,7 @@ struct item_handle
{
}
static const item_handle s_null_item;
static CIFPP_EXPORT const item_handle s_null_item;
friend void swap(item_handle a, item_handle b)
{

View File

@@ -28,6 +28,8 @@
#include <cif++/row.hpp>
#include <array>
namespace cif
{

View File

@@ -1,79 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 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
#include <memory>
namespace cif
{
// --------------------------------------------------------------------
template<typename Allocator = std::allocator<void>>
class list
{
public:
protected:
struct list_item
{
list_item *m_next = nullptr;
};
using list_item_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<list_item>;
using list_item_allocator_traits = std::allocator_traits<item_allocator_type>;
list_item_allocator_traits::pointer get_item()
{
list_item_allocator_type ia(get_allocator());
return list_item_allocator_traits::allocate(ia, 1);
}
template<typename ...Arguments>
list_item *create_list_item(uint16_t column_ix, Arguments... args)
{
auto p = this->get_item();
list_item_allocator_type ia(get_allocator());
list_item_allocator_traits::construct(ia, p, std::forward<Arguments>(args)...);
return p;
}
void delete_list_item(list_item *iv)
{
list_item_allocator_type ia(get_allocator());
list_item_allocator_traits::destroy(ia, iv);
list_item_allocator_traits::deallocate(ia, iv, 1);
}
list_item *m_head = nullptr, *m_tail = nullptr;
};
} // namespace cif

View File

@@ -26,10 +26,10 @@
#pragma once
#include <numeric>
#include <cif++/atom_type.hpp>
#include <numeric>
#if __cpp_lib_format
#include <format>
#endif
@@ -50,7 +50,7 @@ class atom
private:
struct atom_impl : public std::enable_shared_from_this<atom_impl>
{
atom_impl(datablock &db, std::string_view id)
atom_impl(const datablock &db, std::string_view id)
: m_db(db)
, m_cat(db["atom_site"])
, m_id(id)
@@ -111,7 +111,7 @@ class atom
}
const datablock &m_db;
category &m_cat;
const category &m_cat;
std::string m_id;
point m_location;
std::string m_symop = "1_555";
@@ -130,7 +130,7 @@ class atom
{
}
atom(datablock &db, row_handle &row)
atom(const datablock &db, const row_handle &row)
: atom(std::make_shared<atom_impl>(db, row["id"].as<std::string>()))
{
}
@@ -321,13 +321,6 @@ class atom
friend std::ostream &operator<<(std::ostream &os, const atom &atom);
// /// \brief Synchronize data with underlying cif data
// void sync()
// {
// if (m_impl)
// m_impl->prefetch();
// }
private:
friend class structure;
@@ -341,25 +334,6 @@ class atom
std::shared_ptr<atom_impl> m_impl;
};
// template <>
// inline std::string atom::get_property<std::string>(const std::string_view name) const
// {
// return get_property(name);
// }
// template <>
// inline int atom::get_property<int>(const std::string_view name) const
// {
// auto v = impl().get_property(name);
// return v.empty() ? 0 : stoi(v);
// }
// template <>
// inline float atom::get_property<float>(const std::string_view name) const
// {
// return stof(impl().get_property(name));
// }
inline void swap(atom &a, atom &b)
{
a.swap(b);
@@ -394,7 +368,7 @@ class residue
friend class structure;
// constructor
residue(const structure &structure, const std::string &compoundID,
residue(structure &structure, const std::string &compoundID,
const std::string &asymID, int seqID,
const std::string &authAsymID, const std::string &authSeqID,
const std::string &pdbInsCode)
@@ -408,6 +382,8 @@ class residue
{
}
residue(structure &structure, const std::vector<atom> &atoms);
residue(const residue &rhs) = delete;
residue &operator=(const residue &rhs) = delete;
@@ -430,7 +406,7 @@ class residue
const std::string &get_compound_id() const { return m_compound_id; }
void set_compound_id(const std::string &id) { m_compound_id = id; }
const structure *get_structure() const { return m_structure; }
structure *get_structure() const { return m_structure; }
// const compound &compound() const;
@@ -487,7 +463,7 @@ class residue
protected:
residue() {}
const structure *m_structure = nullptr;
structure *m_structure = nullptr;
std::string m_compound_id, m_asym_id;
int m_seq_id = 0;
std::string m_auth_asym_id, m_auth_seq_id, m_pdb_ins_code;
@@ -571,7 +547,7 @@ class monomer : public residue
class polymer : public std::vector<monomer>
{
public:
polymer(const structure &s, const std::string &entityID, const std::string &asymID, const std::string &auth_asym_id);
polymer(structure &s, const std::string &entityID, const std::string &asymID, const std::string &auth_asym_id);
polymer(const polymer &) = delete;
polymer &operator=(const polymer &) = delete;
@@ -579,7 +555,7 @@ class polymer : public std::vector<monomer>
// monomer &getBySeqID(int seqID);
// const monomer &getBySeqID(int seqID) const;
const structure *get_structure() const { return m_structure; }
structure *get_structure() const { return m_structure; }
std::string get_asym_id() const { return m_asym_id; }
std::string get_auth_asym_id() const { return m_auth_asym_id; } // The PDB chain ID, actually
@@ -588,7 +564,7 @@ class polymer : public std::vector<monomer>
// int Distance(const monomer &a, const monomer &b) const;
private:
const structure *m_structure;
structure *m_structure;
std::string m_entity_id;
std::string m_asym_id;
std::string m_auth_asym_id;
@@ -602,7 +578,7 @@ class branch;
class sugar : public residue
{
public:
sugar(const branch &branch, const std::string &compoundID,
sugar(branch &branch, const std::string &compoundID,
const std::string &asymID, int authSeqID);
sugar(sugar &&rhs);
@@ -629,27 +605,44 @@ class sugar : public residue
return result;
}
cif::mm::atom add_atom(row_initializer atom_info);
private:
const branch *m_branch;
branch *m_branch;
atom m_link;
};
class branch : public std::vector<sugar>
{
public:
branch(structure &structure, const std::string &asymID);
branch(structure &structure, const std::string &asym_id, const std::string &entity_id);
branch(const branch &) = delete;
branch &operator=(const branch &) = delete;
branch(branch &&) = default;
branch &operator=(branch &&) = default;
void link_atoms();
std::string name() const;
float weight() const;
std::string get_asym_id() const { return m_asym_id; }
std::string get_entity_id() const { return m_entity_id; }
structure &get_structure() { return *m_structure; }
const structure &get_structure() const { return *m_structure; }
structure &get_structure() const { return *m_structure; }
sugar &getSugarByNum(int nr);
const sugar &getSugarByNum(int nr) const;
sugar &get_sugar_by_num(int nr);
const sugar &get_sugar_by_num(int nr) const
{
return const_cast<branch *>(this)->get_sugar_by_num(nr);
}
sugar &construct_sugar(const std::string &compound_id);
sugar &construct_sugar(const std::string &compound_id, const std::string &atom_id,
int linked_sugar_nr, const std::string &linked_atom_id);
private:
friend sugar;
@@ -657,7 +650,7 @@ class branch : public std::vector<sugar>
std::string name(const sugar &s) const;
structure *m_structure;
std::string m_asym_id;
std::string m_asym_id, m_entity_id;
};
// // --------------------------------------------------------------------
@@ -763,6 +756,9 @@ class structure
/// \brief Return the atom closest to point \a p with atom type \a type in a residue of type \a res_type
atom get_atom_by_position_and_type(point p, std::string_view type, std::string_view res_type) const;
/// \brief Create a non-poly residue based on atoms already present in this structure.
residue &create_residue(const std::vector<atom> &atoms);
/// \brief Get a non-poly residue for an asym with id \a asymID
residue &get_residue(const std::string &asymID)
{
@@ -820,10 +816,7 @@ class structure
///
/// \param asym_id The asym ID
/// \param seq_id The sequence ID
void remove_residue(const std::string &asym_id, int seq_id, const std::string &auth_seq_id)
{
remove_residue(get_residue(asym_id, seq_id, auth_seq_id));
}
void remove_residue(const std::string &asym_id, int seq_id, const std::string &auth_seq_id);
/// \brief Create a new non-polymer entity, returns new ID
/// \param mon_id The mon_id for the new nonpoly, must be an existing and known compound from CCD
@@ -846,6 +839,9 @@ class structure
/// \return The newly create asym ID
std::string create_non_poly(const std::string &entity_id, std::vector<row_initializer> atoms);
/// \brief Create a new and empty (sugar) branch
branch &create_branch();
/// \brief Create a new (sugar) branch with one first NAG containing atoms constructed from \a atoms
branch &create_branch(std::vector<row_initializer> atoms);
@@ -893,6 +889,18 @@ class structure
void validate_atoms() const;
// TODO: make this protected?
void load_atoms_for_model(StructureOpenOptions options);
template <typename... Args>
atom &emplace_atom(Args&... args)
{
return emplace_atom(atom{ std::forward<Args>(args)... });
}
atom &emplace_atom(atom &&atom);
private:
friend polymer;
friend residue;
@@ -903,16 +911,6 @@ class structure
void load_data();
void load_atoms_for_model(StructureOpenOptions options);
template <typename... Args>
atom &emplace_atom(Args... args)
{
return emplace_atom(atom{ std::forward<Args>(args)... });
}
atom &emplace_atom(atom &&atom);
void remove_atom(atom &a, bool removeFromResidue);
void remove_sugar(sugar &sugar);
@@ -925,4 +923,11 @@ class structure
std::vector<residue> m_non_polymers;
};
// --------------------------------------------------------------------
/// \brief Reconstruct all missing categories for an assumed PDBx file.
/// Some people believe that simply dumping some atom records is enough.
/// \param db The cif::datablock that hopefully contains some valid data
void reconstruct_pdbx(datablock &db);
} // namespace cif::mm

View File

@@ -26,10 +26,11 @@
#pragma once
#include <map>
#include <cif++/row.hpp>
#include <map>
#include <regex>
namespace cif
{
@@ -93,23 +94,23 @@ class sac_parser
static bool is_unquoted_string(std::string_view text)
{
auto s = text.begin();
bool result = text.empty() or is_ordinary(text.front());
bool result = is_ordinary(*s++);
while (result and s != text.end())
{
result = is_non_blank(*s);
++s;
}
// but be careful it does not contain e.g. stop_
if (result)
{
static const std::regex reservedRx(R"((^(?:data|save)|.*(?:loop|stop|global))_.+)", std::regex_constants::icase);
result = not std::regex_match(text.begin(), text.end(), reservedRx);
for (auto ch : text)
{
if (is_non_blank(ch))
continue;
result = false;
break;
}
}
return result;
static const std::regex kReservedRx(R"(loop_|stop_|global_|data_\S+|save_\S+)", std::regex_constants::icase);
// but be careful it does not contain e.g. stop_
return result and not std::regex_match(text.begin(), text.end(), kReservedRx);
}
protected:

View File

@@ -26,19 +26,15 @@
#pragma once
#include <cif++.hpp>
#include <string>
#include <tuple>
#include <vector>
#include <cif++.hpp>
namespace cif
{
extern const int
kResidueNrWildcard,
kNoSeqNum;
struct tls_selection;
struct tls_residue;

View File

@@ -26,6 +26,9 @@
#pragma once
#include <cif++/exports.hpp>
#include <array>
#include <cmath>
#include <complex>
#include <functional>
@@ -54,7 +57,7 @@ class quaternion_type
public:
using value_type = T;
constexpr explicit quaternion_type(value_type const &value_a = value_type(), value_type const &value_b = value_type(), value_type const &value_c = value_type(), value_type const &value_d = value_type())
constexpr explicit quaternion_type(value_type const &value_a = {}, value_type const &value_b = {}, value_type const &value_c = {}, value_type const &value_d = {})
: a(value_a)
, b(value_b)
, c(value_c)
@@ -305,6 +308,21 @@ class quaternion_type
constexpr value_type get_c() const { return c; }
constexpr value_type get_d() const { return d; }
constexpr bool operator==(const quaternion_type &rhs) const
{
return a == rhs.a and b == rhs.b and c == rhs.c and d == rhs.d;
}
constexpr bool operator!=(const quaternion_type &rhs) const
{
return a != rhs.a or b != rhs.b or c != rhs.c or d != rhs.d;
}
constexpr operator bool() const
{
return operator!=({});
}
private:
value_type a, b, c, d;
};
@@ -483,6 +501,13 @@ struct point_type
m_z = p.get_d();
}
constexpr void rotate(const quaternion &q, point_type pivot)
{
operator-=(pivot);
rotate(q);
operator+=(pivot);
}
#if HAVE_LIBCLIPPER
operator clipper::Coord_orth() const
{
@@ -665,6 +690,12 @@ point nudge(point p, float offset);
quaternion construct_from_angle_axis(float angle, point axis);
std::tuple<double, point> quaternion_to_angle_axis(quaternion q);
/// @brief Given four points and an angle, return the quaternion required to rotate
/// point p4 along the p2-p3 axis and around point p3 to obtain the required within
/// an accuracy of esd
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
float angle, float esd);
point centroid(const std::vector<point> &Points);
point center_points(std::vector<point> &Points);

View File

@@ -28,6 +28,8 @@
#include <cif++/item.hpp>
#include <array>
namespace cif
{

View File

@@ -26,6 +26,8 @@
#pragma once
#include <cif++/exports.hpp>
#include <array>
#include <cstdint>
#include <string>
@@ -50,8 +52,8 @@ struct space_group
int nr;
};
extern const space_group kSpaceGroups[];
extern const std::size_t kNrOfSpaceGroups;
extern CIFPP_EXPORT const space_group kSpaceGroups[];
extern CIFPP_EXPORT const std::size_t kNrOfSpaceGroups;
// --------------------------------------------------------------------
@@ -139,8 +141,8 @@ struct symop_datablock
static_assert(sizeof(symop_datablock) == sizeof(uint64_t), "Size of symop_data is wrong");
extern const symop_datablock kSymopNrTable[];
extern const std::size_t kSymopNrTableSize;
extern CIFPP_EXPORT const symop_datablock kSymopNrTable[];
extern CIFPP_EXPORT const std::size_t kSymopNrTableSize;
// --------------------------------------------------------------------

View File

@@ -26,6 +26,8 @@
#pragma once
#include <cif++/exports.hpp>
#include <charconv>
#include <cmath>
#include <limits>
@@ -34,70 +36,11 @@
#include <tuple>
#include <vector>
#if __has_include(<experimental/type_traits>)
#include <experimental/type_traits>
#else
#include <type_traits>
#endif
#if (not defined(__cpp_lib_experimental_detect) or (__cpp_lib_experimental_detect < 201505)) and (not defined(_LIBCPP_VERSION) or _LIBCPP_VERSION < 5000)
// This code is copied from:
// https://ld2015.scusa.lsu.edu/cppreference/en/cpp/experimental/is_detected.html
namespace std
{
template< class... >
using void_t = void;
namespace experimental
{
namespace detail
{
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector
{
using value_t = false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
// Note that std::void_t is a c++17 feature
using value_t = true_type;
using type = Op<Args...>;
};
} // namespace detail
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
template <template<class...> class Op, class... Args>
constexpr inline bool is_detected_v = is_detected<Op,Args...>::value;
template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
template <class Expected, template <class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
template <class Expected, template<class...> class Op, class... Args>
constexpr inline bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value;
}
}
// sub optimal, but replicating the same code is worse
#include <zeep/type-traits.hpp>
#endif
namespace cif
@@ -249,7 +192,7 @@ typedef std::set<std::string, iless> iset;
// --------------------------------------------------------------------
// This really makes a difference, having our own tolower routines
extern const uint8_t kCharToLowerMap[256];
extern CIFPP_EXPORT const uint8_t kCharToLowerMap[256];
inline char tolower(int ch)
{
@@ -448,8 +391,8 @@ std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_f
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt, int precision)
{
int size = last - first;
int r;
int size = static_cast<int>(last - first);
int r = 0;
switch (fmt)
{

View File

@@ -26,6 +26,8 @@
#pragma once
#include <cif++/exports.hpp>
#include <filesystem>
#ifndef STDOUT_FILENO
@@ -50,7 +52,7 @@
namespace cif
{
extern int VERBOSE;
extern CIFPP_EXPORT int VERBOSE;
// the git 'build' number
std::string get_version_nr();

View File

@@ -26,13 +26,13 @@
#pragma once
#include <cif++/text.hpp>
#include <filesystem>
#include <list>
#include <mutex>
#include <utility>
#include <cif++/text.hpp>
namespace cif
{

View File

@@ -182,24 +182,24 @@ const struct ionic_radii
{ F, { kNA, kNA, 119, kNA, kNA, kNA, kNA, kNA, kNA, 22, kNA } }, // Fluorine
{ Na, { kNA, kNA, kNA, 116, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Sodium
{ Mg, { kNA, kNA, kNA, kNA, 86, kNA, kNA, kNA, kNA, kNA, kNA } }, // Magnesium
{ Al, { kNA, kNA, kNA, kNA, kNA, 67.5, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
{ Al, { kNA, kNA, kNA, kNA, kNA, 67.5f, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
{ Si, { kNA, kNA, kNA, kNA, kNA, kNA, 54, kNA, kNA, kNA, kNA } }, // Silicon
{ P, { kNA, kNA, kNA, kNA, kNA, 58, kNA, 52, kNA, kNA, kNA } }, // Phosphorus
{ S, { kNA, 170, kNA, kNA, kNA, kNA, 51, kNA, 43, kNA, kNA } }, // Sulfur
{ Cl, { kNA, kNA, 181, kNA, kNA, kNA, kNA, 26, kNA, 41, kNA } }, // Chlorine
{ K, { kNA, kNA, kNA, 152, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Potassium
{ Ca, { kNA, kNA, kNA, kNA, 114, kNA, kNA, kNA, kNA, kNA, kNA } }, // Calcium
{ Sc, { kNA, kNA, kNA, kNA, kNA, 88.5, kNA, kNA, kNA, kNA, kNA } }, // Scandium
{ Ti, { kNA, kNA, kNA, kNA, 100, 81, 74.5, kNA, kNA, kNA, kNA } }, // Titanium
{ Sc, { kNA, kNA, kNA, kNA, kNA, 88.5f, kNA, kNA, kNA, kNA, kNA } }, // Scandium
{ Ti, { kNA, kNA, kNA, kNA, 100, 81, 74.5f, kNA, kNA, kNA, kNA } }, // Titanium
{ V, { kNA, kNA, kNA, kNA, 93, 78, 72, 68, kNA, kNA, kNA } }, // Vanadium
{ Cr, { kNA, kNA, kNA, kNA, 87, 75.5, 69, 63, 58, kNA, kNA } }, // Chromium ls
{ Cr, { kNA, kNA, kNA, kNA, 87, 75.5f, 69, 63, 58, kNA, kNA } }, // Chromium ls
// { Cr,{ kNA, kNA, kNA, kNA, 94, kNA, kNA, kNA, kNA, kNA, kNA } }, // Chromium hs
{ Mn, { kNA, kNA, kNA, kNA, 81, 72, 67, 47, 39.5, 60, kNA } }, // Manganese ls
// { Mn,{ kNA, kNA, kNA, kNA, 97, 78.5, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
{ Fe, { kNA, kNA, kNA, kNA, 75, 69, 72.5, kNA, 39, kNA, kNA } }, // Iron ls
// { Fe,{ kNA, kNA, kNA, kNA, 92, 78.5, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
{ Co, { kNA, kNA, kNA, kNA, 79, 68.5, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
// { Co,{ kNA, kNA, kNA, kNA, 88.5, 75, 67, kNA, kNA, kNA, kNA } }, // Cobalt hs
{ Mn, { kNA, kNA, kNA, kNA, 81, 72, 67, 47, 39.5f, 60, kNA } }, // Manganese ls
// { Mn,{ kNA, kNA, kNA, kNA, 97, 78.5f, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
{ Fe, { kNA, kNA, kNA, kNA, 75, 69, 72.5f, kNA, 39, kNA, kNA } }, // Iron ls
// { Fe,{ kNA, kNA, kNA, kNA, 92, 78.5f, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
{ Co, { kNA, kNA, kNA, kNA, 79, 68.5f, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
// { Co,{ kNA, kNA, kNA, kNA, 88.5f, 75, 67, kNA, kNA, kNA, kNA } }, // Cobalt hs
{ Ni, { kNA, kNA, kNA, kNA, 83, 70, 62, kNA, kNA, kNA, kNA } }, // Nickel ls
// { Ni,{ kNA, kNA, kNA, kNA, kNA, 74, kNA, kNA, kNA, kNA, kNA } }, // Nickel hs
{ Cu, { kNA, kNA, kNA, 91, 87, 68, kNA, kNA, kNA, kNA, kNA } }, // Copper
@@ -215,10 +215,10 @@ const struct ionic_radii
{ Zr, { kNA, kNA, kNA, kNA, kNA, kNA, 86, kNA, kNA, kNA, kNA } }, // Zirconium
{ Nb, { kNA, kNA, kNA, kNA, kNA, 86, 82, 78, kNA, kNA, kNA } }, // Niobium
{ Mo, { kNA, kNA, kNA, kNA, kNA, 83, 79, 75, 73, kNA, kNA } }, // Molybdenum
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 78.5, 74, kNA, 70, kNA } }, // Technetium
{ Ru, { kNA, kNA, kNA, kNA, kNA, 82, 76, 70.5, kNA, 52, 150 } }, // Ruthenium
{ Rh, { kNA, kNA, kNA, kNA, kNA, 80.5, 74, 69, kNA, kNA, kNA } }, // Rhodium
{ Pd, { kNA, kNA, kNA, 73, 100, 90, 75.5, kNA, kNA, kNA, kNA } }, // Palladium
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 78.5f, 74, kNA, 70, kNA } }, // Technetium
{ Ru, { kNA, kNA, kNA, kNA, kNA, 82, 76, 70.5f, kNA, 52, 150 } }, // Ruthenium
{ Rh, { kNA, kNA, kNA, kNA, kNA, 80.5f, 74, 69, kNA, kNA, kNA } }, // Rhodium
{ Pd, { kNA, kNA, kNA, 73, 100, 90, 75.5f, kNA, kNA, kNA, kNA } }, // Palladium
{ Ag, { kNA, kNA, kNA, 129, 108, 89, kNA, kNA, kNA, kNA, kNA } }, // Silver
{ Cd, { kNA, kNA, kNA, kNA, 109, kNA, kNA, kNA, kNA, kNA, kNA } }, // Cadmium
{ In, { kNA, kNA, kNA, kNA, kNA, 94, kNA, kNA, kNA, kNA, kNA } }, // Indium
@@ -229,32 +229,32 @@ const struct ionic_radii
{ Xe, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 62 } }, // Xenon
{ Cs, { kNA, kNA, kNA, 167, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Caesium
{ Ba, { kNA, kNA, kNA, kNA, 149, kNA, kNA, kNA, kNA, kNA, kNA } }, // Barium
{ La, { kNA, kNA, kNA, kNA, kNA, 117.2, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
{ La, { kNA, kNA, kNA, kNA, kNA, 117.2f, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
{ Ce, { kNA, kNA, kNA, kNA, kNA, 115, 101, kNA, kNA, kNA, kNA } }, // Cerium
{ Pr, { kNA, kNA, kNA, kNA, kNA, 113, 99, kNA, kNA, kNA, kNA } }, // Praseodymium
{ Nd, { kNA, kNA, kNA, kNA, 143, 112.3, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
{ Nd, { kNA, kNA, kNA, kNA, 143, 112.3f, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
{ Pm, { kNA, kNA, kNA, kNA, kNA, 111, kNA, kNA, kNA, kNA, kNA } }, // Promethium
{ Sm, { kNA, kNA, kNA, kNA, 136, 109.8, kNA, kNA, kNA, kNA, kNA } }, // Samarium
{ Eu, { kNA, kNA, kNA, kNA, 131, 108.7, kNA, kNA, kNA, kNA, kNA } }, // Europium
{ Gd, { kNA, kNA, kNA, kNA, kNA, 107.8, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
{ Tb, { kNA, kNA, kNA, kNA, kNA, 106.3, 90, kNA, kNA, kNA, kNA } }, // Terbium
{ Dy, { kNA, kNA, kNA, kNA, 121, 105.2, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
{ Ho, { kNA, kNA, kNA, kNA, kNA, 104.1, kNA, kNA, kNA, kNA, kNA } }, // Holmium
{ Sm, { kNA, kNA, kNA, kNA, 136, 109.8f, kNA, kNA, kNA, kNA, kNA } }, // Samarium
{ Eu, { kNA, kNA, kNA, kNA, 131, 108.7f, kNA, kNA, kNA, kNA, kNA } }, // Europium
{ Gd, { kNA, kNA, kNA, kNA, kNA, 107.8f, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
{ Tb, { kNA, kNA, kNA, kNA, kNA, 106.3f, 90, kNA, kNA, kNA, kNA } }, // Terbium
{ Dy, { kNA, kNA, kNA, kNA, 121, 105.2f, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
{ Ho, { kNA, kNA, kNA, kNA, kNA, 104.1f, kNA, kNA, kNA, kNA, kNA } }, // Holmium
{ Er, { kNA, kNA, kNA, kNA, kNA, 103, kNA, kNA, kNA, kNA, kNA } }, // Erbium
{ Tm, { kNA, kNA, kNA, kNA, 117, 102, kNA, kNA, kNA, kNA, kNA } }, // Thulium
{ Yb, { kNA, kNA, kNA, kNA, 116, 100.8, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
{ Lu, { kNA, kNA, kNA, kNA, kNA, 100.1, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
{ Yb, { kNA, kNA, kNA, kNA, 116, 100.8f, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
{ Lu, { kNA, kNA, kNA, kNA, kNA, 100.1f, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
{ Hf, { kNA, kNA, kNA, kNA, kNA, kNA, 85, kNA, kNA, kNA, kNA } }, // Hafnium
{ Ta, { kNA, kNA, kNA, kNA, kNA, 86, 82, 78, kNA, kNA, kNA } }, // Tantalum
{ W, { kNA, kNA, kNA, kNA, kNA, kNA, 80, 76, 74, kNA, kNA } }, // Tungsten
{ Re, { kNA, kNA, kNA, kNA, kNA, kNA, 77, 72, 69, 67, kNA } }, // Rhenium
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 77, 71.5, 68.5, 66.5, 53 } }, // Osmium
{ Ir, { kNA, kNA, kNA, kNA, kNA, 82, 76.5, 71, kNA, kNA, kNA } }, // Iridium
{ Pt, { kNA, kNA, kNA, kNA, 94, kNA, 76.5, 71, kNA, kNA, kNA } }, // Platinum
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 77, 71.5f, 68.5f, 66.5f, 53 } }, // Osmium
{ Ir, { kNA, kNA, kNA, kNA, kNA, 82, 76.5f, 71, kNA, kNA, kNA } }, // Iridium
{ Pt, { kNA, kNA, kNA, kNA, 94, kNA, 76.5f, 71, kNA, kNA, kNA } }, // Platinum
{ Au, { kNA, kNA, kNA, 151, kNA, 99, kNA, 71, kNA, kNA, kNA } }, // Gold
{ Hg, { kNA, kNA, kNA, 133, 116, kNA, kNA, kNA, kNA, kNA, kNA } }, // Mercury
{ Tl, { kNA, kNA, kNA, 164, kNA, 102.5, kNA, kNA, kNA, kNA, kNA } }, // Thallium
{ Pb, { kNA, kNA, kNA, kNA, 133, kNA, 91.5, kNA, kNA, kNA, kNA } }, // Lead
{ Tl, { kNA, kNA, kNA, 164, kNA, 102.5f, kNA, kNA, kNA, kNA, kNA } }, // Thallium
{ Pb, { kNA, kNA, kNA, kNA, 133, kNA, 91.5f, kNA, kNA, kNA, kNA } }, // Lead
{ Bi, { kNA, kNA, kNA, kNA, kNA, 117, kNA, 90, kNA, kNA, kNA } }, // Bismuth
{ Po, { kNA, kNA, kNA, kNA, kNA, kNA, 108, kNA, 81, kNA, kNA } }, // Polonium
{ At, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 76, kNA } }, // Astatine
@@ -263,16 +263,16 @@ const struct ionic_radii
{ Ac, { kNA, kNA, kNA, kNA, kNA, 126, kNA, kNA, kNA, kNA, kNA } }, // Actinium
{ Th, { kNA, kNA, kNA, kNA, kNA, kNA, 108, kNA, kNA, kNA, kNA } }, // Thorium
{ Pa, { kNA, kNA, kNA, kNA, kNA, 116, 104, 92, kNA, kNA, kNA } }, // Protactinium
{ U, { kNA, kNA, kNA, kNA, kNA, 116.5, 103, 90, 87, kNA, kNA } }, // Uranium
{ U, { kNA, kNA, kNA, kNA, kNA, 116.5f, 103, 90, 87, kNA, kNA } }, // Uranium
{ Np, { kNA, kNA, kNA, kNA, 124, 115, 101, 89, 86, 85, kNA } }, // Neptunium
{ Pu, { kNA, kNA, kNA, kNA, kNA, 114, 100, 88, 85, kNA, kNA } }, // Plutonium
{ Am, { kNA, kNA, kNA, kNA, 140, 111.5, 99, kNA, kNA, kNA, kNA } }, // Americium
{ Am, { kNA, kNA, kNA, kNA, 140, 111.5f, 99, kNA, kNA, kNA, kNA } }, // Americium
{ Cm, { kNA, kNA, kNA, kNA, kNA, 111, 99, kNA, kNA, kNA, kNA } }, // Curium
{ Bk, { kNA, kNA, kNA, kNA, kNA, 110, 97, kNA, kNA, kNA, kNA } }, // Berkelium
{ Cf, { kNA, kNA, kNA, kNA, kNA, 109, 96.1, kNA, kNA, kNA, kNA } }, // Californium
{ Es, { kNA, kNA, kNA, kNA, kNA, 92.8, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
{ Cf, { kNA, kNA, kNA, kNA, kNA, 109, 96.1f, kNA, kNA, kNA, kNA } }, // Californium
{ Es, { kNA, kNA, kNA, kNA, kNA, 92.8f, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
}, kEffectiveIonicRadii[] = {
{ H, { kNA, kNA, 139.9, -18, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Hydrogen
{ H, { kNA, kNA, 139.9f, -18, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Hydrogen
{ Li, { kNA, kNA, kNA, 76, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Lithium
{ Be, { kNA, kNA, kNA, kNA, 45, kNA, kNA, kNA, kNA, kNA, kNA } }, // Beryllium
{ B, { kNA, kNA, kNA, kNA, kNA, 27, kNA, kNA, kNA, kNA, kNA } }, // Boron
@@ -282,24 +282,24 @@ const struct ionic_radii
{ F, { kNA, kNA, 133, kNA, kNA, kNA, kNA, kNA, kNA, 8, kNA } }, // Fluorine
{ Na, { kNA, kNA, kNA, 102, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Sodium
{ Mg, { kNA, kNA, kNA, kNA, 72, kNA, kNA, kNA, kNA, kNA, kNA } }, // Magnesium
{ Al, { kNA, kNA, kNA, kNA, kNA, 53.5, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
{ Al, { kNA, kNA, kNA, kNA, kNA, 53.5f, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
{ Si, { kNA, kNA, kNA, kNA, kNA, kNA, 40, kNA, kNA, kNA, kNA } }, // Silicon
{ P, { 212, kNA, kNA, kNA, kNA, 44, kNA, 38, kNA, kNA, kNA } }, // Phosphorus
{ S, { kNA, 184, kNA, kNA, kNA, kNA, 37, kNA, 29, kNA, kNA } }, // Sulfur
{ Cl, { kNA, kNA, 181, kNA, kNA, kNA, kNA, 12, kNA, 27, kNA } }, // Chlorine
{ K, { kNA, kNA, kNA, 138, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Potassium
{ Ca, { kNA, kNA, kNA, kNA, 100, kNA, kNA, kNA, kNA, kNA, kNA } }, // Calcium
{ Sc, { kNA, kNA, kNA, kNA, kNA, 74.5, kNA, kNA, kNA, kNA, kNA } }, // Scandium
{ Ti, { kNA, kNA, kNA, kNA, 86, 67, 60.5, kNA, kNA, kNA, kNA } }, // Titanium
{ Sc, { kNA, kNA, kNA, kNA, kNA, 74.5f, kNA, kNA, kNA, kNA, kNA } }, // Scandium
{ Ti, { kNA, kNA, kNA, kNA, 86, 67, 60.5f, kNA, kNA, kNA, kNA } }, // Titanium
{ V, { kNA, kNA, kNA, kNA, 79, 64, 58, 54, kNA, kNA, kNA } }, // Vanadium
{ Cr, { kNA, kNA, kNA, kNA, 73, 61.5, 55, 49, 44, kNA, kNA } }, // Chromium ls
{ Cr, { kNA, kNA, kNA, kNA, 73, 61.5f, 55, 49, 44, kNA, kNA } }, // Chromium ls
{ Cr, { kNA, kNA, kNA, kNA, 80, kNA, kNA, kNA, kNA, kNA, kNA } }, // Chromium hs
{ Mn, { kNA, kNA, kNA, kNA, 67, 58, 53, 33, 25.5, 46, kNA } }, // Manganese ls
{ Mn, { kNA, kNA, kNA, kNA, 83, 64.5, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
{ Fe, { kNA, kNA, kNA, kNA, 61, 55, 58.5, kNA, 25, kNA, kNA } }, // Iron ls
{ Fe, { kNA, kNA, kNA, kNA, 78, 64.5, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
{ Co, { kNA, kNA, kNA, kNA, 65, 54.5, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
{ Co, { kNA, kNA, kNA, kNA, 74.5, 61, 53, kNA, kNA, kNA, kNA } }, // Cobalt hs
{ Mn, { kNA, kNA, kNA, kNA, 67, 58, 53, 33, 25.5f, 46, kNA } }, // Manganese ls
{ Mn, { kNA, kNA, kNA, kNA, 83, 64.5f, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
{ Fe, { kNA, kNA, kNA, kNA, 61, 55, 58.5f, kNA, 25, kNA, kNA } }, // Iron ls
{ Fe, { kNA, kNA, kNA, kNA, 78, 64.5f, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
{ Co, { kNA, kNA, kNA, kNA, 65, 54.5f, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
{ Co, { kNA, kNA, kNA, kNA, 74.5f, 61, 53, kNA, kNA, kNA, kNA } }, // Cobalt hs
{ Ni, { kNA, kNA, kNA, kNA, 69, 56, 48, kNA, kNA, kNA, kNA } }, // Nickel ls
{ Ni, { kNA, kNA, kNA, kNA, kNA, 60, kNA, kNA, kNA, kNA, kNA } }, // Nickel hs
{ Cu, { kNA, kNA, kNA, 77, 73, 54, kNA, kNA, kNA, kNA, kNA } }, // Copper
@@ -315,10 +315,10 @@ const struct ionic_radii
{ Zr, { kNA, kNA, kNA, kNA, kNA, kNA, 72, kNA, kNA, kNA, kNA } }, // Zirconium
{ Nb, { kNA, kNA, kNA, kNA, kNA, 72, 68, 64, kNA, kNA, kNA } }, // Niobium
{ Mo, { kNA, kNA, kNA, kNA, kNA, 69, 65, 61, 59, kNA, kNA } }, // Molybdenum
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 64.5, 60, kNA, 56, kNA } }, // Technetium
{ Ru, { kNA, kNA, kNA, kNA, kNA, 68, 62, 56.5, kNA, 38, 36 } }, // Ruthenium
{ Rh, { kNA, kNA, kNA, kNA, kNA, 66.5, 60, 55, kNA, kNA, kNA } }, // Rhodium
{ Pd, { kNA, kNA, kNA, 59, 86, 76, 61.5, kNA, kNA, kNA, kNA } }, // Palladium
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 64.5f, 60, kNA, 56, kNA } }, // Technetium
{ Ru, { kNA, kNA, kNA, kNA, kNA, 68, 62, 56.5f, kNA, 38, 36 } }, // Ruthenium
{ Rh, { kNA, kNA, kNA, kNA, kNA, 66.5f, 60, 55, kNA, kNA, kNA } }, // Rhodium
{ Pd, { kNA, kNA, kNA, 59, 86, 76, 61.5f, kNA, kNA, kNA, kNA } }, // Palladium
{ Ag, { kNA, kNA, kNA, 115, 94, 75, kNA, kNA, kNA, kNA, kNA } }, // Silver
{ Cd, { kNA, kNA, kNA, kNA, 95, kNA, kNA, kNA, kNA, kNA, kNA } }, // Cadmium
{ In, { kNA, kNA, kNA, kNA, kNA, 80, kNA, kNA, kNA, kNA, kNA } }, // Indium
@@ -329,48 +329,48 @@ const struct ionic_radii
{ Xe, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 48 } }, // Xenon
{ Cs, { kNA, kNA, kNA, 167, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Caesium
{ Ba, { kNA, kNA, kNA, kNA, 135, kNA, kNA, kNA, kNA, kNA, kNA } }, // Barium
{ La, { kNA, kNA, kNA, kNA, kNA, 103.2, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
{ La, { kNA, kNA, kNA, kNA, kNA, 103.2f, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
{ Ce, { kNA, kNA, kNA, kNA, kNA, 101, 87, kNA, kNA, kNA, kNA } }, // Cerium
{ Pr, { kNA, kNA, kNA, kNA, kNA, 99, 85, kNA, kNA, kNA, kNA } }, // Praseodymium
{ Nd, { kNA, kNA, kNA, kNA, 129, 98.3, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
{ Nd, { kNA, kNA, kNA, kNA, 129, 98.3f, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
{ Pm, { kNA, kNA, kNA, kNA, kNA, 97, kNA, kNA, kNA, kNA, kNA } }, // Promethium
{ Sm, { kNA, kNA, kNA, kNA, 122, 95.8, kNA, kNA, kNA, kNA, kNA } }, // Samarium
{ Eu, { kNA, kNA, kNA, kNA, 117, 94.7, kNA, kNA, kNA, kNA, kNA } }, // Europium
{ Gd, { kNA, kNA, kNA, kNA, kNA, 93.5, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
{ Tb, { kNA, kNA, kNA, kNA, kNA, 92.3, 76, kNA, kNA, kNA, kNA } }, // Terbium
{ Dy, { kNA, kNA, kNA, kNA, 107, 91.2, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
{ Ho, { kNA, kNA, kNA, kNA, kNA, 90.1, kNA, kNA, kNA, kNA, kNA } }, // Holmium
{ Sm, { kNA, kNA, kNA, kNA, 122, 95.8f, kNA, kNA, kNA, kNA, kNA } }, // Samarium
{ Eu, { kNA, kNA, kNA, kNA, 117, 94.7f, kNA, kNA, kNA, kNA, kNA } }, // Europium
{ Gd, { kNA, kNA, kNA, kNA, kNA, 93.5f, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
{ Tb, { kNA, kNA, kNA, kNA, kNA, 92.3f, 76, kNA, kNA, kNA, kNA } }, // Terbium
{ Dy, { kNA, kNA, kNA, kNA, 107, 91.2f, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
{ Ho, { kNA, kNA, kNA, kNA, kNA, 90.1f, kNA, kNA, kNA, kNA, kNA } }, // Holmium
{ Er, { kNA, kNA, kNA, kNA, kNA, 89, kNA, kNA, kNA, kNA, kNA } }, // Erbium
{ Tm, { kNA, kNA, kNA, kNA, 103, 88, kNA, kNA, kNA, kNA, kNA } }, // Thulium
{ Yb, { kNA, kNA, kNA, kNA, 102, 86.8, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
{ Lu, { kNA, kNA, kNA, kNA, kNA, 86.1, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
{ Yb, { kNA, kNA, kNA, kNA, 102, 86.8f, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
{ Lu, { kNA, kNA, kNA, kNA, kNA, 86.1f, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
{ Hf, { kNA, kNA, kNA, kNA, kNA, kNA, 71, kNA, kNA, kNA, kNA } }, // Hafnium
{ Ta, { kNA, kNA, kNA, kNA, kNA, 72, 68, 64, kNA, kNA, kNA } }, // Tantalum
{ W, { kNA, kNA, kNA, kNA, kNA, kNA, 66, 62, 60, kNA, kNA } }, // Tungsten
{ Re, { kNA, kNA, kNA, kNA, kNA, kNA, 63, 58, 55, 53, kNA } }, // Rhenium
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 63, 57.5, 54.5, 52.5, 39 } }, // Osmium
{ Ir, { kNA, kNA, kNA, kNA, kNA, 68, 62.5, 57, kNA, kNA, kNA } }, // Iridium
{ Pt, { kNA, kNA, kNA, kNA, 80, kNA, 62.5, 57, kNA, kNA, kNA } }, // Platinum
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 63, 57.5f, 54.5f, 52.5f, 39 } }, // Osmium
{ Ir, { kNA, kNA, kNA, kNA, kNA, 68, 62.5f, 57, kNA, kNA, kNA } }, // Iridium
{ Pt, { kNA, kNA, kNA, kNA, 80, kNA, 62.5f, 57, kNA, kNA, kNA } }, // Platinum
{ Au, { kNA, kNA, kNA, 137, kNA, 85, kNA, 57, kNA, kNA, kNA } }, // Gold
{ Hg, { kNA, kNA, kNA, 119, 102, kNA, kNA, kNA, kNA, kNA, kNA } }, // Mercury
{ Tl, { kNA, kNA, kNA, 150, kNA, 88.5, kNA, kNA, kNA, kNA, kNA } }, // Thallium
{ Pb, { kNA, kNA, kNA, kNA, 119, kNA, 77.5, kNA, kNA, kNA, kNA } }, // Lead
{ Tl, { kNA, kNA, kNA, 150, kNA, 88.5f, kNA, kNA, kNA, kNA, kNA } }, // Thallium
{ Pb, { kNA, kNA, kNA, kNA, 119, kNA, 77.5f, kNA, kNA, kNA, kNA } }, // Lead
{ Bi, { kNA, kNA, kNA, kNA, kNA, 103, kNA, 76, kNA, kNA, kNA } }, // Bismuth
{ Po, { kNA, 223, kNA, kNA, kNA, kNA, 94, kNA, 67, kNA, kNA } }, // Polonium
{ At, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 62, kNA } }, // Astatine
{ Fr, { kNA, kNA, kNA, 180, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Francium
{ Ra, { kNA, kNA, kNA, kNA, 148, kNA, kNA, kNA, kNA, kNA, kNA } }, // Radium
{ Ac, { kNA, kNA, kNA, kNA, kNA, 106.5, kNA, kNA, kNA, kNA, kNA } }, // Actinium
{ Ac, { kNA, kNA, kNA, kNA, kNA, 106.5f, kNA, kNA, kNA, kNA, kNA } }, // Actinium
{ Th, { kNA, kNA, kNA, kNA, kNA, kNA, 94, kNA, kNA, kNA, kNA } }, // Thorium
{ Pa, { kNA, kNA, kNA, kNA, kNA, 104, 90, 78, kNA, kNA, kNA } }, // Protactinium
{ U, { kNA, kNA, kNA, kNA, kNA, 102.5, 89, 76, 73, kNA, kNA } }, // Uranium
{ U, { kNA, kNA, kNA, kNA, kNA, 102.5f, 89, 76, 73, kNA, kNA } }, // Uranium
{ Np, { kNA, kNA, kNA, kNA, 110, 101, 87, 75, 72, 71, kNA } }, // Neptunium
{ Pu, { kNA, kNA, kNA, kNA, kNA, 100, 86, 74, 71, kNA, kNA } }, // Plutonium
{ Am, { kNA, kNA, kNA, kNA, 126, 97.5, 85, kNA, kNA, kNA, kNA } }, // Americium
{ Am, { kNA, kNA, kNA, kNA, 126, 97.5f, 85, kNA, kNA, kNA, kNA } }, // Americium
{ Cm, { kNA, kNA, kNA, kNA, kNA, 97, 85, kNA, kNA, kNA, kNA } }, // Curium
{ Bk, { kNA, kNA, kNA, kNA, kNA, 96, 83, kNA, kNA, kNA, kNA } }, // Berkelium
{ Cf, { kNA, kNA, kNA, kNA, kNA, 95, 82.1, kNA, kNA, kNA, kNA } }, // Californium
{ Es, { kNA, kNA, kNA, kNA, kNA, 83.5, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
{ Cf, { kNA, kNA, kNA, kNA, kNA, 95, 82.1f, kNA, kNA, kNA, kNA } }, // Californium
{ Es, { kNA, kNA, kNA, kNA, kNA, 83.5f, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
};
@@ -1028,6 +1028,9 @@ atom_type_traits::atom_type_traits(const std::string& symbol)
break;
}
}
if (symbol == "X")
m_info = &data::kKnownAtoms[0];
if (m_info == nullptr)
throw std::invalid_argument("Not a known element: " + symbol);

View File

@@ -24,14 +24,14 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <numeric>
#include <stack>
#include <cif++/category.hpp>
#include <cif++/datablock.hpp>
#include <cif++/parser.hpp>
#include <cif++/utilities.hpp>
#include <numeric>
#include <stack>
// TODO: Find out what the rules are exactly for linked items, the current implementation
// is inconsistent. It all depends whether a link is satified if a field taking part in the
// set of linked items is null at one side and not null in the other.
@@ -595,8 +595,6 @@ category::category(const category &rhs)
, m_columns(rhs.m_columns)
, m_validator(rhs.m_validator)
, m_cat_validator(rhs.m_cat_validator)
, m_parent_links(rhs.m_parent_links)
, m_child_links(rhs.m_child_links)
, m_cascade(rhs.m_cascade)
{
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
@@ -645,8 +643,6 @@ category &category::operator=(const category &rhs)
m_validator = rhs.m_validator;
m_cat_validator = rhs.m_cat_validator;
m_parent_links = rhs.m_parent_links;
m_child_links = rhs.m_child_links;
if (m_cat_validator != nullptr)
m_index = new category_index(this);
@@ -983,11 +979,19 @@ bool category::validate_links() const
row_handle category::operator[](const key_type &key)
{
if (m_index == nullptr)
throw std::logic_error("Category " + m_name + " does not have an index");
row_handle result{};
auto row = m_index->find_by_value(key);
return row != nullptr ? row_handle{ *this, *row } : row_handle{};
if (not empty())
{
if (m_index == nullptr)
throw std::logic_error("Category " + m_name + " does not have an index");
auto row = m_index->find_by_value(key);
if (row != nullptr)
result = { *this, *row };
}
return result;
}
// --------------------------------------------------------------------
@@ -1142,10 +1146,6 @@ category::iterator category::erase(iterator pos)
row *r = rh.get_row();
iterator result = ++pos;
iset keys;
if (m_cat_validator)
keys = iset(m_cat_validator->m_keys.begin(), m_cat_validator->m_keys.end());
if (m_head == nullptr)
throw std::runtime_error("erase");
@@ -1174,7 +1174,7 @@ category::iterator category::erase(iterator pos)
// in mmcif_pdbx.dic dictionary.
//
// For each link group in _pdbx_item_linked_group_list
// a std::set of keys from one category is mapped to another.
// a set of keys from one category is mapped to another.
// If all values in a child are the same as the specified parent ones
// the child is removed as well, recursively of course.
@@ -1198,25 +1198,29 @@ category::iterator category::erase(iterator pos)
return result;
}
size_t category::erase(condition &&cond)
template<typename T>
class save_value
{
size_t result = 0;
cond.prepare(*this);
auto ri = begin();
while (ri != end())
public:
save_value(T &v, const T nv = {})
: m_v(v)
, m_sv(std::exchange(m_v, nv))
{
if (cond(*ri))
{
ri = erase(ri);
++result;
}
else
++ri;
}
return result;
~save_value()
{
m_v = m_sv;
}
private:
T &m_v;
const T m_sv;
};
size_t category::erase(condition &&cond)
{
return erase(std::move(cond), {});
}
size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit)
@@ -1225,12 +1229,26 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
cond.prepare(*this);
std::map<category *, condition> potential_orphans;
auto ri = begin();
while (ri != end())
{
if (cond(*ri))
{
visit(*ri);
if (visit)
visit(*ri);
for (auto &&[childCat, link] : m_child_links)
{
auto ccond = get_children_condition(*ri, *childCat);
if (not ccond)
continue;
potential_orphans[childCat] = std::move(potential_orphans[childCat]) or std::move(ccond);
}
save_value sv(m_validator);
ri = erase(ri);
++result;
}
@@ -1238,6 +1256,9 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
++ri;
}
for (auto &&[childCat, condition] : potential_orphans)
childCat->erase_orphans(std::move(condition), *this);
return result;
}

View File

@@ -24,16 +24,15 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/compound.hpp>
#include <filesystem>
#include <fstream>
#include <map>
#include <mutex>
#include <numeric>
#include <shared_mutex>
#include <filesystem>
#include <fstream>
#include <cif++/compound.hpp>
namespace fs = std::filesystem;
namespace cif
@@ -223,6 +222,28 @@ bool compound::atoms_bonded(const std::string &atomId_1, const std::string &atom
return i != m_bonds.end();
}
float compound::bond_length(const std::string &atomId_1, const std::string &atomId_2) const
{
auto i = find_if(m_bonds.begin(), m_bonds.end(),
[&](const compound_bond &b)
{
return (b.atom_id[0] == atomId_1 and b.atom_id[1] == atomId_2) or (b.atom_id[0] == atomId_2 and b.atom_id[1] == atomId_1);
});
float result = std::numeric_limits<float>::max();
if (i != m_bonds.end())
{
auto a = get_atom_by_atom_id(atomId_1);
auto b = get_atom_by_atom_id(atomId_2);
result = distance(point{a.x, a.y, a.z}, point{b.x, b.y, b.z});
}
return result;
}
// --------------------------------------------------------------------
// known amino acids and bases
@@ -655,13 +676,13 @@ compound_factory::compound_factory()
{
auto ccd = cif::load_resource("components.cif");
if (ccd)
m_impl.reset(new CCD_compound_factory_impl(m_impl));
m_impl = std::make_shared<CCD_compound_factory_impl>(m_impl);
else if (cif::VERBOSE > 0)
std::cerr << "CCD components.cif file was not found" << std::endl;
const char *clibd_mon = getenv("CLIBD_MON");
if (clibd_mon != nullptr and fs::is_directory(clibd_mon))
m_impl.reset(new CCP4_compound_factory_impl(clibd_mon));
m_impl = std::make_shared<CCP4_compound_factory_impl>(clibd_mon, m_impl);
else if (cif::VERBOSE > 0)
std::cerr << "CCP4 monomers library not found, CLIBD_MON is not defined" << std::endl;
}

View File

@@ -63,7 +63,7 @@ namespace detail
condition_impl *key_equals_condition_impl::prepare(const category &c)
{
m_item_ix = get_column_ix(c, m_item_tag);
m_item_ix = c.get_column_ix(m_item_tag);
m_icase = is_column_type_uchar(c, m_item_tag);
if (c.get_cat_validator() != nullptr and
@@ -76,53 +76,82 @@ namespace detail
return this;
}
condition_impl *and_condition_impl::prepare(const category &c)
bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
{
for (auto &sub : mSub)
sub = sub->prepare(c);
bool result = true;
for (;;)
for (auto s = b; s != e; ++s)
{
auto si = find_if(mSub.begin(), mSub.end(), [](condition_impl *sub) { return dynamic_cast<and_condition_impl *>(sub) != nullptr; });
if (si == mSub.end())
auto &cs = (*s)->m_sub;
if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i) { return i->equals(c); }) == cs.end())
{
result = false;
break;
and_condition_impl *sub_and = static_cast<and_condition_impl *>(*si);
mSub.erase(si);
mSub.insert(mSub.end(), sub_and->mSub.begin(), sub_and->mSub.end());
sub_and->mSub.clear();
delete sub_and;
}
}
return this;
return result;
}
condition_impl *and_condition_impl::combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc)
{
and_condition_impl *and_result = nullptr;
auto first = subs.front();
auto &fc = first->m_sub;
for (auto c : fc)
{
if (not found_in_range(c, subs.begin() + 1, subs.end()))
continue;
if (and_result == nullptr)
and_result = new and_condition_impl();
and_result->m_sub.push_back(c);
fc.erase(remove(fc.begin(), fc.end(), c), fc.end());
for (auto sub : subs)
{
auto &ssub = sub->m_sub;
for (auto sc : ssub)
{
if (not sc->equals(c))
continue;
ssub.erase(remove(ssub.begin(), ssub.end(), sc), ssub.end());
delete sc;
break;
}
}
}
if (and_result != nullptr)
{
and_result->m_sub.push_back(oc);
return and_result;
}
return oc;
}
condition_impl *or_condition_impl::prepare(const category &c)
{
condition_impl *result = this;
std::vector<and_condition_impl *> and_conditions;
mA = mA->prepare(c);
mB = mB->prepare(c);
key_equals_condition_impl *equals = dynamic_cast<key_equals_condition_impl*>(mA);
key_is_empty_condition_impl *empty = dynamic_cast<key_is_empty_condition_impl*>(mB);
if (equals == nullptr and empty == nullptr)
for (auto &sub : m_sub)
{
equals = dynamic_cast<key_equals_condition_impl*>(mB);
empty = dynamic_cast<key_is_empty_condition_impl*>(mA);
sub = sub->prepare(c);
if (typeid(*sub) == typeid(and_condition_impl))
and_conditions.push_back(static_cast<and_condition_impl *>(sub));
}
if (equals != nullptr and empty != nullptr and equals->m_item_tag == empty->m_item_tag)
{
result = new detail::key_equals_or_empty_condition_impl(equals);
result = result->prepare(c);
delete this;
}
if (and_conditions.size() == m_sub.size())
return and_condition_impl::combine_equal(and_conditions, this);
return result;
return this;
}
} // namespace detail

View File

@@ -29,6 +29,30 @@
namespace cif
{
datablock::datablock(const datablock &db)
: std::list<category>(db)
, m_name(db.m_name)
, m_validator(db.m_validator)
{
for (auto &cat : *this)
cat.update_links(*this);
}
datablock &datablock::operator=(const datablock &db)
{
if (this != &db)
{
std::list<category>::operator=(db);
m_name = db.m_name;
m_validator = db.m_validator;
for (auto &cat : *this)
cat.update_links(*this);
}
return *this;
}
void datablock::set_validator(const validator *v)
{
m_validator = v;

View File

@@ -125,7 +125,7 @@ void file::load_dictionary(std::string_view name)
bool file::contains(std::string_view name) const
{
return std::find_if(begin(), end(), [name](const datablock &db) { return db.name() == name; }) != end();
return std::find_if(begin(), end(), [name](const datablock &db) { return iequals(db.name(), name); }) != end();
}
datablock &file::operator[](std::string_view name)

View File

@@ -24,10 +24,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cassert>
#include <cif++/row.hpp>
#include <cassert>
namespace cif
{

View File

@@ -34,8 +34,6 @@
namespace fs = std::filesystem;
extern int VERBOSE;
namespace cif::mm
{
@@ -305,6 +303,25 @@ std::ostream &operator<<(std::ostream &os, const atom &atom)
// --------------------------------------------------------------------
// residue
residue::residue(structure &structure, const std::vector<atom> &atoms)
: m_structure(&structure)
{
if (atoms.empty())
throw std::runtime_error("Empty list of atoms");
auto &a = atoms.front();
m_compound_id = a.get_label_comp_id();
m_asym_id = a.get_label_asym_id();
m_seq_id = a.get_label_seq_id();
m_auth_asym_id = a.get_auth_asym_id();
m_auth_seq_id = a.get_auth_seq_id();
m_pdb_ins_code = a.get_pdb_ins_code();
for (auto atom : atoms)
m_atoms.push_back(atom);
}
// residue::residue(residue &&rhs)
// : m_structure(rhs.m_structure)
// , m_compound_id(std::move(rhs.m_compound_id))
@@ -601,20 +618,20 @@ float monomer::phi() const
{
float result = 360;
try
if (m_index > 0)
{
if (m_index > 0)
auto &prev = m_polymer->operator[](m_index - 1);
if (prev.m_seq_id + 1 == m_seq_id)
{
auto &prev = m_polymer->operator[](m_index - 1);
if (prev.m_seq_id + 1 == m_seq_id)
result = static_cast<float>(dihedral_angle(prev.C().get_location(), N().get_location(), CAlpha().get_location(), C().get_location()));
auto a1 = prev.C();
auto a2 = N();
auto a3 = CAlpha();
auto a4 = C();
if (a1 and a2 and a3 and a4)
result = dihedral_angle(a1.get_location(), a2.get_location(), a3.get_location(), a4.get_location());
}
}
catch (const std::exception &ex)
{
if (VERBOSE > 0)
std::cerr << ex.what() << std::endl;
}
return result;
}
@@ -623,20 +640,20 @@ float monomer::psi() const
{
float result = 360;
try
if (m_index + 1 < m_polymer->size())
{
if (m_index + 1 < m_polymer->size())
auto &next = m_polymer->operator[](m_index + 1);
if (m_seq_id + 1 == next.m_seq_id)
{
auto &next = m_polymer->operator[](m_index + 1);
if (m_seq_id + 1 == next.m_seq_id)
result = static_cast<float>(dihedral_angle(N().get_location(), CAlpha().get_location(), C().get_location(), next.N().get_location()));
auto a1 = N();
auto a2 = CAlpha();
auto a3 = C();
auto a4 = next.N();
if (a1 and a2 and a3 and a4)
result = dihedral_angle(a1.get_location(), a2.get_location(), a3.get_location(), a4.get_location());
}
}
catch (const std::exception &ex)
{
if (VERBOSE > 0)
std::cerr << ex.what() << std::endl;
}
return result;
}
@@ -918,30 +935,30 @@ float monomer::omega(const monomer &a, const monomer &b)
{
float result = 360;
try
{
auto a1 = a.get_atom_by_atom_id("CA");
auto a2 = a.get_atom_by_atom_id("C");
auto a3 = b.get_atom_by_atom_id("N");
auto a4 = b.get_atom_by_atom_id("CA");
if (a1 and a2 and a3 and a4)
result = static_cast<float>(dihedral_angle(
a.get_atom_by_atom_id("CA").get_location(),
a.get_atom_by_atom_id("C").get_location(),
b.get_atom_by_atom_id("N").get_location(),
b.get_atom_by_atom_id("CA").get_location()));
}
catch (...)
{
}
a1.get_location(),
a2.get_location(),
a3.get_location(),
a4.get_location()));
return result;
}
bool monomer::is_cis(const monomer &a, const monomer &b)
{
return omega(a, b) < 30.0f;
return std::abs(omega(a, b)) < 30.0f;
}
// --------------------------------------------------------------------
// polymer
polymer::polymer(const structure &s, const std::string &entityID, const std::string &asym_id, const std::string &auth_asym_id)
polymer::polymer(structure &s, const std::string &entityID, const std::string &asym_id, const std::string &auth_asym_id)
: m_structure(const_cast<structure *>(&s))
, m_entity_id(entityID)
, m_asym_id(asym_id)
@@ -957,8 +974,12 @@ polymer::polymer(const structure &s, const std::string &entityID, const std::str
for (auto r : poly_seq_scheme.find("asym_id"_key == asym_id))
{
int seqID;
std::optional<int> pdbSeqNum;
std::string compoundID, authSeqID, pdbInsCode;
cif::tie(seqID, authSeqID, compoundID, pdbInsCode) = r.get("seq_id", "auth_seq_num", "mon_id", "pdb_ins_code");
cif::tie(seqID, authSeqID, compoundID, pdbInsCode, pdbSeqNum) = r.get("seq_id", "auth_seq_num", "mon_id", "pdb_ins_code", "pdb_seq_num");
if (authSeqID.empty() and pdbSeqNum.has_value())
authSeqID = std::to_string(*pdbSeqNum);
size_t index = size();
@@ -1027,7 +1048,7 @@ polymer::polymer(const structure &s, const std::string &entityID, const std::str
// --------------------------------------------------------------------
sugar::sugar(const branch &branch, const std::string &compoundID,
sugar::sugar(branch &branch, const std::string &compoundID,
const std::string &asym_id, int authSeqID)
: residue(branch.get_structure(), compoundID, asym_id, 0, asym_id, std::to_string(authSeqID), "")
, m_branch(&branch)
@@ -1095,9 +1116,39 @@ std::string sugar::name() const
return result;
}
branch::branch(structure &structure, const std::string &asym_id)
cif::mm::atom sugar::add_atom(row_initializer atom_info)
{
auto &db = m_structure->get_datablock();
auto &atom_site = db["atom_site"];
auto atom_id = atom_site.get_unique_id("");
atom_info.set_value({"group_PDB", "HETATM"});
atom_info.set_value({"id", atom_id});
atom_info.set_value({"label_entity_id", m_branch->get_entity_id()});
atom_info.set_value({"label_asym_id", m_branch->get_asym_id()});
atom_info.set_value({"label_comp_id", m_compound_id});
atom_info.set_value({"label_seq_id", "."});
atom_info.set_value({"label_alt_id", "."});
atom_info.set_value({"auth_asym_id", m_branch->get_asym_id()});
atom_info.set_value({"auth_comp_id", m_compound_id});
atom_info.set_value({"auth_seq_id", m_auth_seq_id});
atom_info.set_value({"occupancy", 1.0, 2});
atom_info.set_value({"B_iso_or_equiv", 30.0, 2});
atom_info.set_value({"pdbx_PDB_model_num", 1});
auto row = atom_site.emplace(std::move(atom_info));
auto result = m_structure->emplace_atom(db, row);
residue::add_atom(result);
return result;
}
branch::branch(structure &structure, const std::string &asym_id, const std::string &entity_id)
: m_structure(&structure)
, m_asym_id(asym_id)
, m_entity_id(entity_id)
{
using namespace literals;
@@ -1106,7 +1157,7 @@ branch::branch(structure &structure, const std::string &asym_id)
auto &branch_scheme = db["pdbx_branch_scheme"];
auto &branch_link = db["pdbx_entity_branch_link"];
for (const auto &entity_id : struct_asym.find<std::string>("id"_key == asym_id, "entity_id"))
for (const auto &asym_entity_id : struct_asym.find<std::string>("id"_key == asym_id, "entity_id"))
{
for (const auto &[comp_id, num] : branch_scheme.find<std::string, int>(
"asym_id"_key == asym_id, "mon_id", "pdb_seq_num"))
@@ -1115,7 +1166,7 @@ branch::branch(structure &structure, const std::string &asym_id)
}
for (const auto &[num1, num2, atom1, atom2] : branch_link.find<size_t, size_t, std::string, std::string>(
"entity_id"_key == entity_id, "entity_branch_list_num_1", "entity_branch_list_num_2", "atom_id_1", "atom_id_2"))
"entity_id"_key == asym_entity_id, "entity_branch_list_num_1", "entity_branch_list_num_2", "atom_id_1", "atom_id_2"))
{
// if (not iequals(atom1, "c1"))
// throw std::runtime_error("invalid pdbx_entity_branch_link");
@@ -1155,11 +1206,92 @@ void branch::link_atoms()
}
}
sugar &branch::get_sugar_by_num(int nr)
{
auto i = find_if(begin(), end(), [nr](const sugar &s) { return s.num() == nr; });
if (i == end())
throw std::out_of_range("Sugar with num " + std::to_string(nr) + " not found in branch " + m_asym_id);
return *i;
}
std::string branch::name() const
{
return empty() ? "" : name(front());
}
sugar &branch::construct_sugar(const std::string &compound_id)
{
auto &db = m_structure->get_datablock();
auto compound = compound_factory::instance().create(compound_id);
if (compound == nullptr)
throw std::runtime_error("Trying to insert unknown compound " + compound_id + " (not found in CCD)");
auto &chemComp = db["chem_comp"];
auto r = chemComp.find(key("id") == compound_id);
if (r.empty())
{
chemComp.emplace({
{"id", compound_id},
{"name", compound->name()},
{"formula", compound->formula()},
{"formula_weight", compound->formula_weight()},
{"type", compound->type()}});
}
sugar &result = emplace_back(*this, compound_id, m_asym_id, static_cast<int>(size() + 1));
db["pdbx_branch_scheme"].emplace({
{"asym_id", result.get_asym_id()},
{"entity_id", result.get_entity_id()},
{"num", result.num()},
{"mon_id", result.get_compound_id()},
{"pdb_asym_id", result.get_asym_id()},
{"pdb_seq_num", result.num()},
{"pdb_mon_id", result.get_compound_id()},
{"auth_asym_id", result.get_auth_asym_id()},
{"auth_mon_id", result.get_compound_id()},
{"auth_seq_num", result.get_auth_seq_id()},
{"hetero", "n"}
});
return result;
}
sugar &branch::construct_sugar(const std::string &compound_id, const std::string &atom_id,
int linked_sugar_nr, const std::string &linked_atom_id)
{
auto &result = construct_sugar(compound_id);
auto &linked = get_sugar_by_num(linked_sugar_nr);
result.set_link(linked.get_atom_by_atom_id(linked_atom_id));
auto &db = m_structure->get_datablock();
auto &pdbx_entity_branch_link = db["pdbx_entity_branch_link"];
auto linkID = pdbx_entity_branch_link.get_unique_id("");
db["pdbx_entity_branch_link"].emplace({
{ "link_id", linkID },
{ "entity_id", get_entity_id() },
{ "entity_branch_list_num_1", result.num() },
{ "comp_id_1", compound_id },
{ "atom_id_1", atom_id },
{ "leaving_atom_id_1", "O1" }, /// TODO: Need to fix this!
{ "entity_branch_list_num_2", linked.num() },
{ "comp_id_2", linked.get_compound_id() },
{ "atom_id_2", linked_atom_id },
{ "leaving_atom_id_2", "." },
{ "value_order", "sing" }
});
return result;
}
std::string branch::name(const sugar &s) const
{
using namespace literals;
@@ -1279,10 +1411,10 @@ void structure::load_data()
auto &branchScheme = m_db["pdbx_branch_scheme"];
for (const auto &asym_id : branchScheme.rows<std::string>("asym_id"))
for (const auto &[asym_id, entity_id] : branchScheme.rows<std::string,std::string>("asym_id", "entity_id"))
{
if (m_branches.empty() or m_branches.back().get_asym_id() != asym_id)
m_branches.emplace_back(*this, asym_id);
m_branches.emplace_back(*this, asym_id, entity_id);
}
auto &nonPolyScheme = m_db["pdbx_nonpoly_scheme"];
@@ -1514,6 +1646,11 @@ polymer &structure::get_polymer_by_asym_id(const std::string &asym_id)
throw std::runtime_error("polymer with asym id " + asym_id + " not found");
}
residue &structure::create_residue(const std::vector<atom> &atoms)
{
return m_non_polymers.emplace_back(*this, atoms);
}
residue &structure::get_residue(const std::string &asym_id, int seqID, const std::string &authSeqID)
{
if (seqID == 0)
@@ -1643,7 +1780,7 @@ std::string structure::insert_compound(const std::string &compoundID, bool is_en
{
auto &pdbxEntityNonpoly = m_db["pdbx_entity_nonpoly"];
entity_id = pdbxEntityNonpoly.find1<std::string>("comp_id"_key == compoundID, "entity_id");
entity_id = pdbxEntityNonpoly.find_first<std::string>("comp_id"_key == compoundID, "entity_id");
if (entity_id.empty())
{
@@ -1688,7 +1825,10 @@ atom &structure::emplace_atom(atom &&atom)
R = i - 1;
}
m_atom_index.insert(m_atom_index.begin() + R + 1, m_atoms.size());
if (R == -1) // msvc...
m_atom_index.insert(m_atom_index.begin(), m_atoms.size());
else
m_atom_index.insert(m_atom_index.begin() + R + 1, m_atoms.size());
// make sure the atom_type is known
auto &atom_type = m_db["atom_type"];
@@ -1814,7 +1954,7 @@ void structure::change_residue(residue &res, const std::string &newCompound,
// create a copy of the entity first
auto &entity = m_db["entity"];
entityID = entity.find1<std::string>("type"_key == "non-polymer" and "pdbx_description"_key == compound->name(), "id");
entityID = entity.find_first<std::string>("type"_key == "non-polymer" and "pdbx_description"_key == compound->name(), "id");
if (entityID.empty())
{
@@ -1895,6 +2035,51 @@ void structure::change_residue(residue &res, const std::string &newCompound,
}
}
void structure::remove_residue(const std::string &asym_id, int seq_id, const std::string &auth_seq_id)
{
if (seq_id == 0)
{
for (auto &res : m_non_polymers)
{
if (res.get_asym_id() == asym_id and (auth_seq_id.empty() or res.get_auth_seq_id() == auth_seq_id))
{
remove_residue(res);
return;
}
}
}
for (auto &poly : m_polymers)
{
if (poly.get_asym_id() != asym_id)
continue;
for (auto &res : poly)
{
if (res.get_seq_id() == seq_id)
{
remove_residue(res);
return;
}
}
}
for (auto &branch : m_branches)
{
if (branch.get_asym_id() != asym_id)
continue;
for (auto &sugar : branch)
{
if (sugar.get_asym_id() == asym_id and sugar.get_auth_seq_id() == auth_seq_id)
{
remove_residue(sugar);
return;
}
}
}
}
void structure::remove_residue(residue &res)
{
using namespace literals;
@@ -2181,55 +2366,18 @@ std::string structure::create_non_poly(const std::string &entity_id, std::vector
return asym_id;
}
branch &structure::create_branch(std::vector<row_initializer> atoms)
branch &structure::create_branch()
{
// sanity check
for (auto &nag_atom : atoms)
{
for (const auto &[name, value] : nag_atom)
{
if (name == "label_comp_id" and value != "NAG")
throw std::logic_error("The first sugar in a branch should be a NAG");
}
}
using namespace literals;
auto &entity = m_db["entity"];
auto &struct_asym = m_db["struct_asym"];
std::string asym_id = struct_asym.get_unique_id();
auto &branch = m_branches.emplace_back(*this, asym_id);
auto &sugar = branch.emplace_back(branch, "NAG", asym_id, 1);
auto tmp_entity_id = m_db["entity"].get_unique_id("");
auto entity_id = entity.get_unique_id("");
auto asym_id = struct_asym.get_unique_id();
auto &atom_site = m_db["atom_site"];
for (auto &atom : atoms)
{
auto atom_id = atom_site.get_unique_id("");
atom.set_value("id", atom_id);
atom.set_value("label_asym_id", asym_id);
atom.set_value("auth_asym_id", asym_id);
atom.set_value("label_entity_id", tmp_entity_id);
atom.set_value({ "auth_seq_id", 1 });
atom.set_value_if_empty({"group_PDB", "HETATM"});
atom.set_value_if_empty({"label_comp_id", "NAG"});
atom.set_value_if_empty({"label_seq_id", "."});
atom.set_value_if_empty({"auth_comp_id", "NAG"});
atom.set_value_if_empty({"pdbx_PDB_model_num", 1});
atom.set_value_if_empty({"label_alt_id", ""});
auto row = atom_site.emplace(atom.begin(), atom.end());
auto &newAtom = emplace_atom(std::make_shared<atom::atom_impl>(m_db, atom_id));
sugar.add_atom(newAtom);
}
// now we can create the entity and get the real ID
auto entity_id = create_entity_for_branch(branch);
assert(not entity_id.empty());
entity.emplace({
{"id", entity_id},
{"type", "branched"}
});
struct_asym.emplace({
{"id", asym_id},
@@ -2239,131 +2387,183 @@ branch &structure::create_branch(std::vector<row_initializer> atoms)
{"details", "?"}
});
for (auto &a : sugar.atoms())
a.set_property("label_entity_id", entity_id);
m_db["pdbx_branch_scheme"].emplace({
{"asym_id", asym_id},
{"entity_id", entity_id},
{"num", 1},
{"mon_id", "NAG"},
{"pdb_asym_id", asym_id},
{"pdb_seq_num", 1},
{"pdb_mon_id", "NAG"},
// TODO: need fix, collect from nag_atoms?
{"auth_asym_id", asym_id},
{"auth_mon_id", "NAG"},
{"auth_seq_num", 1},
{"hetero", "n"}
});
return branch;
return m_branches.emplace_back(*this, asym_id, entity_id);
}
branch &structure::extend_branch(const std::string &asym_id, std::vector<row_initializer> atom_info,
int link_sugar, const std::string &link_atom)
{
// sanity check
std::string compoundID;
// branch &structure::create_branch(std::vector<row_initializer> atoms)
// {
// // // sanity check
// // for (auto &nag_atom : atoms)
// // {
// // for (const auto &[name, value] : nag_atom)
// // {
// // if (name == "label_comp_id" and value != "NAG")
// // throw std::logic_error("The first sugar in a branch should be a NAG");
// // }
// // }
for (auto &atom : atom_info)
{
for (const auto &[name, value] : atom)
{
if (name != "label_comp_id")
continue;
// // using namespace literals;
if (compoundID.empty())
compoundID = value;
else if (value != compoundID)
throw std::logic_error("All atoms should be of the same type");
}
}
// // auto &branch = create_branch();
// // auto asym_id = branch.get_asym_id();
// // auto entity_id = branch.get_entity_id();
using namespace literals;
// // auto &sugar = branch.emplace_back(branch, "NAG", asym_id, 1);
// auto &branch = m_branches.emplace_back(*this, asym_id);
auto tmp_entity_id = m_db["entity"].get_unique_id("");
// // auto &atom_site = m_db["atom_site"];
auto &atom_site = m_db["atom_site"];
// // for (auto &atom : atoms)
// // {
// // auto atom_id = atom_site.get_unique_id("");
auto bi = std::find_if(m_branches.begin(), m_branches.end(), [asym_id](branch &b)
{ return b.get_asym_id() == asym_id; });
if (bi == m_branches.end())
throw std::logic_error("Create a branch first!");
// // atom.set_value("id", atom_id);
// // atom.set_value("label_asym_id", asym_id);
// // atom.set_value("auth_asym_id", asym_id);
// // atom.set_value("label_entity_id", entity_id);
// // atom.set_value({ "auth_seq_id", 1 });
branch &branch = *bi;
// // atom.set_value_if_empty({"group_PDB", "HETATM"});
// // atom.set_value_if_empty({"label_comp_id", "NAG"});
// // atom.set_value_if_empty({"label_seq_id", "."});
// // atom.set_value_if_empty({"auth_comp_id", "NAG"});
// // atom.set_value_if_empty({"pdbx_PDB_model_num", 1});
// // atom.set_value_if_empty({"label_alt_id", ""});
int sugarNum = static_cast<int>(branch.size() + 1);
// // auto row = atom_site.emplace(atom.begin(), atom.end());
auto &sugar = branch.emplace_back(branch, compoundID, asym_id, sugarNum);
// // auto &newAtom = emplace_atom(std::make_shared<atom::atom_impl>(m_db, atom_id));
// // sugar.add_atom(newAtom);
// // }
for (auto &atom : atom_info)
{
auto atom_id = atom_site.get_unique_id("");
// // // // now we can create the entity and get the real ID
// // // auto entity_id = create_entity_for_branch(branch);
// // // assert(not entity_id.empty());
atom.set_value("id", atom_id);
atom.set_value("label_asym_id", asym_id);
atom.set_value("auth_asym_id", asym_id);
atom.set_value("label_entity_id", tmp_entity_id);
atom.set_value({"auth_seq_id", sugarNum });
// // for (auto &a : sugar.atoms())
// // a.set_property("label_entity_id", entity_id);
atom.set_value_if_empty({"group_PDB", "HETATM"});
atom.set_value_if_empty({"label_comp_id", compoundID});
atom.set_value_if_empty({"auth_comp_id", compoundID});
atom.set_value_if_empty({"pdbx_PDB_model_num", 1});
atom.set_value_if_empty({"label_alt_id", ""});
// // m_db["pdbx_branch_scheme"].emplace({
// // {"asym_id", asym_id},
// // {"entity_id", entity_id},
// // {"num", 1},
// // {"mon_id", "NAG"},
auto row = atom_site.emplace(atom.begin(), atom.end());
// // {"pdb_asym_id", asym_id},
// // {"pdb_seq_num", 1},
// // {"pdb_mon_id", "NAG"},
auto &newAtom = emplace_atom(std::make_shared<atom::atom_impl>(m_db, atom_id));
sugar.add_atom(newAtom);
}
// // // TODO: need fix, collect from nag_atoms?
// // {"auth_asym_id", asym_id},
// // {"auth_mon_id", "NAG"},
// // {"auth_seq_num", 1},
sugar.set_link(branch.at(link_sugar - 1).get_atom_by_atom_id(link_atom));
// // {"hetero", "n"}
// // });
auto entity_id = create_entity_for_branch(branch);
// // return branch;
// }
// Update the entity id of the asym
auto &struct_asym = m_db["struct_asym"];
auto r = struct_asym.find1("id"_key == asym_id);
r["entity_id"] = entity_id;
// branch &structure::extend_branch(const std::string &asym_id, std::vector<row_initializer> atom_info,
// int link_sugar, const std::string &link_atom)
// {
// // // sanity check
// // std::string compoundID;
for (auto &s2 : branch)
{
for (auto atom : s2.atoms())
atom.set_property("label_entity_id", entity_id);
}
// // for (auto &atom : atom_info)
// // {
// // for (const auto &[name, value] : atom)
// // {
// // if (name != "label_comp_id")
// // continue;
auto &pdbx_branch_scheme = m_db["pdbx_branch_scheme"];
pdbx_branch_scheme.erase("asym_id"_key == asym_id);
// // if (compoundID.empty())
// // compoundID = value;
// // else if (value != compoundID)
// // throw std::logic_error("All atoms should be of the same type");
// // }
// // }
for (auto &s2 : branch)
{
pdbx_branch_scheme.emplace({
{"asym_id", asym_id},
{"entity_id", entity_id},
{"num", s2.num()},
{"mon_id", s2.get_compound_id()},
// // using namespace literals;
{"pdb_asym_id", asym_id},
{"pdb_seq_num", s2.num()},
{"pdb_mon_id", s2.get_compound_id()},
// // // auto &branch = m_branches.emplace_back(*this, asym_id);
// // auto tmp_entity_id = m_db["entity"].get_unique_id("");
// TODO: need fix, collect from nag_atoms?
{"auth_asym_id", asym_id},
{"auth_mon_id", s2.get_compound_id()},
{"auth_seq_num", s2.get_auth_seq_id()},
// // auto &atom_site = m_db["atom_site"];
{"hetero", "n"}
});
}
// // auto bi = std::find_if(m_branches.begin(), m_branches.end(), [asym_id](branch &b)
// // { return b.get_asym_id() == asym_id; });
// // if (bi == m_branches.end())
// // throw std::logic_error("Create a branch first!");
return branch;
}
// // branch &branch = *bi;
// // int sugarNum = static_cast<int>(branch.size() + 1);
// // auto &sugar = branch.emplace_back(branch, compoundID, asym_id, sugarNum);
// // for (auto &atom : atom_info)
// // {
// // auto atom_id = atom_site.get_unique_id("");
// // atom.set_value("id", atom_id);
// // atom.set_value("label_asym_id", asym_id);
// // atom.set_value("auth_asym_id", asym_id);
// // atom.set_value("label_entity_id", tmp_entity_id);
// // atom.set_value({"auth_seq_id", sugarNum });
// // atom.set_value_if_empty({"group_PDB", "HETATM"});
// // atom.set_value_if_empty({"label_comp_id", compoundID});
// // atom.set_value_if_empty({"auth_comp_id", compoundID});
// // atom.set_value_if_empty({"pdbx_PDB_model_num", 1});
// // atom.set_value_if_empty({"label_alt_id", ""});
// // auto row = atom_site.emplace(atom.begin(), atom.end());
// // auto &newAtom = emplace_atom(std::make_shared<atom::atom_impl>(m_db, atom_id));
// // sugar.add_atom(newAtom);
// // }
// // sugar.set_link(branch.at(link_sugar - 1).get_atom_by_atom_id(link_atom));
// // auto entity_id = create_entity_for_branch(branch);
// // // Update the entity id of the asym
// // auto &struct_asym = m_db["struct_asym"];
// // auto r = struct_asym.find1("id"_key == asym_id);
// // r["entity_id"] = entity_id;
// // for (auto &s2 : branch)
// // {
// // for (auto atom : s2.atoms())
// // atom.set_property("label_entity_id", entity_id);
// // }
// // auto &pdbx_branch_scheme = m_db["pdbx_branch_scheme"];
// // pdbx_branch_scheme.erase("asym_id"_key == asym_id);
// // for (auto &s2 : branch)
// // {
// // pdbx_branch_scheme.emplace({
// // {"asym_id", asym_id},
// // {"entity_id", entity_id},
// // {"num", s2.num()},
// // {"mon_id", s2.get_compound_id()},
// // {"pdb_asym_id", asym_id},
// // {"pdb_seq_num", s2.num()},
// // {"pdb_mon_id", s2.get_compound_id()},
// // // TODO: need fix, collect from nag_atoms?
// // {"auth_asym_id", asym_id},
// // {"auth_mon_id", s2.get_compound_id()},
// // {"auth_seq_num", s2.get_auth_seq_id()},
// // {"hetero", "n"}
// // });
// // }
// // return branch;
// }
std::string structure::create_entity_for_branch(branch &branch)
{
@@ -2373,7 +2573,7 @@ std::string structure::create_entity_for_branch(branch &branch)
auto &entity = m_db["entity"];
std::string entityID = entity.find1<std::string>("type"_key == "branched" and "pdbx_description"_key == entityName, "id");
std::string entityID = entity.find_first<std::string>("type"_key == "branched" and "pdbx_description"_key == entityName, "id");
if (entityID.empty())
{
@@ -2382,11 +2582,13 @@ std::string structure::create_entity_for_branch(branch &branch)
if (VERBOSE)
std::cout << "Creating new entity " << entityID << " for branched sugar " << entityName << std::endl;
entity.emplace({{"id", entityID},
entity.emplace({
{"id", entityID},
{"type", "branched"},
{"src_method", "man"},
{"pdbx_description", entityName},
{"formula_weight", branch.weight()}});
auto &pdbx_entity_branch_list = m_db["pdbx_entity_branch_list"];
for (auto &sugar : branch)
{
@@ -2575,4 +2777,14 @@ void structure::validate_atoms() const
assert(atoms.empty());
}
// --------------------------------------------------------------------
void reconstruct_pdbx(datablock &db)
{
if (db.get("atom_site") == nullptr)
throw std::runtime_error("Cannot reconstruct PDBx file, atom data missing");
}
} // namespace pdbx

View File

@@ -24,23 +24,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/utilities.hpp>
#include <cif++/forward_decl.hpp>
#include <cif++/parser.hpp>
#include <cif++/file.hpp>
#include <cassert>
#include <iostream>
#include <map>
#include <regex>
#include <stack>
#include <cif++/utilities.hpp>
#include <cif++/forward_decl.hpp>
#include <cif++/parser.hpp>
#include <cif++/file.hpp>
namespace cif
{
extern int VERBOSE;
}
namespace cif
{
@@ -380,18 +374,13 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
std::string s = to_lower_copy(m_token_value);
if (s == "global_")
result = CIFToken::GLOBAL;
else if (s == "stop_")
result = CIFToken::STOP;
else if (s == "loop_")
result = CIFToken::LOOP;
else if (s == "data_")
if (s == "data_")
{
state = State::DATA;
continue;
}
else if (s == "save_")
if (s == "save_")
{
state = State::SAVE;
continue;
@@ -405,6 +394,12 @@ sac_parser::CIFToken sac_parser::get_next_token()
if (m_token_value == ".")
mTokenType = CIFValue::Inapplicable;
else if (iequals(m_token_value, "global_"))
result = CIFToken::GLOBAL;
else if (iequals(m_token_value, "stop_"))
result = CIFToken::STOP;
else if (iequals(m_token_value, "loop_"))
result = CIFToken::LOOP;
else if (m_token_value == "?")
{
mTokenType = CIFValue::Unknown;
@@ -786,6 +781,9 @@ void sac_parser::parse_save_frame()
void parser::produce_datablock(const std::string &name)
{
if (VERBOSE >= 4)
std::cerr << "producing data_" << name << std::endl;
const auto &[iter, ignore] = m_file.emplace(name);
m_datablock = &(*iter);
}
@@ -801,7 +799,7 @@ void parser::produce_category(const std::string &name)
void parser::produce_row()
{
if (VERBOSE >= 4)
if (VERBOSE >= 4 and m_category != nullptr)
std::cerr << "producing row for category " << m_category->name() << std::endl;
if (m_category == nullptr)

View File

@@ -24,6 +24,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++.hpp>
#include <cif++/pdb/cif2pdb.hpp>
#include <cif++/gzio.hpp>
#include <cmath>
#include <deque>
#include <iomanip>
@@ -31,9 +35,6 @@
#include <regex>
#include <set>
#include <cif++.hpp>
#include <cif++/pdb/cif2pdb.hpp>
#include <cif++/gzio.hpp>
namespace cif::pdb
{
@@ -121,9 +122,9 @@ std::string cifSoftware(const datablock &db, SoftwareType sw)
{
switch (sw)
{
case eRefinement: result = db["computing"].find1<std::string>(key("entry_id") == db.name(), "structure_refinement"); break;
case eDataScaling: result = db["computing"].find1<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ds"); break;
case eDataReduction: result = db["computing"].find1<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ii"); break;
case eRefinement: result = db["computing"].find_first<std::string>(key("entry_id") == db.name(), "structure_refinement"); break;
case eDataScaling: result = db["computing"].find_first<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ds"); break;
case eDataReduction: result = db["computing"].find_first<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ii"); break;
default: break;
}
@@ -135,11 +136,11 @@ std::string cifSoftware(const datablock &db, SoftwareType sw)
switch (sw)
{
case eRefinement: r = software.find1(key("classification") == "refinement"); break;
case eDataScaling: r = software.find1(key("classification") == "data scaling"); break;
case eDataExtraction: r = software.find1(key("classification") == "data extraction"); break;
case eDataReduction: r = software.find1(key("classification") == "data reduction"); break;
case ePhasing: r = software.find1(key("classification") == "phasing"); break;
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())
@@ -671,6 +672,7 @@ class Fi : public FBase
virtual void out(std::ostream &os)
{
std::string s{ text() };
if (s.empty())
{
os << "NULL";
@@ -678,7 +680,18 @@ class Fi : public FBase
os << std::string(os.width() - 4, ' ');
}
else
os << std::stol(s);
{
long l = 0;
auto r = std::from_chars(s.data(), s.data() + s.length(), l);
if (r.ec != std::errc())
{
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" << std::endl;
os << s;
}
else
os << l;
}
}
};
@@ -711,7 +724,7 @@ class Ff : public FBase
if (r.ec != std::errc())
{
if (VERBOSE > 0)
std::cerr << "Failed to write '" << s << "' as a double, this indicates an error in the code for writing PDB files" << std::endl;
std::cerr << "Failed to write '" << s << "' as a double from field " << mField << ", this indicates an error in the code for writing PDB files" << std::endl;
os << s;
}
else
@@ -957,7 +970,7 @@ void WriteRemark3BusterTNT(std::ostream &pdbFile, const datablock &db)
for (auto t : tls)
{
std::string id = t["id"].as<std::string>();
auto g = db["pdbx_refine_tls_group"].find1(key("refine_tls_id") == id);
auto g = db["pdbx_refine_tls_group"].find_first(key("refine_tls_id") == id);
pdbFile << RM3("") << std::endl
<< RM3(" TLS GROUP : ") << id << std::endl
@@ -1383,7 +1396,7 @@ void WriteRemark3Refmac(std::ostream &pdbFile, const datablock &db)
unit = " : ";
pdbFile << RM3(" ", 18) << type
<< SEP("", -2) << Fi(l, "pdbx_ens_id")
<< 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")
@@ -1655,7 +1668,7 @@ void WriteRemark3Phenix(std::ostream &pdbFile, const datablock &db)
{
std::string id = t["id"].as<std::string>();
auto pdbx_refine_tls_group = db["pdbx_refine_tls_group"].find1(key("refine_tls_id") == id);
auto pdbx_refine_tls_group = db["pdbx_refine_tls_group"].find_first(key("refine_tls_id") == id);
pdbFile << RM3(" TLS GROUP : ") << id << std::endl
<< RM3(" SELECTION: ") << Fs(pdbx_refine_tls_group, "selection_details") << std::endl
@@ -2187,20 +2200,20 @@ void WriteRemark200(std::ostream &pdbFile, const datablock &db)
std::string diffrn_id = diffrn["id"].as<std::string>();
std::string crystal_id = diffrn["crystal_id"].as<std::string>();
auto diffrn_radiation = db["diffrn_radiation"].find1(key("diffrn_id") == diffrn_id);
auto diffrn_radiation_wavelength = db["diffrn_radiation_wavelength"].find1(key("id") == diffrn_radiation["wavelength_id"].as<std::string>());
auto diffrn_source = db["diffrn_source"].find1(key("diffrn_id") == diffrn_id);
auto diffrn_detector = db["diffrn_detector"].find1(key("diffrn_id") == diffrn_id);
auto exptl = db["exptl"].find1(key("entry_id") == db.name());
auto exptl_crystal = db["exptl_crystal"].find1(key("id") == crystal_id);
auto exptl_crystal_grow = db["exptl_crystal_grow"].find1(key("crystal_id") == crystal_id);
auto computing = db["computing"].find1(key("entry_id") == db.name());
auto reflns = db["reflns"].find1(key("entry_id") == db.name());
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<std::string>());
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<std::string>();
auto reflns_shell = db["reflns_shell"].find1(key("pdbx_diffrn_id") == pdbx_diffrn_id);
auto refine = db["refine"].find1(key("pdbx_diffrn_id") == pdbx_diffrn_id);
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>());
@@ -2325,7 +2338,7 @@ void WriteRemark280(std::ostream &pdbFile, const datablock &db)
for (auto exptl_crystal : db["exptl_crystal"])
{
std::string crystal_id = exptl_crystal["id"].as<std::string>();
auto exptl_crystal_grow = db["exptl_crystal_grow"].find1(key("crystal_id") == crystal_id);
auto exptl_crystal_grow = db["exptl_crystal_grow"].find_first(key("crystal_id") == crystal_id);
pdbFile
<< RM("") << std::endl
@@ -2457,7 +2470,7 @@ void WriteRemark350(std::ostream &pdbFile, const datablock &db)
}
}
auto gen = db["pdbx_struct_assembly_gen"].find1(key("assembly_id") == id);
auto gen = db["pdbx_struct_assembly_gen"].find_first(key("assembly_id") == id);
if (gen)
{
@@ -2471,7 +2484,7 @@ void WriteRemark350(std::ostream &pdbFile, const datablock &db)
for (auto oper_id : split<std::string>(oper_id_list, ",", true))
{
auto r = db["pdbx_struct_oper_list"].find1(key("id") == oper_id);
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]")
@@ -2951,7 +2964,7 @@ int WriteHeterogen(std::ostream &pdbFile, const datablock &db)
if (id == water_comp_id)
continue;
std::string syn = db["chem_comp"].find1<std::string>(key("id") == id, "pdbx_synonyms");
std::string syn = db["chem_comp"].find_first<std::string>(key("id") == id, "pdbx_synonyms");
if (syn.empty())
continue;
@@ -3104,7 +3117,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
std::string initResName, initChainID, initICode, endResName, endChainID, endICode;
int initSeqNum, endSeqNum;
auto r1 = db["struct_sheet_range"].find1(key("sheet_id") == sheetID and key("id") == rangeID1);
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",
@@ -3119,7 +3132,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
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"].find1(key("sheet_id") == sheetID and key("id") == rangeID2);
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",
@@ -3288,10 +3301,10 @@ int WriteMiscellaneousFeatures(std::ostream &pdbFile, const datablock &db)
void WriteCrystallographic(std::ostream &pdbFile, const datablock &db)
{
auto r = db["symmetry"].find1(key("entry_id") == db.name());
auto r = db["symmetry"].find_first(key("entry_id") == db.name());
std::string symmetry = r["space_group_name_H-M"].as<std::string>();
r = db["cell"].find1(key("entry_id") == db.name());
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<double>(), r["length_b"].as<double>(), r["length_c"].as<double>(), r["angle_alpha"].as<double>(), r["angle_beta"].as<double>(), r["angle_gamma"].as<double>(), symmetry, r["Z_PDB"].as<int>()) << std::endl;
}
@@ -3338,10 +3351,16 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
const std::map<std::string, std::tuple<std::string, int, std::string>> &last_resseq_for_chain_map,
std::set<std::string> &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();
@@ -3358,10 +3377,21 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
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 and stol(modelNum) != model_nr)
if (modelNum.empty() == false)
{
++ri;
continue;
int nr = 0;
auto r = std::from_chars(modelNum.data(), modelNum.data() + modelNum.length(), nr);
if (r.ec != std::errc())
{
if (VERBOSE > 0)
std::cerr << "Model number '" << modelNum << "' is not a valid integer" << std::endl;
}
if (nr != model_nr)
{
++ri;
continue;
}
}
if (chainID.empty() == false and terminatedChains.count(chainID) == 0)
@@ -3404,6 +3434,16 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
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");
int entity_id = r.get<int>("label_entity_id");
auto type = entity.find1<std::string>("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<int>("asym_id"_key == r.get<std::string>("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<int>("asym_id"_key == r.get<std::string>("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num");
else if (type == "polymer")
resSeq = pdbx_poly_seq_scheme.find1<int>("asym_id"_key == r.get<std::string>("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num");
if (chainID.length() > 1)
throw std::runtime_error("Chain ID " + chainID + " won't fit into a PDB file");
@@ -3418,7 +3458,7 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
++numCoord;
auto ai = atom_site_anisotrop.find1(key("id") == id);
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; });

View File

@@ -24,17 +24,16 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++.hpp>
#include <cif++/pdb/pdb2cif.hpp>
#include <cif++/pdb/pdb2cif_remark_3.hpp>
#include <cif++/gzio.hpp>
#include <iomanip>
#include <map>
#include <set>
#include <stack>
#include <cif++.hpp>
#include <cif++/pdb/pdb2cif.hpp>
#include <cif++/pdb/pdb2cif_remark_3.hpp>
#include <cif++/gzio.hpp>
using cif::category;
using cif::datablock;
using cif::iequals;
@@ -1583,7 +1582,7 @@ void PDBFileParser::ParseTitle()
if (not iequals(key, "MOL_ID") and mCompounds.empty())
{
if (cif::VERBOSE >= 0)
if (cif::VERBOSE > 0)
std::cerr << "Ignoring invalid COMPND record" << std::endl;
break;
}
@@ -3820,41 +3819,48 @@ void PDBFileParser::ConstructEntities()
for (std::string monID : monIds)
{
std::string authMonID, authSeqNum, authInsCode;
std::string authMonID, authSeqNum, authInsCode{'.'};
if (res.mSeen)
{
authMonID = monID;
authSeqNum = std::to_string(res.mSeqNum);
if (res.mIcode != ' ' and res.mIcode != 0)
authInsCode = std::string{ res.mIcode };
cat->emplace({
{ "asym_id", asymID },
{ "entity_id", mMolID2EntityID[chain.mMolID] },
{ "seq_id", seqID },
{ "mon_id", monID },
{ "ndb_seq_num", seqID },
{ "pdb_seq_num", res.mSeqNum },
{ "auth_seq_num", authSeqNum },
{ "pdb_mon_id", authMonID },
{ "auth_mon_id", authMonID },
{ "pdb_strand_id", std::string{ chain.mDbref.chainID } },
{ "pdb_ins_code", authInsCode },
{ "hetero", res.mAlts.empty() ? "n" : "y" } });
}
else
{
authMonID = res.mMonID;
authSeqNum = std::to_string(res.mSeqNum);
if (res.mIcode != ' ' and res.mIcode != 0)
authInsCode = std::string{ res.mIcode } + "A";
else
authInsCode = "A";
cat->emplace({
{ "asym_id", asymID },
{ "entity_id", mMolID2EntityID[chain.mMolID] },
{ "seq_id", seqID },
{ "mon_id", monID },
{ "ndb_seq_num", seqID },
{ "pdb_seq_num", res.mSeqNum },
{ "auth_seq_num", "." },
{ "pdb_mon_id", "." },
{ "auth_mon_id", "." },
{ "pdb_strand_id", std::string{ chain.mDbref.chainID } },
{ "pdb_ins_code", authInsCode },
{ "hetero", res.mAlts.empty() ? "n" : "y" } });
}
if (authInsCode.empty())
authInsCode = ".";
cat->emplace({
{ "asym_id", asymID },
{ "entity_id", mMolID2EntityID[chain.mMolID] },
{ "seq_id", seqID },
{ "mon_id", monID },
{ "ndb_seq_num", seqID },
{ "pdb_seq_num", res.mSeqNum },
{ "auth_seq_num", authSeqNum },
{ "pdb_mon_id", authMonID },
{ "auth_mon_id", authMonID },
{ "pdb_strand_id", std::string{ chain.mDbref.chainID } },
{ "pdb_ins_code", authInsCode },
{ "hetero", res.mAlts.empty() ? "n" : "y" } });
}
}
}
@@ -4196,7 +4202,8 @@ void PDBFileParser::ConstructEntities()
// done with the sugar, resume operation as before
std::map<char, std::string> waterChains;
std::map<std::tuple<std::string, std::string>, int> ndbSeqNum; // for nonpoly scheme
std::map<std::tuple<std::string, std::string>, int> ndbSeqNum; // for nonpoly scheme
std::map<std::string,int> entityAuthSeqNum; // for nonpoly scheme too
for (size_t i = 0; i < mHets.size(); ++i)
{
@@ -4325,6 +4332,7 @@ void PDBFileParser::ConstructEntities()
}
int seqNr = ++ndbSeqNum[std::make_tuple(hetID, asymID)];
int authSeqNr = ++entityAuthSeqNum[hetID];
std::string iCode{ het.iCode };
cif::trim(iCode);
@@ -4333,13 +4341,13 @@ void PDBFileParser::ConstructEntities()
getCategory("pdbx_nonpoly_scheme")->emplace({
{ "asym_id", asymID },
{ "entity_id", mHet2EntityID[hetID] },
{ "mon_id", hetID },
{ "ndb_seq_num", seqNr },
{ "pdb_seq_num", het.seqNum },
// { "auth_seq_num", het.seqNum }, // ????
{ "entity_id", mHet2EntityID[hetID] },
{ "mon_id", hetID },
{ "ndb_seq_num", seqNr },
{ "pdb_seq_num", het.seqNum },
{ "auth_seq_num", authSeqNr }, // Yes
{ "pdb_mon_id", hetID },
// { "auth_mon_id", hetID },
{ "auth_mon_id", hetID },
{ "pdb_strand_id", std::string{ het.chainID } },
{ "pdb_ins_code", iCode } });
@@ -6102,13 +6110,6 @@ int PDBFileParser::PDBChain::AlignResToSeqRes()
switch (tb(x, y))
{
case -1:
// if (cif::VERBOSE > 0)
// std::cerr << "A residue found in the ATOM records "
// << "(" << ry[y].mMonID << " @ " << mDbref.chainID << ":" << ry[y].mSeqNum
// << ((ry[y].mIcode == ' ' or ry[y].mIcode == 0) ? "" : std::string{ ry[y].mIcode }) << ")"
// << " was not found in the SEQRES records" << std::endl;
// --y;
throw std::runtime_error("A residue found in the ATOM records (" + ry[y].mMonID +
" @ " + std::string{ mDbref.chainID } + ":" + std::to_string(ry[y].mSeqNum) +
((ry[y].mIcode == ' ' or ry[y].mIcode == 0) ? "" : std::string{ ry[y].mIcode }) +
@@ -6123,10 +6124,11 @@ int PDBFileParser::PDBChain::AlignResToSeqRes()
break;
case 0:
if (cif::VERBOSE > 3 and rx[x].mMonID != ry[y].mMonID)
std::cerr << "Warning, unaligned residues at " << x << "/" << y << "(" << rx[x].mMonID << '/' << ry[y].mMonID << ')' << std::endl;
else if (cif::VERBOSE > 4)
std::cerr << rx[x].mMonID << " -> " << ry[y].mMonID << " (" << ry[y].mSeqNum << ')' << std::endl;
if (rx[x].mMonID != ry[y].mMonID)
{
std::cerr << "Warning, unaligned residues at " << x << "/" << y << "(" << rx[x].mMonID << '/' << ry[y].mMonID << ") SEQRES does not agree with ATOM records" << std::endl;
rx[x].mMonID = ry[y].mMonID;
}
rx[x].mSeqNum = ry[y].mSeqNum;
rx[x].mIcode = ry[y].mIcode;
@@ -6246,4 +6248,4 @@ file read(const std::filesystem::path &file)
}
}
} // namespace pdbx
} // namespace pdbx

View File

@@ -25,12 +25,11 @@
*/
#include <cif++.hpp>
#include <cif++/pdb/pdb2cif_remark_3.hpp>
#include <map>
#include <set>
#include <cif++/pdb/pdb2cif_remark_3.hpp>
namespace cif::pdb
{

View File

@@ -27,12 +27,12 @@
// #include <sys/ioctl.h>
// #include <termios.h>
#include <iomanip>
#include <iostream>
#include <cif++.hpp>
#include <cif++/pdb/tls.hpp>
#include <iomanip>
#include <iostream>
namespace cif
{

View File

@@ -24,11 +24,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/point.hpp>
#include <cassert>
#include <random>
#include <cif++/point.hpp>
namespace cif
{
@@ -87,17 +87,17 @@ class Matrix : public MatrixExpression<Matrix>
Matrix &operator=(Matrix &&m) = default;
Matrix &operator=(const Matrix &m) = default;
uint32_t dim_m() const { return m_m; }
uint32_t dim_n() const { return m_n; }
size_t dim_m() const { return m_m; }
size_t dim_n() const { return m_n; }
double operator()(uint32_t i, uint32_t j) const
double operator()(size_t i, size_t j) const
{
assert(i < m_m);
assert(j < m_n);
return m_data[i * m_n + j];
}
double &operator()(uint32_t i, uint32_t j)
double &operator()(size_t i, size_t j)
{
assert(i < m_m);
assert(j < m_n);
@@ -105,7 +105,7 @@ class Matrix : public MatrixExpression<Matrix>
}
private:
uint32_t m_m = 0, m_n = 0;
size_t m_m = 0, m_n = 0;
std::vector<double> m_data;
};
@@ -355,6 +355,44 @@ point center_points(std::vector<point> &Points)
return t;
}
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
float angle, float esd)
{
p1 -= p3;
p2 -= p3;
p4 -= p3;
p3 -= p3;
quaternion q;
auto axis = p2;
float dh = dihedral_angle(p1, p2, p3, p4);
for (int iteration = 0; iteration < 100; ++iteration)
{
float delta = std::fmod(angle - dh, 360.0f);
if (delta < -180)
delta += 360;
if (delta > 180)
delta -= 360;
if (std::abs(delta) < esd)
break;
// if (iteration > 0)
// std::cout << cif::coloured(("iteration " + std::to_string(iteration)).c_str(), cif::scBLUE, cif::scBLACK) << " delta: " << delta << std::endl;
auto q2 = construct_from_angle_axis(delta, axis);
q = iteration == 0 ? q2 : q * q2;
p4.rotate(q2);
dh = dihedral_angle(p1, p2, p3, p4);
}
return q;
}
point centroid(const std::vector<point> &pts)
{
point result;
@@ -522,15 +560,17 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
point nudge(point p, float offset)
{
static const float kPI_f = static_cast<float>(kPI);
static std::random_device rd;
static std::mt19937_64 rng(rd());
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI);
std::normal_distribution<> randomOffset(0, offset);
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI_f);
std::normal_distribution<float> randomOffset(0, offset);
float theta = randomAngle(rng);
float phi1 = randomAngle(rng) - kPI;
float phi2 = randomAngle(rng) - kPI;
float phi1 = randomAngle(rng) - kPI_f;
float phi2 = randomAngle(rng) - kPI_f;
quaternion q = spherical(1.0f, theta, phi1, phi2);

View File

@@ -24,10 +24,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdexcept>
#include <cif++/symmetry.hpp>
#include <stdexcept>
#include "./symop_table_data.hpp"
namespace cif

View File

@@ -24,11 +24,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/text.hpp>
#include <algorithm>
#include <cassert>
#include <cif++/text.hpp>
namespace cif
{

View File

@@ -24,6 +24,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/utilities.hpp>
#include "revision.hpp"
#include <atomic>
#include <cassert>
#include <cmath>
@@ -44,10 +47,6 @@
#include <termios.h>
#endif
#include <cif++/utilities.hpp>
#include "revision.hpp"
namespace fs = std::filesystem;
// --------------------------------------------------------------------
@@ -124,7 +123,8 @@ std::string get_executable_path()
{
using namespace std::literals;
char path[PATH_MAX] = "";
// This used to be PATH_MAX, but lets simply assume 1024 is enough...
char path[1024] = "";
if (readlink("/proc/self/exe", path, sizeof(path)) == -1)
throw std::runtime_error("could not get exe path "s + strerror(errno));
return {path};
@@ -170,13 +170,15 @@ struct ProgressImpl
void ProgressImpl::Run()
{
using namespace std::literals;
bool printedAny = false;
try
{
for (;;)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(2s);
std::unique_lock lock(mMutex);
@@ -405,9 +407,9 @@ struct rsrc_imp
#if _MSC_VER
extern "C" const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
extern "C" const char *gResourceDataDefault[1] = {};
extern "C" const char *gResourceNameDefault[1] = {};
extern "C" CIFPP_EXPORT const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
extern "C" CIFPP_EXPORT const char *gResourceDataDefault[1] = {};
extern "C" CIFPP_EXPORT const char *gResourceNameDefault[1] = {};
extern "C" const mrsrc::rsrc_imp gResourceIndex[];
extern "C" const char gResourceData[];

View File

@@ -24,6 +24,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/dictionary_parser.hpp>
#include <cif++/validate.hpp>
#include <cif++/utilities.hpp>
#include <cif++/gzio.hpp>
#include <cassert>
#include <fstream>
#include <iostream>
@@ -41,12 +46,6 @@ using boost::regex;
using std::regex;
#endif
#include <cif++/dictionary_parser.hpp>
#include <cif++/validate.hpp>
#include <cif++/utilities.hpp>
#include <cif++/gzio.hpp>
namespace cif
{

View File

@@ -58,6 +58,12 @@ bool init_unit_test()
// not a test, just initialize test dir
if (boost::unit_test::framework::master_test_suite().argc == 2)
gTestDir = boost::unit_test::framework::master_test_suite().argv[1];
else
{
while (not gTestDir.empty() and not std::filesystem::exists(gTestDir / "test"))
gTestDir = gTestDir.parent_path();
gTestDir /= "test";
}
// do this now, avoids the need for installing
cif::add_file_resource("mmcif_pdbx.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx.dic");

View File

@@ -39,6 +39,12 @@ int main(int argc, char* argv[])
if (argc == 3)
testdir = argv[2];
else
{
while (not testdir.empty() and not std::filesystem::exists(testdir / "test"))
testdir = testdir.parent_path();
testdir /= "test";
}
if (std::filesystem::exists(testdir / ".." / "data" / "ccd-subset.cif"))
cif::add_file_resource("components.cif", testdir / ".." / "data" / "ccd-subset.cif");

View File

@@ -96,87 +96,87 @@ BOOST_AUTO_TEST_CASE(sugar_name_1)
}
}
// --------------------------------------------------------------------
// // --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(create_sugar_1)
{
using namespace cif::literals;
// BOOST_AUTO_TEST_CASE(create_sugar_1)
// {
// using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
cif::file file(example.string());
cif::mm::structure s(file);
// const std::filesystem::path example(gTestDir / "1juh.cif.gz");
// cif::file file(example.string());
// cif::mm::structure s(file);
// collect atoms from asym L first
auto &NAG = s.get_residue("L");
auto nagAtoms = NAG.atoms();
// // collect atoms from asym L first
// auto &NAG = s.get_residue("L");
// auto nagAtoms = NAG.atoms();
std::vector<cif::row_initializer> ai;
// std::vector<cif::row_initializer> ai;
auto &db = s.get_datablock();
auto &as = db["atom_site"];
// auto &db = s.get_datablock();
// auto &as = db["atom_site"];
// NOTE, row_initializer does not actually hold the data, so copy it first
// before it gets destroyed by remove_residue
// // NOTE, row_initializer does not actually hold the data, so copy it first
// // before it gets destroyed by remove_residue
for (auto r : as.find("label_asym_id"_key == "L"))
/*auto &ri = */ai.emplace_back(r);
// for (auto r : as.find("label_asym_id"_key == "L"))
// /*auto &ri = */ai.emplace_back(r);
s.remove_residue(NAG);
// s.remove_residue(NAG);
auto &branch = s.create_branch(ai);
// auto &branch = s.create_branch(ai);
BOOST_CHECK_EQUAL(branch.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose");
BOOST_CHECK_EQUAL(branch.size(), 1);
// BOOST_CHECK_EQUAL(branch.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose");
// BOOST_CHECK_EQUAL(branch.size(), 1);
BOOST_CHECK_EQUAL(branch[0].atoms().size(), nagAtoms.size());
// BOOST_CHECK_EQUAL(branch[0].atoms().size(), nagAtoms.size());
BOOST_CHECK(file.is_valid());
// BOOST_CHECK(file.is_valid());
file.save(gTestDir / "test-create_sugar_1.cif");
}
// file.save(gTestDir / "test-create_sugar_1.cif");
// }
// --------------------------------------------------------------------
// // --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(create_sugar_2)
{
using namespace cif::literals;
// BOOST_AUTO_TEST_CASE(create_sugar_2)
// {
// using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
cif::file file(example.string());
cif::mm::structure s(file);
// const std::filesystem::path example(gTestDir / "1juh.cif.gz");
// cif::file file(example.string());
// cif::mm::structure s(file);
// Get branch for H
auto &bH = s.get_branch_by_asym_id("H");
// // Get branch for H
// auto &bH = s.get_branch_by_asym_id("H");
BOOST_CHECK_EQUAL(bH.size(), 2);
// BOOST_CHECK_EQUAL(bH.size(), 2);
std::vector<cif::row_initializer> ai[2];
// std::vector<cif::row_initializer> ai[2];
auto &db = s.get_datablock();
auto &as = db["atom_site"];
// auto &db = s.get_datablock();
// auto &as = db["atom_site"];
for (size_t i = 0; i < 2; ++i)
{
for (auto r : as.find("label_asym_id"_key == "H" and "auth_seq_id"_key == i + 1))
/*auto &ri = */ai[i].emplace_back(r);
}
// for (size_t i = 0; i < 2; ++i)
// {
// for (auto r : as.find("label_asym_id"_key == "H" and "auth_seq_id"_key == i + 1))
// /*auto &ri = */ai[i].emplace_back(r);
// }
s.remove_branch(bH);
// s.remove_branch(bH);
BOOST_CHECK(file.is_valid());
// BOOST_CHECK(file.is_valid());
auto &bN = s.create_branch(ai[0]);
s.extend_branch(bN.get_asym_id(), ai[1], 1, "O4");
// auto &bN = s.create_branch(ai[0]);
// s.extend_branch(bN.get_asym_id(), ai[1], 1, "O4");
BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose-(1-4)-2-acetamido-2-deoxy-beta-D-glucopyranose");
BOOST_CHECK_EQUAL(bN.size(), 2);
// BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose-(1-4)-2-acetamido-2-deoxy-beta-D-glucopyranose");
// BOOST_CHECK_EQUAL(bN.size(), 2);
BOOST_CHECK(file.is_valid());
// BOOST_CHECK(file.is_valid());
file.save(gTestDir / "test-create_sugar_2.cif");
// file.save(gTestDir / "test-create_sugar_2.cif");
BOOST_CHECK_NO_THROW(cif::mm::structure s2(file));
}
// BOOST_CHECK_NO_THROW(cif::mm::structure s2(file));
// }
// --------------------------------------------------------------------

View File

@@ -87,19 +87,20 @@ BOOST_AUTO_TEST_CASE(t1)
// q = Normalize(q);
// Quaternion q{ 0.1, 0.2, 0.3, 0.4 };
cif::quaternion q{0.5, 0.5, 0.5, 0.5};
cif::quaternion q{ 0.5, 0.5, 0.5, 0.5 };
q = normalize(q);
const auto &&[angle0, axis0] = cif::quaternion_to_angle_axis(q);
std::vector<cif::point> p1{
{16.979, 13.301, 44.555},
{18.150, 13.525, 43.680},
{18.656, 14.966, 43.784},
{17.890, 15.889, 44.078},
{17.678, 13.270, 42.255},
{16.248, 13.734, 42.347},
{15.762, 13.216, 43.724}};
{ 16.979f, 13.301f, 44.555f },
{ 18.150f, 13.525f, 43.680f },
{ 18.656f, 14.966f, 43.784f },
{ 17.890f, 15.889f, 44.078f },
{ 17.678f, 13.270f, 42.255f },
{ 16.248f, 13.734f, 42.347f },
{ 15.762f, 13.216f, 43.724f }
};
auto p2 = p1;
@@ -119,7 +120,7 @@ BOOST_AUTO_TEST_CASE(t1)
for (auto &p : p1)
p.rotate(q2);
float rmsd = cif::RMSd(p1, p2);
auto rmsd = cif::RMSd(p1, p2);
BOOST_TEST(rmsd < 1e-5);
@@ -136,7 +137,7 @@ BOOST_AUTO_TEST_CASE(t2)
cif::point xp = cif::cross_product(p[1] - p[0], p[2] - p[0]);
auto q = cif::construct_from_angle_axis(45, xp); //mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
auto q = cif::construct_from_angle_axis(45, xp); // mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
auto &&[angle, axis] = cif::quaternion_to_angle_axis(q);
@@ -153,7 +154,7 @@ BOOST_AUTO_TEST_CASE(t3)
cif::point xp = cif::cross_product(p[1] - p[0], p[2] - p[0]);
auto q = cif::construct_from_angle_axis(45, xp); //mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
auto q = cif::construct_from_angle_axis(45, xp); // mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
auto v = p[1];
v -= p[0];
@@ -166,3 +167,48 @@ BOOST_AUTO_TEST_CASE(t3)
BOOST_TEST(a == 45, tt::tolerance(0.01));
}
BOOST_AUTO_TEST_CASE(dh_q_1)
{
struct
{
float angle;
cif::point pts[4];
} tests[] = {
{ -97.5f,
{ { 68.8649979f, -7.34800005f, 54.3769989f },
{ 68.1350021f, -8.18700027f, 53.6489983f },
{ 68.7760239f, -9.07335377f, 52.7140236f },
{ 68.9000015f, -10.3944235f, 53.2217026f } } },
{ 80.3f,
{ { 0.304512024f, 0.531184196f, 2.25860214f },
{ 0.956512451f, 0.0321846008f, 1.07460022f },
{ 0, 0, 0 },
{ 0.21336633f, -1.09552193f, -0.878999829f } } },
{ -97.5f,
{ { 0.088973999f, 1.72535372f, 1.66297531f },
{ -0.641021729f, 0.886353493f, 0.93497467f },
{ 0, 0, 0 },
{ 1.29433727f, -0.395142615f, 0.432300746f } } },
{ -97.5f,
{
{ 0.088973999f, 1.72535372f, 1.66297531f },
{ -0.641021729f, 0.886353493f, 0.93497467f },
{ 0, 0, 0 },
{ 1.33983064f, 0.384027064f, -0.275154471f },
} }
};
for (auto &&[angle, pts] : tests)
{
auto q = cif::construct_for_dihedral_angle(pts[0], pts[1], pts[2], pts[3], angle, 1);
pts[3] -= pts[2];
pts[3].rotate(q);
pts[3] += pts[2];
auto dh = cif::dihedral_angle(pts[0], pts[1], pts[2], pts[3]);
BOOST_TEST(dh == angle, tt::tolerance(0.1f));
}
}

View File

@@ -78,23 +78,23 @@ bool init_unit_test()
BOOST_AUTO_TEST_CASE(cc_1)
{
std::tuple<std::string_view, float, char> tests[] = {
{ "1.0", 1.0, 0 },
{ "1.0e10", 1.0e10, 0 },
{ "-1.1e10", -1.1e10, 0 },
{ "-.2e11", -.2e11, 0 },
{ "1.3e-10", 1.3e-10, 0 },
{ "1.0", 1.0f, 0 },
{ "1.0e10", 1.0e10f, 0 },
{ "-1.1e10", -1.1e10f, 0 },
{ "-.2e11", -.2e11f, 0 },
{ "1.3e-10", 1.3e-10f, 0 },
{ "1.0 ", 1.0, ' ' },
{ "1.0e10 ", 1.0e10, ' ' },
{ "-1.1e10 ", -1.1e10, ' ' },
{ "-.2e11 ", -.2e11, ' ' },
{ "1.3e-10 ", 1.3e-10, ' ' },
{ "1.0 ", 1.0f, ' ' },
{ "1.0e10 ", 1.0e10f, ' ' },
{ "-1.1e10 ", -1.1e10f, ' ' },
{ "-.2e11 ", -.2e11f, ' ' },
{ "1.3e-10 ", 1.3e-10f, ' ' },
{ "3.0", 3.0, 0 },
{ "3.0 ", 3.0, ' ' },
{ "3.0", 3.0f, 0 },
{ "3.0 ", 3.0f, ' ' },
{ "3.000000", 3.0, 0 },
{ "3.000000 ", 3.0, ' ' },
{ "3.000000", 3.0f, 0 },
{ "3.000000 ", 3.0f, ' ' },
};
for (const auto &[txt, val, ch] : tests)
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(cc_1)
BOOST_AUTO_TEST_CASE(cc_2)
{
std::tuple<float, int, std::string_view> tests[] = {
{ 1.1, 1, "1.1" }
{ 1.1f, 1, "1.1" }
};
for (const auto &[val, prec, test] : tests)
@@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(item_1)
using namespace cif;
item i1("1", "1");
item i2("2", 2.0);
item i2("2", 2.0f);
item i3("3", '3');
item ci1(i1);
@@ -163,23 +163,23 @@ BOOST_AUTO_TEST_CASE(r_1)
c.emplace({
{ "f-1", 1 },
{ "f-2", "two" },
{ "f-3", 3.0, 3 },
{ "f-3", 3.0f, 3 },
});
auto row = c.front();
BOOST_CHECK_EQUAL(row["f-1"].compare(1), 0);
BOOST_CHECK_EQUAL(row["f-2"].compare("two"), 0);
BOOST_CHECK_EQUAL(row["f-3"].compare(3.0), 0); // This fails when running in valgrind... sigh
BOOST_CHECK_EQUAL(row["f-3"].compare(3.0f), 0); // This fails when running in valgrind... sigh
const auto &[f1, f2, f3] = row.get<int, std::string, float>("f-1", "f-2", "f-3");
BOOST_CHECK_EQUAL(f1, 1);
BOOST_CHECK_EQUAL(f2, "two");
BOOST_CHECK_EQUAL(f3, 3.0); // This fails when running in valgrind... sigh
BOOST_CHECK_EQUAL(f3, 3.0f); // This fails when running in valgrind... sigh
BOOST_CHECK_EQUAL(row.get<int>("f-1"), 1);
BOOST_CHECK_EQUAL(row.get<std::string>("f-2"), "two");
BOOST_CHECK_EQUAL(row.get<float>("f-3"), 3.0);
BOOST_CHECK_EQUAL(row.get<float>("f-3"), 3.0f);
int f_1;
std::string f_2;
@@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(r_1)
BOOST_CHECK_EQUAL(f_1, 1);
BOOST_CHECK_EQUAL(f_2, "two");
BOOST_CHECK_EQUAL(f_3, 3.0); // This fails when running in valgrind... sigh
BOOST_CHECK_EQUAL(f_3, 3.0f); // This fails when running in valgrind... sigh
}
BOOST_AUTO_TEST_CASE(r_2)
@@ -486,14 +486,14 @@ _test.value
BOOST_CHECK_EQUAL(++n, 1);
BOOST_CHECK_EQUAL(r["id"].as<int>(), 1);
BOOST_CHECK_EQUAL(r["name"].as<std::string>(), "aap");
BOOST_CHECK_EQUAL(r["value"].as<float>(), 1.0);
BOOST_CHECK_EQUAL(r["value"].as<float>(), 1.0f);
}
auto t = test.find(cif::key("id") == 1);
BOOST_CHECK(not t.empty());
BOOST_CHECK_EQUAL(t.front()["name"].as<std::string>(), "aap");
auto t2 = test.find(cif::key("value") == 1.2);
auto t2 = test.find(cif::key("value") == 1.2f);
BOOST_CHECK(not t2.empty());
BOOST_CHECK_EQUAL(t2.front()["name"].as<std::string>(), "mies");
}
@@ -1774,8 +1774,6 @@ _test.name
BOOST_AUTO_TEST_CASE(c3)
{
cif::VERBOSE = 1;
auto f = R"(data_TEST
#
loop_
@@ -1811,6 +1809,43 @@ _test.name
BOOST_CHECK_EQUAL(name, "aap");
}
BOOST_AUTO_TEST_CASE(c4)
{
auto f = R"(data_TEST
#
loop_
_test.id
_test.name
1 aap
2 noot
3 mies
4 .
5 ?
)"_cf;
auto &db = f.front();
// query tests
BOOST_TEST(db["test"].find_max<int>("id") == 5);
BOOST_TEST(db["test"].find_max<int>("id", cif::key("name") != cif::null) == 3);
BOOST_TEST(db["test"].find_min<int>("id") == 1);
BOOST_TEST(db["test"].find_min<int>("id", cif::key("name") == cif::null) == 4);
// count tests
BOOST_TEST(db["test"].count(cif::all()) == 5);
BOOST_TEST(db["test"].count(cif::key("name") != cif::null) == 3);
BOOST_TEST(db["test"].count(cif::key("name") == cif::null) == 2);
// find_first tests
BOOST_TEST(db["test"].find_first<int>(cif::key("id") == 1, "id") == 1);
BOOST_TEST(db["test"].find_first<int>(cif::all(), "id") == 1);
// find1 tests
BOOST_TEST(db["test"].find1<int>(cif::key("id") == 1, "id") == 1);
BOOST_CHECK_THROW(db["test"].find1<int>(cif::all(), "id"), cif::multiple_results_error);
}
// --------------------------------------------------------------------
// rename test
@@ -2322,15 +2357,22 @@ _test.text ??
BOOST_AUTO_TEST_CASE(output_test_1)
{
cif::VERBOSE = 5;
auto data1 = R"(
data_Q
loop_
_test.text
"stop_the_crap"
stop_the_crap
'and stop_ this too'
'data_dinges'
'blablaglobal_bla'
blablaglobal_bla
boo.data_.whatever
'data_.whatever'
'stop_'
'loop_'
'global_'
'_with.leading_underscore'
)"_cf;
auto &db1 = data1.front();
@@ -2341,11 +2383,16 @@ boo.data_.whatever
const char *s;
bool q;
} kS[] = {
{ "stop_the_crap", false },
{ "stop_the_crap", true },
{ "and stop_ this too", false },
{ "data_dinges", false },
{ "blablaglobal_bla", false },
{ "boo.data_.whatever", true }
{ "blablaglobal_bla", true },
{ "boo.data_.whatever", true },
{ "data_.whatever", false },
{ "stop_", false },
{ "loop_", false },
{ "global_", false },
{ "_with.leading_underscore", false }
};
BOOST_CHECK_EQUAL(test1.size(), sizeof(kS) / sizeof(T));

View File

@@ -1,55 +1,71 @@
#!/bin/sh
# Code updated based on a bug report in Ubuntu:
# Bug #1999259 reported by Kyler Laird on 2022-12-09
set -e
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
# Get the effective UID, but do so in a compatible way (we may be running dash)
euid=${EUID:-$(id -u)}
if [ "${euid}" -ne 0 ]; then
echo "Please run as root"
exit
fi
if [ -f "@CIFPP_ETC_DIR@/libcifpp.conf" ] ; then
if [ -f "@CIFPP_ETC_DIR@/libcifpp.conf" ]; then
. "@CIFPP_ETC_DIR@/libcifpp.conf"
fi
# check to see if we're supposed to run at all
if [ "$update" != "true" ] ; then
if [ "$update" != "true" ]; then
exit
fi
# if cache directory doesn't exist, exit.
# if cache directory doesn't exist, exit.
if ! [ -d "@CIFPP_CACHE_DIR@" ]; then
exit
fi
fetch_dictionary () {
# Create a temp file in the right directory and
# make sure it is cleaned up when this script exits
tmpfile=$(mktemp)
trap "rm -f \"${tmpfile}\"" EXIT
update_dictionary() {
dict=$1
source=$2
wget -O${dict}.gz ${source}
# Using curl with
# --location (follow redirects)
# --silent (no diagnostic output at all)
# --time-cond (only fetch if source is newer)
#
# Output is extracted and written to $tmpfile and when successful
# the tmpfile is placed at the desired location and updated is set
# to true
# be careful not to nuke an existing dictionary file
# extract to a temporary file first
gunzip -c ${dict}.gz > ${dict}-tmp
# then move the extracted file to the final location
mv ${dict}-tmp ${dict}
# and clean up afterwards
rm ${dict}.gz
curl --silent --location --compressed --time-cond "${dict}" "${source}" | (
# uncompress the file on the fly, if it is compressed
if [ "${source%.gz}" != "${source}" ]; then
gunzip -c > "${tmpfile}" 2>/dev/null
else
cat > "${tmpfile}"
fi
) && (
mv "${tmpfile}" "${dict}" && chmod a+r "${dict}"
) || true
}
# fetch the dictionaries
# Update the dictionaries
fetch_dictionary "@CIFPP_CACHE_DIR@/mmcif_pdbx.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
fetch_dictionary "@CIFPP_CACHE_DIR@/components.cif" "ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
update_dictionary "@CIFPP_CACHE_DIR@/components.cif" "https://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
update_dictionary "@CIFPP_CACHE_DIR@/mmcif_pdbx.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
update_dictionary "@CIFPP_CACHE_DIR@/mmcif_ma.dic" "https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic"
# notify subscribers, will fail on FreeBSD
if [ -d "@CIFPP_ETC_DIR@/libcifpp/cache-update.d" ] && [ -x /bin/run-parts ]; then
run-parts --arg "@CIFPP_CACHE_DIR@" -- "@CIFPP_ETC_DIR@/libcifpp/cache-update.d"
fi
wget -O"@CIFPP_CACHE_DIR@/mmcif_ma.dic" "https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic"