mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 22:14:24 +08:00
Compare commits
189 Commits
develop-ci
...
using-fmt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb02969604 | ||
|
|
31090c6ec5 | ||
|
|
9e30d2bc1a | ||
|
|
93d703f7a1 | ||
|
|
3c241048a5 | ||
|
|
2788536799 | ||
|
|
314d435a18 | ||
|
|
37edcd8666 | ||
|
|
10e290fbdf | ||
|
|
58cda1241e | ||
|
|
3659aaabff | ||
|
|
727a39cc54 | ||
|
|
fd9ccdfff9 | ||
|
|
aabee270b3 | ||
|
|
647c58f8ec | ||
|
|
0b8024d19c | ||
|
|
d59b0bf27f | ||
|
|
398c16eac2 | ||
|
|
fa869bdc7d | ||
|
|
c20d0d2a30 | ||
|
|
000f2736c2 | ||
|
|
cfcc81bb62 | ||
|
|
82eae05868 | ||
|
|
e8fb53c49b | ||
|
|
604c97afe1 | ||
|
|
7e60cdf272 | ||
|
|
9ea7cfcc80 | ||
|
|
a7a4a16f79 | ||
|
|
6717059934 | ||
|
|
714747c280 | ||
|
|
81cd305c80 | ||
|
|
5de872bbb3 | ||
|
|
ce6a75a920 | ||
|
|
874a5cb2f2 | ||
|
|
6e2202d4f1 | ||
|
|
bcf33df701 | ||
|
|
3bdcf21c69 | ||
|
|
4b36bdc58c | ||
|
|
6d9008ee8c | ||
|
|
ee93692707 | ||
|
|
2bcc368bce | ||
|
|
6cc4467d53 | ||
|
|
425f98dc07 | ||
|
|
cf34a9f3ad | ||
|
|
3b2f347428 | ||
|
|
bd82c3cc4f | ||
|
|
af319866c7 | ||
|
|
b6ab29398e | ||
|
|
a5bb1797c0 | ||
|
|
a9647671c4 | ||
|
|
63f784e7da | ||
|
|
5da3379e0b | ||
|
|
2f3514689d | ||
|
|
89a3ea4e24 | ||
|
|
467e9555f4 | ||
|
|
5b32ca15f7 | ||
|
|
92402817d2 | ||
|
|
60ad3031d5 | ||
|
|
724cddb481 | ||
|
|
41c0521480 | ||
|
|
85ac2b1f63 | ||
|
|
13a97353aa | ||
|
|
f49c166b9b | ||
|
|
fffa326f80 | ||
|
|
da446adbb2 | ||
|
|
617fec5c69 | ||
|
|
cfefa69c9c | ||
|
|
00638a9e23 | ||
|
|
e241e03a15 | ||
|
|
b1faa3bd48 | ||
|
|
6d28f487ec | ||
|
|
b231f92f76 | ||
|
|
7d33d56c0e | ||
|
|
f86f34e5e1 | ||
|
|
5e7b52b7de | ||
|
|
0459d344e9 | ||
|
|
71e525cd76 | ||
|
|
1480706d8b | ||
|
|
96655b6d80 | ||
|
|
eed2aa0d0d | ||
|
|
de0c078a23 | ||
|
|
321e995a54 | ||
|
|
da9f1f81d7 | ||
|
|
c6d4477a24 | ||
|
|
523b073cdc | ||
|
|
2591bee21b | ||
|
|
d881ca00c9 | ||
|
|
329dbff474 | ||
|
|
d84a9fe6dc | ||
|
|
dcd812a996 | ||
|
|
6750194d9b | ||
|
|
05865c3d9b | ||
|
|
21e224bf00 | ||
|
|
f401d3fd0c | ||
|
|
fd436871f1 | ||
|
|
fcf7864a4b | ||
|
|
c4003956d9 | ||
|
|
de622b6162 | ||
|
|
41b4bdb90e | ||
|
|
af73cb3ad3 | ||
|
|
240b631963 | ||
|
|
c2a747af8c | ||
|
|
5959647826 | ||
|
|
9542e211bc | ||
|
|
d07890db7f | ||
|
|
ca241bd8f2 | ||
|
|
e444092711 | ||
|
|
a96b1e07f4 | ||
|
|
f48c31bcb5 | ||
|
|
d85ab93a35 | ||
|
|
a6804b5aca | ||
|
|
e4dcb211ee | ||
|
|
a5a5f47f7a | ||
|
|
25c900c387 | ||
|
|
4e95f7b83e | ||
|
|
66ad3b0cee | ||
|
|
e853cd1ca0 | ||
|
|
b9544033c6 | ||
|
|
17840cb8cc | ||
|
|
f85b6d94b8 | ||
|
|
6c32a9f198 | ||
|
|
cefeebbfb8 | ||
|
|
941a015b43 | ||
|
|
ae0e9fbe77 | ||
|
|
3484c3dd2e | ||
|
|
5be8f749bd | ||
|
|
cf484707a0 | ||
|
|
f12e529c0b | ||
|
|
01b90a2ba5 | ||
|
|
cd1e952812 | ||
|
|
996f1e4277 | ||
|
|
2d84694f86 | ||
|
|
65718c64cc | ||
|
|
6e30365f55 | ||
|
|
c0555b6d86 | ||
|
|
1ff9b6c071 | ||
|
|
c1a51a1dfa | ||
|
|
bfbbeb90e7 | ||
|
|
588e075325 | ||
|
|
66717fee68 | ||
|
|
844f52c955 | ||
|
|
e679cd05c1 | ||
|
|
1e72ce4830 | ||
|
|
3bb21c5403 | ||
|
|
6d1be23ad0 | ||
|
|
0472b9a4a4 | ||
|
|
c9acff49f9 | ||
|
|
7cab560595 | ||
|
|
ac98531a2f | ||
|
|
917e0ba79c | ||
|
|
3ebceb7522 | ||
|
|
92bd52da12 | ||
|
|
fb56a9cd6e | ||
|
|
a4680f7d38 | ||
|
|
da8a72a8aa | ||
|
|
ac497932b5 | ||
|
|
9927b5061a | ||
|
|
cedaab9642 | ||
|
|
50bf2145ec | ||
|
|
dc77729f50 | ||
|
|
e3330d667a | ||
|
|
9822f397a1 | ||
|
|
a3b5ce9959 | ||
|
|
9eb06e929a | ||
|
|
629e06d647 | ||
|
|
51ccb92184 | ||
|
|
3cd27f13fd | ||
|
|
ae668530c0 | ||
|
|
4a8b1c056c | ||
|
|
d7a5e598bc | ||
|
|
3f1ee32cc6 | ||
|
|
725d6ead98 | ||
|
|
baf70579de | ||
|
|
cd28ab58a3 | ||
|
|
a78fa0a81d | ||
|
|
82130be5f5 | ||
|
|
510ce62dfb | ||
|
|
93375a5087 | ||
|
|
be738e7fb1 | ||
|
|
9c78131df3 | ||
|
|
d94f6f4d19 | ||
|
|
9a3eced350 | ||
|
|
2fed7a76fb | ||
|
|
f02e59df1b | ||
|
|
04147a2fe9 | ||
|
|
0e83bc31dc | ||
|
|
75a5f7960f | ||
|
|
3f93c27b07 | ||
|
|
ab781d4516 |
6
.github/workflows/build-documentation.yml
vendored
6
.github/workflows/build-documentation.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set reusable strings
|
||||
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
ls -l ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
@@ -62,4 +62,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ docs/api
|
||||
docs/conf.py
|
||||
build_ci/
|
||||
data/components.cif
|
||||
perf.data*
|
||||
|
||||
464
CMakeLists.txt
464
CMakeLists.txt
@@ -22,29 +22,28 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# set the project name
|
||||
project(
|
||||
libcifpp
|
||||
VERSION 7.0.0
|
||||
VERSION 9.0.0
|
||||
LANGUAGES CXX)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(FindAtomic)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(GenerateExportHeader)
|
||||
include(CTest)
|
||||
include(FetchContent)
|
||||
include(ExternalProject)
|
||||
|
||||
set(CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
include(FetchContent)
|
||||
include(CPM)
|
||||
|
||||
# When building with ninja-multiconfig, build both debug and release by default
|
||||
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
|
||||
@@ -61,42 +60,39 @@ elseif(MSVC)
|
||||
endif()
|
||||
|
||||
# Build documentation?
|
||||
option(BUILD_DOCUMENTATION "Build the documentation" OFF)
|
||||
set(BUILD_DOCUMENTATION OFF CACHE BOOL "Build the documentation")
|
||||
|
||||
# Optionally build a version to be installed inside CCP4
|
||||
option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4")
|
||||
set(BUILD_FOR_CCP4 OFF CACHE BOOL "Build a version to be installed in CCP4")
|
||||
|
||||
# Building shared libraries?
|
||||
if(NOT(BUILD_FOR_CCP4 AND WIN32))
|
||||
option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build a shared library instead of a static one")
|
||||
endif()
|
||||
|
||||
if(BUILD_FOR_CCP4)
|
||||
unset(CIFPP_DOWNLOAD_CCD)
|
||||
unset(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
else()
|
||||
if(PROJECT_IS_TOP_LEVEL AND NOT BUILD_FOR_CCP4)
|
||||
# Lots of code depend on the availability of the components.cif file
|
||||
option(CIFPP_DOWNLOAD_CCD
|
||||
"Download the CCD file components.cif during installation" ON)
|
||||
set(CIFPP_DOWNLOAD_CCD ON CACHE BOOL "Download the CCD file components.cif during installation")
|
||||
|
||||
# An optional cron script can be installed to keep the data files up-to-date
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(CIFPP_INSTALL_UPDATE_SCRIPT
|
||||
"Install the script to update CCD and dictionary files" ON)
|
||||
set(CIFPP_INSTALL_UPDATE_SCRIPT ON CACHE BOOL "Install the script to update CCD and dictionary files")
|
||||
endif()
|
||||
else()
|
||||
unset(CIFPP_DOWNLOAD_CCD)
|
||||
unset(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
endif()
|
||||
|
||||
# When CCP4 is sourced in the environment, we can recreate the symmetry
|
||||
# operations table
|
||||
if(EXISTS "$ENV{CCP4}/lib/data/syminfo.lib")
|
||||
option(CIFPP_RECREATE_SYMOP_DATA
|
||||
"Recreate SymOp data table in case it is out of date" ON)
|
||||
set(CIFPP_RECREATE_SYMOP_DATA ON CACHE BOOL "Recreate SymOp data table in case it is out of date")
|
||||
endif()
|
||||
|
||||
# CCP4 build
|
||||
if(BUILD_FOR_CCP4)
|
||||
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced")
|
||||
message(FATAL_ERROR "cifpp: A CCP4 built was requested but CCP4 was not sourced")
|
||||
else()
|
||||
list(PREPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(PREPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
@@ -126,8 +122,6 @@ if(WIN32)
|
||||
add_definitions(-D _WIN32_WINNT=0x0501)
|
||||
endif()
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
|
||||
# We do not want to write an export file for all our symbols...
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
@@ -137,6 +131,7 @@ if(MSVC)
|
||||
add_compile_options(/permissive- /bigobj)
|
||||
add_link_options(/NODEFAULTLIB:library)
|
||||
|
||||
# This is dubious...
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
else()
|
||||
@@ -146,55 +141,8 @@ endif()
|
||||
|
||||
# Libraries
|
||||
|
||||
# Start by finding out if std:regex is usable. Note that the current
|
||||
# implementation in GCC is not acceptable, it crashes on long lines. The
|
||||
# implementation in libc++ (clang) and MSVC seem to be OK.
|
||||
check_cxx_source_compiles(
|
||||
"
|
||||
#include <iostream>
|
||||
#ifndef __GLIBCXX__
|
||||
#error
|
||||
#endif
|
||||
int main(int argc, char *argv[]) { return 0; }"
|
||||
GXX_LIBSTDCPP)
|
||||
|
||||
if(GXX_LIBSTDCPP)
|
||||
message(
|
||||
STATUS "Testing for known regex bug, since you're using GNU libstdc++")
|
||||
|
||||
try_run(STD_REGEX_RUNNING STD_REGEX_COMPILING
|
||||
${CMAKE_CURRENT_BINARY_DIR}/test
|
||||
${PROJECT_SOURCE_DIR}/cmake/test-rx.cpp)
|
||||
|
||||
if(STD_REGEX_RUNNING STREQUAL FAILED_TO_RUN)
|
||||
message(
|
||||
STATUS
|
||||
"You are probably trying to compile using the g++ standard library which contains a crashing std::regex implementation. Will use boost::regex instead"
|
||||
)
|
||||
|
||||
find_package(Boost 1.80 QUIET COMPONENTS regex)
|
||||
|
||||
if(NOT Boost_FOUND)
|
||||
set(BOOST_REGEX_STANDALONE ON)
|
||||
|
||||
FetchContent_Declare(
|
||||
boost-rx
|
||||
GIT_REPOSITORY https://github.com/boostorg/regex
|
||||
GIT_TAG boost-1.83.0)
|
||||
|
||||
FetchContent_MakeAvailable(boost-rx)
|
||||
endif()
|
||||
|
||||
set(BOOST_REGEX ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG)
|
||||
find_package(Threads)
|
||||
|
||||
if(MSVC)
|
||||
# Avoid linking the shared library of zlib Search ZLIB_ROOT first if it is
|
||||
# Avoid linking the shared library of zlib. Search ZLIB_ROOT first if it is
|
||||
# set.
|
||||
if(ZLIB_ROOT)
|
||||
set(_ZLIB_SEARCH_ROOT PATHS ${ZLIB_ROOT} NO_DEFAULT_PATH)
|
||||
@@ -221,7 +169,16 @@ if(MSVC)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
# find_package(pcre2) is unfortunately broken
|
||||
|
||||
include(FindPCRE2x)
|
||||
|
||||
find_package(ZLIB QUIET)
|
||||
find_package(Threads)
|
||||
|
||||
if(NOT ZLIB_FOUND)
|
||||
message(FATAL_ERROR "cifpp: The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)")
|
||||
endif()
|
||||
|
||||
# Using Eigen3 is a bit of a thing. We don't want to build it completely since
|
||||
# we only need a couple of header files. Nothing special. But often, eigen3 is
|
||||
@@ -232,118 +189,122 @@ if(Eigen3_FOUND AND TARGET Eigen3::Eigen)
|
||||
get_target_property(EIGEN_INCLUDE_DIR Eigen3::Eigen
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
# Create a private copy of eigen3 and populate it only, no need to build
|
||||
FetchContent_Declare(
|
||||
my-eigen3
|
||||
# Use ExternalProject since FetchContent always tries to install the result...
|
||||
ExternalProject_Add(my-eigen3
|
||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
||||
GIT_TAG 3.4.0)
|
||||
GIT_TAG 3.4.0
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
FetchContent_GetProperties(my-eigen3)
|
||||
|
||||
if(NOT my-eigen3_POPULATED)
|
||||
FetchContent_Populate(my-eigen3)
|
||||
endif()
|
||||
|
||||
set(EIGEN_INCLUDE_DIR ${my-eigen3_SOURCE_DIR})
|
||||
ExternalProject_Get_Property(my-eigen3 SOURCE_DIR)
|
||||
set(EIGEN_INCLUDE_DIR ${SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
include(FindFilesystem)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
|
||||
|
||||
include(FindAtomic)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPATOMIC_LIBRARY})
|
||||
message(STATUS "cifpp: Eigen include dir is ${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
include(VersionString)
|
||||
write_version_header(${PROJECT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
|
||||
write_version_header(${CMAKE_CURRENT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
|
||||
|
||||
# SymOp data table
|
||||
if(CIFPP_RECREATE_SYMOP_DATA)
|
||||
# The tool to create the table
|
||||
add_executable(symop-map-generator
|
||||
"${PROJECT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
|
||||
target_compile_features(symop-map-generator PUBLIC cxx_std_20)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
COMMAND
|
||||
$<TARGET_FILE:symop-map-generator> $ENV{CLIBD}/syminfo.lib
|
||||
$ENV{CLIBD}/symop.lib ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
$ENV{CLIBD}/symop.lib ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
|
||||
add_custom_target(
|
||||
OUTPUT
|
||||
${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
|
||||
"$ENV{CLIBD}/symop.lib")
|
||||
endif()
|
||||
|
||||
# Sources
|
||||
set(project_sources
|
||||
${PROJECT_SOURCE_DIR}/src/category.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/condition.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/datablock.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/file.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/item.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/parser.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/row.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/validate.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/text.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/utilities.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/atom_type.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/compound.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/point.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/symmetry.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/model.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/category.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/condition.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/datablock.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/file.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/item.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/row.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/text.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utilities.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/atom_type.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/compound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/point.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symmetry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/model.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
)
|
||||
|
||||
set(project_headers
|
||||
${PROJECT_SOURCE_DIR}/include/cif++.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/utilities.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/item.hpp
|
||||
${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++/iterator.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/parser.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/forward_decl.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/dictionary_parser.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/condition.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/category.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/row.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/atom_type.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/compound.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/point.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/symmetry.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/model.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/cif2pdb.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/io.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/pdb2cif.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/tls.hpp)
|
||||
include/cif++.hpp
|
||||
include/cif++/atom_type.hpp
|
||||
include/cif++/category.hpp
|
||||
include/cif++/compound.hpp
|
||||
include/cif++/condition.hpp
|
||||
include/cif++/datablock.hpp
|
||||
include/cif++/dictionary_parser.hpp
|
||||
include/cif++/exports.hpp
|
||||
include/cif++/file.hpp
|
||||
include/cif++/format.hpp
|
||||
include/cif++/forward_decl.hpp
|
||||
include/cif++/gzio.hpp
|
||||
include/cif++/item.hpp
|
||||
include/cif++/iterator.hpp
|
||||
include/cif++/matrix.hpp
|
||||
include/cif++/model.hpp
|
||||
include/cif++/parser.hpp
|
||||
include/cif++/pdb/cif2pdb.hpp
|
||||
include/cif++/pdb.hpp
|
||||
include/cif++/pdb/io.hpp
|
||||
include/cif++/pdb/pdb2cif.hpp
|
||||
include/cif++/pdb/tls.hpp
|
||||
include/cif++/point.hpp
|
||||
include/cif++/row.hpp
|
||||
include/cif++/symmetry.hpp
|
||||
include/cif++/text.hpp
|
||||
include/cif++/utilities.hpp
|
||||
include/cif++/validate.hpp
|
||||
)
|
||||
|
||||
add_library(cifpp ${project_sources} ${project_headers}
|
||||
${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
add_library(cifpp)
|
||||
add_library(cifpp::cifpp ALIAS cifpp)
|
||||
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
set_target_properties(cifpp PROPERTIES DEBUG_POSTFIX "d")
|
||||
if(TARGET my-eigen3)
|
||||
add_dependencies(cifpp my-eigen3)
|
||||
endif()
|
||||
|
||||
target_sources(cifpp
|
||||
PRIVATE ${project_sources}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
PUBLIC
|
||||
FILE_SET cifpp_headers TYPE HEADERS
|
||||
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
FILES ${project_headers}
|
||||
)
|
||||
|
||||
# The code now really requires C++20
|
||||
target_compile_features(cifpp PUBLIC cxx_std_20)
|
||||
|
||||
generate_export_header(cifpp EXPORT_FILE_NAME
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/exports.hpp)
|
||||
|
||||
if(BOOST_REGEX)
|
||||
target_compile_definitions(cifpp PRIVATE USE_BOOST_REGEX=1
|
||||
BOOST_REGEX_STANDALONE=1)
|
||||
get_target_property(BOOST_REGEX_INCLUDE_DIR Boost::regex
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/cif++/exports.hpp)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(cifpp PUBLIC NOMINMAX=1)
|
||||
@@ -353,12 +314,13 @@ set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(
|
||||
cifpp
|
||||
PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
PRIVATE "${BOOST_REGEX_INCLUDE_DIR}" "${EIGEN_INCLUDE_DIR}")
|
||||
PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB
|
||||
${CIFPP_REQUIRED_LIBRARIES})
|
||||
target_link_libraries(cifpp
|
||||
PUBLIC Threads::Threads ZLIB::ZLIB $<$<TARGET_EXISTS:std::atomic>:std::atomic>
|
||||
PRIVATE $<BUILD_INTERFACE:pcre2-8>)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
@@ -366,13 +328,13 @@ endif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
|
||||
if(CIFPP_DOWNLOAD_CCD)
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${PROJECT_SOURCE_DIR}/rsrc/components.cif)
|
||||
set(COMPONENTS_CIF ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/components.cif)
|
||||
|
||||
if(EXISTS ${COMPONENTS_CIF})
|
||||
file(SIZE ${COMPONENTS_CIF} CCD_FILE_SIZE)
|
||||
|
||||
if(CCD_FILE_SIZE EQUAL 0)
|
||||
message(STATUS "Removing empty ${COMPONENTS_CIF} file")
|
||||
message(STATUS "cifpp: Removing empty ${COMPONENTS_CIF} file")
|
||||
file(REMOVE "${COMPONENTS_CIF}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -401,7 +363,7 @@ if(CIFPP_DOWNLOAD_CCD)
|
||||
add_custom_command(
|
||||
OUTPUT ${COMPONENTS_CIF}
|
||||
COMMAND "${GUNZIP}" ${COMPONENTS_CIF}.gz
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/rsrc/)
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/)
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
endif()
|
||||
@@ -411,7 +373,7 @@ if(CIFPP_DOWNLOAD_CCD)
|
||||
|
||||
if(CCD_FETCH_STATUS_CODE)
|
||||
message(
|
||||
FATAL_ERROR "Error trying to download CCD file: ${CCD_FETCH_STATUS}")
|
||||
FATAL_ERROR "cifpp: Error trying to download CCD file: ${CCD_FETCH_STATUS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -429,6 +391,11 @@ endif()
|
||||
|
||||
if(CIFPP_DATA_DIR)
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
set_target_properties(cifpp PROPERTIES CIFPP_DATA_DIR ${CIFPP_DATA_DIR})
|
||||
endif()
|
||||
|
||||
if(NOT PROJECT_IS_TOP_LEVEL)
|
||||
set(CIFPP_SHARE_DIR ${CIFPP_DATA_DIR} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT BUILD_FOR_CCP4)
|
||||
@@ -452,14 +419,9 @@ else()
|
||||
endif()
|
||||
|
||||
# Install rules
|
||||
install(
|
||||
TARGETS cifpp
|
||||
EXPORT cifpp-targets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(TARGETS cifpp
|
||||
EXPORT cifpp
|
||||
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
install(
|
||||
@@ -475,54 +437,37 @@ file(GLOB OLD_CONFIG_FILES
|
||||
|
||||
if(OLD_CONFIG_FILES)
|
||||
message(
|
||||
STATUS "Installation will remove old config files: ${OLD_CONFIG_FILES}")
|
||||
STATUS "cifpp: Installation will remove old config files: ${OLD_CONFIG_FILES}")
|
||||
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
|
||||
endif()
|
||||
|
||||
install(
|
||||
EXPORT cifpp-targets
|
||||
FILE "cifpp-targets.cmake"
|
||||
install(EXPORT cifpp
|
||||
NAMESPACE cifpp::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp)
|
||||
FILE "cifpp-targets.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
install(
|
||||
DIRECTORY include/cif++
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT Devel)
|
||||
FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
install(
|
||||
FILES include/cif++.hpp
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT Devel)
|
||||
|
||||
if(CIFPP_DATA_DIR)
|
||||
install(
|
||||
FILES ${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ma.dic ${COMPONENTS_CIF}
|
||||
DESTINATION ${CIFPP_DATA_DIR})
|
||||
if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD)
|
||||
install(FILES ${COMPONENTS_CIF}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
endif()
|
||||
|
||||
if(CIFPP_CACHE_DIR)
|
||||
install(
|
||||
FILES ${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ma.dic ${COMPONENTS_CIF}
|
||||
DESTINATION ${CIFPP_CACHE_DIR})
|
||||
endif()
|
||||
|
||||
set(CONFIG_TEMPLATE_FILE ${PROJECT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
|
||||
set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
|
||||
|
||||
configure_package_config_file(
|
||||
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
|
||||
INSTALL_DESTINATION lib/cmake/cifpp
|
||||
PATH_VARS CIFPP_DATA_DIR)
|
||||
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
|
||||
COMPONENT Devel)
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
set_target_properties(
|
||||
cifpp
|
||||
@@ -540,109 +485,42 @@ write_basic_package_version_file(
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
# In case we're included as sub_directory:
|
||||
if(NOT PROJECT_IS_TOP_LEVEL)
|
||||
set(CIFPP_SHARE_DIR ${PROJECT_SOURCE_DIR}/rsrc PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# We're using the older version 2 of Catch2
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v2.13.9)
|
||||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
|
||||
list(
|
||||
APPEND
|
||||
CIFPP_tests
|
||||
unit-v2
|
||||
unit-3d
|
||||
format
|
||||
model
|
||||
rename-compound
|
||||
sugar
|
||||
spinner
|
||||
reconstruction
|
||||
validate-pdbx)
|
||||
|
||||
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
|
||||
set(CIFPP_TEST "${CIFPP_TEST}-test")
|
||||
set(CIFPP_TEST_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/test/${CIFPP_TEST}.cpp")
|
||||
|
||||
add_executable(
|
||||
${CIFPP_TEST} ${CIFPP_TEST_SOURCE}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/test/test-main.cpp")
|
||||
|
||||
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp::cifpp
|
||||
Catch2::Catch2)
|
||||
target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
if(MSVC)
|
||||
# Specify unwind semantics so that MSVC knowns how to handle exceptions
|
||||
target_compile_options(${CIFPP_TEST} PRIVATE /EHsc)
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
"run-${CIFPP_TEST}"
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch ${CIFPP_TEST})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
|
||||
add_test(NAME ${CIFPP_TEST} COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
endforeach()
|
||||
if(BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Optionally install the update scripts for CCD and dictionary files
|
||||
if(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL
|
||||
"GNU")
|
||||
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local")
|
||||
set(CIFPP_CRON_DIR
|
||||
"/etc/cron.weekly"
|
||||
CACHE PATH "The cron directory, for the update script")
|
||||
else()
|
||||
set(CIFPP_CRON_DIR
|
||||
"${CIFPP_ETC_DIR}/cron.weekly"
|
||||
CACHE PATH "The cron directory, for the update script")
|
||||
endif()
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(CIFPP_CRON_DIR
|
||||
"${CIFPP_ETC_DIR}/periodic/weekly"
|
||||
CACHE PATH "The cron directory, for the update script")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tools/update-libcifpp-data.in
|
||||
update-libcifpp-data @ONLY)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "GNU" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cron.weekly
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE
|
||||
WORLD_READ)
|
||||
else()
|
||||
message(FATAL_ERROR "Don't know where to install the update script")
|
||||
message(FATAL_ERROR "cifpp: Don't know where to install the update script")
|
||||
endif()
|
||||
|
||||
configure_file(${PROJECT_SOURCE_DIR}/tools/update-libcifpp-data.in
|
||||
update-libcifpp-data @ONLY)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CIFPP_CRON_DIR}
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE
|
||||
WORLD_READ)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CIFPP_CACHE_DIR})
|
||||
|
||||
# a config file, to make it complete
|
||||
if(NOT EXISTS "${CIFPP_ETC_DIR}/libcifpp.conf")
|
||||
# install(DIRECTORY DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/libcifpp")
|
||||
if(NOT EXISTS "${CMAKE_INSTALL_SYSCONFDIR}/libcifpp.conf")
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
[[# Uncomment the next line to enable automatic updates
|
||||
# update=true
|
||||
]])
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
DESTINATION "${CIFPP_ETC_DIR}")
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
install(
|
||||
CODE "message(\"A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")"
|
||||
CODE "message(\"cifpp: A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")"
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION "${CIFPP_ETC_DIR}/libcifpp/cache-update.d")
|
||||
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/libcifpp/cache-update.d)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
@@ -651,13 +529,3 @@ endif()
|
||||
if(BUILD_DOCUMENTATION)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_SOURCE_TGZ ON)
|
||||
set(CPACK_SOURCE_TBZ2 OFF)
|
||||
set(CPACK_SOURCE_TXZ OFF)
|
||||
set(CPACK_SOURCE_TZ OFF)
|
||||
set(CPACK_SOURCE_IGNORE_FILES "/rsrc/components.cif;/build;/.vscode;/.git")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME})
|
||||
include(CPack)
|
||||
|
||||
18
README.md
18
README.md
@@ -32,7 +32,7 @@ The documentation can be found at [github.io](https://pdb-redo.github.io/libcifp
|
||||
|
||||
## Synopsis
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// A simple program counting residues with an OXT atom
|
||||
|
||||
#include <filesystem>
|
||||
@@ -52,7 +52,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file" << std::endl;
|
||||
std::cerr << "Empty file\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ int main(int argc, char *argv[])
|
||||
auto n = atom_site.count(cif::key("label_atom_id") == "OXT");
|
||||
|
||||
std::cout << "File contains " << atom_site.size() << " atoms of which "
|
||||
<< n << (n == 1 ? " is" : " are") << " OXT" << std::endl
|
||||
<< "residues with an OXT are:" << std::endl;
|
||||
<< n << (n == 1 ? " is" : " are") << " OXT\n"
|
||||
<< "residues with an OXT are:\n";
|
||||
|
||||
// Loop over all atoms with atom-id "OXT" and print out some info.
|
||||
// That info is extracted using structured binding in C++
|
||||
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
|
||||
cif::key("label_atom_id") == "OXT",
|
||||
"label_asym_id", "label_comp_id", "label_seq_id"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -117,12 +117,8 @@ Other libraries you might want to install beforehand are:
|
||||
`libeigen3-dev`
|
||||
- [zlib](https://github.com/madler/zlib), the development version of this
|
||||
library. On Debian/Ubuntu this is the package `zlib1g-dev`.
|
||||
- [boost](https://www.boost.org), in Debian/Ubuntu this is `libboost-dev`.
|
||||
|
||||
The Boost libraries are only needed in case you are using GCC due to a long
|
||||
standing bug in GNU's implementation of std::regex. It simply crashes
|
||||
on the regular expressions used in the mmcif_pdbx dictionary and so
|
||||
we use the boost regex implementation instead.
|
||||
- [pcre2](https://www.pcre.org/), the Perl Compatible Regular Expression
|
||||
library. On Debian/Ubuntu this is the package `libpcre2-dev`.
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
64
changelog
64
changelog
@@ -1,3 +1,67 @@
|
||||
Version 9.0.0
|
||||
- Rename fields of cif::mm::polymer to match the naming
|
||||
in mmcif_pdbx.dic. Also, related, fix building mm::structure
|
||||
using the correct mapping between atom_site and residues.
|
||||
- _atom_site.auth_alt_id does not exist, it should be
|
||||
_atom_site.pdbx_auth_alt_id of course.
|
||||
- Added a more lightweight fixup for mmcif_pdbx files
|
||||
that lack certain categories.
|
||||
|
||||
Version 8.0.1
|
||||
- Fix cif::mm::structure::cleanup_empty_categories, removed too much
|
||||
- Add default value for B_iso_or_equiv in residue::create_new_atom
|
||||
- Reconstruct some branch records in bare pdbx files
|
||||
- Fix parsing PDB files (bug due to missing validator in dest. cat.)
|
||||
- Do not fail conversion of PDB files when compound info is missing
|
||||
|
||||
Version 8.0.0
|
||||
- A dictionary is for a datablock and a file can have
|
||||
datablocks with differing dictionaries.
|
||||
|
||||
Version 7.0.10
|
||||
- Deal with missing _entity.type in reconstructing mmCIF files
|
||||
- Replace code creating quaternions from rotation matrices
|
||||
that might sometimes give incorrect results. Or at least,
|
||||
the test code failed on this particular kind of code. Sometimes.
|
||||
- Fix reconstruction to build pdbx_nonpoly_scheme
|
||||
|
||||
Version 7.0.9
|
||||
- Using cif::file::load_dictionary it is now possible to
|
||||
load a dictionary along with its extensions in one go.
|
||||
E.g. file.load_dictionary("mmcif_pdbx;dssp-extension")
|
||||
- Fix in compound factory to avoid errors with lower case
|
||||
compound id's
|
||||
- Fix sac_parser's index to be case insensitive
|
||||
|
||||
Version 7.0.8
|
||||
- Fix PDB Remark 3 parser
|
||||
- Added three way comparison for point
|
||||
|
||||
Version 7.0.7
|
||||
- Set CIFPP_DATA_DIR on target cifpp for use in projects that include
|
||||
libcifpp directly
|
||||
|
||||
Version 7.0.6
|
||||
- Fix linking to std::atomic
|
||||
|
||||
Version 7.0.5
|
||||
- Fix case where category index was not updated for updated value
|
||||
|
||||
Version 7.0.4
|
||||
- Do not install headers and library in case we're not the top project
|
||||
|
||||
Version 7.0.3
|
||||
- Fix installation, write exports.hpp again
|
||||
|
||||
Version 7.0.2
|
||||
- Fix in testing error_code results.
|
||||
|
||||
Version 7.0.1
|
||||
- Various reconstruction fixes
|
||||
- category order in output fixed
|
||||
- better implementation of constructors for file, datablock and category
|
||||
- small optimisation in iterator
|
||||
|
||||
Version 7.0.0
|
||||
- Renaming many methods and parameters to be more
|
||||
consistent with the mmCIF dictionaries.
|
||||
|
||||
1291
cmake/CPM.cmake
Normal file
1291
cmake/CPM.cmake
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,75 +0,0 @@
|
||||
# Simplistic reimplementation of https://github.com/vector-of-bool/CMakeCM/blob/master/modules/FindFilesystem.cmake
|
||||
|
||||
if(TARGET std::filesystem)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
cmake_push_check_state()
|
||||
|
||||
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
|
||||
set(code [[
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
|
||||
int main() {
|
||||
auto cwd = std::filesystem::current_path();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
]])
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 8.4.0)
|
||||
# >> https://stackoverflow.com/questions/63902528/program-crashes-when-filesystempath-is-destroyed
|
||||
set(CXX_FILESYSTEM_NO_LINK_NEEDED 0)
|
||||
else()
|
||||
# Check a simple filesystem program without any linker flags
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
endif()
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
set(_found 1)
|
||||
else()
|
||||
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# Add the libstdc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set(_found ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
|
||||
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
# Try the libc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set(_found ${CXX_FILESYSTEM_CPPFS_NEEDED})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_found)
|
||||
add_library(std::filesystem INTERFACE IMPORTED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
# Nothing to add...
|
||||
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set_target_properties(std::filesystem PROPERTIES IMPORTED_LIBNAME stdc++fs)
|
||||
set(STDCPPFS_LIBRARY stdc++fs)
|
||||
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set_target_properties(std::filesystem PROPERTIES IMPORTED_LIBNAME c++fs)
|
||||
set(STDCPPFS_LIBRARY c++fs)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||
mark_as_advanced(Filesystem_FOUND)
|
||||
|
||||
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
|
||||
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
|
||||
endif()
|
||||
|
||||
33
cmake/FindPCRE2x.cmake
Normal file
33
cmake/FindPCRE2x.cmake
Normal file
@@ -0,0 +1,33 @@
|
||||
set(PCRE2_USE_STATIC_LIBS ON)
|
||||
|
||||
find_package(pcre2 CONFIG)
|
||||
|
||||
if(PCRE2_FOUND)
|
||||
message(STATUS "Using pcre2 found using find_package")
|
||||
else()
|
||||
include(FindPkgConfig)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PCRE2 IMPORTED_TARGET libpcre2-8)
|
||||
|
||||
if(PCRE2_FOUND)
|
||||
message(STATUS "Using pcre2 found using pkg-config")
|
||||
|
||||
add_library(pcre2-8 ALIAS PkgConfig::PCRE2)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT PCRE2_FOUND)
|
||||
message(STATUS "Using pcre2 using FetchContent")
|
||||
|
||||
set(PCRE2_BUILD_TESTS OFF)
|
||||
FetchContent_Declare(
|
||||
pcre2
|
||||
GIT_REPOSITORY https://github.com/PCRE2Project/pcre2
|
||||
GIT_TAG pcre2-10.45
|
||||
EXCLUDE_FROM_ALL)
|
||||
FetchContent_MakeAvailable(pcre2)
|
||||
|
||||
# add_subdirectory(${pcre2_SOURCE_DIR} EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
@@ -1,18 +0,0 @@
|
||||
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string s(100'000, '*');
|
||||
std::smatch m;
|
||||
std::regex r("^(.*?)$");
|
||||
|
||||
std::regex_search(s, m, r);
|
||||
|
||||
std::cout << s.substr(0, 10) << '\n';
|
||||
std::cout << m.str(1).substr(0, 10) << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -217,7 +217,7 @@ A simple case:
|
||||
#include <cif++.hpp>
|
||||
|
||||
cif::file f("1cbs.cif.gz");
|
||||
f.load_dictionary("mmcif_pdbx");
|
||||
f.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
if (not f.is_valid())
|
||||
std::cout << "This file is not valid\n";
|
||||
|
||||
@@ -27,7 +27,7 @@ Using *libcifpp* is easy, if you are familiar with modern C++:
|
||||
|
||||
.. literalinclude:: ../README.md
|
||||
:language: c++
|
||||
:start-after: ```c++
|
||||
:start-after: ```cpp
|
||||
:end-before: ```
|
||||
|
||||
.. toctree::
|
||||
|
||||
@@ -13,7 +13,7 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cif::file file = cif::pdb::read(argv[1]);
|
||||
cif::file file(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
|
||||
@@ -200,7 +200,7 @@ enum class radius_type
|
||||
};
|
||||
|
||||
/// @brief The number of radii per element which can be requested from atom_type_info
|
||||
constexpr size_t kRadiusTypeCount = static_cast<size_t>(radius_type::type_count);
|
||||
constexpr std::size_t kRadiusTypeCount = static_cast<std::size_t>(radius_type::type_count);
|
||||
|
||||
/// An enum used to select either the effective or the crystal radius of an ion.
|
||||
/// See explanation on Wikipedia: https://en.wikipedia.org/wiki/Ionic_radius
|
||||
@@ -276,7 +276,7 @@ class atom_type_traits
|
||||
{
|
||||
if (type >= radius_type::type_count)
|
||||
throw std::invalid_argument("invalid radius requested");
|
||||
return m_info->radii[static_cast<size_t>(type)] / 100.f;
|
||||
return m_info->radii[static_cast<std::size_t>(type)] / 100.f;
|
||||
}
|
||||
|
||||
/// \brief Return the radius for a charged version of this atom in a solid crystal
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -51,6 +50,11 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
struct category_validator;
|
||||
struct item_validator;
|
||||
struct link_validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// special exceptions
|
||||
|
||||
@@ -141,31 +145,49 @@ class category
|
||||
|
||||
/// \endcond
|
||||
|
||||
category() = default; ///< Default constructor
|
||||
category(std::string_view name); ///< Constructor taking a \a name
|
||||
category(const category &rhs); ///< Copy constructor
|
||||
category(category &&rhs); ///< Move constructor
|
||||
category &operator=(const category &rhs); ///< Copy assignement operator
|
||||
category &operator=(category &&rhs); ///< Move assignement operator
|
||||
category() = default; ///< Default constructor
|
||||
category(std::string_view name); ///< Constructor taking a \a name
|
||||
|
||||
/// @brief Constructor creating a category named @a name and filled with @a rows
|
||||
/// @param name Name for the new category
|
||||
/// @param rows The data stored in the category
|
||||
category(std::string_view name, row_initializer &&rows)
|
||||
: category(name)
|
||||
{
|
||||
emplace(std::forward<row_initializer>(rows));
|
||||
}
|
||||
|
||||
category(const category &rhs); ///< Copy constructor
|
||||
|
||||
category(category &&rhs) noexcept ///< Move constructor
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
category &operator=(category rhs) ///< assignement operator
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
/// @note Please note that the destructor is not virtual. It is assumed that
|
||||
/// you will not derive from this class.
|
||||
~category();
|
||||
|
||||
friend void swap(category &a, category &b) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
const std::string &name() const { return m_name; } ///< Returns the name of the category
|
||||
|
||||
[[deprecated("use key_items instead")]]
|
||||
iset key_fields() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
[[deprecated("use key_items instead")]] iset key_fields() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
|
||||
iset key_items() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
iset key_items() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
|
||||
[[deprecated("use key_item_indices instead")]]
|
||||
std::set<uint16_t> key_field_indices() const; ///< Returns a set of indices for the key items.
|
||||
[[deprecated("use key_item_indices instead")]] std::set<uint16_t> key_field_indices() const; ///< Returns a set of indices for the key items.
|
||||
|
||||
std::set<uint16_t> key_item_indices() const; ///< Returns a set of indices for the key items.
|
||||
std::set<uint16_t> key_item_indices() const; ///< Returns a set of indices for the key items.
|
||||
|
||||
/// @brief Set the validator for this category to @a v
|
||||
/// @param v The category_validator to assign. A nullptr value is allowed.
|
||||
@@ -174,7 +196,7 @@ class category
|
||||
|
||||
/// @brief Update the links in this category
|
||||
/// @param db The enclosing @ref datablock
|
||||
void update_links(datablock &db);
|
||||
void update_links(const datablock &db);
|
||||
|
||||
/// @brief Return the global @ref validator for the data
|
||||
/// @return The @ref validator or nullptr if not assigned
|
||||
@@ -201,6 +223,11 @@ class category
|
||||
/// @return Returns true is all validations pass
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Strip removes items from this category that are invalid according to the assigned validator
|
||||
*/
|
||||
void strip();
|
||||
|
||||
/// @brief Equality operator, returns true if @a rhs is equal to this
|
||||
/// @param rhs The object to compare with
|
||||
/// @return True if the data contained is equal
|
||||
@@ -285,15 +312,15 @@ class category
|
||||
}
|
||||
|
||||
/// Return a count of the rows in this container
|
||||
size_t size() const
|
||||
std::size_t size() const
|
||||
{
|
||||
return std::distance(cbegin(), cend());
|
||||
}
|
||||
|
||||
/// Return the theoretical maximum number or rows that can be stored
|
||||
size_t max_size() const
|
||||
std::size_t max_size() const
|
||||
{
|
||||
return std::numeric_limits<size_t>::max(); // this is a bit optimistic, I guess
|
||||
return std::numeric_limits<std::size_t>::max(); // this is a bit optimistic, I guess
|
||||
}
|
||||
|
||||
/// Return true if the category is empty
|
||||
@@ -305,8 +332,16 @@ class category
|
||||
// --------------------------------------------------------------------
|
||||
// A category can have a key, as defined by the validator/dictionary
|
||||
|
||||
/// @brief The type of an element of the key_type
|
||||
struct key_element_type
|
||||
{
|
||||
std::string name; ///< Name of the item
|
||||
std::string value; ///< Value to be found
|
||||
bool may_be_null = false; ///< If true, value should be same or empty
|
||||
};
|
||||
|
||||
/// @brief The key type
|
||||
using key_type = row_initializer;
|
||||
using key_type = std::vector<key_element_type>;
|
||||
|
||||
/// @brief Return a row_handle for the row specified by \a key
|
||||
/// @param key The value for the key, items specified in the dictionary should have a value
|
||||
@@ -823,9 +858,9 @@ class category
|
||||
/// @brief Return the total number of rows that match condition @a cond
|
||||
/// @param cond The condition to match
|
||||
/// @return The count
|
||||
size_t count(condition &&cond) const
|
||||
std::size_t count(condition &&cond) const
|
||||
{
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
|
||||
if (cond)
|
||||
{
|
||||
@@ -895,14 +930,14 @@ class category
|
||||
/// @brief Erase all rows that match condition @a cond
|
||||
/// @param cond The condition
|
||||
/// @return The number of rows that have been erased
|
||||
size_t erase(condition &&cond);
|
||||
std::size_t erase(condition &&cond);
|
||||
|
||||
/// @brief Erase all rows that match condition @a cond calling
|
||||
/// the visitor function @a visit for each before actually erasing it.
|
||||
/// @param cond The condition
|
||||
/// @param visit The visitor function
|
||||
/// @return The number of rows that have been erased
|
||||
size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
|
||||
std::size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
|
||||
|
||||
/// @brief Emplace the values in @a ri in a new row
|
||||
/// @param ri An object containing the values to insert
|
||||
@@ -939,6 +974,12 @@ class category
|
||||
return insert_impl(cend(), r);
|
||||
}
|
||||
|
||||
void emplace(const_iterator b, const_iterator e)
|
||||
{
|
||||
while (b != e)
|
||||
emplace(*b++);
|
||||
}
|
||||
|
||||
/// @brief Completely erase all rows contained in this category
|
||||
void clear();
|
||||
|
||||
@@ -964,6 +1005,32 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
using value_provider_type = std::function<std::string_view(std::string_view)>;
|
||||
|
||||
/// \brief Update a single item named @a item_name in the rows that match
|
||||
/// \a cond to values provided by a callback function \a value_provider
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(condition &&cond, std::string_view item_name,
|
||||
value_provider_type &&value_provider)
|
||||
{
|
||||
auto rs = find(std::move(cond));
|
||||
std::vector<row_handle> rows;
|
||||
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
|
||||
update_value(rows, item_name, std::move(value_provider));
|
||||
}
|
||||
|
||||
/// \brief Update a single item named @a item_name in the rows \a rows
|
||||
/// to values provided by a callback function \a value_provider
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name,
|
||||
value_provider_type &&value_provider);
|
||||
|
||||
/// \brief Update a single item named @a item_name in the rows that match \a cond to value \a value
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
@@ -982,15 +1049,18 @@ class category
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value);
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
|
||||
{
|
||||
update_value(rows, item_name, [value](std::string_view)
|
||||
{ return value; });
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Naming used to be very inconsistent. For backward compatibility,
|
||||
// the old function names are here as deprecated variants.
|
||||
|
||||
/// \brief Return the index number for \a column_name
|
||||
[[deprecated("Use get_item_ix instead")]]
|
||||
uint16_t get_column_ix(std::string_view column_name) const
|
||||
[[deprecated("Use get_item_ix instead")]] uint16_t get_column_ix(std::string_view column_name) const
|
||||
{
|
||||
return get_item_ix(column_name);
|
||||
}
|
||||
@@ -998,8 +1068,7 @@ class category
|
||||
/// @brief Return the name for column with index @a ix
|
||||
/// @param ix The index number
|
||||
/// @return The name of the column
|
||||
[[deprecated("use get_item_name instead")]]
|
||||
std::string_view get_column_name(uint16_t ix) const
|
||||
[[deprecated("use get_item_name instead")]] std::string_view get_column_name(uint16_t ix) const
|
||||
{
|
||||
return get_item_name(ix);
|
||||
}
|
||||
@@ -1007,8 +1076,7 @@ class category
|
||||
/// @brief Make sure a item with name @a item_name is known and return its index number
|
||||
/// @param item_name The name of the item
|
||||
/// @return The index number of the item
|
||||
[[deprecated("use add_item instead")]]
|
||||
uint16_t add_column(std::string_view item_name)
|
||||
[[deprecated("use add_item instead")]] uint16_t add_column(std::string_view item_name)
|
||||
{
|
||||
return add_item(item_name);
|
||||
}
|
||||
@@ -1016,15 +1084,13 @@ class category
|
||||
/** @brief Remove column name @a colum_name
|
||||
* @param column_name The column to be removed
|
||||
*/
|
||||
[[deprecated("use remove_item instead")]]
|
||||
void remove_column(std::string_view column_name)
|
||||
[[deprecated("use remove_item instead")]] void remove_column(std::string_view column_name)
|
||||
{
|
||||
remove_item(column_name);
|
||||
}
|
||||
|
||||
/** @brief Rename column @a from_name to @a to_name */
|
||||
[[deprecated("use rename_item instead")]]
|
||||
void rename_column(std::string_view from_name, std::string_view to_name)
|
||||
[[deprecated("use rename_item instead")]] void rename_column(std::string_view from_name, std::string_view to_name)
|
||||
{
|
||||
rename_item(from_name, to_name);
|
||||
}
|
||||
@@ -1032,15 +1098,13 @@ class category
|
||||
/// @brief Return whether a column with name @a name exists in this category
|
||||
/// @param name The name of the column
|
||||
/// @return True if the column exists
|
||||
[[deprecated("use has_item instead")]]
|
||||
bool has_column(std::string_view name) const
|
||||
[[deprecated("use has_item instead")]] bool has_column(std::string_view name) const
|
||||
{
|
||||
return has_item(name);
|
||||
}
|
||||
|
||||
/// @brief Return the cif::iset of columns in this category
|
||||
[[deprecated("use get_items instead")]]
|
||||
iset get_columns() const
|
||||
[[deprecated("use get_items instead")]] iset get_columns() const
|
||||
{
|
||||
return get_items();
|
||||
}
|
||||
@@ -1048,25 +1112,7 @@ class category
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief Return the index number for \a item_name
|
||||
|
||||
uint16_t get_item_ix(std::string_view item_name) const
|
||||
{
|
||||
uint16_t result;
|
||||
|
||||
for (result = 0; result < m_items.size(); ++result)
|
||||
{
|
||||
if (iequals(item_name, m_items[result].m_name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (VERBOSE > 0 and result == m_items.size() and m_cat_validator != nullptr) // validate the name, if it is known at all (since it was not found)
|
||||
{
|
||||
auto iv = m_cat_validator->get_validator_for_item(item_name);
|
||||
if (iv == nullptr)
|
||||
std::cerr << "Invalid name used '" << item_name << "' is not a known item in " + m_name << '\n';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
uint16_t get_item_ix(std::string_view item_name) const;
|
||||
|
||||
/// @brief Return the name for item with index @a ix
|
||||
/// @param ix The index number
|
||||
@@ -1082,28 +1128,7 @@ class category
|
||||
/// @brief Make sure a item with name @a item_name is known and return its index number
|
||||
/// @param item_name The name of the item
|
||||
/// @return The index number of the item
|
||||
uint16_t add_item(std::string_view item_name)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
uint16_t result = get_item_ix(item_name);
|
||||
|
||||
if (result == m_items.size())
|
||||
{
|
||||
const item_validator *item_validator = nullptr;
|
||||
|
||||
if (m_cat_validator != nullptr)
|
||||
{
|
||||
item_validator = m_cat_validator->get_validator_for_item(item_name);
|
||||
if (item_validator == nullptr)
|
||||
m_validator->report_error( validation_error::item_not_allowed_in_category, m_name, item_name, false);
|
||||
}
|
||||
|
||||
m_items.emplace_back(item_name, item_validator);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
uint16_t add_item(std::string_view item_name);
|
||||
|
||||
/** @brief Remove item name @a colum_name
|
||||
* @param item_name The item to be removed
|
||||
@@ -1140,8 +1165,7 @@ class category
|
||||
|
||||
/// This function returns effectively the list of fully qualified item
|
||||
/// names, that is category_name + '.' + item_name for each item
|
||||
[[deprecated("use get_item_order instead")]]
|
||||
std::vector<std::string> get_tag_order() const
|
||||
[[deprecated("use get_item_order instead")]] std::vector<std::string> get_tag_order() const
|
||||
{
|
||||
return get_item_order();
|
||||
}
|
||||
@@ -1233,6 +1257,7 @@ class category
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: NEED TO FIX THIS!
|
||||
category *linked;
|
||||
const link_validator *v;
|
||||
};
|
||||
|
||||
@@ -138,7 +138,7 @@ struct compound_bond
|
||||
/// This information is derived from the CDD by default.
|
||||
///
|
||||
/// To create compounds, you use the factory method. You can add your own
|
||||
/// compound definitions by calling the addExtraComponents function and
|
||||
/// compound definitions by calling the push_dictionary function and
|
||||
/// pass it a valid CCD formatted file.
|
||||
|
||||
class compound
|
||||
@@ -180,7 +180,6 @@ class compound
|
||||
friend class local_compound_factory_impl;
|
||||
|
||||
compound(cif::datablock &db);
|
||||
compound(cif::datablock &db, int);
|
||||
|
||||
std::string m_id;
|
||||
std::string m_name;
|
||||
@@ -291,6 +290,13 @@ class compound_factory
|
||||
|
||||
void report_missing_compound(std::string_view compound_id);
|
||||
|
||||
bool get_report_missing() const { return m_report_missing; }
|
||||
|
||||
void set_report_missing(bool report)
|
||||
{
|
||||
m_report_missing = report;
|
||||
}
|
||||
|
||||
private:
|
||||
compound_factory();
|
||||
|
||||
@@ -302,6 +308,7 @@ class compound_factory
|
||||
static bool s_use_thread_local_instance;
|
||||
|
||||
std::shared_ptr<compound_factory_impl> m_impl;
|
||||
bool m_report_missing = true;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/format.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
@@ -48,49 +50,49 @@
|
||||
* @code {.cpp}
|
||||
* cif::condition c = cif::key("id") == 1;
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* That will find rows where the ID item contains the number 1. If
|
||||
* using cif::key is a bit too much typing, you can also write:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* using namespace cif::literals;
|
||||
*
|
||||
*
|
||||
* cif::condition c2 = "id"_key == 1;
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* Now if you want both ID = 1 and ID = 2 in the result:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c3 = "id"_key == 1 or "id"_key == 2;
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* There are some special values you can use. To find rows with item that
|
||||
* do not have a value:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c4 = "type"_key == cif::null;
|
||||
* @endcode
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* Of if it should not be NULL:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c5 = "type"_key != cif::null;
|
||||
* @endcode
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* There's even a way to find all records:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c6 = cif::all;
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* And when you want to search for any item containing the value 'foo':
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c7 = cif::any == "foo";
|
||||
* @endcode
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* All these conditions can be chained together again:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c8 = std::move(c3) and std::move(c5);
|
||||
* @endcode
|
||||
@@ -105,7 +107,7 @@ namespace cif
|
||||
|
||||
/**
|
||||
* @brief Get the items that can be used as key in conditions for a category
|
||||
*
|
||||
*
|
||||
* @param cat The category whose items to return
|
||||
* @return iset The set of key item names
|
||||
*/
|
||||
@@ -114,7 +116,7 @@ iset get_category_fields(const category &cat);
|
||||
|
||||
/**
|
||||
* @brief Get the items that can be used as key in conditions for a category
|
||||
*
|
||||
*
|
||||
* @param cat The category whose items to return
|
||||
* @return iset The set of key field names
|
||||
*/
|
||||
@@ -122,7 +124,7 @@ iset get_category_items(const category &cat);
|
||||
|
||||
/**
|
||||
* @brief Get the item index for item @a col in category @a cat
|
||||
*
|
||||
*
|
||||
* @param cat The category
|
||||
* @param col The name of the item
|
||||
* @return uint16_t The index
|
||||
@@ -131,7 +133,7 @@ uint16_t get_item_ix(const category &cat, std::string_view col);
|
||||
|
||||
/**
|
||||
* @brief Return whether the item @a col in category @a cat has a primitive type of *uchar*
|
||||
*
|
||||
*
|
||||
* @param cat The category
|
||||
* @param col The item name
|
||||
* @return true If the primitive type is of type *uchar*
|
||||
@@ -174,14 +176,13 @@ namespace detail
|
||||
class condition
|
||||
{
|
||||
public:
|
||||
|
||||
/** @cond */
|
||||
using condition_impl = detail::condition_impl;
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Construct a new, empty condition object
|
||||
*
|
||||
*
|
||||
*/
|
||||
condition()
|
||||
: m_impl(nullptr)
|
||||
@@ -190,7 +191,7 @@ class condition
|
||||
|
||||
/**
|
||||
* @brief Construct a new condition object with implementation @a impl
|
||||
*
|
||||
*
|
||||
* @param impl The implementation to use
|
||||
*/
|
||||
explicit condition(condition_impl *impl)
|
||||
@@ -229,15 +230,15 @@ class condition
|
||||
/**
|
||||
* @brief Prepare the condition to be used on category @a c. This will
|
||||
* take care of setting the correct indices for items e.g.
|
||||
*
|
||||
*
|
||||
* @param c The category this query should act upon
|
||||
*/
|
||||
void prepare(const category &c);
|
||||
|
||||
/**
|
||||
* @brief This operator returns true if the row referenced by @a r is
|
||||
* @brief This operator returns true if the row referenced by @a r is
|
||||
* a match for this condition.
|
||||
*
|
||||
*
|
||||
* @param r The reference to a row.
|
||||
* @return true If there is a match
|
||||
* @return false If there is no match
|
||||
@@ -262,7 +263,7 @@ class condition
|
||||
/**
|
||||
* @brief If the prepare step found out there is only one hit
|
||||
* this single hit can be returned by this method.
|
||||
*
|
||||
*
|
||||
* @return std::optional<row_handle> The result will contain
|
||||
* a row reference if there is a single hit, it will be empty otherwise
|
||||
*/
|
||||
@@ -291,7 +292,7 @@ class condition
|
||||
|
||||
/**
|
||||
* @brief Operator to use to write out a condition to @a os, for debugging purposes
|
||||
*
|
||||
*
|
||||
* @param os The std::ostream to write to
|
||||
* @param cond The condition to write
|
||||
* @return std::ostream& The same as @a os
|
||||
@@ -370,7 +371,7 @@ namespace detail
|
||||
{
|
||||
key_equals_condition_impl(item &&i)
|
||||
: m_item_name(i.name())
|
||||
, m_value(i.value())
|
||||
, m_value(std::forward<item>(i).value())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -470,6 +471,106 @@ namespace detail
|
||||
std::optional<row_handle> m_single_hit;
|
||||
};
|
||||
|
||||
struct key_equals_number_condition_impl : public condition_impl
|
||||
{
|
||||
key_equals_number_condition_impl(const std::string &name, double v)
|
||||
: m_item_name(name)
|
||||
, m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
return m_single_hit.has_value() ? *m_single_hit == r : r[m_item_ix].compare(m_value) == 0;
|
||||
}
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_name << " == " << m_value;
|
||||
}
|
||||
|
||||
virtual std::optional<row_handle> single() const override
|
||||
{
|
||||
return m_single_hit;
|
||||
}
|
||||
|
||||
virtual bool equals(const condition_impl *rhs) const override
|
||||
{
|
||||
if (typeid(*rhs) == typeid(key_equals_number_condition_impl))
|
||||
{
|
||||
auto ri = static_cast<const key_equals_number_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 item_names 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_name == ri->m_item_name;
|
||||
}
|
||||
return this == rhs;
|
||||
}
|
||||
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
double m_value;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
};
|
||||
|
||||
struct key_equals_number_or_empty_condition_impl : public condition_impl
|
||||
{
|
||||
key_equals_number_or_empty_condition_impl(key_equals_number_condition_impl *equals)
|
||||
: m_item_name(equals->m_item_name)
|
||||
, m_value(equals->m_value)
|
||||
, m_single_hit(equals->m_single_hit)
|
||||
{
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_item_ix(c, m_item_name);
|
||||
return this;
|
||||
}
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
bool result = false;
|
||||
if (m_single_hit.has_value())
|
||||
result = *m_single_hit == r;
|
||||
else
|
||||
result = r[m_item_ix].empty() or r[m_item_ix].compare(m_value) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << '(' << m_item_name << " == " << m_value << " OR " << m_item_name << " IS NULL)";
|
||||
}
|
||||
|
||||
virtual std::optional<row_handle> single() const override
|
||||
{
|
||||
return m_single_hit;
|
||||
}
|
||||
|
||||
virtual bool equals(const condition_impl *rhs) const override
|
||||
{
|
||||
if (typeid(*rhs) == typeid(key_equals_number_or_empty_condition_impl))
|
||||
{
|
||||
auto ri = static_cast<const key_equals_number_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 item_names 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_name == ri->m_item_name;
|
||||
}
|
||||
return this == rhs;
|
||||
}
|
||||
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
double m_value;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
};
|
||||
|
||||
struct key_compare_condition_impl : public condition_impl
|
||||
{
|
||||
template <typename COMP>
|
||||
@@ -651,28 +752,9 @@ namespace detail
|
||||
delete sub;
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
for (auto &sub : m_sub)
|
||||
sub = sub->prepare(c);
|
||||
return this;
|
||||
}
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (sub->test(r))
|
||||
continue;
|
||||
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
bool test(row_handle r) const override;
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
@@ -719,6 +801,7 @@ namespace detail
|
||||
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
|
||||
|
||||
std::vector<condition_impl *> m_sub;
|
||||
std::optional<row_handle> m_single; // Potential result of index lookup
|
||||
};
|
||||
|
||||
struct or_condition_impl : public condition_impl
|
||||
@@ -876,8 +959,9 @@ inline condition operator or(condition &&a, condition &&b)
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
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))
|
||||
|
||||
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);
|
||||
@@ -886,6 +970,26 @@ inline condition operator or(condition &&a, condition &&b)
|
||||
return condition(new detail::key_equals_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
if (typeid(*a.m_impl) == typeid(detail::key_equals_number_condition_impl) and
|
||||
typeid(*b.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_number_condition_impl *>(a.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(b.m_impl);
|
||||
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
return condition(new detail::key_equals_number_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
if (typeid(*b.m_impl) == typeid(detail::key_equals_number_condition_impl) and
|
||||
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_number_condition_impl *>(b.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(a.m_impl);
|
||||
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
return condition(new detail::key_equals_number_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
|
||||
}
|
||||
|
||||
@@ -897,7 +1001,7 @@ inline condition operator or(condition &&a, condition &&b)
|
||||
|
||||
/**
|
||||
* @brief A helper class to make it possible to search for empty items (NULL)
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* "id"_key == cif::empty_type();
|
||||
* @endcode
|
||||
@@ -909,7 +1013,7 @@ struct empty_type
|
||||
|
||||
/**
|
||||
* @brief A helper to make it possible to have conditions like
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* "id"_key == cif::null;
|
||||
* @endcode
|
||||
@@ -919,14 +1023,14 @@ inline constexpr empty_type null = empty_type();
|
||||
|
||||
/**
|
||||
* @brief Class to use in creating conditions, creates a reference to a item or item
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct key
|
||||
{
|
||||
/**
|
||||
* @brief Construct a new key object using @a item_name as name
|
||||
*
|
||||
* @param item_name
|
||||
*
|
||||
* @param item_name
|
||||
*/
|
||||
explicit key(const std::string &item_name)
|
||||
: m_item_name(item_name)
|
||||
@@ -935,8 +1039,8 @@ struct key
|
||||
|
||||
/**
|
||||
* @brief Construct a new key object using @a item_name as name
|
||||
*
|
||||
* @param item_name
|
||||
*
|
||||
* @param item_name
|
||||
*/
|
||||
explicit key(const char *item_name)
|
||||
: m_item_name(item_name)
|
||||
@@ -945,8 +1049,8 @@ struct key
|
||||
|
||||
/**
|
||||
* @brief Construct a new key object using @a item_name as name
|
||||
*
|
||||
* @param item_name
|
||||
*
|
||||
* @param item_name
|
||||
*/
|
||||
explicit key(std::string_view item_name)
|
||||
: m_item_name(item_name)
|
||||
@@ -959,13 +1063,16 @@ struct key
|
||||
std::string m_item_name; ///< The item name
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
concept Numeric = ((std::is_floating_point_v<T> or std::is_integral_v<T>) and not std::is_same_v<T, bool>);
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a numeric value @a v
|
||||
*/
|
||||
template <Numeric T>
|
||||
condition operator==(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_name, v }));
|
||||
return condition(new detail::key_equals_number_condition_impl(key.m_item_name, v));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -979,6 +1086,16 @@ inline condition operator==(const key &key, std::string_view value)
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a value @a value
|
||||
*/
|
||||
template <typename T>
|
||||
requires std::is_same_v<T, bool>
|
||||
inline condition operator==(const key &key, T value)
|
||||
{
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_name, value ? "y" : "n" }));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a not equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
@@ -999,61 +1116,93 @@ inline condition operator!=(const key &key, std::string_view value)
|
||||
/**
|
||||
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator>(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " > " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].template compare<T>(v, icase) > 0; },
|
||||
s.str()));
|
||||
{ return r[item_name].compare(v) > 0; },
|
||||
std::format(" > {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator>=(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " >= " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].template compare<T>(v, icase) >= 0; },
|
||||
s.str()));
|
||||
{ return r[item_name].compare(v) >= 0; },
|
||||
std::format(" >= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator<(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " < " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].template compare<T>(v, icase) < 0; },
|
||||
s.str()));
|
||||
{ return r[item_name].compare(v) < 0; },
|
||||
std::format(" < {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator<=(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " <= " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].template compare<T>(v, icase) <= 0; },
|
||||
s.str()));
|
||||
{ return r[item_name].compare(v) <= 0; },
|
||||
std::format(" <= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator>(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) > 0; },
|
||||
std::format(" > {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator>=(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) >= 0; },
|
||||
std::format(" >= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator<(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) < 0; },
|
||||
std::format(" < {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator<=(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) <= 0; },
|
||||
std::format(" <= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1093,6 +1242,19 @@ condition operator==(const key &key, const std::optional<T> &v)
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a condition to search any item for a value @a v if @a v contains a value
|
||||
* compare to null if not.
|
||||
*/
|
||||
template <typename T>
|
||||
condition operator!=(const key &key, const std::optional<T> &v)
|
||||
{
|
||||
if (v.has_value())
|
||||
return condition(new detail::not_condition_impl(condition(new detail::key_equals_condition_impl({ key.m_item_name, *v }))));
|
||||
else
|
||||
return condition(new detail::not_condition_impl(condition(new detail::key_is_empty_condition_impl(key.m_item_name))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a boolean opposite of the condition in @a rhs
|
||||
*/
|
||||
@@ -1141,12 +1303,12 @@ namespace literals
|
||||
{
|
||||
/**
|
||||
* @brief Return a cif::key for the item name @a text
|
||||
*
|
||||
*
|
||||
* @param text The name of the item
|
||||
* @param length The length of @a text
|
||||
* @return key The cif::key created
|
||||
*/
|
||||
inline key operator""_key(const char *text, size_t length)
|
||||
inline key operator""_key(const char *text, std::size_t length)
|
||||
{
|
||||
return key(std::string(text, length));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
/** \file datablock.hpp
|
||||
* Each valid mmCIF file contains at least one @ref cif::datablock.
|
||||
* A datablock has a name and can contain one or more @ref cif::category "categories"
|
||||
@@ -61,12 +63,26 @@ class datablock : public std::list<category>
|
||||
|
||||
/** @cond */
|
||||
datablock(const datablock &);
|
||||
datablock(datablock &&) = default;
|
||||
|
||||
datablock &operator=(const datablock &);
|
||||
datablock &operator=(datablock &&) = default;
|
||||
datablock(datablock &&db) noexcept
|
||||
{
|
||||
swap_(*this, db);
|
||||
}
|
||||
|
||||
datablock &operator=(datablock db)
|
||||
{
|
||||
swap_(*this, db);
|
||||
return *this;
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
friend void swap_(datablock &a, datablock &b) noexcept
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_validator, b.m_validator);
|
||||
std::swap(static_cast<std::list<category>&>(a), static_cast<std::list<category>&>(b));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -84,6 +100,12 @@ class datablock : public std::list<category>
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the dictionary specified in audit_conform category
|
||||
*
|
||||
*/
|
||||
void load_dictionary();
|
||||
|
||||
/**
|
||||
* @brief Set the validator object to @a v
|
||||
*
|
||||
@@ -106,15 +128,6 @@ class datablock : public std::list<category>
|
||||
*/
|
||||
bool is_valid() const;
|
||||
|
||||
/**
|
||||
* @brief Validates the content of this datablock and all its content
|
||||
* and updates or removes the audit_conform category to match the result.
|
||||
*
|
||||
* @return true If the content is valid
|
||||
* @return false If the content is not valid
|
||||
*/
|
||||
bool is_valid();
|
||||
|
||||
/**
|
||||
* @brief Validates all contained data for valid links between parents and children
|
||||
* as defined in the validator
|
||||
@@ -124,6 +137,14 @@ class datablock : public std::list<category>
|
||||
*/
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Strip removes all categories and items that are invalid according
|
||||
* to the assigned validator. Will also add a valid audit_conform block.
|
||||
*
|
||||
* @return true if the remaining datablock is valid
|
||||
*/
|
||||
bool strip();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -162,6 +183,15 @@ class datablock : public std::list<category>
|
||||
*/
|
||||
const category *get(std::string_view name) const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return true if this datablock contains a non-empty category
|
||||
*/
|
||||
bool contains(std::string_view name) const
|
||||
{
|
||||
return get(name) != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to find a category with name @a name and will create a
|
||||
* new one if it is not found. The result is a tuple of an iterator
|
||||
@@ -220,4 +250,4 @@ class datablock : public std::list<category>
|
||||
const validator *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -38,13 +38,8 @@ namespace cif
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Parse the contents of @a is and create a new validator object with name @a name
|
||||
* @brief Parse the contents of @a is and place content in validator @a v
|
||||
*/
|
||||
validator parse_dictionary(std::string_view name, std::istream &is);
|
||||
|
||||
/**
|
||||
* @brief Extend the definitions in validator @a v with the contents of stream @a is
|
||||
*/
|
||||
void extend_dictionary(validator &v, std::istream &is);
|
||||
void parse_dictionary(validator &v, std::istream &is);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -85,11 +85,11 @@ class file : public std::list<datablock>
|
||||
* @param data The pointer to the character string with data to load
|
||||
* @param length The length of the data
|
||||
*/
|
||||
explicit file(const char *data, size_t length)
|
||||
explicit file(const char *data, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -100,25 +100,24 @@ class file : public std::list<datablock>
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
file(const file &) = default;
|
||||
file(file &&) = default;
|
||||
file &operator=(const file &) = default;
|
||||
file &operator=(file &&) = default;
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Set the validator object to @a v
|
||||
*/
|
||||
void set_validator(const validator *v);
|
||||
|
||||
/**
|
||||
* @brief Get the validator object
|
||||
*/
|
||||
const validator *get_validator() const
|
||||
file(const file &rhs)
|
||||
: std::list<datablock>(rhs)
|
||||
{
|
||||
return m_validator;
|
||||
}
|
||||
|
||||
file(file &&rhs)
|
||||
{
|
||||
this->swap(rhs);
|
||||
}
|
||||
|
||||
file &operator=(file f)
|
||||
{
|
||||
this->swap(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Validate the content and return true if everything was valid.
|
||||
*
|
||||
@@ -153,21 +152,6 @@ class file : public std::list<datablock>
|
||||
*/
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Attempt to load a dictionary (validator) based on
|
||||
* the contents of the *audit_conform* category, if available.
|
||||
*/
|
||||
void load_dictionary();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the named dictionary @a name and
|
||||
* create a validator based on it.
|
||||
*
|
||||
* @param name The name of the dictionary to load
|
||||
*/
|
||||
void load_dictionary(std::string_view name);
|
||||
|
||||
/**
|
||||
* @brief Return true if a datablock with the name @a name is part of this file
|
||||
*/
|
||||
@@ -220,6 +204,12 @@ class file : public std::list<datablock>
|
||||
/** Load the data from @a is */
|
||||
void load(std::istream &is);
|
||||
|
||||
/** Load the data from the file specified by @a p using validator @a v */
|
||||
void load(const std::filesystem::path &p, const validator &v);
|
||||
|
||||
/** Load the data from @a is using validator @a v */
|
||||
void load(std::istream &is, const validator &v);
|
||||
|
||||
/** Save the data to the file specified by @a p */
|
||||
void save(const std::filesystem::path &p) const;
|
||||
|
||||
@@ -234,9 +224,6 @@ class file : public std::list<datablock>
|
||||
f.save(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
const validator *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,139 +26,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <string>
|
||||
|
||||
/** \file format.hpp
|
||||
*
|
||||
* File containing a basic reimplementation of boost::format
|
||||
* but then a bit more simplistic. Still this allowed me to move my code
|
||||
* from using boost::format to something without external dependency easily.
|
||||
* Now using std::format instead of a home grown rip off
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct to_varg
|
||||
{
|
||||
using type = T;
|
||||
|
||||
to_varg(const T &v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value; }
|
||||
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_varg<const char *>
|
||||
{
|
||||
using type = const char *;
|
||||
|
||||
to_varg(const char *v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value.c_str(); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_varg<std::string>
|
||||
{
|
||||
using type = const char *;
|
||||
|
||||
to_varg(const std::string &v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value.c_str(); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/** @cond */
|
||||
|
||||
template <typename... Args>
|
||||
class format_plus_arg
|
||||
{
|
||||
public:
|
||||
using args_vector_type = std::tuple<detail::to_varg<Args>...>;
|
||||
using vargs_vector_type = std::tuple<typename detail::to_varg<Args>::type...>;
|
||||
|
||||
format_plus_arg(const format_plus_arg &) = delete;
|
||||
format_plus_arg &operator=(const format_plus_arg &) = delete;
|
||||
|
||||
|
||||
format_plus_arg(std::string_view fmt, Args... args)
|
||||
: m_fmt(fmt)
|
||||
, m_args(std::forward<Args>(args)...)
|
||||
{
|
||||
auto ix = std::make_index_sequence<sizeof...(Args)>();
|
||||
copy_vargs(ix);
|
||||
}
|
||||
|
||||
std::string str()
|
||||
{
|
||||
char buffer[1024];
|
||||
std::string::size_type r = std::apply(snprintf, std::tuple_cat(std::make_tuple(buffer, sizeof(buffer), m_fmt.c_str()), m_vargs));
|
||||
return { buffer, r };
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const format_plus_arg &f)
|
||||
{
|
||||
char buffer[1024];
|
||||
std::string::size_type r = std::apply(snprintf, std::tuple_cat(std::make_tuple(buffer, sizeof(buffer), f.m_fmt.c_str()), f.m_vargs));
|
||||
os.write(buffer, r);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <size_t... I>
|
||||
void copy_vargs(std::index_sequence<I...>)
|
||||
{
|
||||
((std::get<I>(m_vargs) = *std::get<I>(m_args)), ...);
|
||||
}
|
||||
|
||||
std::string m_fmt;
|
||||
args_vector_type m_args;
|
||||
vargs_vector_type m_vargs;
|
||||
};
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief A simplistic reimplementation of boost::format, in fact it is
|
||||
* actually a way to call the C function snprintf to format the arguments
|
||||
* in @a args into the format string @a fmt
|
||||
*
|
||||
* The string in @a fmt should thus be a C style format string.
|
||||
*
|
||||
* TODO: Move to C++23 style of printing.
|
||||
*
|
||||
* @tparam Args The types of the arguments
|
||||
* @param fmt The format string
|
||||
* @param args The arguments
|
||||
* @return An object that can be written out to a std::ostream using operator<<
|
||||
*/
|
||||
|
||||
template <typename... Args>
|
||||
constexpr auto format(std::string_view fmt, Args... args)
|
||||
{
|
||||
return format_plus_arg(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// A streambuf that fills out lines with spaces up until a specified width
|
||||
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
// Copyright Maarten L. Hekkelman, 2022
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Original code comes from libgxrio at https://github.com/mhekkel/gxrio
|
||||
This is a stripped down version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -36,7 +62,7 @@ namespace cif::gzio
|
||||
{
|
||||
|
||||
/** The default buffer size to use */
|
||||
const size_t kDefaultBufferSize = 256;
|
||||
const std::size_t kDefaultBufferSize = 256;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -112,7 +138,7 @@ class basic_streambuf : public std::basic_streambuf<CharT, Traits>
|
||||
/// This implementation of streambuf can decompress (inflate) data compressed
|
||||
/// using zlib.
|
||||
|
||||
template <typename CharT, typename Traits, size_t BufferSize = kDefaultBufferSize>
|
||||
template <typename CharT, typename Traits, std::size_t BufferSize = kDefaultBufferSize>
|
||||
class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
{
|
||||
public:
|
||||
@@ -317,7 +343,7 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
///
|
||||
/// This implementation of streambuf can compress (deflate) data using zlib.
|
||||
|
||||
template <typename CharT, typename Traits, size_t BufferSize = kDefaultBufferSize>
|
||||
template <typename CharT, typename Traits, std::size_t BufferSize = kDefaultBufferSize>
|
||||
class basic_ogzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -117,11 +117,9 @@ class item
|
||||
char buffer[32];
|
||||
|
||||
auto r = to_chars(buffer, buffer + sizeof(buffer) - 1, value, chars_format::fixed, precision);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("Could not format number");
|
||||
|
||||
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
|
||||
*r.ptr = 0;
|
||||
m_value.assign(buffer, r.ptr - buffer);
|
||||
}
|
||||
|
||||
@@ -138,11 +136,9 @@ class item
|
||||
char buffer[32];
|
||||
|
||||
auto r = to_chars(buffer, buffer + sizeof(buffer) - 1, value, chars_format::general);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("Could not format number");
|
||||
|
||||
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
|
||||
*r.ptr = 0;
|
||||
m_value.assign(buffer, r.ptr - buffer);
|
||||
}
|
||||
|
||||
@@ -155,11 +151,9 @@ class item
|
||||
char buffer[32];
|
||||
|
||||
auto r = std::to_chars(buffer, buffer + sizeof(buffer) - 1, value);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("Could not format number");
|
||||
|
||||
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
|
||||
*r.ptr = 0;
|
||||
m_value.assign(buffer, r.ptr - buffer);
|
||||
}
|
||||
|
||||
@@ -174,12 +168,21 @@ class item
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content value \a value
|
||||
item(const std::string_view name, const std::string_view value)
|
||||
item(const std::string_view name, std::string_view value)
|
||||
: m_name(name)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content value \a value
|
||||
template<typename T, std::enable_if_t<std::is_same_v<T, std::string>, int> = 0>
|
||||
item(const std::string_view name, T &&value)
|
||||
: m_name(name)
|
||||
, m_value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content the optional value \a value
|
||||
template <typename T>
|
||||
@@ -219,7 +222,8 @@ class item
|
||||
/** @endcond */
|
||||
|
||||
std::string_view name() const { return m_name; } ///< Return the name of the item
|
||||
std::string_view value() const { return m_value; } ///< Return the value of the item
|
||||
std::string_view value() const & { return m_value; } ///< Return the value of the item
|
||||
std::string value() const && { return std::move(m_value); } ///< Return the value of the item
|
||||
|
||||
/// \brief replace the content of the stored value with \a v
|
||||
void value(std::string_view v) { m_value = v; }
|
||||
@@ -234,10 +238,10 @@ class item
|
||||
bool is_unknown() const { return m_value == "?"; }
|
||||
|
||||
/// \brief the length of the value string
|
||||
size_t length() const { return m_value.length(); }
|
||||
std::size_t length() const { return m_value.length(); }
|
||||
|
||||
/// \brief support for structured binding
|
||||
template <size_t N>
|
||||
template <std::size_t N>
|
||||
decltype(auto) get() const
|
||||
{
|
||||
if constexpr (N == 0)
|
||||
@@ -246,6 +250,8 @@ class item
|
||||
return value();
|
||||
}
|
||||
|
||||
auto operator<=>(const item &rhs) const = default;
|
||||
|
||||
private:
|
||||
std::string_view m_name;
|
||||
std::string m_value;
|
||||
@@ -284,19 +290,16 @@ struct item_value
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
item_value(item_value &&rhs)
|
||||
item_value(item_value &&rhs) noexcept
|
||||
: m_length(std::exchange(rhs.m_length, 0))
|
||||
, m_storage(std::exchange(rhs.m_storage, 0))
|
||||
{
|
||||
}
|
||||
|
||||
item_value &operator=(item_value &&rhs)
|
||||
item_value &operator=(item_value &&rhs) noexcept
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
m_length = std::exchange(rhs.m_length, m_length);
|
||||
m_storage = std::exchange(rhs.m_storage, m_storage);
|
||||
}
|
||||
std::swap(m_length, rhs.m_length);
|
||||
std::swap(m_storage, rhs.m_storage);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -318,7 +321,7 @@ struct item_value
|
||||
return m_length != 0;
|
||||
}
|
||||
|
||||
size_t m_length = 0; ///< Length of the data
|
||||
std::size_t m_length = 0; ///< Length of the data
|
||||
union
|
||||
{
|
||||
char m_local_data[8]; ///< Storage area for small strings (strings smaller than kBufferSize)
|
||||
@@ -327,7 +330,7 @@ struct item_value
|
||||
};
|
||||
|
||||
/** The maximum length of locally stored strings */
|
||||
static constexpr size_t kBufferSize = sizeof(m_local_data);
|
||||
static constexpr std::size_t kBufferSize = sizeof(m_local_data);
|
||||
|
||||
// By using std::string_view instead of c_str we obain a
|
||||
// nice performance gain since we avoid many calls to strlen.
|
||||
@@ -363,8 +366,35 @@ struct item_handle
|
||||
template <typename T>
|
||||
item_handle &operator=(const T &value)
|
||||
{
|
||||
item v{ "", value };
|
||||
assign_value(v);
|
||||
assign_value(item{ "", value }.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign value @a value to the item referenced
|
||||
*
|
||||
* @tparam T Type of the value
|
||||
* @param value The value
|
||||
* @return reference to this item_handle
|
||||
*/
|
||||
template <typename T>
|
||||
item_handle &operator=(T &&value)
|
||||
{
|
||||
assign_value(item{ "", std::forward<T>(value) }.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign value @a value to the item referenced
|
||||
*
|
||||
* @tparam T Type of the value
|
||||
* @param value The value
|
||||
* @return reference to this item_handle
|
||||
*/
|
||||
template <std::size_t N>
|
||||
item_handle &operator=(const char (&value)[N])
|
||||
{
|
||||
assign_value(item{ "", std::move(value) }.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -508,7 +538,7 @@ struct item_handle
|
||||
uint16_t m_item_ix;
|
||||
row_handle &m_row_handle;
|
||||
|
||||
void assign_value(const item &value);
|
||||
void assign_value(std::string_view value);
|
||||
};
|
||||
|
||||
// So sad that older gcc implementations of from_chars did not support floats yet...
|
||||
@@ -532,7 +562,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
|
||||
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1])) ? selected_charconv<value_type>::from_chars(b + 1, e, result) : selected_charconv<value_type>::from_chars(b, e, result);
|
||||
|
||||
if (r.ec != std::errc() or r.ptr != e)
|
||||
if ((bool)r.ec or r.ptr != e)
|
||||
{
|
||||
result = {};
|
||||
if (cif::VERBOSE)
|
||||
@@ -567,7 +597,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
|
||||
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1])) ? selected_charconv<value_type>::from_chars(b + 1, e, v) : selected_charconv<value_type>::from_chars(b, e, v);
|
||||
|
||||
if (r.ec != std::errc() or r.ptr != e)
|
||||
if ((bool)r.ec or r.ptr != e)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
{
|
||||
@@ -580,6 +610,8 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
}
|
||||
result = 1;
|
||||
}
|
||||
else if (std::abs(v - value) <= std::numeric_limits<value_type>::epsilon())
|
||||
result = 0;
|
||||
else if (v < value)
|
||||
result = -1;
|
||||
else if (v > value)
|
||||
@@ -634,7 +666,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, bool>>>
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
template <std::size_t N>
|
||||
struct item_handle::item_value_as<char[N]>
|
||||
{
|
||||
static std::string convert(const item_handle &ref)
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace cif
|
||||
/**
|
||||
* @brief Implementation of an iterator that can return
|
||||
* multiple values in a tuple. Of course, that tuple can
|
||||
* then used in structured binding to receive the values
|
||||
* then be used in structured binding to receive the values
|
||||
* in a for loop e.g.
|
||||
*
|
||||
* @tparam Category The category for this iterator
|
||||
@@ -67,7 +67,7 @@ class iterator_impl
|
||||
/** @endcond */
|
||||
|
||||
/** variable that contains the number of elements in the tuple */
|
||||
static constexpr size_t N = sizeof...(Ts);
|
||||
static constexpr std::size_t N = sizeof...(Ts);
|
||||
|
||||
/** @cond */
|
||||
using category_type = std::remove_cv_t<Category>;
|
||||
@@ -84,11 +84,11 @@ class iterator_impl
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <typename C2, typename... T2s>
|
||||
iterator_impl(const iterator_impl<C2, T2s...> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
@@ -96,8 +96,7 @@ class iterator_impl
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(iterator_impl<IRowType, Ts...> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(const_cast<row_type *>(rhs.m_current))
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
@@ -106,19 +105,17 @@ class iterator_impl
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, N> &cix)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_item_ix(cix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
iterator_impl &operator=(const iterator_impl &i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
m_category = i.m_category;
|
||||
m_current = i.m_current;
|
||||
m_item_ix = i.m_item_ix;
|
||||
m_value = i.m_value;
|
||||
std::swap(m_current, i.m_current);
|
||||
std::swap(m_item_ix, i.m_item_ix);
|
||||
std::swap(m_value, i.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -136,18 +133,18 @@ class iterator_impl
|
||||
|
||||
operator const row_handle() const
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
m_current = m_current->m_next;
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
|
||||
@@ -179,20 +176,13 @@ class iterator_impl
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
template <size_t... Is>
|
||||
template <std::size_t... Is>
|
||||
tuple_type get(std::index_sequence<Is...>) const
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
{
|
||||
row_handle rh{ *m_category, *m_current };
|
||||
return tuple_type{ rh[m_item_ix[Is]].template as<Ts>()... };
|
||||
}
|
||||
|
||||
return {};
|
||||
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template as<Ts>()... } : tuple_type{};
|
||||
}
|
||||
|
||||
category_type *m_category = nullptr;
|
||||
row_type *m_current = nullptr;
|
||||
row_handle m_current;
|
||||
value_type m_value;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
@@ -219,37 +209,34 @@ class iterator_impl<Category>
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = row_handle;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = row_handle;
|
||||
using reference = row_handle;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <typename C2>
|
||||
iterator_impl(const iterator_impl<C2> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(const_cast<row_type *>(rhs.m_current))
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl(Category &cat, row *current)
|
||||
: m_category(const_cast<category_type *>(&cat))
|
||||
, m_current(current)
|
||||
: m_current(cat, *current)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 0> &)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl &operator=(const iterator_impl &i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
m_category = i.m_category;
|
||||
m_current = i.m_current;
|
||||
std::swap(m_current, i.m_current);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -257,7 +244,7 @@ class iterator_impl<Category>
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
@@ -267,18 +254,18 @@ class iterator_impl<Category>
|
||||
|
||||
operator const row_handle() const
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
m_current = m_current->m_next;
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -308,8 +295,7 @@ class iterator_impl<Category>
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
category_type *m_category = nullptr;
|
||||
row_type *m_current = nullptr;
|
||||
row_handle m_current;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -342,11 +328,11 @@ class iterator_impl<Category, T>
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <typename C2, typename T2>
|
||||
iterator_impl(const iterator_impl<C2, T2> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
@@ -354,29 +340,26 @@ class iterator_impl<Category, T>
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(iterator_impl<IRowType, T> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(const_cast<row_type *>(rhs.m_current))
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get(m_current);
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_item_ix(cix[0])
|
||||
{
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
iterator_impl &operator=(const iterator_impl &i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
m_category = i.m_category;
|
||||
m_current = i.m_current;
|
||||
m_item_ix = i.m_item_ix;
|
||||
m_value = i.m_value;
|
||||
std::swap(m_current, i.m_current);
|
||||
std::swap(m_item_ix, i.m_item_ix);
|
||||
std::swap(m_value, i.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -394,18 +377,18 @@ class iterator_impl<Category, T>
|
||||
|
||||
operator const row_handle() const
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
m_current = m_current->m_next;
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
m_value = get();
|
||||
|
||||
@@ -439,17 +422,10 @@ class iterator_impl<Category, T>
|
||||
private:
|
||||
value_type get() const
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
{
|
||||
row_handle rh{ *m_category, *m_current };
|
||||
return rh[m_item_ix].template as<T>();
|
||||
}
|
||||
|
||||
return {};
|
||||
return m_current ? m_current[m_item_ix].template as<value_type>() : value_type{};
|
||||
}
|
||||
|
||||
category_type *m_category = nullptr;
|
||||
row_type *m_current = nullptr;
|
||||
row_handle m_current;
|
||||
value_type m_value;
|
||||
uint16_t m_item_ix;
|
||||
};
|
||||
@@ -474,7 +450,7 @@ class iterator_proxy
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const size_t N = sizeof...(Ts);
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = Category;
|
||||
using row_type = std::conditional_t<std::is_const_v<category_type>, const row, row>;
|
||||
@@ -497,7 +473,7 @@ class iterator_proxy
|
||||
|
||||
bool empty() const { return m_begin == m_end; } ///< Return true if the range is empty
|
||||
explicit operator bool() const { return not empty(); } ///< Easy way to detect if the range is empty
|
||||
size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
// row front() { return *begin(); }
|
||||
// row back() { return *(std::prev(end())); }
|
||||
@@ -536,7 +512,7 @@ class conditional_iterator_proxy
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const size_t N = sizeof...(Ts);
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = std::remove_cv_t<CategoryType>;
|
||||
|
||||
@@ -630,7 +606,7 @@ class conditional_iterator_proxy
|
||||
|
||||
bool empty() const; ///< Return true if the range is empty
|
||||
explicit operator bool() const { return not empty(); } ///< Easy way to detect if the range is empty
|
||||
size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
row_handle front() { return *begin(); } ///< Return reference to the first row
|
||||
// row_handle back() { return *begin(); }
|
||||
|
||||
@@ -59,27 +59,27 @@ template <typename M>
|
||||
class matrix_expression
|
||||
{
|
||||
public:
|
||||
constexpr size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
constexpr size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
constexpr std::size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
constexpr std::size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
|
||||
constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; } ///< Convenient way to test for empty matrices
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr auto &operator()(size_t i, size_t j)
|
||||
constexpr auto &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
return static_cast<M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<const M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Swap the contents of rows @a r1 and @a r2 */
|
||||
void swap_row(size_t r1, size_t r2)
|
||||
void swap_row(std::size_t r1, std::size_t r2)
|
||||
{
|
||||
for (size_t c = 0; c < dim_m(); ++c)
|
||||
for (std::size_t c = 0; c < dim_m(); ++c)
|
||||
{
|
||||
auto v = operator()(r1, c);
|
||||
operator()(r1, c) = operator()(r2, c);
|
||||
@@ -88,9 +88,9 @@ class matrix_expression
|
||||
}
|
||||
|
||||
/** Swap the contents of columns @a c1 and @a c2 */
|
||||
void swap_col(size_t c1, size_t c2)
|
||||
void swap_col(std::size_t c1, std::size_t c2)
|
||||
{
|
||||
for (size_t r = 0; r < dim_n(); ++r)
|
||||
for (std::size_t r = 0; r < dim_n(); ++r)
|
||||
{
|
||||
auto &a = operator()(r, c1);
|
||||
auto &b = operator()(r, c2);
|
||||
@@ -103,11 +103,11 @@ class matrix_expression
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (size_t i = 0; i < m.dim_m(); ++i)
|
||||
for (std::size_t i = 0; i < m.dim_m(); ++i)
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (size_t j = 0; j < m.dim_n(); ++j)
|
||||
for (std::size_t j = 0; j < m.dim_n(); ++j)
|
||||
{
|
||||
os << m(i, j);
|
||||
if (j + 1 < m.dim_n())
|
||||
@@ -156,9 +156,9 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
, m_n(m.dim_n())
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
for (size_t i = 0; i < m_m; ++i)
|
||||
for (std::size_t i = 0; i < m_m; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < m_n; ++j)
|
||||
for (std::size_t j = 0; j < m_n; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
* @param n Requested dimension N
|
||||
* @param v Value to store in each element
|
||||
*/
|
||||
matrix(size_t m, size_t n, value_type v = 0)
|
||||
matrix(std::size_t m, std::size_t n, value_type v = 0)
|
||||
: m_m(m)
|
||||
, m_n(n)
|
||||
, m_data(m_m * m_n)
|
||||
@@ -187,11 +187,11 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
matrix &operator=(const matrix &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
constexpr size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
@@ -199,7 +199,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
@@ -207,7 +207,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_m = 0, m_n = 0;
|
||||
std::size_t m_m = 0, m_n = 0;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
@@ -224,7 +224,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
|
||||
template <typename F, size_t M, size_t N>
|
||||
template <typename F, std::size_t M, std::size_t N>
|
||||
class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
{
|
||||
public:
|
||||
@@ -232,16 +232,16 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
using value_type = F;
|
||||
|
||||
/** The storage size */
|
||||
static constexpr size_t kSize = M * N;
|
||||
static constexpr std::size_t kSize = M * N;
|
||||
|
||||
/** Copy constructor */
|
||||
template <typename M2>
|
||||
matrix_fixed(const M2 &m)
|
||||
{
|
||||
assert(M == m.dim_m() and N == m.dim_n());
|
||||
for (size_t i = 0; i < M; ++i)
|
||||
for (std::size_t i = 0; i < M; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < N; ++j)
|
||||
for (std::size_t j = 0; j < N; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
@@ -266,18 +266,18 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
/** @endcond */
|
||||
|
||||
/** Store the values in @a a in the matrix */
|
||||
template<size_t... Ixs>
|
||||
template<std::size_t... Ixs>
|
||||
matrix_fixed& fill(const F (&a)[kSize], std::index_sequence<Ixs...>)
|
||||
{
|
||||
m_data = { a[Ixs]... };
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return N; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return N; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
@@ -285,7 +285,7 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
@@ -322,7 +322,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
using value_type = F;
|
||||
|
||||
/** constructor for a matrix of size @a n x @a n elements with value @a v */
|
||||
symmetric_matrix(size_t n, value_type v = 0)
|
||||
symmetric_matrix(std::size_t n, value_type v = 0)
|
||||
: m_n(n)
|
||||
, m_data((m_n * (m_n + 1)) / 2)
|
||||
{
|
||||
@@ -337,11 +337,11 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
symmetric_matrix &operator=(const symmetric_matrix &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
constexpr size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
@@ -349,7 +349,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
@@ -358,7 +358,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_n;
|
||||
std::size_t m_n;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
@@ -373,7 +373,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
template <typename F, size_t M>
|
||||
template <typename F, std::size_t M>
|
||||
class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F, M>>
|
||||
{
|
||||
public:
|
||||
@@ -393,11 +393,11 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
|
||||
symmetric_matrix_fixed &operator=(const symmetric_matrix_fixed &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
constexpr size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return M; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return M; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
@@ -405,7 +405,7 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
@@ -444,22 +444,22 @@ class identity_matrix : public matrix_expression<identity_matrix<F>>
|
||||
using value_type = F;
|
||||
|
||||
/** constructor taking a dimension @a n */
|
||||
identity_matrix(size_t n)
|
||||
identity_matrix(std::size_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<value_type>(i == j ? 1 : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_n;
|
||||
std::size_t m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -484,11 +484,11 @@ class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
@@ -523,17 +523,17 @@ class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_mult
|
||||
assert(m1.dim_m() == m2.dim_n());
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
using value_type = decltype(m_m1(0, 0));
|
||||
|
||||
value_type result = {};
|
||||
|
||||
for (size_t k = 0; k < m_m1.dim_m(); ++k)
|
||||
for (std::size_t k = 0; k < m_m1.dim_m(); ++k)
|
||||
result += m_m1(i, k) * m_m2(k, j);
|
||||
|
||||
return result;
|
||||
@@ -564,11 +564,11 @@ class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_mult
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
@@ -655,21 +655,21 @@ class matrix_cofactors : public matrix_expression<matrix_cofactors<M>>
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
const size_t ixs[4][3] = {
|
||||
const std::size_t ixs[4][3] = {
|
||||
{ 1, 2, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 1, 2 }
|
||||
};
|
||||
|
||||
const size_t *ix = ixs[i];
|
||||
const size_t *iy = ixs[j];
|
||||
const std::size_t *ix = ixs[i];
|
||||
const std::size_t *iy = ixs[j];
|
||||
|
||||
auto result =
|
||||
m_m(ix[0], iy[0]) * m_m(ix[1], iy[1]) * m_m(ix[2], iy[2]) +
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <numeric>
|
||||
|
||||
#if __cpp_lib_format
|
||||
#include <format>
|
||||
# include <format>
|
||||
#endif
|
||||
|
||||
/** @file model.hpp
|
||||
@@ -106,8 +106,6 @@ class atom
|
||||
|
||||
atom_impl(const atom_impl &i) = default;
|
||||
|
||||
void prefetch();
|
||||
|
||||
int compare(const atom_impl &b) const;
|
||||
|
||||
// bool getAnisoU(float anisou[6]) const;
|
||||
@@ -345,12 +343,17 @@ class atom
|
||||
std::string get_auth_asym_id() const { return get_property("auth_asym_id"); } ///< Return the auth_asym_id property
|
||||
std::string get_auth_seq_id() const { return get_property("auth_seq_id"); } ///< Return the auth_seq_id property
|
||||
std::string get_auth_atom_id() const { return get_property("auth_atom_id"); } ///< Return the auth_atom_id property
|
||||
std::string get_auth_alt_id() const { return get_property("auth_alt_id"); } ///< Return the auth_alt_id property
|
||||
std::string get_auth_alt_id() const { return get_property("pdbx_auth_alt_id"); } ///< Return the auth_alt_id property
|
||||
std::string get_auth_comp_id() const { return get_property("auth_comp_id"); } ///< Return the auth_comp_id property
|
||||
std::string get_pdb_ins_code() const { return get_property("pdbx_PDB_ins_code"); } ///< Return the pdb_ins_code property
|
||||
|
||||
/// Return true if this atom is an alternate
|
||||
bool is_alternate() const { return not get_label_alt_id().empty(); }
|
||||
bool is_alternate() const
|
||||
{
|
||||
if (auto alt_id = get_label_alt_id(); alt_id.empty() or alt_id == ".")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Convenience method to return a string that might be ID in PDB space
|
||||
std::string pdb_id() const
|
||||
@@ -476,8 +479,8 @@ class residue
|
||||
, m_compound_id(compoundID)
|
||||
, m_asym_id(asymID)
|
||||
, m_seq_id(seqID)
|
||||
, m_auth_asym_id(authAsymID)
|
||||
, m_auth_seq_id(authSeqID)
|
||||
, m_pdb_strand_id(authAsymID)
|
||||
, m_pdb_seq_num(authSeqID)
|
||||
, m_pdb_ins_code(pdbInsCode)
|
||||
{
|
||||
}
|
||||
@@ -504,9 +507,9 @@ class residue
|
||||
const std::string &get_asym_id() const { return m_asym_id; } ///< Return the asym_id
|
||||
int get_seq_id() const { return m_seq_id; } ///< Return the seq_id
|
||||
|
||||
const std::string get_auth_asym_id() const { return m_auth_asym_id; } ///< Return the auth_asym_id
|
||||
const std::string get_auth_seq_id() const { return m_auth_seq_id; } ///< Return the auth_seq_id
|
||||
std::string get_pdb_ins_code() const { return m_pdb_ins_code; } ///< Return the pdb_ins_code
|
||||
const std::string get_pdb_strand_id() const { return m_pdb_strand_id; } ///< Return the pdb_strand_id
|
||||
const std::string get_pdb_seq_num() const { return m_pdb_seq_num; } ///< Return the pdb_seq_num
|
||||
std::string get_pdb_ins_code() const { return m_pdb_ins_code; } ///< Return the pdb_ins_code
|
||||
|
||||
const std::string &get_compound_id() const { return m_compound_id; } ///< Return the compound_id
|
||||
void set_compound_id(const std::string &id) { m_compound_id = id; } ///< Set the compound_id to @a id
|
||||
@@ -535,6 +538,9 @@ class residue
|
||||
/// \brief Return the atom with atom_id @a atomID
|
||||
atom get_atom_by_atom_id(const std::string &atomID) const;
|
||||
|
||||
/// \brief Return the atom with atom_id @a atomID and alternate_id @a altID
|
||||
atom get_atom_by_atom_id(const std::string &atomID, const std::string &altID) const;
|
||||
|
||||
/// \brief Return the list of atoms having ID \a atomID
|
||||
///
|
||||
/// This includes all alternate atoms with this ID
|
||||
@@ -550,6 +556,9 @@ class residue
|
||||
/// \brief Return true if this residue has alternate atoms
|
||||
bool has_alternate_atoms() const;
|
||||
|
||||
/// \brief Return true if this residue has alternate atoms for the atom \a atomID
|
||||
bool has_alternate_atoms_for(const std::string &atomID) const;
|
||||
|
||||
/// \brief Return the list of unique alt ID's present in this residue
|
||||
std::set<std::string> get_alternate_ids() const;
|
||||
|
||||
@@ -569,9 +578,13 @@ class residue
|
||||
m_seq_id == rhs.m_seq_id and
|
||||
m_asym_id == rhs.m_asym_id and
|
||||
m_compound_id == rhs.m_compound_id and
|
||||
m_auth_seq_id == rhs.m_auth_seq_id);
|
||||
m_pdb_seq_num == rhs.m_pdb_seq_num);
|
||||
}
|
||||
|
||||
/// @brief Create a new atom and add it to the list
|
||||
/// @return newly created atom
|
||||
virtual atom create_new_atom(atom_type inType, const std::string &inAtomID, point inLocation);
|
||||
|
||||
protected:
|
||||
/** @cond */
|
||||
residue() {}
|
||||
@@ -579,7 +592,7 @@ class residue
|
||||
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;
|
||||
std::string m_pdb_strand_id, m_pdb_seq_num, m_pdb_ins_code;
|
||||
std::vector<atom> m_atoms;
|
||||
/** @endcond */
|
||||
};
|
||||
@@ -604,12 +617,15 @@ class monomer : public residue
|
||||
monomer &operator=(monomer &&rhs);
|
||||
|
||||
/// \brief constructor with actual values
|
||||
monomer(const polymer &polymer, size_t index, int seqID, const std::string &authSeqID,
|
||||
monomer(const polymer &polymer, std::size_t index, int seqID, const std::string &authSeqID,
|
||||
const std::string &pdbInsCode, const std::string &compoundID);
|
||||
|
||||
bool is_first_in_chain() const; ///< Return if this residue is the first residue in the chain
|
||||
bool is_last_in_chain() const; ///< Return if this residue is the last residue in the chain
|
||||
|
||||
const monomer &prev() const; // Return previous monomer in polymer
|
||||
const monomer &next() const; // Return next monomer in polymer
|
||||
|
||||
// convenience
|
||||
bool has_alpha() const; ///< Return if a alpha value can be calculated (depends on location in chain)
|
||||
bool has_kappa() const; ///< Return if a kappa value can be calculated (depends on location in chain)
|
||||
@@ -624,8 +640,8 @@ class monomer : public residue
|
||||
float omega() const; ///< Return the omega value for this residue
|
||||
|
||||
// torsion angles
|
||||
size_t nr_of_chis() const; ///< Return how many torsion angles can be calculated
|
||||
float chi(size_t i) const; ///< Return torsion angle @a i
|
||||
std::size_t nr_of_chis() const; ///< Return how many torsion angles can be calculated
|
||||
float chi(std::size_t i) const; ///< Return torsion angle @a i
|
||||
|
||||
bool is_cis() const; ///< Return true if this residue is in a cis conformation
|
||||
|
||||
@@ -672,9 +688,11 @@ class monomer : public residue
|
||||
return m_polymer == rhs.m_polymer and m_index == rhs.m_index;
|
||||
}
|
||||
|
||||
atom create_new_atom(atom_type inType, const std::string &inAtomID, point inLocation) override;
|
||||
|
||||
private:
|
||||
const polymer *m_polymer;
|
||||
size_t m_index;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -694,15 +712,15 @@ class polymer : public std::vector<monomer>
|
||||
|
||||
structure *get_structure() const { return m_structure; } ///< Return the structure
|
||||
|
||||
std::string get_asym_id() const { return m_asym_id; } ///< Return the asym_id
|
||||
std::string get_auth_asym_id() const { return m_auth_asym_id; } ///< Return the PDB chain ID, actually
|
||||
std::string get_entity_id() const { return m_entity_id; } ///< Return the entity_id
|
||||
std::string get_asym_id() const { return m_asym_id; } ///< Return the asym_id
|
||||
std::string get_pdb_strand_id() const { return m_pdb_strand_id; } ///< Return the PDB chain ID, actually
|
||||
std::string get_entity_id() const { return m_entity_id; } ///< Return the entity_id
|
||||
|
||||
private:
|
||||
structure *m_structure;
|
||||
std::string m_entity_id;
|
||||
std::string m_asym_id;
|
||||
std::string m_auth_asym_id;
|
||||
std::string m_pdb_strand_id;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -740,8 +758,8 @@ class sugar : public residue
|
||||
int num() const
|
||||
{
|
||||
int result;
|
||||
auto r = std::from_chars(m_auth_seq_id.data(), m_auth_seq_id.data() + m_auth_seq_id.length(), result);
|
||||
if (r.ec != std::errc())
|
||||
auto r = std::from_chars(m_pdb_seq_num.data(), m_pdb_seq_num.data() + m_pdb_seq_num.length(), result);
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("The auth_seq_id should be a number for a sugar");
|
||||
return result;
|
||||
}
|
||||
@@ -756,9 +774,9 @@ class sugar : public residue
|
||||
void set_link(atom link) { m_link = link; }
|
||||
|
||||
/// \brief Return the sugar number of the sugar linked to C1
|
||||
size_t get_link_nr() const
|
||||
std::size_t get_link_nr() const
|
||||
{
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
if (m_link)
|
||||
result = m_link.get_property_int("auth_seq_id");
|
||||
return result;
|
||||
@@ -839,19 +857,38 @@ class branch : public std::vector<sugar>
|
||||
std::string m_asym_id, m_entity_id;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief A still very limited set of options for reading structures
|
||||
enum class StructureOpenOptions
|
||||
/** @brief Enumeration for controlling atom selection based on occupancy. */
|
||||
enum class occupancy_policy
|
||||
{
|
||||
SkipHydrogen = 1 << 0 ///< Do not include hydrogen atoms in the structure object
|
||||
/** @brief Include all atoms regardless of their occupancy factor. */
|
||||
ALL = 0,
|
||||
|
||||
/** @brief Select only alternate atoms with the maximum occupancy factor.
|
||||
* If multiple atoms have the same maximum occupancy, choose the one with the minimum B-factor.
|
||||
* If multiple atoms share both the maximum occupancy and the minimum B-factor, select the first encountered atom.
|
||||
*/
|
||||
MAX = 1,
|
||||
|
||||
/** @brief Select only alternate atoms with the minimum occupancy factor.
|
||||
* Similar to MAX, if multiple atoms have the same minimum occupancy, choose the one with the minimum B-factor.
|
||||
* If multiple atoms share both the minimum occupancy and the minimum B-factor, select the first encountered atom.
|
||||
*/
|
||||
MIN = 2,
|
||||
|
||||
/** @brief Exclude all atoms with an occupancy factor greater than zero. */
|
||||
UNOCCUPIED = 3
|
||||
};
|
||||
|
||||
/// \brief A way to combine two options. Not very useful as there is only one...
|
||||
constexpr inline bool operator&(StructureOpenOptions a, StructureOpenOptions b)
|
||||
struct structure_open_options
|
||||
{
|
||||
return static_cast<int>(a) bitand static_cast<int>(b);
|
||||
}
|
||||
bool skip_hydrogen = false; ///< Do not include hydrogen atoms in the structure object
|
||||
bool skip_hetatom = false; ///< Do not include HET atoms in the structure object
|
||||
bool skip_water = false; ///< Do not include water atoms in the structure object
|
||||
occupancy_policy occupancy_mode = occupancy_policy::ALL; ///< By default, the occupancy policy is set to occupancy_policy::ALL
|
||||
std::vector<std::string> asyms; ///< The asyms to load, if empty load all
|
||||
std::optional<float> min_b_factor; ///< Only load atoms with at least this b_factor
|
||||
std::optional<float> max_b_factor; ///< Only load atoms with at most this b_factor
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -865,10 +902,10 @@ class structure
|
||||
{
|
||||
public:
|
||||
/// \brief Read the structure from cif::file @a p
|
||||
structure(file &p, size_t modelNr = 1, StructureOpenOptions options = {});
|
||||
structure(file &p, std::size_t modelNr = 1, structure_open_options options = {});
|
||||
|
||||
/// \brief Load the structure from already parsed mmCIF data in @a db
|
||||
structure(datablock &db, size_t modelNr = 1, StructureOpenOptions options = {});
|
||||
structure(datablock &db, std::size_t modelNr = 1, structure_open_options options = {});
|
||||
|
||||
/** @cond */
|
||||
structure(structure &&s) = default;
|
||||
@@ -881,7 +918,7 @@ class structure
|
||||
~structure() = default;
|
||||
|
||||
/// \brief Return the model number
|
||||
size_t get_model_nr() const { return m_model_nr; }
|
||||
std::size_t get_model_nr() const { return m_model_nr; }
|
||||
|
||||
/// \brief Return a list of all the atoms in this structure
|
||||
const std::vector<atom> &atoms() const { return m_atoms; }
|
||||
@@ -978,18 +1015,18 @@ class structure
|
||||
/**
|
||||
* @brief Change residue @a res to a new compound ID optionally
|
||||
* remapping atoms.
|
||||
*
|
||||
*
|
||||
* A new chem_comp entry as well as an entity is created if needed and
|
||||
* if the list of @a remappedAtoms is not empty it is used to remap.
|
||||
*
|
||||
*
|
||||
* The array in @a remappedAtoms contains tuples of strings, both
|
||||
* strings contain an atom_id. The first is the one in the current
|
||||
* residue and the second is the atom_id that should be used instead.
|
||||
* If the second string is empty, the atom is removed from the residue.
|
||||
*
|
||||
* @param res
|
||||
* @param newcompound
|
||||
* @param remappedAtoms
|
||||
*
|
||||
* @param res
|
||||
* @param newcompound
|
||||
* @param remappedAtoms
|
||||
*/
|
||||
void change_residue(residue &res, const std::string &newcompound,
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms);
|
||||
@@ -1091,11 +1128,14 @@ class structure
|
||||
/// \brief emplace the moved atom @a atom
|
||||
atom &emplace_atom(atom &&atom);
|
||||
|
||||
/// \brief Reorder atom_site atoms based on 'natural' ordering
|
||||
void reorder_atoms();
|
||||
|
||||
private:
|
||||
friend polymer;
|
||||
friend residue;
|
||||
|
||||
void load_atoms_for_model(StructureOpenOptions options);
|
||||
void load_atoms_for_model(structure_open_options options);
|
||||
|
||||
std::string insert_compound(const std::string &compoundID, bool is_entity);
|
||||
|
||||
@@ -1107,9 +1147,9 @@ class structure
|
||||
void remove_sugar(sugar &sugar);
|
||||
|
||||
datablock &m_db;
|
||||
size_t m_model_nr;
|
||||
std::size_t m_model_nr;
|
||||
std::vector<atom> m_atoms;
|
||||
std::vector<size_t> m_atom_index;
|
||||
std::vector<std::size_t> m_atom_index;
|
||||
std::list<polymer> m_polymers;
|
||||
std::list<branch> m_branches;
|
||||
std::vector<residue> m_non_polymers;
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Exception that is thrown when the mmCIF file contains a parsing error */
|
||||
@@ -73,7 +75,15 @@ class sac_parser
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
using datablock_index = std::map<std::string, std::size_t>;
|
||||
struct iless_op
|
||||
{
|
||||
bool operator()(std::string_view a, std::string_view b) const
|
||||
{
|
||||
return icompare(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
using datablock_index = std::map<std::string, std::size_t, iless_op>;
|
||||
|
||||
virtual ~sac_parser() = default;
|
||||
/** @endcond */
|
||||
@@ -299,6 +309,14 @@ class sac_parser
|
||||
class parser : public sac_parser
|
||||
{
|
||||
public:
|
||||
/// \brief constructor, generates data into @a file from @a is using validator @a v
|
||||
parser(std::istream &is, file &file, const validator *v)
|
||||
: sac_parser(is)
|
||||
, m_file(file)
|
||||
, m_validator(v)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor, generates data into @a file from @a is
|
||||
parser(std::istream &is, file &file)
|
||||
: sac_parser(is)
|
||||
@@ -319,6 +337,7 @@ class parser : public sac_parser
|
||||
file &m_file;
|
||||
datablock *m_datablock = nullptr;
|
||||
category *m_category = nullptr;
|
||||
const validator *m_validator = nullptr;
|
||||
row_handle m_row;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
@@ -103,16 +104,50 @@ inline void write(const std::filesystem::path &p, const file &f)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Quickly fix a PDB file that lacks some often needed categories
|
||||
*
|
||||
* This differs from reconstruct_pdbx which does a much more thorough job
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
*/
|
||||
|
||||
void fixup_pdbx(file &pdbx_file);
|
||||
|
||||
/**
|
||||
* @brief Quickly fix a PDB file that lacks some often needed categories
|
||||
*
|
||||
* This differs from reconstruct_pdbx which does a much more thorough job
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param v The validator to use
|
||||
*/
|
||||
|
||||
void fixup_pdbx(file &pdbx_file, const validator &v);
|
||||
|
||||
/** \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
*
|
||||
* Some people believe that simply dumping some atom records is enough.
|
||||
*
|
||||
* This version uses the audit_conform information and falls back to
|
||||
* using mmcif_pdbx.dic if not specified.
|
||||
*
|
||||
* \param file The cif::file that hopefully contains some valid data
|
||||
* \param dictionary The mmcif dictionary to use
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \result Returns true if the resulting file is valid
|
||||
*/
|
||||
|
||||
bool reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx");
|
||||
bool reconstruct_pdbx(file &pdbx_file);
|
||||
|
||||
/** \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
*
|
||||
* Some people believe that simply dumping some atom records is enough.
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param v The validator to use
|
||||
* \result Returns true if the resulting file is valid
|
||||
*/
|
||||
|
||||
bool reconstruct_pdbx(file &pdbx_file, const validator &v);
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
@@ -125,12 +160,13 @@ bool reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx
|
||||
*
|
||||
* This function throws a std::system_error in case of an error
|
||||
*
|
||||
* \param file The input file
|
||||
* \param dictionary The mmcif dictionary to use
|
||||
* \param pdbx_file The input file
|
||||
* \param v The validator to use
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, std::string_view dictionary = "mmcif_pdbx");
|
||||
bool is_valid_pdbx_file(const file &pdbx_file,
|
||||
const validator &v = validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
@@ -145,7 +181,6 @@ bool is_valid_pdbx_file(const file &pdbx_file, std::string_view dictionary = "mm
|
||||
* default mmcif_pdbx.dic dictionary.
|
||||
*
|
||||
* \param file The input file
|
||||
* \param ec The error_code in case something was wrong
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
@@ -161,12 +196,12 @@ bool is_valid_pdbx_file(const file &pdbx_file, std::error_code &ec);
|
||||
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
|
||||
*
|
||||
* \param file The input file
|
||||
* \param dictionary The dictionary to use
|
||||
* \param v The validator to use
|
||||
* \param ec The error_code in case something was wrong
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, std::string_view dictionary,
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, const validator &v,
|
||||
std::error_code &ec);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -662,12 +662,23 @@ struct point_type
|
||||
return std::make_tuple(std::ref(m_x), std::ref(m_y), std::ref(m_z));
|
||||
}
|
||||
|
||||
/// \brief Compare with @a rhs
|
||||
#if defined(__cpp_impl_three_way_comparison)
|
||||
/// \brief a default spaceship operator
|
||||
constexpr auto operator<=>(const point_type &rhs) const = default;
|
||||
#else
|
||||
/// \brief a default equals operator
|
||||
constexpr bool operator==(const point_type &rhs) const
|
||||
{
|
||||
return m_x == rhs.m_x and m_y == rhs.m_y and m_z == rhs.m_z;
|
||||
}
|
||||
|
||||
/// \brief a default not-equals operator
|
||||
constexpr bool operator!=(const point_type &rhs) const
|
||||
{
|
||||
return not operator==(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
// consider point as a vector... perhaps I should rename point?
|
||||
|
||||
/// \brief looking at the point as if it is a vector, return the squared length
|
||||
@@ -867,7 +878,7 @@ class spherical_dots
|
||||
}
|
||||
|
||||
/// \brief The number of points
|
||||
size_t size() const { return P; }
|
||||
std::size_t size() const { return P; }
|
||||
|
||||
/// \brief Access a point by index
|
||||
const point operator[](uint32_t inIx) const { return m_points[inIx]; }
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace detail
|
||||
template <typename... C>
|
||||
struct get_row_result
|
||||
{
|
||||
static constexpr size_t N = sizeof...(C);
|
||||
static constexpr std::size_t N = sizeof...(C);
|
||||
|
||||
get_row_result(const row_handle &r, std::array<uint16_t, N> &&items)
|
||||
: m_row(r)
|
||||
@@ -104,7 +104,7 @@ namespace detail
|
||||
return get<Ts...>(std::index_sequence_for<Ts...>{});
|
||||
}
|
||||
|
||||
template <typename... Ts, size_t... Is>
|
||||
template <typename... Ts, std::size_t... Is>
|
||||
std::tuple<Ts...> get(std::index_sequence<Is...>) const
|
||||
{
|
||||
return std::tuple<Ts...>{ m_row[m_items[Is]].template as<Ts>()... };
|
||||
@@ -208,6 +208,7 @@ class row_handle
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
template <typename, typename...> friend class iterator_impl;
|
||||
|
||||
row_handle() = default;
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ namespace literals
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
inline sym_op operator""_symop(const char *text, size_t length)
|
||||
inline sym_op operator""_symop(const char *text, std::size_t length)
|
||||
{
|
||||
return sym_op({ text, length });
|
||||
}
|
||||
@@ -464,7 +464,7 @@ class spacegroup : public std::vector<transformation>
|
||||
|
||||
private:
|
||||
int m_nr;
|
||||
size_t m_index;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -352,7 +352,7 @@ std::string cif_id_for_number(int number);
|
||||
* a dynamic programming approach to get the most efficient filling of
|
||||
* the space.
|
||||
*/
|
||||
std::vector<std::string> word_wrap(const std::string &text, size_t width);
|
||||
std::vector<std::string> word_wrap(const std::string &text, std::size_t width);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief std::from_chars for floating point types.
|
||||
@@ -378,12 +378,12 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
|
||||
} state = IntegerSign;
|
||||
int sign = 1;
|
||||
unsigned long long vi = 0;
|
||||
long double f = 1;
|
||||
int fl = 0, tz = 0;
|
||||
int exponent_sign = 1;
|
||||
int exponent = 0;
|
||||
bool done = false;
|
||||
|
||||
while (not done and result.ec == std::errc())
|
||||
while (not done and not (bool)result.ec)
|
||||
{
|
||||
char ch = result.ptr != last ? *result.ptr : 0;
|
||||
++result.ptr;
|
||||
@@ -427,7 +427,14 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
|
||||
if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
vi = 10 * vi + (ch - '0');
|
||||
f /= 10;
|
||||
|
||||
if (ch == '0')
|
||||
tz += 1;
|
||||
else
|
||||
{
|
||||
fl += tz + 1;
|
||||
tz = 0;
|
||||
}
|
||||
}
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = ExponentSign;
|
||||
@@ -467,9 +474,12 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
|
||||
}
|
||||
}
|
||||
|
||||
if (result.ec == std::errc())
|
||||
if (not (bool)result.ec)
|
||||
{
|
||||
long double v = f * vi * sign;
|
||||
while (tz-- > 0)
|
||||
vi /= 10;
|
||||
|
||||
long double v = std::pow(10, -fl) * vi * sign;
|
||||
if (exponent != 0)
|
||||
v *= std::pow(10, exponent * exponent_sign);
|
||||
|
||||
|
||||
@@ -113,16 +113,12 @@ namespace colour
|
||||
/**
|
||||
* @brief Struct for delimited strings.
|
||||
*/
|
||||
template <typename StringType>
|
||||
struct coloured_string_t
|
||||
{
|
||||
static_assert(std::is_reference_v<StringType> or std::is_pointer_v<StringType>,
|
||||
"String type must be pointer or reference");
|
||||
|
||||
/**
|
||||
* @brief Construct a new coloured string t object
|
||||
*/
|
||||
coloured_string_t(StringType s, colour_type fc, colour_type bc, style_type st)
|
||||
coloured_string_t(std::string_view s, colour_type fc, colour_type bc, style_type st)
|
||||
: m_str(s)
|
||||
, m_fore_colour(static_cast<int>(fc) + 30)
|
||||
, m_back_colour(static_cast<int>(bc) + 40)
|
||||
@@ -152,12 +148,14 @@ namespace colour
|
||||
<< cs.m_str
|
||||
<< "\033[0m";
|
||||
}
|
||||
else
|
||||
os << cs.m_str;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/// @cond
|
||||
StringType m_str;
|
||||
std::string_view m_str;
|
||||
int m_fore_colour, m_back_colour;
|
||||
int m_style;
|
||||
/// @endcond
|
||||
@@ -191,39 +189,13 @@ namespace colour
|
||||
* @param st Text style to use
|
||||
*/
|
||||
|
||||
template <typename char_type>
|
||||
inline auto coloured(const char_type *str,
|
||||
template <typename T>
|
||||
requires std::is_assignable_v<std::string_view, T>
|
||||
inline auto coloured(T str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<const char_type *>(str, fg, bg, st);
|
||||
}
|
||||
|
||||
/// @brief Manipulator for coloured strings.
|
||||
template <typename char_type, typename traits_type, typename allocator_type>
|
||||
inline auto coloured(const std::basic_string<char_type, traits_type, allocator_type> &str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<const std::basic_string<char_type, traits_type, allocator_type> &>(str, fg, bg, st);
|
||||
}
|
||||
|
||||
/// @brief Manipulator for coloured strings.
|
||||
template <typename char_type, typename traits_type, typename allocator_type>
|
||||
inline auto coloured(std::basic_string<char_type, traits_type, allocator_type> &str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<std::basic_string<char_type, traits_type, allocator_type> &>(str, fg, bg, st);
|
||||
}
|
||||
|
||||
/// @brief Manipulator for coloured strings.
|
||||
template <typename char_type, typename traits_type>
|
||||
inline auto coloured(std::basic_string_view<char_type, traits_type> &str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<std::basic_string_view<char_type, traits_type> &>(str, fg, bg, st);
|
||||
return colour::detail::coloured_string_t(str, fg, bg, st);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -26,12 +26,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
@@ -48,6 +50,7 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
struct category_validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -120,7 +123,7 @@ class validation_category_impl : public std::error_category
|
||||
case validation_error::missing_key_items:
|
||||
return "An index could not be constructed due to missing key items";
|
||||
case validation_error::item_not_allowed_in_category:
|
||||
return "Requested item allowed in category according to dictionary";
|
||||
return "Requested item not allowed in category according to dictionary";
|
||||
case validation_error::empty_file:
|
||||
return "The file contains no datablocks";
|
||||
case validation_error::empty_datablock:
|
||||
@@ -227,38 +230,39 @@ struct type_validator
|
||||
{
|
||||
std::string m_name; ///< The name of the type
|
||||
DDL_PrimitiveType m_primitive_type; ///< The primitive_type of the type
|
||||
regex_impl *m_rx; ///< The regular expression for the type
|
||||
std::shared_ptr<regex_impl> m_rx; ///< The regular expression for the type
|
||||
|
||||
type_validator() = delete;
|
||||
|
||||
/// @brief Constructor
|
||||
type_validator(std::string_view name, DDL_PrimitiveType type, std::string_view rx);
|
||||
|
||||
type_validator(const type_validator &) = delete;
|
||||
|
||||
/// @brief Copy constructor
|
||||
type_validator(type_validator &&rhs)
|
||||
: m_name(std::move(rhs.m_name))
|
||||
, m_primitive_type(rhs.m_primitive_type)
|
||||
{
|
||||
m_rx = std::exchange(rhs.m_rx, nullptr);
|
||||
}
|
||||
|
||||
type_validator &operator=(const type_validator &) = delete;
|
||||
type_validator(const type_validator &tv);
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator &operator=(type_validator &&rhs)
|
||||
type_validator(type_validator &&rhs)
|
||||
{
|
||||
m_name = std::move(rhs.m_name);
|
||||
m_primitive_type = rhs.m_primitive_type;
|
||||
m_rx = std::exchange(rhs.m_rx, nullptr);
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator &operator=(type_validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
~type_validator();
|
||||
|
||||
friend void swap(type_validator &a, type_validator &b)
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_primitive_type, b.m_primitive_type);
|
||||
std::swap(a.m_rx, b.m_rx);
|
||||
}
|
||||
|
||||
/// @brief Return the sorting order
|
||||
bool operator<(const type_validator &rhs) const
|
||||
{
|
||||
@@ -303,13 +307,13 @@ struct item_alias
|
||||
*/
|
||||
struct item_validator
|
||||
{
|
||||
std::string m_item_name; ///< The item name
|
||||
bool m_mandatory; ///< Flag indicating this item is mandatory
|
||||
const type_validator *m_type; ///< The type for this item
|
||||
cif::iset m_enums; ///< If filled, the set of allowed values
|
||||
std::string m_default; ///< If filled, a default value for this item
|
||||
category_validator *m_category = nullptr; ///< The category_validator this item_validator belongs to
|
||||
std::vector<item_alias> m_aliases; ///< The aliases for this item
|
||||
std::string m_item_name; ///< The item name
|
||||
bool m_mandatory; ///< Flag indicating this item is mandatory
|
||||
const type_validator *m_type; ///< The type for this item
|
||||
cif::iset m_enums; ///< If filled, the set of allowed values
|
||||
std::string m_default; ///< If filled, a default value for this item
|
||||
std::string m_category; ///< The category this item_validator belongs to
|
||||
std::vector<item_alias> m_aliases; ///< The aliases for this item
|
||||
|
||||
/// @brief Compare based on the name
|
||||
bool operator<(const item_validator &rhs) const
|
||||
@@ -396,24 +400,48 @@ class validator
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator(std::string_view name)
|
||||
: m_name(name)
|
||||
validator()
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
* @param is The data to parse
|
||||
*/
|
||||
validator(std::istream &is)
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
parse(is);
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
|
||||
validator(const validator &rhs) = delete;
|
||||
validator &operator=(const validator &rhs) = delete;
|
||||
validator(const validator &rhs);
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs) = default;
|
||||
validator(validator &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// @brief move assignment operator
|
||||
validator &operator=(validator &&rhs) = default;
|
||||
validator &operator=(validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend void swap(validator &a, validator &b) noexcept;
|
||||
|
||||
friend class dictionary_parser;
|
||||
friend class validator_factory;
|
||||
|
||||
/// @brief Parse dictionary in @a is and put content in this validator, optionally extending it
|
||||
/// @param is The stream containing a valid cif dictionary
|
||||
void parse(std::istream &is);
|
||||
|
||||
/// @brief Add type_validator @a v to the list of type validators
|
||||
void add_type_validator(type_validator &&v);
|
||||
@@ -456,18 +484,22 @@ class validator
|
||||
void report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const;
|
||||
|
||||
const std::string &name() const { return m_name; } ///< Get the name of this validator
|
||||
void set_name(const std::string &name) { m_name = name; } ///< Set the name of this validator
|
||||
/// @brief Write out the audit_conform data for this validator
|
||||
/// @param audit_conform
|
||||
void fill_audit_conform(category &audit_conform) const;
|
||||
|
||||
const std::string &version() const { return m_version; } ///< Get the version of this validator
|
||||
void set_version(const std::string &version) { m_version = version; } ///< Set the version of this validator
|
||||
/// @brief Return true if this validator matches @a audit_conform
|
||||
bool matches_audit_conform(const category &audit_conform) const;
|
||||
|
||||
/// @brief Add info
|
||||
void append_audit_conform(const std::string &name, const std::optional<std::string> &version);
|
||||
|
||||
private:
|
||||
// name is fully qualified here:
|
||||
item_validator *get_validator_for_item(std::string_view name) const;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
category m_audit_conform;
|
||||
|
||||
bool m_strict = false;
|
||||
std::set<type_validator> m_type_validators;
|
||||
std::set<category_validator> m_category_validators;
|
||||
@@ -487,17 +519,28 @@ class validator_factory
|
||||
/// @brief Return the singleton instance
|
||||
static validator_factory &instance();
|
||||
|
||||
/// @brief Return the validator with name @a dictionary_name
|
||||
const validator &operator[](std::string_view dictionary_name);
|
||||
/// @brief Return validator with info recorded in @a audit_conform
|
||||
const validator &get(const category &audit_conform);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is
|
||||
const validator &construct_validator(std::string_view name, std::istream &is);
|
||||
/// @brief Return the single-file validator with name @a dictionary_name
|
||||
const validator &get(std::string_view dictionary_name);
|
||||
|
||||
/// @brief Return true if the version @a found is equal or higher than @a expected for dictionary @a name
|
||||
static bool check_version(std::string_view name, std::string_view expected, std::string_view found);
|
||||
|
||||
/// @brief Add validator @a v to the list of known validators
|
||||
const validator &add(validator &&v)
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
return m_validators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
private:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator_factory() = default;
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is with at least version @a version if specified
|
||||
validator construct_validator(std::string_view name, std::optional<std::string> version);
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::list<validator> m_validators;
|
||||
};
|
||||
|
||||
9473
rsrc/mmcif_pdbx.dic
9473
rsrc/mmcif_pdbx.dic
File diff suppressed because it is too large
Load Diff
277
src/category.cpp
277
src/category.cpp
@@ -28,6 +28,7 @@
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <numeric>
|
||||
#include <stack>
|
||||
@@ -91,7 +92,7 @@ class row_comparator
|
||||
return d;
|
||||
}
|
||||
|
||||
int operator()(const category &cat, const row_initializer &a, const row *b) const
|
||||
int operator()(const category &cat, const category::key_type &a, const row *b) const
|
||||
{
|
||||
assert(b);
|
||||
|
||||
@@ -104,10 +105,11 @@ class row_comparator
|
||||
{
|
||||
assert(ai != a.end());
|
||||
|
||||
std::string_view ka = ai->value();
|
||||
std::string_view ka = ai->value;
|
||||
std::string_view kb = rhb[k].text();
|
||||
|
||||
d = f(ka, kb);
|
||||
if (not (ai->may_be_null and rhb[k].empty()))
|
||||
d = f(ka, kb);
|
||||
|
||||
if (d != 0)
|
||||
break;
|
||||
@@ -141,7 +143,7 @@ class category_index
|
||||
}
|
||||
|
||||
row *find(const category &cat, row *k) const;
|
||||
row *find_by_value(const category &cat, row_initializer k) const;
|
||||
row *find_by_value(const category &cat, const category::key_type &k) const;
|
||||
|
||||
void insert(category &cat, row *r);
|
||||
void erase(category &cat, row *r);
|
||||
@@ -164,7 +166,7 @@ class category_index
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t size() const;
|
||||
std::size_t size() const;
|
||||
// bool isValid() const;
|
||||
|
||||
private:
|
||||
@@ -351,19 +353,19 @@ row *category_index::find(const category &cat, row *k) const
|
||||
return r ? r->m_row : nullptr;
|
||||
}
|
||||
|
||||
row *category_index::find_by_value(const category &cat, row_initializer k) const
|
||||
row *category_index::find_by_value(const category &cat, const category::key_type &k) const
|
||||
{
|
||||
// sort the values in k first
|
||||
|
||||
row_initializer k2;
|
||||
category::key_type k2;
|
||||
for (auto &f : cat.key_item_indices())
|
||||
{
|
||||
auto fld = cat.get_item_name(f);
|
||||
|
||||
auto ki = find_if(k.begin(), k.end(), [&fld](auto &i)
|
||||
{ return i.name() == fld; });
|
||||
{ return i.name == fld; });
|
||||
if (ki == k.end())
|
||||
k2.emplace_back(fld, "");
|
||||
k2.emplace_back(std::string{ fld }, "");
|
||||
else
|
||||
k2.emplace_back(*ki);
|
||||
}
|
||||
@@ -475,12 +477,12 @@ category_index::entry *category_index::erase(category &cat, entry *h, row *k)
|
||||
return fix_up(h);
|
||||
}
|
||||
|
||||
size_t category_index::size() const
|
||||
std::size_t category_index::size() const
|
||||
{
|
||||
std::stack<entry *> s;
|
||||
s.push(m_root);
|
||||
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
|
||||
while (not s.empty())
|
||||
{
|
||||
@@ -521,71 +523,18 @@ category::category(const category &rhs)
|
||||
m_index = new category_index(*this);
|
||||
}
|
||||
|
||||
category::category(category &&rhs)
|
||||
: m_name(std::move(rhs.m_name))
|
||||
, m_items(std::move(rhs.m_items))
|
||||
, m_validator(rhs.m_validator)
|
||||
, m_cat_validator(rhs.m_cat_validator)
|
||||
, m_parent_links(std::move(rhs.m_parent_links))
|
||||
, m_child_links(std::move(rhs.m_child_links))
|
||||
, m_cascade(rhs.m_cascade)
|
||||
, m_index(rhs.m_index)
|
||||
, m_head(rhs.m_head)
|
||||
, m_tail(rhs.m_tail)
|
||||
void swap(category &a, category &b) noexcept
|
||||
{
|
||||
rhs.m_head = nullptr;
|
||||
rhs.m_tail = nullptr;
|
||||
rhs.m_index = nullptr;
|
||||
}
|
||||
|
||||
category &category::operator=(const category &rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
if (not empty())
|
||||
clear();
|
||||
|
||||
m_name = rhs.m_name;
|
||||
m_items = rhs.m_items;
|
||||
m_cascade = rhs.m_cascade;
|
||||
|
||||
m_validator = nullptr;
|
||||
m_cat_validator = nullptr;
|
||||
|
||||
delete m_index;
|
||||
m_index = nullptr;
|
||||
|
||||
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
|
||||
insert_impl(cend(), clone_row(*r));
|
||||
|
||||
m_validator = rhs.m_validator;
|
||||
m_cat_validator = rhs.m_cat_validator;
|
||||
|
||||
if (m_cat_validator != nullptr and m_index == nullptr)
|
||||
m_index = new category_index(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
category &category::operator=(category &&rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
m_name = std::move(rhs.m_name);
|
||||
m_items = std::move(rhs.m_items);
|
||||
m_cascade = rhs.m_cascade;
|
||||
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;
|
||||
|
||||
std::swap(m_index, rhs.m_index);
|
||||
std::swap(m_head, rhs.m_head);
|
||||
std::swap(m_tail, rhs.m_tail);
|
||||
}
|
||||
|
||||
return *this;
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_items, b.m_items);
|
||||
std::swap(a.m_validator, b.m_validator);
|
||||
std::swap(a.m_cat_validator, b.m_cat_validator);
|
||||
std::swap(a.m_parent_links, b.m_parent_links);
|
||||
std::swap(a.m_child_links, b.m_child_links);
|
||||
std::swap(a.m_cascade, b.m_cascade);
|
||||
std::swap(a.m_index, b.m_index);
|
||||
std::swap(a.m_head, b.m_head);
|
||||
std::swap(a.m_tail, b.m_tail);
|
||||
}
|
||||
|
||||
category::~category()
|
||||
@@ -595,9 +544,52 @@ category::~category()
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
uint16_t category::get_item_ix(std::string_view item_name) const
|
||||
{
|
||||
uint16_t result;
|
||||
|
||||
for (result = 0; result < m_items.size(); ++result)
|
||||
{
|
||||
if (iequals(item_name, m_items[result].m_name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (VERBOSE > 0 and result == m_items.size() and m_cat_validator != nullptr) // validate the name, if it is known at all (since it was not found)
|
||||
{
|
||||
auto iv = m_cat_validator->get_validator_for_item(item_name);
|
||||
if (iv == nullptr)
|
||||
std::cerr << "Invalid name used '" << item_name << "' is not a known item in " + m_name << '\n';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t category::add_item(std::string_view item_name)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
uint16_t result = get_item_ix(item_name);
|
||||
|
||||
if (result == m_items.size())
|
||||
{
|
||||
const item_validator *item_validator = nullptr;
|
||||
|
||||
if (m_cat_validator != nullptr)
|
||||
{
|
||||
item_validator = m_cat_validator->get_validator_for_item(item_name);
|
||||
if (item_validator == nullptr)
|
||||
m_validator->report_error(validation_error::item_not_allowed_in_category, m_name, item_name, false);
|
||||
}
|
||||
|
||||
m_items.emplace_back(item_name, item_validator);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void category::remove_item(std::string_view item_name)
|
||||
{
|
||||
for (size_t ix = 0; ix < m_items.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < m_items.size(); ++ix)
|
||||
{
|
||||
if (not iequals(item_name, m_items[ix].m_name))
|
||||
continue;
|
||||
@@ -616,7 +608,7 @@ void category::remove_item(std::string_view item_name)
|
||||
|
||||
void category::rename_item(std::string_view from_name, std::string_view to_name)
|
||||
{
|
||||
for (size_t ix = 0; ix < m_items.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < m_items.size(); ++ix)
|
||||
{
|
||||
if (not iequals(from_name, m_items[ix].m_name))
|
||||
continue;
|
||||
@@ -719,7 +711,7 @@ void category::set_validator(const validator *v, datablock &db)
|
||||
update_links(db);
|
||||
}
|
||||
|
||||
void category::update_links(datablock &db)
|
||||
void category::update_links(const datablock &db)
|
||||
{
|
||||
m_child_links.clear();
|
||||
m_parent_links.clear();
|
||||
@@ -728,7 +720,7 @@ void category::update_links(datablock &db)
|
||||
{
|
||||
for (auto link : m_validator->get_links_for_parent(m_name))
|
||||
{
|
||||
auto childCat = db.get(link->m_child_category);
|
||||
auto childCat = const_cast<category *>(db.get(link->m_child_category));
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
m_child_links.emplace_back(childCat, link);
|
||||
@@ -736,7 +728,7 @@ void category::update_links(datablock &db)
|
||||
|
||||
for (auto link : m_validator->get_links_for_child(m_name))
|
||||
{
|
||||
auto parentCat = db.get(link->m_parent_category);
|
||||
auto parentCat = const_cast<category *>(db.get(link->m_parent_category));
|
||||
if (parentCat == nullptr)
|
||||
continue;
|
||||
m_parent_links.emplace_back(parentCat, link);
|
||||
@@ -771,7 +763,7 @@ bool category::is_valid() const
|
||||
auto iv = m_cat_validator->get_validator_for_item(col.m_name);
|
||||
if (iv == nullptr)
|
||||
{
|
||||
m_validator->report_error(validation_error::unknown_item, col.m_name, m_name, false);
|
||||
m_validator->report_error(validation_error::unknown_item, m_name, col.m_name, false);
|
||||
result = false;
|
||||
}
|
||||
|
||||
@@ -844,7 +836,7 @@ bool category::is_valid() const
|
||||
|
||||
iv->validate_value(vi->text(), ec);
|
||||
|
||||
if (ec != std::errc())
|
||||
if ((bool)ec)
|
||||
{
|
||||
m_validator->report_error(ec, m_name, m_items[cix].m_name, false);
|
||||
continue;
|
||||
@@ -885,7 +877,7 @@ bool category::validate_links() const
|
||||
if (name() == "atom_site" and (parent->name() == "pdbx_poly_seq_scheme" or parent->name() == "entity_poly_seq"))
|
||||
continue;
|
||||
|
||||
size_t missing = 0;
|
||||
std::size_t missing = 0;
|
||||
category first_missing_rows(name());
|
||||
|
||||
for (auto r : *this)
|
||||
@@ -923,6 +915,24 @@ bool category::validate_links() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void category::strip()
|
||||
{
|
||||
std::vector<std::string> to_be_removed;
|
||||
|
||||
for (auto &item : m_items)
|
||||
{
|
||||
if (item.m_validator == nullptr)
|
||||
to_be_removed.push_back(item.m_name);
|
||||
}
|
||||
|
||||
for (auto item : to_be_removed)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Dropping item " << m_name << '.' << item << '\n';
|
||||
remove_item(item);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
row_handle category::operator[](const key_type &key)
|
||||
@@ -962,7 +972,7 @@ condition category::get_parents_condition(row_handle rh, const category &parentC
|
||||
{
|
||||
condition cond;
|
||||
|
||||
for (size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
|
||||
{
|
||||
auto childValue = rh[link->m_child_keys[ix]];
|
||||
|
||||
@@ -1004,7 +1014,7 @@ condition category::get_children_condition(row_handle rh, const category &childC
|
||||
{
|
||||
condition cond;
|
||||
|
||||
for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
|
||||
{
|
||||
auto childKey = link->m_child_keys[ix];
|
||||
auto parentKey = link->m_parent_keys[ix];
|
||||
@@ -1180,14 +1190,14 @@ class save_value
|
||||
const T m_sv;
|
||||
};
|
||||
|
||||
size_t category::erase(condition &&cond)
|
||||
std::size_t category::erase(condition &&cond)
|
||||
{
|
||||
return erase(std::move(cond), {});
|
||||
}
|
||||
|
||||
size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit)
|
||||
std::size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit)
|
||||
{
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
|
||||
cond.prepare(*this);
|
||||
|
||||
@@ -1327,7 +1337,7 @@ std::string category::get_unique_value(std::string_view item_name)
|
||||
if (result.empty())
|
||||
{
|
||||
// brain-dead implementation
|
||||
for (size_t ix = 0; ix < size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < size(); ++ix)
|
||||
{
|
||||
// result = m_name + "-" + std::to_string(ix);
|
||||
result = cif_id_for_number(ix);
|
||||
@@ -1339,7 +1349,8 @@ std::string category::get_unique_value(std::string_view item_name)
|
||||
return result;
|
||||
}
|
||||
|
||||
void category::update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
|
||||
void category::update_value(const std::vector<row_handle> &rows, std::string_view item_name,
|
||||
value_provider_type &&value_provider)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
@@ -1352,40 +1363,29 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
|
||||
auto &col = m_items[colIx];
|
||||
|
||||
// this is expensive, but better throw early on
|
||||
// check the value
|
||||
if (col.m_validator)
|
||||
{
|
||||
std::error_code ec;
|
||||
col.m_validator->validate_value(value, ec);
|
||||
if (ec)
|
||||
throw validation_exception(ec, m_name, item_name);
|
||||
}
|
||||
|
||||
// first some sanity checks, what was the old value and is it the same for all rows?
|
||||
std::string oldValue{ rows.front()[item_name].text() };
|
||||
for (auto row : rows)
|
||||
{
|
||||
if (oldValue != row[item_name].text())
|
||||
for (auto row : rows)
|
||||
{
|
||||
std::ostringstream os;
|
||||
std::string value{ value_provider(row[item_name].text()) };
|
||||
|
||||
os << "Inconsistent old values in update_value, trying to set " << std::quoted(value)
|
||||
<< " as value for item " << item_name << " in category " << m_name;
|
||||
|
||||
throw std::runtime_error(os.str());
|
||||
std::error_code ec;
|
||||
col.m_validator->validate_value(value, ec);
|
||||
if (ec)
|
||||
throw validation_exception(ec, m_name, item_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldValue == value) // no need to do anything
|
||||
return;
|
||||
|
||||
// update rows, but do not cascade
|
||||
for (auto row : rows)
|
||||
row.assign(colIx, value, false);
|
||||
|
||||
// see if we need to update any child categories that depend on this value
|
||||
// update and see if we need to update any child categories that depend on this value
|
||||
for (auto parent : rows)
|
||||
{
|
||||
std::string oldValue{ parent[item_name].text() };
|
||||
std::string value{ value_provider(oldValue) };
|
||||
|
||||
update_value(parent.get_row(), colIx, value, false, false);
|
||||
|
||||
for (auto &&[childCat, linked] : m_child_links)
|
||||
{
|
||||
if (std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), item_name) == linked->m_parent_keys.end())
|
||||
@@ -1394,7 +1394,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
condition cond;
|
||||
std::string childItemName;
|
||||
|
||||
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
{
|
||||
std::string pk = linked->m_parent_keys[ix];
|
||||
std::string ck = linked->m_child_keys[ix];
|
||||
@@ -1425,7 +1425,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
{
|
||||
condition cond_c;
|
||||
|
||||
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
{
|
||||
std::string pk = linked->m_parent_keys[ix];
|
||||
std::string ck = linked->m_child_keys[ix];
|
||||
@@ -1443,7 +1443,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
// oops, we need to split this child, unless a row already exists for the new value
|
||||
condition check;
|
||||
|
||||
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
{
|
||||
std::string pk = linked->m_parent_keys[ix];
|
||||
std::string ck = linked->m_child_keys[ix];
|
||||
@@ -1507,8 +1507,7 @@ void category::update_value(row *row, uint16_t item, std::string_view value, boo
|
||||
// before updating
|
||||
|
||||
bool reinsert = false;
|
||||
if (updateLinked and // an update of an Item's value
|
||||
m_index != nullptr and key_item_indices().count(item))
|
||||
if (m_index != nullptr and key_item_indices().count(item))
|
||||
{
|
||||
reinsert = m_index->find(*this, row);
|
||||
if (reinsert)
|
||||
@@ -1539,7 +1538,7 @@ void category::update_value(row *row, uint16_t item, std::string_view value, boo
|
||||
condition cond;
|
||||
std::string childItemName;
|
||||
|
||||
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
{
|
||||
std::string pk = linked->m_parent_keys[ix];
|
||||
std::string ck = linked->m_child_keys[ix];
|
||||
@@ -1576,7 +1575,7 @@ void category::update_value(row *row, uint16_t item, std::string_view value, boo
|
||||
|
||||
condition cond_n;
|
||||
|
||||
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
|
||||
{
|
||||
std::string pk = linked->m_parent_keys[ix];
|
||||
std::string ck = linked->m_child_keys[ix];
|
||||
@@ -1722,7 +1721,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
|
||||
m_index->insert(*this, n);
|
||||
|
||||
// insert at end, most often this is the case
|
||||
if (pos.m_current == nullptr)
|
||||
if (pos.m_current.m_row == nullptr)
|
||||
{
|
||||
if (m_head == nullptr)
|
||||
m_tail = m_head = n;
|
||||
@@ -1733,7 +1732,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
|
||||
{
|
||||
assert(m_head != nullptr);
|
||||
|
||||
if (pos.m_current == m_head)
|
||||
if (pos.m_current.m_row == m_head)
|
||||
m_head = n->m_next = m_head;
|
||||
else
|
||||
n = n->m_next = m_head->m_next;
|
||||
@@ -1761,6 +1760,12 @@ void category::swap_item(uint16_t item_ix, row_handle &a, row_handle &b)
|
||||
auto &ra = *a.m_row;
|
||||
auto &rb = *b.m_row;
|
||||
|
||||
while (ra.size() <= item_ix)
|
||||
ra.emplace_back("");
|
||||
|
||||
while (rb.size() <= item_ix)
|
||||
rb.emplace_back("");
|
||||
|
||||
std::swap(ra.at(item_ix), rb.at(item_ix));
|
||||
}
|
||||
|
||||
@@ -1783,7 +1788,7 @@ void category::sort(std::function<int(row_handle, row_handle)> f)
|
||||
m_tail = rows.back().get_row();
|
||||
|
||||
auto r = m_head;
|
||||
for (size_t i = 1; i < rows.size(); ++i)
|
||||
for (std::size_t i = 1; i < rows.size(); ++i)
|
||||
r = r->m_next = rows[i].get_row();
|
||||
r->m_next = nullptr;
|
||||
|
||||
@@ -1799,7 +1804,7 @@ void category::reorder_by_index()
|
||||
|
||||
namespace detail
|
||||
{
|
||||
size_t write_value(std::ostream &os, std::string_view value, size_t offset, size_t width, bool right_aligned)
|
||||
std::size_t write_value(std::ostream &os, std::string_view value, std::size_t offset, std::size_t width, bool right_aligned)
|
||||
{
|
||||
if (value.find('\n') != std::string::npos or width == 0 or value.length() > 132) // write as text item
|
||||
{
|
||||
@@ -1960,7 +1965,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
{
|
||||
os << "loop_\n";
|
||||
|
||||
std::vector<size_t> itemWidths(m_items.size());
|
||||
std::vector<std::size_t> itemWidths(m_items.size());
|
||||
|
||||
for (auto cix : order)
|
||||
{
|
||||
@@ -1982,7 +1987,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
|
||||
if (v->text().find('\n') == std::string_view::npos)
|
||||
{
|
||||
size_t l = v->text().length();
|
||||
std::size_t l = v->text().length();
|
||||
|
||||
if (not sac_parser::is_unquoted_string(v->text()))
|
||||
l += 2;
|
||||
@@ -1998,11 +2003,11 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
|
||||
for (auto r = m_head; r != nullptr; r = r->m_next) // loop over rows
|
||||
{
|
||||
size_t offset = 0;
|
||||
std::size_t offset = 0;
|
||||
|
||||
for (uint16_t cix : order)
|
||||
{
|
||||
size_t w = itemWidths[cix];
|
||||
std::size_t w = itemWidths[cix];
|
||||
|
||||
std::string_view s;
|
||||
auto iv = r->get(cix);
|
||||
@@ -2012,7 +2017,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
if (s.empty())
|
||||
s = "?";
|
||||
|
||||
size_t l = s.length();
|
||||
std::size_t l = s.length();
|
||||
if (not sac_parser::is_unquoted_string(s))
|
||||
l += 2;
|
||||
if (l < w)
|
||||
@@ -2040,7 +2045,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
else
|
||||
{
|
||||
// first find the indent level
|
||||
size_t l = 0;
|
||||
std::size_t l = 0;
|
||||
|
||||
for (auto &col : m_items)
|
||||
{
|
||||
@@ -2052,7 +2057,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
|
||||
l += 3;
|
||||
|
||||
size_t width = 1;
|
||||
std::size_t width = 1;
|
||||
|
||||
for (auto cix : order)
|
||||
{
|
||||
@@ -2067,7 +2072,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
if (s.empty())
|
||||
s = "?";
|
||||
|
||||
size_t l2 = s.length();
|
||||
std::size_t l2 = s.length();
|
||||
|
||||
if (not sac_parser::is_unquoted_string(s))
|
||||
l2 += 2;
|
||||
@@ -2093,7 +2098,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
|
||||
if (s.empty())
|
||||
s = "?";
|
||||
|
||||
size_t offset = l;
|
||||
std::size_t offset = l;
|
||||
if (s.length() + l >= kMaxLineLength)
|
||||
{
|
||||
os << '\n';
|
||||
@@ -2133,7 +2138,7 @@ bool category::operator==(const category &rhs) const
|
||||
typedef std::function<int(std::string_view, std::string_view)> compType;
|
||||
std::vector<std::tuple<std::string, compType>> item_names;
|
||||
std::vector<std::string> keys;
|
||||
std::vector<size_t> keyIx;
|
||||
std::vector<std::size_t> keyIx;
|
||||
|
||||
if (catValidator == nullptr)
|
||||
{
|
||||
@@ -2231,4 +2236,4 @@ bool category::operator==(const category &rhs) const
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
268
src/compound.cpp
268
src/compound.cpp
@@ -177,89 +177,6 @@ compound::compound(cif::datablock &db)
|
||||
}
|
||||
}
|
||||
|
||||
compound::compound(cif::datablock &db, int)
|
||||
{
|
||||
auto &chemComp = db["chem_comp"];
|
||||
|
||||
if (chemComp.size() != 1)
|
||||
throw std::runtime_error("Invalid compound file, chem_comp should contain a single row");
|
||||
|
||||
cif::tie(m_id, m_name) =
|
||||
chemComp.front().get("id", "name");
|
||||
|
||||
cif::trim(m_name);
|
||||
|
||||
m_type = "NON-POLYMER";
|
||||
|
||||
auto &chemCompAtom = db["chem_comp_atom"];
|
||||
for (auto row : chemCompAtom)
|
||||
{
|
||||
compound_atom atom;
|
||||
std::string type_symbol;
|
||||
cif::tie(atom.id, type_symbol, atom.charge, atom.x, atom.y, atom.z) =
|
||||
row.get("atom_id", "type_symbol", "charge", "x", "y", "z");
|
||||
atom.type_symbol = atom_type_traits(type_symbol).type();
|
||||
|
||||
m_formal_charge += atom.charge;
|
||||
|
||||
m_atoms.push_back(std::move(atom));
|
||||
}
|
||||
|
||||
auto &chemCompBond = db["chem_comp_bond"];
|
||||
for (auto row : chemCompBond)
|
||||
{
|
||||
compound_bond bond;
|
||||
std::string btype;
|
||||
cif::tie(bond.atom_id[0], bond.atom_id[1], btype, bond.aromatic) = row.get("atom_id_1", "atom_id_2", "type", "aromatic");
|
||||
|
||||
using cif::iequals;
|
||||
|
||||
if (iequals(btype, "single"))
|
||||
bond.type = bond_type::sing;
|
||||
else if (iequals(btype, "double"))
|
||||
bond.type = bond_type::doub;
|
||||
else if (iequals(btype, "triple"))
|
||||
bond.type = bond_type::trip;
|
||||
else if (iequals(btype, "deloc") or iequals(btype, "aromat") or iequals(btype, "aromatic"))
|
||||
bond.type = bond_type::delo;
|
||||
else
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Unimplemented chem_comp_bond.type " << btype << " in " << db.name() << '\n';
|
||||
bond.type = bond_type::sing;
|
||||
}
|
||||
m_bonds.push_back(std::move(bond));
|
||||
}
|
||||
|
||||
// reconstruct a formula and weight
|
||||
|
||||
m_formula_weight = 0;
|
||||
|
||||
std::map<atom_type, int> f;
|
||||
for (auto &atom : m_atoms)
|
||||
f[atom.type_symbol] += 1;
|
||||
|
||||
if (f.count(atom_type::C))
|
||||
{
|
||||
atom_type_traits att(atom_type::C);
|
||||
m_formula += att.symbol() + std::to_string(f[atom_type::C]) + ' ';
|
||||
m_formula_weight += att.weight() * f[atom_type::C];
|
||||
}
|
||||
|
||||
for (const auto &[type, count] : f)
|
||||
{
|
||||
if (type == atom_type::C)
|
||||
continue;
|
||||
|
||||
atom_type_traits att(type);
|
||||
m_formula += att.symbol() + std::to_string(count) + ' ';
|
||||
m_formula_weight += att.weight() * count;
|
||||
}
|
||||
|
||||
if (not m_formula.empty())
|
||||
m_formula.pop_back();
|
||||
}
|
||||
|
||||
compound_atom compound::get_atom_by_atom_id(const std::string &atom_id) const
|
||||
{
|
||||
compound_atom result = {};
|
||||
@@ -379,41 +296,17 @@ class compound_factory_impl : public std::enable_shared_from_this<compound_facto
|
||||
|
||||
compound *get(std::string id)
|
||||
{
|
||||
cif::to_upper(id);
|
||||
|
||||
std::shared_lock lock(mMutex);
|
||||
|
||||
compound *result = nullptr;
|
||||
|
||||
// walk the list, see if any of the implementations has the compound already
|
||||
|
||||
for (auto impl = shared_from_this(); impl; impl = impl->m_next)
|
||||
{
|
||||
for (auto cmp : impl->m_compounds)
|
||||
{
|
||||
if (iequals(cmp->id(), id))
|
||||
{
|
||||
result = cmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
result = impl->create(id);
|
||||
if (result != nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == nullptr and m_missing.count(id) == 0)
|
||||
{
|
||||
for (auto impl = shared_from_this(); impl; impl = impl->m_next)
|
||||
{
|
||||
result = impl->create(id);
|
||||
if (result != nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == nullptr)
|
||||
m_missing.insert(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -444,7 +337,7 @@ class compound_factory_impl : public std::enable_shared_from_this<compound_facto
|
||||
cif::parser::datablock_index m_index;
|
||||
|
||||
std::vector<compound *> m_compounds;
|
||||
std::set<std::string> m_missing;
|
||||
cif::iset m_missing;
|
||||
std::shared_ptr<compound_factory_impl> m_next;
|
||||
};
|
||||
|
||||
@@ -465,6 +358,14 @@ compound_factory_impl::compound_factory_impl(const fs::path &file, std::shared_p
|
||||
|
||||
compound *compound_factory_impl::create(const std::string &id)
|
||||
{
|
||||
// shortcut
|
||||
|
||||
if (m_missing.contains(id))
|
||||
return nullptr;
|
||||
|
||||
if (auto i = find_if(m_compounds.begin(), m_compounds.end(), [id](compound *c) { return c->id() == id; }); i != m_compounds.end())
|
||||
return *i;
|
||||
|
||||
compound *result = nullptr;
|
||||
|
||||
std::unique_ptr<std::istream> ccd;
|
||||
@@ -496,7 +397,7 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
m_index = parser.index_datablocks();
|
||||
|
||||
if (cif::VERBOSE > 1)
|
||||
std::cout << " done" << std::endl;
|
||||
std::cout << " done\n";
|
||||
|
||||
// reload the resource, perhaps this should be improved...
|
||||
if (m_file.empty())
|
||||
@@ -519,7 +420,7 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
parser.parse_single_datablock(id, m_index);
|
||||
|
||||
if (cif::VERBOSE > 1)
|
||||
std::cout << " done" << std::endl;
|
||||
std::cout << " done\n";
|
||||
|
||||
if (not file.empty())
|
||||
{
|
||||
@@ -533,6 +434,9 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
}
|
||||
}
|
||||
|
||||
if (result == nullptr)
|
||||
m_missing.insert(id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -550,28 +454,147 @@ class local_compound_factory_impl : public compound_factory_impl
|
||||
compound *create(const std::string &id) override;
|
||||
|
||||
private:
|
||||
const cif::file &m_local_file;
|
||||
|
||||
compound *construct_compound(const datablock &db, const std::string &id, const std::string &name, const std::string &three_letter_code, const std::string &group);
|
||||
|
||||
cif::file m_local_file;
|
||||
};
|
||||
|
||||
compound *local_compound_factory_impl::create(const std::string &id)
|
||||
{
|
||||
if (m_missing.contains(id))
|
||||
return nullptr;
|
||||
|
||||
if (auto i = find_if(m_compounds.begin(), m_compounds.end(), [id](compound *c) { return c->id() == id; }); i != m_compounds.end())
|
||||
return *i;
|
||||
|
||||
compound *result = nullptr;
|
||||
|
||||
for (auto &db : m_local_file)
|
||||
{
|
||||
if (db.name() == "comp_" + id)
|
||||
if (db.name() == id)
|
||||
{
|
||||
cif::datablock db_copy(db);
|
||||
auto chem_comp = db.get("chem_comp");
|
||||
if (not chem_comp)
|
||||
break;
|
||||
|
||||
result = new compound(db_copy, 1);
|
||||
try
|
||||
{
|
||||
const auto &[id, name, threeLetterCode, group] =
|
||||
chem_comp->front().get<std::string, std::string, std::string, std::string>("id", "name", "three_letter_code", "group");
|
||||
|
||||
std::shared_lock lock(mMutex);
|
||||
m_compounds.push_back(result);
|
||||
result = construct_compound(db, id, name, threeLetterCode, group);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
std::throw_with_nested(std::runtime_error("Error loading compound " + id));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == nullptr)
|
||||
m_missing.insert(id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
compound *local_compound_factory_impl::construct_compound(const datablock &rdb, const std::string &id,
|
||||
const std::string &name, const std::string &three_letter_code, const std::string &group)
|
||||
{
|
||||
cif::datablock db(id);
|
||||
|
||||
float formula_weight = 0;
|
||||
int formal_charge = 0;
|
||||
std::map<std::string,std::size_t> formula_data;
|
||||
|
||||
for (std::size_t ord = 1; const auto &[atom_id, type_symbol, type, charge, x, y, z, xi, yi, zi] :
|
||||
rdb["chem_comp_atom"].rows<std::string, std::string, std::string, int,
|
||||
std::optional<float>, std::optional<float>, std::optional<float>,
|
||||
std::optional<float>, std::optional<float>, std::optional<float>>(
|
||||
"atom_id", "type_symbol", "type", "charge",
|
||||
"model_Cartn_x", "model_Cartn_y", "model_Cartn_z",
|
||||
"pdbx_model_Cartn_x_ideal", "pdbx_model_Cartn_y_ideal", "pdbx_model_Cartn_z_ideal"))
|
||||
{
|
||||
auto atom = cif::atom_type_traits(type_symbol);
|
||||
formula_weight += atom.weight();
|
||||
|
||||
formula_data[type_symbol] += 1;
|
||||
|
||||
db["chem_comp_atom"].emplace({
|
||||
{ "comp_id", id },
|
||||
{ "atom_id", atom_id },
|
||||
{ "type_symbol", type_symbol },
|
||||
{ "charge", charge },
|
||||
{ "model_Cartn_x", x.has_value() ? x : xi, 3 },
|
||||
{ "model_Cartn_y", y.has_value() ? y : yi, 3 },
|
||||
{ "model_Cartn_z", z.has_value() ? z : zi, 3 },
|
||||
{ "pdbx_ordinal", ord++ }
|
||||
});
|
||||
|
||||
formal_charge += charge;
|
||||
}
|
||||
|
||||
for (std::size_t ord = 1; const auto &[atom_id_1, atom_id_2, type, aromatic] :
|
||||
rdb["chem_comp_bond"].rows<std::string, std::string, std::string, bool>("atom_id_1", "atom_id_2", "type", "aromatic"))
|
||||
{
|
||||
std::string value_order("SING");
|
||||
|
||||
if (cif::iequals(type, "single") or cif::iequals(type, "sing"))
|
||||
value_order = "SING";
|
||||
else if (cif::iequals(type, "double") or cif::iequals(type, "doub"))
|
||||
value_order = "DOUB";
|
||||
else if (cif::iequals(type, "triple") or cif::iequals(type, "trip"))
|
||||
value_order = "TRIP";
|
||||
|
||||
db["chem_comp_bond"].emplace({
|
||||
{ "comp_id", id },
|
||||
{ "atom_id_1", atom_id_1 },
|
||||
{ "atom_id_2", atom_id_2 },
|
||||
{ "value_order", value_order },
|
||||
{ "pdbx_aromatic_flag", aromatic },
|
||||
// TODO: fetch stereo_config info from chem_comp_chir
|
||||
{ "pdbx_ordinal", ord++ }
|
||||
});
|
||||
}
|
||||
|
||||
db.emplace_back(rdb["pdbx_chem_comp_descriptor"]);
|
||||
|
||||
std::string formula;
|
||||
for (bool first = true; const auto &[symbol, count]: formula_data)
|
||||
{
|
||||
if (std::exchange(first, false))
|
||||
formula += ' ';
|
||||
formula += symbol;
|
||||
if (count > 1)
|
||||
formula += std::to_string(count);
|
||||
}
|
||||
|
||||
std::string type;
|
||||
if (cif::iequals(group, "peptide") or cif::iequals(group, "l-peptide") or cif::iequals(group, "l-peptide linking"))
|
||||
type = "L-PEPTIDE LINKING";
|
||||
else if (cif::iequals(group, "dna"))
|
||||
type = "DNA LINKING";
|
||||
else if (cif::iequals(group, "rna"))
|
||||
type = "RNA LINKING";
|
||||
else
|
||||
type = "NON-POLYMER";
|
||||
|
||||
db["chem_comp"].emplace({
|
||||
{ "id", id },
|
||||
{ "name", name },
|
||||
{ "type", type },
|
||||
{ "formula", formula },
|
||||
{ "pdbx_formal_charge", formal_charge },
|
||||
{ "formula_weight", formula_weight },
|
||||
{ "three_letter_code", three_letter_code }
|
||||
});
|
||||
|
||||
std::shared_lock lock(mMutex);
|
||||
|
||||
auto result = new compound(db);
|
||||
m_compounds.push_back(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -734,8 +757,7 @@ bool compound_factory::is_monomer(std::string_view res_name) const
|
||||
|
||||
void compound_factory::report_missing_compound(std::string_view compound_id)
|
||||
{
|
||||
static bool s_reported = false;
|
||||
if (std::exchange(s_reported, true) == false)
|
||||
if (std::exchange(m_report_missing, false))
|
||||
{
|
||||
using namespace cif::colour;
|
||||
|
||||
@@ -757,8 +779,8 @@ void compound_factory::report_missing_compound(std::string_view compound_id)
|
||||
<< "update=true\n\n"
|
||||
<< "If you do not have a working cron script, you can manually update the files\n"
|
||||
<< "in /var/cache/libcifpp using the following commands:\n\n"
|
||||
<< "curl -o " << CACHE_DIR << "/components.cif https://files.wwpdb.org/pub/pdb/data/monomers/components.cif.gz\n"
|
||||
<< "curl -o " << CACHE_DIR << "/mmcif_pdbx.dic https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz\n"
|
||||
<< "curl -o " << CACHE_DIR << "/components.cif https://files.wwpdb.org/pub/pdb/data/monomers/components.cif\n"
|
||||
<< "curl -o " << CACHE_DIR << "/mmcif_pdbx.dic https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic\n"
|
||||
<< "curl -o " << CACHE_DIR << "/mmcif_ma.dic https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic\n\n";
|
||||
#endif
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -60,6 +61,52 @@ bool is_item_type_uchar(const category &cat, std::string_view col)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// // index lookup
|
||||
// struct index_lookup_condition_impl : public condition_impl
|
||||
// {
|
||||
// index_lookup_condition_impl(row_initializer &&key_values)
|
||||
// : m_key_values(std::move(key_values))
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// condition_impl *prepare(const category &c) override
|
||||
// {
|
||||
// m_single_hit = c[m_key_values];
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// bool test(row_handle r) const override
|
||||
// {
|
||||
// return m_single_hit == r;
|
||||
// }
|
||||
//
|
||||
// void str(std::ostream &os) const override
|
||||
// {
|
||||
// os << "index scan";
|
||||
// }
|
||||
//
|
||||
// virtual std::optional<row_handle> single() const override
|
||||
// {
|
||||
// return m_single_hit;
|
||||
// }
|
||||
//
|
||||
// virtual bool equals(const condition_impl *rhs) const override
|
||||
// {
|
||||
// if (typeid(*rhs) == typeid(index_lookup_condition_impl))
|
||||
// {
|
||||
// auto ri = static_cast<const index_lookup_condition_impl *>(rhs);
|
||||
// if (m_single_hit or ri->m_single_hit)
|
||||
// return m_single_hit == ri->m_single_hit;
|
||||
// else
|
||||
// // watch out, both m_item_ix might be the same while item_names might be diffent (in case they both do not exist in the category)
|
||||
// return m_key_values == ri->m_key_values;
|
||||
// }
|
||||
// return this == rhs;
|
||||
// }
|
||||
//
|
||||
// row_initializer m_key_values;
|
||||
// row_handle m_single_hit;
|
||||
// };
|
||||
|
||||
condition_impl *key_equals_condition_impl::prepare(const category &c)
|
||||
{
|
||||
@@ -76,6 +123,21 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
condition_impl *key_equals_number_condition_impl::prepare(const category &c)
|
||||
{
|
||||
m_item_ix = c.get_item_ix(m_item_name);
|
||||
|
||||
if (c.get_cat_validator() != nullptr and
|
||||
c.key_item_indices().contains(m_item_ix) and
|
||||
c.key_item_indices().size() == 1)
|
||||
{
|
||||
item v(m_item_name, m_value);
|
||||
m_single_hit = c[{ { m_item_name, std::string{ v.value() }, false } }];
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
|
||||
{
|
||||
bool result = true;
|
||||
@@ -84,7 +146,8 @@ namespace detail
|
||||
{
|
||||
auto &cs = (*s)->m_sub;
|
||||
|
||||
if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i) { return i->equals(c); }) == cs.end())
|
||||
if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i)
|
||||
{ return i->equals(c); }) == cs.end())
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
@@ -101,27 +164,35 @@ namespace detail
|
||||
auto first = subs.front();
|
||||
auto &fc = first->m_sub;
|
||||
|
||||
for (auto c : fc)
|
||||
for (size_t fc_i = 0; fc_i < fc.size();)
|
||||
{
|
||||
auto c = fc[fc_i];
|
||||
if (not found_in_range(c, subs.begin() + 1, subs.end()))
|
||||
{
|
||||
++fc_i;
|
||||
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());
|
||||
fc.erase(fc.begin() + fc_i);
|
||||
|
||||
for (auto sub : subs)
|
||||
{
|
||||
auto &ssub = sub->m_sub;
|
||||
|
||||
for (auto sc : ssub)
|
||||
for (size_t ssub_i = 0; ssub_i < ssub.size();)
|
||||
{
|
||||
auto sc = ssub[ssub_i];
|
||||
if (not sc->equals(c))
|
||||
{
|
||||
++ssub_i;
|
||||
continue;
|
||||
|
||||
ssub.erase(remove(ssub.begin(), ssub.end(), sc), ssub.end());
|
||||
}
|
||||
|
||||
ssub.erase(ssub.begin() + ssub_i);
|
||||
delete sc;
|
||||
break;
|
||||
}
|
||||
@@ -137,6 +208,99 @@ namespace detail
|
||||
return oc;
|
||||
}
|
||||
|
||||
condition_impl *and_condition_impl::prepare(const category &c)
|
||||
{
|
||||
for (auto &sub : m_sub)
|
||||
sub = sub->prepare(c);
|
||||
|
||||
if (auto cv = c.get_cat_validator(); cv != nullptr)
|
||||
{
|
||||
// See if we can collapse a search part of this and_condition into a single index lookup
|
||||
|
||||
cif::iset keys{ cv->m_keys.begin(), cv->m_keys.end() };
|
||||
category::key_type lookup;
|
||||
std::vector<condition_impl *> subs;
|
||||
std::vector<std::string> may_be_empty;
|
||||
|
||||
for (auto &sub : m_sub)
|
||||
{
|
||||
if (auto s = dynamic_cast<const key_equals_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
lookup.emplace_back(s->m_item_name, s->m_value);
|
||||
subs.emplace_back(sub);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_number_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
item v{ s->m_item_name, s->m_value };
|
||||
lookup.emplace_back(s->m_item_name, std::string{ v.value() } );
|
||||
subs.emplace_back(sub);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_or_empty_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
lookup.emplace_back(s->m_item_name, s->m_value, true);
|
||||
subs.emplace_back(sub);
|
||||
may_be_empty.emplace_back(s->m_item_name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_number_or_empty_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
item v{ s->m_item_name, s->m_value };
|
||||
lookup.emplace_back(s->m_item_name, std::string{ v.value() }, true );
|
||||
subs.emplace_back(sub);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (lookup.size() == keys.size())
|
||||
{
|
||||
m_single = c[lookup];
|
||||
|
||||
for (auto s : subs)
|
||||
m_sub.erase(std::remove(m_sub.begin(), m_sub.end(), s), m_sub.end());
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool and_condition_impl::test(row_handle r) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (m_single.has_value() and *m_single != r)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (sub->test(r))
|
||||
continue;
|
||||
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
condition_impl *or_condition_impl::prepare(const category &c)
|
||||
{
|
||||
std::vector<and_condition_impl *> and_conditions;
|
||||
@@ -160,7 +324,7 @@ void condition::prepare(const category &c)
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl = m_impl->prepare(c);
|
||||
|
||||
|
||||
m_prepared = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -38,19 +39,10 @@ datablock::datablock(const datablock &db)
|
||||
cat.update_links(*this);
|
||||
}
|
||||
|
||||
datablock &datablock::operator=(const datablock &db)
|
||||
void datablock::load_dictionary()
|
||||
{
|
||||
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;
|
||||
if (auto *audit_conform = get("audit_conform"); audit_conform and not audit_conform->empty())
|
||||
set_validator(&validator_factory::instance().get(*audit_conform));
|
||||
}
|
||||
|
||||
void datablock::set_validator(const validator *v)
|
||||
@@ -64,6 +56,7 @@ void datablock::set_validator(const validator *v)
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
m_validator = nullptr;
|
||||
throw_with_nested(std::runtime_error("Error while setting validator in datablock " + m_name));
|
||||
}
|
||||
}
|
||||
@@ -76,7 +69,7 @@ const validator *datablock::get_validator() const
|
||||
bool datablock::is_valid() const
|
||||
{
|
||||
if (m_validator == nullptr)
|
||||
throw std::runtime_error("Validator not specified");
|
||||
throw std::runtime_error("Validator not specified for datablock data_" + name());
|
||||
|
||||
bool result = true;
|
||||
for (auto &cat : *this)
|
||||
@@ -85,50 +78,58 @@ bool datablock::is_valid() const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool datablock::is_valid()
|
||||
{
|
||||
if (m_validator == nullptr)
|
||||
throw std::runtime_error("Validator not specified");
|
||||
|
||||
bool result = true;
|
||||
for (auto &cat : *this)
|
||||
result = cat.is_valid() and result;
|
||||
|
||||
// Add or remove the audit_conform block here.
|
||||
if (result)
|
||||
{
|
||||
// If the dictionary declares an audit_conform category, put it in,
|
||||
// but only if it does not exist already!
|
||||
|
||||
if (m_validator->get_validator_for_category("audit_conform") != nullptr)
|
||||
{
|
||||
auto &audit_conform = operator[]("audit_conform");
|
||||
|
||||
audit_conform.clear();
|
||||
audit_conform.emplace({
|
||||
// clang-format off
|
||||
{ "dict_name", m_validator->name() },
|
||||
{ "dict_version", m_validator->version() }
|
||||
// clang-format on
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
erase(std::find_if(begin(), end(), [](category &cat) { return cat.name() == "audit_conform"; }), end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool datablock::validate_links() const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto &cat : *this)
|
||||
const_cast<category &>(cat).update_links(*this);
|
||||
|
||||
for (auto &cat : *this)
|
||||
result = cat.validate_links() and result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool datablock::strip()
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
// remove all categories that have no validator
|
||||
erase(std::remove_if(begin(), end(), [](category &c) {
|
||||
bool result = false;
|
||||
if (c.get_cat_validator() == nullptr)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Dropping category " << c.name() << '\n';
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}), end());
|
||||
|
||||
// then strip the remaining categories
|
||||
for (auto &cat : *this)
|
||||
cat.strip();
|
||||
|
||||
// Add or remove the audit_conform block here.
|
||||
if (is_valid())
|
||||
{
|
||||
// If the dictionary declares an audit_conform category, put it in,
|
||||
// but only if it does not exist already!
|
||||
|
||||
if (auto audit_conform = get("audit_conform");
|
||||
audit_conform != nullptr and m_validator->get_validator_for_category("audit_conform") != nullptr)
|
||||
{
|
||||
audit_conform->clear();
|
||||
m_validator->fill_audit_conform(*audit_conform);
|
||||
}
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
category &datablock::operator[](std::string_view name)
|
||||
@@ -185,11 +186,16 @@ std::tuple<datablock::iterator, bool> datablock::emplace(std::string_view name)
|
||||
|
||||
if (is_new)
|
||||
{
|
||||
i = insert(end(), {name});
|
||||
i = insert(end(), { name });
|
||||
i->set_validator(m_validator, *this);
|
||||
}
|
||||
|
||||
assert(i != end());
|
||||
|
||||
// links may have changed...
|
||||
for (auto &cat : *this)
|
||||
cat.update_links(*this);
|
||||
|
||||
return std::make_tuple(i, is_new);
|
||||
}
|
||||
|
||||
@@ -282,7 +288,11 @@ void datablock::write(std::ostream &os) const
|
||||
cat_order_t cat_order;
|
||||
|
||||
for (auto &cat : *this)
|
||||
{
|
||||
if (cat.name() == "entry" or cat.name() == "audit_conform")
|
||||
continue;
|
||||
cat_order.emplace_back(cat.name(), -1, false);
|
||||
}
|
||||
|
||||
for (auto i = cat_order.begin(); i != cat_order.end(); ++i)
|
||||
calculate_cat_order(cat_order, i, *m_validator);
|
||||
@@ -292,25 +302,18 @@ void datablock::write(std::ostream &os) const
|
||||
const auto &[cat_a, count_a, on_stack_a] = a;
|
||||
const auto &[cat_b, count_b, on_stack_b] = b;
|
||||
|
||||
int d = 0;
|
||||
|
||||
if (cat_a == "audit_conform")
|
||||
d = -1;
|
||||
else if (cat_b == "audit_conform")
|
||||
d = 1;
|
||||
else if (cat_a == "entry")
|
||||
d = -1;
|
||||
else if (cat_b == "entry")
|
||||
d = 1;
|
||||
else
|
||||
{
|
||||
d = std::get<1>(a) - std::get<1>(b);
|
||||
if (d == 0)
|
||||
d = cat_b.compare(cat_a);
|
||||
}
|
||||
int d = std::get<1>(a) - std::get<1>(b);
|
||||
if (d == 0)
|
||||
d = cat_b.compare(cat_a);
|
||||
|
||||
return d < 0; });
|
||||
|
||||
if (auto entry = get("entry"); entry != nullptr)
|
||||
entry->write(os);
|
||||
|
||||
if (auto audit_conform = get("audit_conform"); audit_conform != nullptr)
|
||||
audit_conform->write(os);
|
||||
|
||||
for (auto &&[cat, count, on_stack] : cat_order)
|
||||
get(cat)->write(os);
|
||||
}
|
||||
@@ -320,20 +323,13 @@ void datablock::write(std::ostream &os) const
|
||||
// and if it exists, _AND_ we have a Validator, write out the
|
||||
// audit_conform record.
|
||||
|
||||
for (auto &cat : *this)
|
||||
{
|
||||
if (cat.name() != "entry")
|
||||
continue;
|
||||
|
||||
cat.write(os);
|
||||
|
||||
break;
|
||||
}
|
||||
if (auto entry = get("entry"); entry != nullptr)
|
||||
entry->write(os);
|
||||
|
||||
// If the dictionary declares an audit_conform category, put it in,
|
||||
// but only if it does not exist already!
|
||||
if (get("audit_conform"))
|
||||
get("audit_conform")->write(os);
|
||||
if (auto audit_conform = get("audit_conform"); audit_conform != nullptr)
|
||||
audit_conform->write(os);
|
||||
|
||||
for (auto &cat : *this)
|
||||
{
|
||||
@@ -348,7 +344,7 @@ void datablock::write(std::ostream &os, const std::vector<std::string> &item_nam
|
||||
os << "data_" << m_name << '\n'
|
||||
<< "# \n";
|
||||
|
||||
std::vector<std::string> cat_order;
|
||||
std::vector<std::string> cat_order{ "entry", "audit_conform" };
|
||||
for (auto &o : item_name_order)
|
||||
{
|
||||
std::string cat_name, item_name;
|
||||
@@ -459,4 +455,4 @@ bool datablock::operator==(const datablock &rhs) const
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -96,14 +96,10 @@ class dictionary_parser : public parser
|
||||
link_items();
|
||||
|
||||
// store meta information
|
||||
datablock::iterator info;
|
||||
bool is_new;
|
||||
std::tie(info, is_new) = m_datablock->emplace("dictionary");
|
||||
if (not is_new and not info->empty())
|
||||
if (auto dictionary = m_datablock->get("dictionary"); dictionary != nullptr and not dictionary->empty())
|
||||
{
|
||||
auto r = info->front();
|
||||
m_validator.set_name(r["title"].as<std::string>());
|
||||
m_validator.set_version(r["version"].as<std::string>());
|
||||
const auto &[name, version] = dictionary->front().get<std::string,std::optional<std::string>>("title", "version");
|
||||
m_validator.append_audit_conform(name, version);
|
||||
}
|
||||
|
||||
m_datablock = savedDatablock;
|
||||
@@ -252,7 +248,7 @@ class dictionary_parser : public parser
|
||||
|
||||
auto vi = find(ivs.begin(), ivs.end(), item_validator{ item_name });
|
||||
if (vi == ivs.end())
|
||||
ivs.push_back(item_validator{ item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, nullptr, std::move(aliases) });
|
||||
ivs.push_back(item_validator{ item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, cat_name, std::move(aliases) });
|
||||
else
|
||||
{
|
||||
// need to update the itemValidator?
|
||||
@@ -308,17 +304,17 @@ class dictionary_parser : public parser
|
||||
|
||||
using key_type = std::tuple<std::string, std::string, int>;
|
||||
|
||||
std::map<key_type, size_t> linkIndex;
|
||||
std::map<key_type, std::size_t> linkIndex;
|
||||
|
||||
// Each link group consists of a set of keys
|
||||
std::vector<std::tuple<std::vector<std::string>, std::vector<std::string>>> linkKeys;
|
||||
|
||||
auto addLink = [&](size_t ix, const std::string &pk, const std::string &ck)
|
||||
auto addLink = [&](std::size_t ix, const std::string &pk, const std::string &ck)
|
||||
{
|
||||
auto &&[pkeys, ckeys] = linkKeys.at(ix);
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < pkeys.size(); ++i)
|
||||
for (std::size_t i = 0; i < pkeys.size(); ++i)
|
||||
{
|
||||
if (pkeys[i] == pk and ckeys[i] == ck)
|
||||
{
|
||||
@@ -350,14 +346,14 @@ class dictionary_parser : public parser
|
||||
if (piv == nullptr)
|
||||
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
|
||||
|
||||
key_type key{ piv->m_category->m_name, civ->m_category->m_name, link_group_id };
|
||||
key_type key{ piv->m_category, civ->m_category, link_group_id };
|
||||
if (not linkIndex.count(key))
|
||||
{
|
||||
linkIndex[key] = linkKeys.size();
|
||||
linkKeys.push_back({});
|
||||
}
|
||||
|
||||
size_t ix = linkIndex.at(key);
|
||||
std::size_t ix = linkIndex.at(key);
|
||||
addLink(ix, piv->m_item_name, civ->m_item_name);
|
||||
}
|
||||
|
||||
@@ -378,14 +374,14 @@ class dictionary_parser : public parser
|
||||
if (piv == nullptr)
|
||||
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
|
||||
|
||||
key_type key{ piv->m_category->m_name, civ->m_category->m_name, 0 };
|
||||
key_type key{ piv->m_category, civ->m_category, 0 };
|
||||
if (not linkIndex.count(key))
|
||||
{
|
||||
linkIndex[key] = linkKeys.size();
|
||||
linkKeys.push_back({});
|
||||
}
|
||||
|
||||
size_t ix = linkIndex.at(key);
|
||||
std::size_t ix = linkIndex.at(key);
|
||||
addLink(ix, piv->m_item_name, civ->m_item_name);
|
||||
}
|
||||
}
|
||||
@@ -477,18 +473,7 @@ class dictionary_parser : public parser
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator parse_dictionary(std::string_view name, std::istream &is)
|
||||
{
|
||||
validator result(name);
|
||||
|
||||
file f;
|
||||
dictionary_parser p(result, is, f);
|
||||
p.load_dictionary();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void extend_dictionary(validator &v, std::istream &is)
|
||||
void parse_dictionary(validator &v, std::istream &is)
|
||||
{
|
||||
file f;
|
||||
dictionary_parser p(v, is, f);
|
||||
|
||||
98
src/file.cpp
98
src/file.cpp
@@ -30,19 +30,8 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
void file::set_validator(const validator *v)
|
||||
{
|
||||
m_validator = v;
|
||||
for (auto &db : *this)
|
||||
db.set_validator(v);
|
||||
}
|
||||
|
||||
bool file::is_valid() const
|
||||
{
|
||||
if (m_validator == nullptr)
|
||||
std::runtime_error("No validator loaded explicitly, cannot continue");
|
||||
|
||||
bool result = true;
|
||||
for (auto &d : *this)
|
||||
result = d.is_valid() and result;
|
||||
@@ -55,14 +44,6 @@ bool file::is_valid() const
|
||||
|
||||
bool file::is_valid()
|
||||
{
|
||||
if (m_validator == nullptr)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "No dictionary loaded explicitly, loading default\n";
|
||||
|
||||
load_dictionary();
|
||||
}
|
||||
|
||||
bool result = not empty();
|
||||
|
||||
for (auto &d : *this)
|
||||
@@ -76,56 +57,18 @@ bool file::is_valid()
|
||||
|
||||
bool file::validate_links() const
|
||||
{
|
||||
if (m_validator == nullptr)
|
||||
std::runtime_error("No validator loaded explicitly, cannot continue");
|
||||
|
||||
bool result = true;
|
||||
|
||||
for (auto &db : *this)
|
||||
result = db.validate_links() and result;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void file::load_dictionary()
|
||||
{
|
||||
if (not empty())
|
||||
{
|
||||
auto *audit_conform = front().get("audit_conform");
|
||||
if (audit_conform and not audit_conform->empty())
|
||||
{
|
||||
std::string name = audit_conform->front().get<std::string>("dict_name");
|
||||
|
||||
if (name == "mmcif_pdbx_v50")
|
||||
name = "mmcif_pdbx.dic"; // we had a bug here in libcifpp...
|
||||
|
||||
if (not name.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
load_dictionary(name);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
if (VERBOSE)
|
||||
std::cerr << "Failed to load dictionary " << std::quoted(name) << ": " << ex.what() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (not m_validator)
|
||||
// load_dictionary("mmcif_pdbx.dic"); // TODO: maybe incorrect? Perhaps improve?
|
||||
}
|
||||
|
||||
void file::load_dictionary(std::string_view name)
|
||||
{
|
||||
set_validator(&validator_factory::instance()[name]);
|
||||
}
|
||||
|
||||
bool file::contains(std::string_view name) const
|
||||
{
|
||||
return std::find_if(begin(), end(), [name](const datablock &db) { return iequals(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)
|
||||
@@ -165,10 +108,7 @@ std::tuple<file::iterator, bool> file::emplace(std::string_view name)
|
||||
}
|
||||
|
||||
if (is_new)
|
||||
{
|
||||
i = insert(end(), { name });
|
||||
i->set_validator(m_validator);
|
||||
}
|
||||
|
||||
assert(i != end());
|
||||
return std::make_tuple(i, is_new);
|
||||
@@ -190,18 +130,34 @@ void file::load(const std::filesystem::path &p)
|
||||
}
|
||||
}
|
||||
|
||||
void file::load(std::istream &is)
|
||||
void file::load(const std::filesystem::path &p, const validator &v)
|
||||
{
|
||||
auto saved = m_validator;
|
||||
set_validator(nullptr);
|
||||
gzio::ifstream in(p);
|
||||
if (not in.is_open())
|
||||
throw std::runtime_error("Could not open file '" + p.string() + '\'');
|
||||
|
||||
try
|
||||
{
|
||||
load(in, v);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
throw_with_nested(std::runtime_error("Error reading file '" + p.string() + '\''));
|
||||
}
|
||||
}
|
||||
|
||||
void file::load(std::istream &is, const validator &v)
|
||||
{
|
||||
parser p(is, *this);
|
||||
p.parse_file();
|
||||
for (auto &db : *this)
|
||||
db.set_validator(&v);
|
||||
}
|
||||
|
||||
if (saved != nullptr)
|
||||
set_validator(saved);
|
||||
else
|
||||
load_dictionary();
|
||||
void file::load(std::istream &is)
|
||||
{
|
||||
parser p(is, *this);
|
||||
p.parse_file();
|
||||
}
|
||||
|
||||
void file::save(const std::filesystem::path &p) const
|
||||
@@ -219,4 +175,4 @@ void file::save(std::ostream &os) const
|
||||
db.write(os);
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -52,10 +52,10 @@ std::string_view item_handle::text() const
|
||||
return {};
|
||||
}
|
||||
|
||||
void item_handle::assign_value(const item &v)
|
||||
void item_handle::assign_value(std::string_view value)
|
||||
{
|
||||
assert(not m_row_handle.empty());
|
||||
m_row_handle.assign(m_item_ix, v.value(), true);
|
||||
m_row_handle.assign(m_item_ix, value, true);
|
||||
}
|
||||
|
||||
void item_handle::swap(item_handle &b)
|
||||
|
||||
1140
src/model.cpp
1140
src/model.cpp
File diff suppressed because it is too large
Load Diff
@@ -837,6 +837,9 @@ void parser::produce_datablock(std::string_view name)
|
||||
|
||||
const auto &[iter, ignore] = m_file.emplace(name);
|
||||
m_datablock = &(*iter);
|
||||
|
||||
if (m_validator)
|
||||
m_datablock->set_validator(m_validator);
|
||||
}
|
||||
|
||||
void parser::produce_category(std::string_view name)
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
@@ -58,9 +57,9 @@ std::string cif2pdbDate(const std::string &d)
|
||||
int month = std::stoi(m[2].str());
|
||||
|
||||
if (m[3].matched)
|
||||
result = cif::format("%02.2d-%3.3s-%02.2d", stoi(m[3].str()), kMonths[month - 1], (year % 100)).str();
|
||||
result = std::format("%02.2d-%3.3s-%02.2d", stoi(m[3].str()), kMonths[month - 1], (year % 100));
|
||||
else
|
||||
result = cif::format("%3.3s-%02.2d", kMonths[month - 1], (year % 100)).str();
|
||||
result = std::format("%3.3s-%02.2d", kMonths[month - 1], (year % 100));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -182,7 +181,7 @@ std::vector<std::string> MapAsymIDs2ChainIDs(const std::vector<std::string> &asy
|
||||
}
|
||||
|
||||
// support for wrapping text using a 'continuation marker'
|
||||
size_t WriteContinuedLine(std::ostream &pdbFile, std::string header, int &count, int cLen, std::string text, std::string::size_type lStart = 0)
|
||||
std::size_t WriteContinuedLine(std::ostream &pdbFile, std::string header, int &count, int cLen, std::string text, std::string::size_type lStart = 0)
|
||||
{
|
||||
if (lStart == 0)
|
||||
{
|
||||
@@ -217,15 +216,15 @@ size_t WriteContinuedLine(std::ostream &pdbFile, std::string header, int &count,
|
||||
return lines.size();
|
||||
}
|
||||
|
||||
size_t WriteOneContinuedLine(std::ostream &pdbFile, std::string header, int cLen, std::string line, int lStart = 0)
|
||||
std::size_t WriteOneContinuedLine(std::ostream &pdbFile, std::string header, int cLen, std::string line, int lStart = 0)
|
||||
{
|
||||
int count = 0;
|
||||
return WriteContinuedLine(pdbFile, header, count, cLen, line, lStart);
|
||||
}
|
||||
|
||||
size_t WriteCitation(std::ostream &pdbFile, const datablock &db, row_handle r, int reference)
|
||||
std::size_t WriteCitation(std::ostream &pdbFile, const datablock &db, row_handle r, int reference)
|
||||
{
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
|
||||
std::string s1;
|
||||
|
||||
@@ -258,16 +257,14 @@ size_t WriteCitation(std::ostream &pdbFile, const datablock &db, row_handle r, i
|
||||
{
|
||||
to_upper(pubname);
|
||||
|
||||
const std::string kRefHeader = s1 + "REF %2.2s %-28.28s %2.2s%4.4s %5.5s %4.4s";
|
||||
pdbFile << cif::format(kRefHeader, "" /* continuation */, pubname, (volume.empty() ? "" : "V."), volume, pageFirst, year)
|
||||
pdbFile << s1 + std::format("REF %2.2s %-28.28s %2.2s%4.4s %5.5s %4.4s", "" /* continuation */, pubname, (volume.empty() ? "" : "V."), volume, pageFirst, year)
|
||||
<< '\n';
|
||||
++result;
|
||||
}
|
||||
|
||||
if (not issn.empty())
|
||||
{
|
||||
const std::string kRefHeader = s1 + "REFN ISSN %-25.25s";
|
||||
pdbFile << cif::format(kRefHeader, issn) << '\n';
|
||||
pdbFile << s1 + std::format("REFN ISSN %-25.25s", issn) << '\n';
|
||||
++result;
|
||||
}
|
||||
|
||||
@@ -278,25 +275,23 @@ size_t WriteCitation(std::ostream &pdbFile, const datablock &db, row_handle r, i
|
||||
// const char kRefHeader[] =
|
||||
// "REMARK 1 REFN %4.4s %-6.6s %2.2s %-25.25s";
|
||||
//
|
||||
// pdbFile << (boost::cif::format(kRefHeader)
|
||||
// pdbFile << (boost::std::format(kRefHeader)
|
||||
// % (astm.empty() ? "" : "ASTN")
|
||||
// % astm
|
||||
// % country
|
||||
// % issn).str()
|
||||
// % issn)
|
||||
// << '\n';
|
||||
// }
|
||||
|
||||
if (not pmid.empty())
|
||||
{
|
||||
const std::string kPMID = s1 + "PMID %-60.60s ";
|
||||
pdbFile << cif::format(kPMID, pmid) << '\n';
|
||||
pdbFile << s1 + std::format("PMID %-60.60s ", pmid) << '\n';
|
||||
++result;
|
||||
}
|
||||
|
||||
if (not doi.empty())
|
||||
{
|
||||
const std::string kDOI = s1 + "DOI %-60.60s ";
|
||||
pdbFile << cif::format(kDOI, doi) << '\n';
|
||||
pdbFile << s1 + std::format("DOI %-60.60s ", doi) << '\n';
|
||||
++result;
|
||||
}
|
||||
|
||||
@@ -307,10 +302,10 @@ void write_header_lines(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// HEADER xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDDDDDDDDD IIII
|
||||
const char kHeader[] =
|
||||
"HEADER %-40.40s"
|
||||
"%-9.9s"
|
||||
" %-4.4s";
|
||||
// const char kHeader[] =
|
||||
// "HEADER %-40.40s"
|
||||
// "%-9.9s"
|
||||
// " %-4.4s";
|
||||
|
||||
// HEADER
|
||||
|
||||
@@ -345,7 +340,12 @@ void write_header_lines(std::ostream &pdbFile, const datablock &db)
|
||||
}
|
||||
}
|
||||
|
||||
pdbFile << cif::format(kHeader, keywords, date, db.name()) << '\n';
|
||||
pdbFile << std::format(/* kHeader */
|
||||
"HEADER %-40.40s"
|
||||
"%-9.9s"
|
||||
" %-4.4s"
|
||||
|
||||
, keywords, date, db.name()) << '\n';
|
||||
|
||||
// TODO: implement
|
||||
// OBSLTE (skip for now)
|
||||
@@ -535,7 +535,6 @@ void WriteTitle(std::ostream &pdbFile, const datablock &db)
|
||||
write_header_lines(pdbFile, db);
|
||||
|
||||
// REVDAT
|
||||
const char kRevDatFmt[] = "REVDAT %3d%2.2s %9.9s %4.4s %1d ";
|
||||
auto &cat2 = db["database_PDB_rev"];
|
||||
std::vector<row_handle> rev(cat2.begin(), cat2.end());
|
||||
sort(rev.begin(), rev.end(), [](row_handle a, row_handle b) -> bool
|
||||
@@ -559,9 +558,9 @@ void WriteTitle(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
std::string cs = ++continuation > 1 ? std::to_string(continuation) : std::string();
|
||||
|
||||
pdbFile << cif::format(kRevDatFmt, revNum, cs, date, db.name(), modType);
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
pdbFile << cif::format(" %-6.6s", (i < types.size() ? types[i] : std::string()));
|
||||
pdbFile << std::format("REVDAT %3d%2.2s %9.9s %4.4s %1d ", revNum, cs, date, db.name(), modType);
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
pdbFile << std::format(" %-6.6s", (i < types.size() ? types[i] : std::string()));
|
||||
pdbFile << '\n';
|
||||
|
||||
if (types.size() > 4)
|
||||
@@ -614,7 +613,7 @@ void WriteRemark2(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
float resHigh = refine.front()["ls_d_res_high"].as<float>();
|
||||
pdbFile << "REMARK 2\n"
|
||||
<< cif::format("REMARK 2 RESOLUTION. %7.2f ANGSTROMS.", resHigh) << '\n';
|
||||
<< std::format("REMARK 2 RESOLUTION. %7.2f ANGSTROMS.", resHigh) << '\n';
|
||||
}
|
||||
catch (...)
|
||||
{ /* skip it */
|
||||
@@ -681,7 +680,7 @@ class Fi : public FBase
|
||||
{
|
||||
long l = 0;
|
||||
auto r = std::from_chars(s.data(), s.data() + s.length(), l);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Failed to write '" << s << "' as a long from field " << mField << ", this indicates an error in the code for writing PDB files\n";
|
||||
@@ -719,7 +718,7 @@ class Ff : public FBase
|
||||
|
||||
double d = 0;
|
||||
auto r = cif::from_chars(s.data(), s.data() + s.length(), d);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Failed to write '" << s << "' as a double from field " << mField << ", this indicates an error in the code for writing PDB files\n";
|
||||
@@ -748,7 +747,7 @@ class Fs : public FBase
|
||||
virtual void out(std::ostream &os)
|
||||
{
|
||||
std::string s{ text() };
|
||||
size_t width = os.width();
|
||||
std::size_t width = os.width();
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
@@ -761,10 +760,7 @@ class Fs : public FBase
|
||||
else
|
||||
{
|
||||
os << '\n';
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "REMARK " << std::setw(3) << std::right << mNr << ' ';
|
||||
WriteOneContinuedLine(os, ss.str(), 0, s);
|
||||
WriteOneContinuedLine(os, std::format("REMARK {:3} ", mNr), 0, s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1617,7 +1613,7 @@ void WriteRemark3Phenix(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
percent_reflns_obs /= 100;
|
||||
|
||||
pdbFile << RM3(" ") << cif::format("%3d %7.4f - %7.4f %4.2f %8d %5d %6.4f %6.4f", bin++, d_res_low, d_res_high, percent_reflns_obs, number_reflns_R_work, number_reflns_R_free, R_factor_R_work, R_factor_R_free) << '\n';
|
||||
pdbFile << RM3(" ") << std::format("%3d %7.4f - %7.4f %4.2f %8d %5d %6.4f %6.4f", bin++, d_res_low, d_res_high, percent_reflns_obs, number_reflns_R_work, number_reflns_R_free, R_factor_R_work, R_factor_R_free) << '\n';
|
||||
}
|
||||
|
||||
pdbFile << RM3("") << '\n'
|
||||
@@ -2368,7 +2364,7 @@ void WriteRemark280(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
const char *keys[] = { "pdbx_details", "ph", "method", "temp" };
|
||||
|
||||
for (size_t i = 0; i < (sizeof(keys) / sizeof(const char *)); ++i)
|
||||
for (std::size_t i = 0; i < (sizeof(keys) / sizeof(const char *)); ++i)
|
||||
{
|
||||
const char *c = keys[i];
|
||||
|
||||
@@ -2585,7 +2581,7 @@ void WriteRemark465(std::ostream &pdbFile, const datablock &db)
|
||||
cif::tie(modelNr, resName, chainID, iCode, seqNr) =
|
||||
r.get("PDB_model_num", "auth_comp_id", "auth_asym_id", "PDB_ins_code", "auth_seq_id");
|
||||
|
||||
pdbFile << cif::format("REMARK 465 %3.3s %3.3s %1.1s %5d%1.1s", modelNr, resName, chainID, seqNr, iCode) << '\n';
|
||||
pdbFile << std::format("REMARK 465 %3.3s %3.3s %1.1s %5d%1.1s", modelNr, resName, chainID, seqNr, iCode) << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2632,9 +2628,9 @@ void WriteRemark470(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
while (not a.second.empty())
|
||||
{
|
||||
pdbFile << cif::format("REMARK 470 %3.3s %3.3s %1.1s%4d%1.1s ", modelNr, resName, chainID, seqNr, iCode) << " ";
|
||||
pdbFile << std::format("REMARK 470 %3.3s %3.3s %1.1s%4d%1.1s ", modelNr, resName, chainID, seqNr, iCode) << " ";
|
||||
|
||||
for (size_t i = 0; i < 6 and not a.second.empty(); ++i)
|
||||
for (std::size_t i = 0; i < 6 and not a.second.empty(); ++i)
|
||||
{
|
||||
pdbFile << cif2pdbAtomName(a.second.front(), resName, db) << ' ';
|
||||
a.second.pop_front();
|
||||
@@ -2729,16 +2725,16 @@ int WritePrimaryStructure(std::ostream &pdbFile, const datablock &db)
|
||||
"pdbx_seq_align_end_ins_code", "pdbx_db_accession", "db_align_beg", "pdbx_db_align_beg_ins_code", "db_align_end", "pdbx_db_align_end_ins_code");
|
||||
|
||||
if (dbAccession.length() > 8 or db_code.length() > 12 or atoi(dbseqEnd.c_str()) >= 100000)
|
||||
pdbFile << cif::format(
|
||||
pdbFile << std::format(
|
||||
"DBREF1 %4.4s %1.1s %4.4s%1.1s %4.4s%1.1s %-6.6s %-20.20s",
|
||||
idCode, chainID, seqBegin, insertBegin, seqEnd, insertEnd, db_name, db_code)
|
||||
<< '\n'
|
||||
<< cif::format(
|
||||
<< std::format(
|
||||
"DBREF2 %4.4s %1.1s %-22.22s %10.10s %10.10s",
|
||||
idCode, chainID, dbAccession, dbseqBegin, dbseqEnd)
|
||||
<< '\n';
|
||||
else
|
||||
pdbFile << cif::format(
|
||||
pdbFile << std::format(
|
||||
"DBREF %4.4s %1.1s %4.4s%1.1s %4.4s%1.1s %-6.6s %-8.8s %-12.12s %5.5s%1.1s %5.5s%1.1s",
|
||||
idCode, chainID, seqBegin, insertBegin, seqEnd, insertEnd, db_name, dbAccession, db_code, dbseqBegin, dbinsBeg, dbseqEnd, dbinsEnd)
|
||||
<< '\n';
|
||||
@@ -2757,10 +2753,9 @@ int WritePrimaryStructure(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
to_upper(conflict);
|
||||
|
||||
pdbFile << cif::format(
|
||||
pdbFile << std::format(
|
||||
"SEQADV %4.4s %3.3s %1.1s %4.4s%1.1s %-4.4s %-9.9s %3.3s %5.5s %-21.21s",
|
||||
idCode, resName, chainID, seqNum, iCode, database, dbAccession, dbRes, dbSeq, conflict)
|
||||
.str()
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
@@ -2787,7 +2782,7 @@ int WritePrimaryStructure(std::ostream &pdbFile, const datablock &db)
|
||||
if (t > 13)
|
||||
t = 13;
|
||||
|
||||
pdbFile << cif::format(
|
||||
pdbFile << std::format(
|
||||
"SEQRES %3d %1.1s %4d %-51.51s ",
|
||||
n++, std::string{ chainID }, seqresl[chainID], join(seq.begin(), seq.begin() + t, " "))
|
||||
<< '\n';
|
||||
@@ -2807,10 +2802,9 @@ int WritePrimaryStructure(std::ostream &pdbFile, const datablock &db)
|
||||
cif::tie(chainID, seqNum, resName, iCode, stdRes, comment) =
|
||||
r.get("auth_asym_id", "auth_seq_id", "auth_comp_id", "PDB_ins_code", "parent_comp_id", "details");
|
||||
|
||||
pdbFile << cif::format(
|
||||
pdbFile << std::format(
|
||||
"MODRES %4.4s %3.3s %1.1s %4.4s%1.1s %3.3s %-41.41s",
|
||||
db.name(), resName, chainID, seqNum, iCode, stdRes, comment)
|
||||
.str()
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
@@ -2925,7 +2919,7 @@ int WriteHeterogen(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
if (h.water)
|
||||
continue;
|
||||
pdbFile << cif::format("HET %3.3s %c%4d%c %5d", h.hetID, h.chainID, h.seqNum, h.iCode, h.numHetAtoms) << '\n';
|
||||
pdbFile << std::format("HET %3.3s %c%4d%c %5d", h.hetID, h.chainID, h.seqNum, h.iCode, h.numHetAtoms) << '\n';
|
||||
++numHet;
|
||||
}
|
||||
|
||||
@@ -2940,7 +2934,7 @@ int WriteHeterogen(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pdbFile << cif::format("HETNAM %2.2s %3.3s ", (c > 1 ? std::to_string(c) : std::string()), id);
|
||||
pdbFile << std::format("HETNAM %2.2s %3.3s ", (c > 1 ? std::to_string(c) : std::string()), id);
|
||||
++c;
|
||||
|
||||
if (name.length() > 55)
|
||||
@@ -3032,7 +3026,7 @@ int WriteHeterogen(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
std::stringstream fs;
|
||||
|
||||
fs << cif::format("FORMUL %2d %3.3s %2.2s%c", componentNr, hetID, (c > 1 ? std::to_string(c) : std::string()), (hetID == water_comp_id ? '*' : ' '));
|
||||
fs << std::format("FORMUL %2d %3.3s %2.2s%c", componentNr, hetID, (c > 1 ? std::to_string(c) : std::string()), (hetID == water_comp_id ? '*' : ' '));
|
||||
++c;
|
||||
|
||||
if (formula.length() > 51)
|
||||
@@ -3099,7 +3093,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
|
||||
"pdbx_PDB_helix_class", "pdbx_PDB_helix_length", "beg_auth_seq_id", "end_auth_seq_id");
|
||||
|
||||
++numHelix;
|
||||
pdbFile << cif::format("HELIX %3d %3.3s %3.3s %1.1s %4d%1.1s %3.3s %1.1s %4d%1.1s%2d%-30.30s %5d",
|
||||
pdbFile << std::format("HELIX %3d %3.3s %3.3s %1.1s %4d%1.1s %3.3s %1.1s %4d%1.1s%2d%-30.30s %5d",
|
||||
numHelix, pdbx_PDB_helix_id, beg_label_comp_id, beg_auth_asym_id, beg_auth_seq_id, pdbx_beg_PDB_ins_code, end_label_comp_id, end_auth_asym_id, end_auth_seq_id, pdbx_end_PDB_ins_code, pdbx_PDB_helix_class, details, pdbx_PDB_helix_length)
|
||||
<< '\n';
|
||||
}
|
||||
@@ -3136,7 +3130,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
|
||||
"pdbx_end_PDB_ins_code", "beg_auth_comp_id", "beg_auth_asym_id", "beg_auth_seq_id",
|
||||
"end_auth_comp_id", "end_auth_asym_id", "end_auth_seq_id");
|
||||
|
||||
pdbFile << cif::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d", rangeID1, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, 0) << '\n';
|
||||
pdbFile << std::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d", rangeID1, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, 0) << '\n';
|
||||
|
||||
first = false;
|
||||
}
|
||||
@@ -3155,7 +3149,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
|
||||
|
||||
if (h.empty())
|
||||
{
|
||||
pdbFile << cif::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d", rangeID2, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, sense) << '\n';
|
||||
pdbFile << std::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d", rangeID2, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, sense) << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3168,7 +3162,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
|
||||
curAtom = cif2pdbAtomName(curAtom, compID[0], db);
|
||||
prevAtom = cif2pdbAtomName(prevAtom, compID[1], db);
|
||||
|
||||
pdbFile << cif::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d "
|
||||
pdbFile << std::format("SHEET %3.3s %3.3s%2d %3.3s %1.1s%4d%1.1s %3.3s %1.1s%4d%1.1s%2d "
|
||||
"%-4.4s%3.3s %1.1s%4d%1.1s %-4.4s%3.3s %1.1s%4d%1.1s",
|
||||
rangeID2, sheetID, numStrands, initResName, initChainID, initSeqNum, initICode, endResName, endChainID, endSeqNum, endICode, sense, curAtom, curResName, curChainID, curResSeq, curICode, prevAtom, prevResName, prevChainID, prevResSeq, prevICode)
|
||||
<< '\n';
|
||||
@@ -3207,7 +3201,7 @@ void WriteConnectivity(std::ostream &pdbFile, const datablock &db)
|
||||
sym1 = cif2pdbSymmetry(sym1);
|
||||
sym2 = cif2pdbSymmetry(sym2);
|
||||
|
||||
pdbFile << cif::format("SSBOND %3d CYS %1.1s %4d%1.1s CYS %1.1s %4d%1.1s %6.6s %6.6s %5.2f", nr, chainID1, seqNum1, icode1, chainID2, seqNum2, icode2, sym1, sym2, Length) << '\n';
|
||||
pdbFile << std::format("SSBOND %3d CYS %1.1s %4d%1.1s CYS %1.1s %4d%1.1s %6.6s %6.6s %5.2f", nr, chainID1, seqNum1, icode1, chainID2, seqNum2, icode2, sym1, sym2, Length) << '\n';
|
||||
|
||||
++nr;
|
||||
}
|
||||
@@ -3234,10 +3228,10 @@ void WriteConnectivity(std::ostream &pdbFile, const datablock &db)
|
||||
sym1 = cif2pdbSymmetry(sym1);
|
||||
sym2 = cif2pdbSymmetry(sym2);
|
||||
|
||||
pdbFile << cif::format("LINK %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %6.6s %6.6s", name1, altLoc1, resName1, chainID1, resSeq1, iCode1, name2, altLoc2, resName2, chainID2, resSeq2, iCode2, sym1, sym2);
|
||||
pdbFile << std::format("LINK %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %6.6s %6.6s", name1, altLoc1, resName1, chainID1, resSeq1, iCode1, name2, altLoc2, resName2, chainID2, resSeq2, iCode2, sym1, sym2);
|
||||
|
||||
if (not Length.empty())
|
||||
pdbFile << cif::format(" %5.2f", stod(Length));
|
||||
pdbFile << std::format(" %5.2f", stod(Length));
|
||||
|
||||
pdbFile << '\n';
|
||||
}
|
||||
@@ -3255,7 +3249,7 @@ void WriteConnectivity(std::ostream &pdbFile, const datablock &db)
|
||||
"pdbx_label_comp_id_2", "pdbx_auth_asym_id_2", "pdbx_auth_seq_id_2", "pdbx_PDB_ins_code_2",
|
||||
"pdbx_PDB_model_num", "pdbx_omega_angle");
|
||||
|
||||
pdbFile << cif::format("CISPEP %3.3s %3.3s %1.1s %4d%1.1s %3.3s %1.1s %4d%1.1s %3.3s %6.2f",
|
||||
pdbFile << std::format("CISPEP %3.3s %3.3s %1.1s %4d%1.1s %3.3s %1.1s %4d%1.1s %3.3s %6.2f",
|
||||
serNum, pep1, chainID1, seqNum1, icode1, pep2, chainID2, seqNum2, icode2, modNum, measure) << '\n';
|
||||
}
|
||||
}
|
||||
@@ -3276,7 +3270,7 @@ int WriteMiscellaneousFeatures(std::ostream &pdbFile, const datablock &db)
|
||||
cif::tie(siteID, resName, chainID, seq, iCode) =
|
||||
r.get("site_id", "auth_comp_id", "auth_asym_id", "auth_seq_id", "pdbx_auth_ins_code");
|
||||
|
||||
sites[siteID].push_back(cif::format("%3.3s %1.1s%4d%1.1s ", resName, chainID, seq, iCode).str());
|
||||
sites[siteID].push_back(std::format("%3.3s %1.1s%4d%1.1s ", resName, chainID, seq, iCode));
|
||||
}
|
||||
|
||||
for (auto s : sites)
|
||||
@@ -3284,12 +3278,12 @@ int WriteMiscellaneousFeatures(std::ostream &pdbFile, const datablock &db)
|
||||
std::string siteID = std::get<0>(s);
|
||||
std::deque<std::string> &res = std::get<1>(s);
|
||||
|
||||
size_t numRes = res.size();
|
||||
std::size_t numRes = res.size();
|
||||
|
||||
int nr = 1;
|
||||
while (res.empty() == false)
|
||||
{
|
||||
pdbFile << cif::format("SITE %3d %3.3s %2d ", nr, siteID, numRes);
|
||||
pdbFile << std::format("SITE %3d %3.3s %2d ", nr, siteID, numRes);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
@@ -3318,7 +3312,7 @@ void WriteCrystallographic(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
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>()) << '\n';
|
||||
pdbFile << std::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>()) << '\n';
|
||||
}
|
||||
|
||||
int WriteCoordinateTransformation(std::ostream &pdbFile, const datablock &db)
|
||||
@@ -3327,18 +3321,18 @@ int WriteCoordinateTransformation(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
for (auto r : db["database_PDB_matrix"])
|
||||
{
|
||||
pdbFile << cif::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 1, r["origx[1][1]"].as<float>(), r["origx[1][2]"].as<float>(), r["origx[1][3]"].as<float>(), r["origx_vector[1]"].as<float>()) << '\n';
|
||||
pdbFile << cif::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 2, r["origx[2][1]"].as<float>(), r["origx[2][2]"].as<float>(), r["origx[2][3]"].as<float>(), r["origx_vector[2]"].as<float>()) << '\n';
|
||||
pdbFile << cif::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 3, r["origx[3][1]"].as<float>(), r["origx[3][2]"].as<float>(), r["origx[3][3]"].as<float>(), r["origx_vector[3]"].as<float>()) << '\n';
|
||||
pdbFile << std::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 1, r["origx[1][1]"].as<float>(), r["origx[1][2]"].as<float>(), r["origx[1][3]"].as<float>(), r["origx_vector[1]"].as<float>()) << '\n';
|
||||
pdbFile << std::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 2, r["origx[2][1]"].as<float>(), r["origx[2][2]"].as<float>(), r["origx[2][3]"].as<float>(), r["origx_vector[2]"].as<float>()) << '\n';
|
||||
pdbFile << std::format("ORIGX%1d %10.6f%10.6f%10.6f %10.5f", 3, r["origx[3][1]"].as<float>(), r["origx[3][2]"].as<float>(), r["origx[3][3]"].as<float>(), r["origx_vector[3]"].as<float>()) << '\n';
|
||||
result += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto r : db["atom_sites"])
|
||||
{
|
||||
pdbFile << cif::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 1, r["fract_transf_matrix[1][1]"].as<float>(), r["fract_transf_matrix[1][2]"].as<float>(), r["fract_transf_matrix[1][3]"].as<float>(), r["fract_transf_vector[1]"].as<float>()) << '\n';
|
||||
pdbFile << cif::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 2, r["fract_transf_matrix[2][1]"].as<float>(), r["fract_transf_matrix[2][2]"].as<float>(), r["fract_transf_matrix[2][3]"].as<float>(), r["fract_transf_vector[2]"].as<float>()) << '\n';
|
||||
pdbFile << cif::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 3, r["fract_transf_matrix[3][1]"].as<float>(), r["fract_transf_matrix[3][2]"].as<float>(), r["fract_transf_matrix[3][3]"].as<float>(), r["fract_transf_vector[3]"].as<float>()) << '\n';
|
||||
pdbFile << std::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 1, r["fract_transf_matrix[1][1]"].as<float>(), r["fract_transf_matrix[1][2]"].as<float>(), r["fract_transf_matrix[1][3]"].as<float>(), r["fract_transf_vector[1]"].as<float>()) << '\n';
|
||||
pdbFile << std::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 2, r["fract_transf_matrix[2][1]"].as<float>(), r["fract_transf_matrix[2][2]"].as<float>(), r["fract_transf_matrix[2][3]"].as<float>(), r["fract_transf_vector[2]"].as<float>()) << '\n';
|
||||
pdbFile << std::format("SCALE%1d %10.6f%10.6f%10.6f %10.5f", 3, r["fract_transf_matrix[3][1]"].as<float>(), r["fract_transf_matrix[3][2]"].as<float>(), r["fract_transf_matrix[3][3]"].as<float>(), r["fract_transf_vector[3]"].as<float>()) << '\n';
|
||||
result += 3;
|
||||
break;
|
||||
}
|
||||
@@ -3348,9 +3342,9 @@ int WriteCoordinateTransformation(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
std::string given = r["code"] == "given" ? "1" : "";
|
||||
|
||||
pdbFile << cif::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 1, nr, r["matrix[1][1]"].as<float>(), r["matrix[1][2]"].as<float>(), r["matrix[1][3]"].as<float>(), r["vector[1]"].as<float>(), given) << '\n';
|
||||
pdbFile << cif::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 2, nr, r["matrix[2][1]"].as<float>(), r["matrix[2][2]"].as<float>(), r["matrix[2][3]"].as<float>(), r["vector[2]"].as<float>(), given) << '\n';
|
||||
pdbFile << cif::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 3, nr, r["matrix[3][1]"].as<float>(), r["matrix[3][2]"].as<float>(), r["matrix[3][3]"].as<float>(), r["vector[3]"].as<float>(), given) << '\n';
|
||||
pdbFile << std::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 1, nr, r["matrix[1][1]"].as<float>(), r["matrix[1][2]"].as<float>(), r["matrix[1][3]"].as<float>(), r["vector[1]"].as<float>(), given) << '\n';
|
||||
pdbFile << std::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 2, nr, r["matrix[2][1]"].as<float>(), r["matrix[2][2]"].as<float>(), r["matrix[2][3]"].as<float>(), r["vector[2]"].as<float>(), given) << '\n';
|
||||
pdbFile << std::format("MTRIX%1d %3d%10.6f%10.6f%10.6f %10.5f %1.1s", 3, nr, r["matrix[3][1]"].as<float>(), r["matrix[3][2]"].as<float>(), r["matrix[3][3]"].as<float>(), r["vector[3]"].as<float>(), given) << '\n';
|
||||
|
||||
++nr;
|
||||
result += 3;
|
||||
@@ -3393,7 +3387,7 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
{
|
||||
int nr = 0;
|
||||
auto r = std::from_chars(modelNum.data(), modelNum.data() + modelNum.length(), nr);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Model number '" << modelNum << "' is not a valid integer\n";
|
||||
@@ -3417,7 +3411,7 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
|
||||
if (terminate)
|
||||
{
|
||||
pdbFile << cif::format("TER %5d %3.3s %1.1s%4d%1.1s", serial, resName, chainID, resSeq, iCode) << '\n';
|
||||
pdbFile << std::format("TER %5d %3.3s %1.1s%4d%1.1s", serial, resName, chainID, resSeq, iCode) << '\n';
|
||||
|
||||
++serial;
|
||||
terminatedChains.insert(chainID);
|
||||
@@ -3476,7 +3470,7 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
if (charge != 0)
|
||||
sCharge = std::to_string(charge) + (charge > 0 ? '+' : '-');
|
||||
|
||||
pdbFile << cif::format("%-6.6s%5d %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %8.3f%8.3f%8.3f%6.2f%6.2f %2.2s%2.2s", group, serial, name, altLoc, resName, chainID, resSeq, iCode, x, y, z, occupancy, tempFactor, element, sCharge) << '\n';
|
||||
pdbFile << std::format("%-6.6s%5d %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %8.3f%8.3f%8.3f%6.2f%6.2f %2.2s%2.2s", group, serial, name, altLoc, resName, chainID, resSeq, iCode, x, y, z, occupancy, tempFactor, element, sCharge) << '\n';
|
||||
|
||||
++numCoord;
|
||||
|
||||
@@ -3491,7 +3485,7 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
tie(u11, u22, u33, u12, u13, u23) =
|
||||
ai.get("U[1][1]", "U[2][2]", "U[3][3]", "U[1][2]", "U[1][3]", "U[2][3]");
|
||||
|
||||
pdbFile << cif::format("ANISOU%5d %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %7d%7d%7d%7d%7d%7d %2.2s%2.2s", serial, name, altLoc, resName, chainID, resSeq, iCode, std::lrintf(u11 * 10000), std::lrintf(u22 * 10000), std::lrintf(u33 * 10000), std::lrintf(u12 * 10000), std::lrintf(u13 * 10000), std::lrintf(u23 * 10000), element, sCharge) << '\n';
|
||||
pdbFile << std::format("ANISOU%5d %-4.4s%1.1s%3.3s %1.1s%4d%1.1s %7d%7d%7d%7d%7d%7d %2.2s%2.2s", serial, name, altLoc, resName, chainID, resSeq, iCode, std::lrintf(u11 * 10000), std::lrintf(u22 * 10000), std::lrintf(u33 * 10000), std::lrintf(u12 * 10000), std::lrintf(u13 * 10000), std::lrintf(u23 * 10000), element, sCharge) << '\n';
|
||||
}
|
||||
|
||||
++serial;
|
||||
@@ -3543,7 +3537,7 @@ std::tuple<int, int> WriteCoordinate(std::ostream &pdbFile, const datablock &db)
|
||||
for (int model_nr : models)
|
||||
{
|
||||
if (models.size() > 1)
|
||||
pdbFile << cif::format("MODEL %4d", model_nr) << '\n';
|
||||
pdbFile << std::format("MODEL %4d", model_nr) << '\n';
|
||||
|
||||
std::set<std::string> TERminatedChains;
|
||||
auto n = WriteCoordinatesForModel(pdbFile, db, last_resseq_for_chain_map, TERminatedChains, model_nr);
|
||||
@@ -3615,7 +3609,7 @@ std::string get_HEADER_line(const datablock &db, std::string::size_type truncate
|
||||
}
|
||||
}
|
||||
|
||||
return FixStringLength(cif::format("HEADER %-40.40s%-9.9s %-4.4s", keywords, date, db.name()).str(), truncate_at);
|
||||
return FixStringLength(std::format("HEADER %-40.40s%-9.9s %-4.4s", keywords, date, db.name()), truncate_at);
|
||||
}
|
||||
|
||||
std::string get_COMPND_line(const datablock &db, std::string::size_type truncate_at)
|
||||
@@ -3788,7 +3782,7 @@ void write(std::ostream &os, const datablock &db)
|
||||
numXform = WriteCoordinateTransformation(os, db);
|
||||
std::tie(numCoord, numTer) = WriteCoordinate(os, db);
|
||||
|
||||
os << cif::format("MASTER %5d 0%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", numRemark, numHet, numHelix, numSheet, numTurn, numSite, numXform, numCoord, numTer, numConect, numSeq) << '\n'
|
||||
os << std::format("MASTER %5d 0%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", numRemark, numHet, numHelix, numSheet, numTurn, numSite, numXform, numCoord, numTer, numConect, numSeq) << '\n'
|
||||
<< "END\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ PDBRecord::~PDBRecord()
|
||||
{
|
||||
}
|
||||
|
||||
void *PDBRecord::operator new(size_t size, size_t vLen)
|
||||
void *PDBRecord::operator new(std::size_t size, std::size_t vLen)
|
||||
{
|
||||
return malloc(size + vLen + 1);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ void PDBRecord::operator delete(void *p)
|
||||
free(p);
|
||||
}
|
||||
|
||||
void PDBRecord::operator delete(void *p, size_t vLen)
|
||||
void PDBRecord::operator delete(void *p, std::size_t vLen)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
@@ -180,7 +180,7 @@ bool PDBRecord::is(const char *name) const
|
||||
return iequals(mName, name);
|
||||
}
|
||||
|
||||
char PDBRecord::vC(size_t column)
|
||||
char PDBRecord::vC(std::size_t column)
|
||||
{
|
||||
char result = ' ';
|
||||
if (column - 7 < mVlen)
|
||||
@@ -188,7 +188,7 @@ char PDBRecord::vC(size_t column)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string PDBRecord::vS(size_t columnFirst, size_t columnLast)
|
||||
std::string PDBRecord::vS(std::size_t columnFirst, std::size_t columnLast)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
@@ -272,7 +272,7 @@ int PDBRecord::vI(int columnFirst, int columnLast)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string PDBRecord::vF(size_t columnFirst, size_t columnLast)
|
||||
std::string PDBRecord::vF(std::size_t columnFirst, std::size_t columnLast)
|
||||
{
|
||||
// for now... TODO: check format?
|
||||
return vS(columnFirst, columnLast);
|
||||
@@ -780,17 +780,17 @@ class PDBFileParser
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
char vC(size_t column) const
|
||||
char vC(std::size_t column) const
|
||||
{
|
||||
return mRec->vC(column);
|
||||
}
|
||||
|
||||
std::string vS(size_t columnFirst, size_t columnLast = std::numeric_limits<size_t>::max()) const
|
||||
std::string vS(std::size_t columnFirst, std::size_t columnLast = std::numeric_limits<std::size_t>::max()) const
|
||||
{
|
||||
return mRec->vS(columnFirst, columnLast);
|
||||
}
|
||||
|
||||
std::string vF(size_t columnFirst, size_t columnLast) const
|
||||
std::string vF(std::size_t columnFirst, std::size_t columnLast) const
|
||||
{
|
||||
return mRec->vF(columnFirst, columnLast);
|
||||
}
|
||||
@@ -847,7 +847,7 @@ class PDBFileParser
|
||||
void ParseRemarks();
|
||||
|
||||
// void ParseRemark3();
|
||||
// size_t ParseRemark3(const std::string& program, const Remark3Template templ[], size_t N);
|
||||
// std::size_t ParseRemark3(const std::string& program, const Remark3Template templ[], std::size_t N);
|
||||
// std::string NextRemark3Line();
|
||||
|
||||
void ParseRemark200();
|
||||
@@ -895,12 +895,7 @@ class PDBFileParser
|
||||
if (year < 1950)
|
||||
year += 100;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::setw(4) << std::setfill('0') << year << '-'
|
||||
<< std::setw(2) << std::setfill('0') << month << '-'
|
||||
<< std::setw(2) << std::setfill('0') << day;
|
||||
|
||||
s = ss.str();
|
||||
s = std::format("{:04}-{:02}-{:02}", year, month, day);
|
||||
}
|
||||
else if (regex_match(s, m, rx2))
|
||||
{
|
||||
@@ -912,7 +907,7 @@ class PDBFileParser
|
||||
if (year < 1950)
|
||||
year += 100;
|
||||
|
||||
s = cif::format("%04d-%02d", year, month).str();
|
||||
s = std::format("{:04}-{:02}", year, month);
|
||||
}
|
||||
else
|
||||
ec = error::make_error_code(error::pdbErrors::invalidDate);
|
||||
@@ -1132,7 +1127,7 @@ void PDBFileParser::PreParseInput(std::istream &is)
|
||||
if (not cs.empty())
|
||||
{
|
||||
auto r = std::from_chars(cs.data(), cs.data() + cs.length(), result);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("Continuation std::string '" + cs + "' is not valid");
|
||||
}
|
||||
|
||||
@@ -1320,7 +1315,7 @@ void PDBFileParser::PreParseInput(std::istream &is)
|
||||
{
|
||||
std::string siteName = value.substr(5, 3);
|
||||
cif::trim_right(value);
|
||||
size_t n = value.length() - 12;
|
||||
std::size_t n = value.length() - 12;
|
||||
value += std::string(11 - (n % 11), ' ');
|
||||
|
||||
while (lookahead.substr(0, 6) == type and lookahead.substr(11, 3) == siteName)
|
||||
@@ -1397,7 +1392,7 @@ void PDBFileParser::PreParseInput(std::istream &is)
|
||||
{
|
||||
auto f = cur->vF(74, 78);
|
||||
auto r = cif::from_chars(f.data(), f.data() + f.length(), link.distance);
|
||||
if (r.ec != std::errc() and cif::VERBOSE > 0)
|
||||
if ((bool)r.ec and cif::VERBOSE > 0)
|
||||
std::cerr << "Error parsing link distance at line " << cur->mLineNr << '\n';
|
||||
}
|
||||
// 74 – 78 Real(5.2) Length Link distance
|
||||
@@ -1962,7 +1957,7 @@ void PDBFileParser::ParseRemarks()
|
||||
switch (remarkNr)
|
||||
{
|
||||
case 1:
|
||||
while (mRec->is("REMARK 1"))
|
||||
while (mRec->is("REMARK 1") or mRec->is("REMARK 001"))
|
||||
{
|
||||
if (mRec->mVlen > 15 and vS(12, 20) == "REFERENCE")
|
||||
{
|
||||
@@ -3334,38 +3329,27 @@ void PDBFileParser::ParseRemark350()
|
||||
|
||||
std::string type = mat == std::vector<double>{ 1, 0, 0, 0, 1, 0, 0, 0, 1 } and vec == std::vector<double>{ 0, 0, 0 } ? "identity operation" : "crystal symmetry operation";
|
||||
|
||||
// if (type == "identity operation")
|
||||
// {
|
||||
|
||||
// }
|
||||
// else
|
||||
try
|
||||
{
|
||||
// clang-format off
|
||||
getCategory("pdbx_struct_oper_list")->emplace({
|
||||
auto pdbx_struct_oper_list = getCategory("pdbx_struct_oper_list");
|
||||
if (not pdbx_struct_oper_list->contains(cif::key("id") == operID))
|
||||
getCategory("pdbx_struct_oper_list")->emplace({ // clang-format off
|
||||
{ "id", operID },
|
||||
{ "type", type },
|
||||
// { "name", "" },
|
||||
// { "symmetryOperation", "" },
|
||||
{ "matrix[1][1]", cif::format("%12.10f", mat[0]).str() },
|
||||
{ "matrix[1][2]", cif::format("%12.10f", mat[1]).str() },
|
||||
{ "matrix[1][3]", cif::format("%12.10f", mat[2]).str() },
|
||||
{ "vector[1]", cif::format("%12.10f", vec[0]).str() },
|
||||
{ "matrix[2][1]", cif::format("%12.10f", mat[3]).str() },
|
||||
{ "matrix[2][2]", cif::format("%12.10f", mat[4]).str() },
|
||||
{ "matrix[2][3]", cif::format("%12.10f", mat[5]).str() },
|
||||
{ "vector[2]", cif::format("%12.10f", vec[1]).str() },
|
||||
{ "matrix[3][1]", cif::format("%12.10f", mat[6]).str() },
|
||||
{ "matrix[3][2]", cif::format("%12.10f", mat[7]).str() },
|
||||
{ "matrix[3][3]", cif::format("%12.10f", mat[8]).str() },
|
||||
{ "vector[3]", cif::format("%12.10f", vec[2]).str() }
|
||||
{ "matrix[1][1]", std::format("%12.10f", mat[0]) },
|
||||
{ "matrix[1][2]", std::format("%12.10f", mat[1]) },
|
||||
{ "matrix[1][3]", std::format("%12.10f", mat[2]) },
|
||||
{ "vector[1]", std::format("%12.10f", vec[0]) },
|
||||
{ "matrix[2][1]", std::format("%12.10f", mat[3]) },
|
||||
{ "matrix[2][2]", std::format("%12.10f", mat[4]) },
|
||||
{ "matrix[2][3]", std::format("%12.10f", mat[5]) },
|
||||
{ "vector[2]", std::format("%12.10f", vec[1]) },
|
||||
{ "matrix[3][1]", std::format("%12.10f", mat[6]) },
|
||||
{ "matrix[3][2]", std::format("%12.10f", mat[7]) },
|
||||
{ "matrix[3][3]", std::format("%12.10f", mat[8]) },
|
||||
{ "vector[3]", std::format("%12.10f", vec[2]) }
|
||||
});
|
||||
// clang-format on
|
||||
}
|
||||
catch (duplicate_key_error &ex)
|
||||
{
|
||||
// so what?
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
mat.clear();
|
||||
vec.clear();
|
||||
@@ -4202,7 +4186,7 @@ void PDBFileParser::ConstructEntities()
|
||||
|
||||
chains.push_back(std::string{ chain.mDbref.chainID });
|
||||
|
||||
size_t seqLen = 0, seqCanLen = 0;
|
||||
std::size_t seqLen = 0, seqCanLen = 0;
|
||||
|
||||
for (auto &res : chain.mSeqres)
|
||||
{
|
||||
@@ -4265,7 +4249,7 @@ void PDBFileParser::ConstructEntities()
|
||||
}
|
||||
|
||||
auto cat_ps = getCategory("entity_poly_seq");
|
||||
for (size_t i = 0; i < chain.mSeqres.size(); ++i)
|
||||
for (std::size_t i = 0; i < chain.mSeqres.size(); ++i)
|
||||
{
|
||||
auto &rs = chain.mSeqres[i];
|
||||
|
||||
@@ -4300,6 +4284,8 @@ void PDBFileParser::ConstructEntities()
|
||||
type = "polypeptide(L)";
|
||||
else if (mightBeDNA and not mightBePolyPeptide)
|
||||
type = "polyribonucleotide";
|
||||
else
|
||||
type = "other";
|
||||
|
||||
// clang-format off
|
||||
getCategory("entity_poly")->emplace({
|
||||
@@ -4335,7 +4321,7 @@ void PDBFileParser::ConstructEntities()
|
||||
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)
|
||||
for (std::size_t i = 0; i < mHets.size(); ++i)
|
||||
{
|
||||
auto &heti = mHets[i];
|
||||
|
||||
@@ -4505,7 +4491,7 @@ void PDBFileParser::ConstructEntities()
|
||||
int modResID = 1;
|
||||
std::set<std::string> modResSet;
|
||||
for (auto rec = FindRecord("MODRES"); rec != nullptr and rec->is("MODRES");
|
||||
rec = rec->mNext) // 1 - 6 Record name "MODRES"
|
||||
rec = rec->mNext) // 1 - 6 Record name "MODRES"
|
||||
{ // 8 - 11 IDcode idCode ID code of this datablock.
|
||||
std::string resName = rec->vS(13, 15); // 13 - 15 Residue name resName Residue name used in this datablock.
|
||||
char chainID = rec->vC(17); // 17 Character chainID Chain identifier.
|
||||
@@ -4669,47 +4655,6 @@ void PDBFileParser::ConstructEntities()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finish by calculating the formula_weight for each entity
|
||||
for (auto entity : *getCategory("entity"))
|
||||
{
|
||||
auto entity_id = entity["id"].as<std::string>();
|
||||
float formula_weight = 0;
|
||||
|
||||
if (entity["type"] == "polymer")
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (std::string comp_id : getCategory("pdbx_poly_seq_scheme")->find<std::string>(cif::key("entity_id") == entity_id, "mon_id"))
|
||||
{
|
||||
auto compound = cif::compound_factory::instance().create(comp_id);
|
||||
assert(compound);
|
||||
if (not compound)
|
||||
throw std::runtime_error("missing information for compound " + comp_id);
|
||||
formula_weight += compound->formula_weight();
|
||||
++n;
|
||||
}
|
||||
|
||||
formula_weight -= (n - 1) * 18.015;
|
||||
}
|
||||
else if (entity["type"] == "water")
|
||||
formula_weight = 18.015;
|
||||
else
|
||||
{
|
||||
auto comp_id = getCategory("pdbx_nonpoly_scheme")->find_first<std::optional<std::string>>(cif::key("entity_id") == entity_id, "mon_id");
|
||||
if (comp_id.has_value())
|
||||
{
|
||||
auto compound = cif::compound_factory::instance().create(*comp_id);
|
||||
assert(compound);
|
||||
if (not compound)
|
||||
throw std::runtime_error("missing information for compound " + *comp_id);
|
||||
formula_weight = compound->formula_weight();
|
||||
}
|
||||
}
|
||||
|
||||
if (formula_weight > 0)
|
||||
entity.assign({ { "formula_weight", formula_weight, 3 } });
|
||||
}
|
||||
}
|
||||
|
||||
void PDBFileParser::ConstructSugarTrees(int &asymNr)
|
||||
@@ -5347,7 +5292,7 @@ void PDBFileParser::ParseConnectivtyAnnotation()
|
||||
|
||||
double d;
|
||||
auto r = cif::from_chars(distance.data(), distance.data() + distance.length(), d);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Distance value '" << distance << "' is not a valid float in LINK record\n";
|
||||
@@ -5668,7 +5613,7 @@ void PDBFileParser::ParseCoordinateTransformation()
|
||||
igiven = vC(60) == '1'; // 60 Integer iGiven 1 if coordinates for the representations
|
||||
// which are approximately related by the
|
||||
GetNextRecord(); // transformations of the molecule are
|
||||
} // contained in the datablock. Otherwise, blank.
|
||||
} // contained in the datablock. Otherwise, blank.
|
||||
|
||||
// clang-format off
|
||||
getCategory("struct_ncs_oper")->emplace({
|
||||
@@ -5753,7 +5698,7 @@ void PDBFileParser::ParseCoordinate(int modelNr)
|
||||
stable_sort(atoms.begin(), atoms.end(), rLess);
|
||||
|
||||
// now reiterate the atoms to reorder alternates
|
||||
for (size_t i = 0; i + 1 < atoms.size(); ++i)
|
||||
for (std::size_t i = 0; i + 1 < atoms.size(); ++i)
|
||||
{
|
||||
char altLoc = std::get<3>(atoms[i])->vC(17);
|
||||
|
||||
@@ -5900,7 +5845,7 @@ void PDBFileParser::ParseCoordinate(int modelNr)
|
||||
|
||||
auto f = [](float f) -> std::string
|
||||
{
|
||||
return cif::format("%6.4f", f).str();
|
||||
return std::format("%6.4f", f);
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
@@ -5950,7 +5895,8 @@ void PDBFileParser::Parse(std::istream &is, cif::file &result)
|
||||
{
|
||||
try
|
||||
{
|
||||
mDatablock.set_validator(result.get_validator());
|
||||
if (mDatablock.get_validator() == nullptr)
|
||||
mDatablock.load_dictionary();
|
||||
|
||||
PreParseInput(is);
|
||||
|
||||
@@ -6402,7 +6348,7 @@ bool PDBFileParser::PDBChain::SameSequence(const PDBChain &rhs) const
|
||||
{
|
||||
bool result = mSeqres.size() == rhs.mSeqres.size();
|
||||
|
||||
for (size_t i = 0; result and i < mSeqres.size(); ++i)
|
||||
for (std::size_t i = 0; result and i < mSeqres.size(); ++i)
|
||||
result = mSeqres[i].mMonID == rhs.mSeqres[i].mMonID;
|
||||
|
||||
return result;
|
||||
@@ -6414,12 +6360,22 @@ void read_pdb_file(std::istream &pdbFile, cif::file &cifFile)
|
||||
{
|
||||
PDBFileParser p;
|
||||
|
||||
cifFile.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
p.Parse(pdbFile, cifFile);
|
||||
|
||||
if (not cifFile.is_valid() and cif::VERBOSE >= 0)
|
||||
std::cerr << "Resulting mmCIF file is not valid!\n";
|
||||
if (cifFile.empty())
|
||||
{
|
||||
if (VERBOSE >= 0)
|
||||
std::cerr << "PDB is empty!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cifFile.front().load_dictionary();
|
||||
if (cifFile.front().get_validator() == nullptr)
|
||||
cifFile.front().set_validator(&validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
if (not cifFile.is_valid() and cif::VERBOSE >= 0)
|
||||
std::cerr << "Resulting mmCIF file is not valid!\n";
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -6443,7 +6399,10 @@ file read(std::istream &is)
|
||||
// apart from the letter 'd', the test has changed into the following:
|
||||
|
||||
if (std::isalpha(ch) and std::toupper(ch) != 'D')
|
||||
{
|
||||
read_pdb_file(is, result);
|
||||
fixup_pdbx(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
@@ -6455,15 +6414,31 @@ file read(std::istream &is)
|
||||
std::throw_with_nested(std::runtime_error("Since the file did not start with a valid PDB HEADER line mmCIF was assumed, but that failed."));
|
||||
}
|
||||
|
||||
// Since we're using the cif::pdb way of reading the file, the data may need
|
||||
// reconstruction
|
||||
reconstruct_pdbx(result);
|
||||
if (not(result.empty() or result.front().empty()))
|
||||
{
|
||||
if (auto &db = result.front(); db.get("audit_conform") == nullptr)
|
||||
reconstruct_pdbx(result);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try to see if we can create an mm::structure out of this data.
|
||||
// If that fails, we need to reconstruct a PDBx file out of it.
|
||||
|
||||
cif::mm::structure s(result);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
reconstruct_pdbx(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must be a PDB like file, right?
|
||||
if (result.get_validator() == nullptr)
|
||||
result.load_dictionary("mmcif_pdbx.dic");
|
||||
if (not result.empty() and result.front().get_validator() == nullptr)
|
||||
result.front().set_validator(&validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -980,8 +980,8 @@ std::string Remark3Parser::nextLine()
|
||||
|
||||
while (mRec != nullptr and mRec->is("REMARK 3"))
|
||||
{
|
||||
size_t valueIndent = 0;
|
||||
for (size_t i = 4; i < mRec->mVlen; ++i)
|
||||
std::size_t valueIndent = 0;
|
||||
for (std::size_t i = 4; i < mRec->mVlen; ++i)
|
||||
{
|
||||
if (mRec->mValue[i] == ' ')
|
||||
continue;
|
||||
@@ -1232,7 +1232,7 @@ void Remark3Parser::storeCapture(const char *category, std::initializer_list<con
|
||||
}
|
||||
// else if (iequals(category, "struct_ncs_dom"))
|
||||
// {
|
||||
// size_t id = cat.size() + 1;
|
||||
// std::size_t id = cat.size() + 1;
|
||||
//
|
||||
// cat.emplace({
|
||||
// { "id", id }
|
||||
@@ -1478,8 +1478,13 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
|
||||
best.parser->fixup();
|
||||
|
||||
auto &validator = cif::validator_factory::instance().get("mmcif_pdbx.dic");
|
||||
|
||||
for (auto &cat1 : best.parser->mDb)
|
||||
{
|
||||
if (cat1.empty())
|
||||
continue;
|
||||
|
||||
auto &cat2 = db[cat1.name()];
|
||||
|
||||
// copy only the values in the first row for the following categories
|
||||
@@ -1493,8 +1498,15 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
auto r1 = cat1.front();
|
||||
auto r2 = cat2.front();
|
||||
|
||||
for (auto item : cat1.key_items())
|
||||
r2[item] = r1[item].text();
|
||||
auto cv = cat1.get_cat_validator();
|
||||
if (cv == nullptr)
|
||||
cv = validator.get_validator_for_category(cat1.name());
|
||||
|
||||
if (cv == nullptr)
|
||||
continue;
|
||||
|
||||
for (auto &iv : cv->m_item_validators)
|
||||
r2[iv.m_item_name] = r1[iv.m_item_name].text();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -40,24 +40,24 @@ struct PDBRecord
|
||||
PDBRecord *mNext;
|
||||
uint32_t mLineNr;
|
||||
char mName[11];
|
||||
size_t mVlen;
|
||||
std::size_t mVlen;
|
||||
char mValue[1];
|
||||
|
||||
PDBRecord(uint32_t lineNr, const std::string &name, const std::string &value);
|
||||
~PDBRecord();
|
||||
|
||||
void *operator new(size_t);
|
||||
void *operator new(size_t size, size_t vLen);
|
||||
void *operator new(std::size_t);
|
||||
void *operator new(std::size_t size, std::size_t vLen);
|
||||
|
||||
void operator delete(void *p);
|
||||
void operator delete(void *p, size_t vLen);
|
||||
void operator delete(void *p, std::size_t vLen);
|
||||
|
||||
bool is(const char *name) const;
|
||||
|
||||
char vC(size_t column);
|
||||
std::string vS(size_t columnFirst, size_t columnLast = std::numeric_limits<size_t>::max());
|
||||
char vC(std::size_t column);
|
||||
std::string vS(std::size_t columnFirst, std::size_t columnLast = std::numeric_limits<std::size_t>::max());
|
||||
int vI(int columnFirst, int columnLast);
|
||||
std::string vF(size_t columnFirst, size_t columnLast);
|
||||
std::string vF(std::size_t columnFirst, std::size_t columnLast);
|
||||
};
|
||||
|
||||
} // namespace pdbx
|
||||
@@ -92,6 +92,97 @@ condition get_condition(residue_key_type &k)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void checkEntities(datablock &db)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
auto &cf = cif::compound_factory::instance();
|
||||
|
||||
for (auto entity : db["entity"].find("formula_weight"_key == null or "formula_weight"_key == 0))
|
||||
{
|
||||
auto &&[entity_id, type] = entity.get<std::string, std::string>("id", "type");
|
||||
|
||||
float formula_weight = 0;
|
||||
|
||||
if (type.empty()) // yes, that happens
|
||||
{
|
||||
const auto comp_id = db["atom_site"].find_first<std::string>("label_entity_id"_key == entity_id, "label_comp_id");
|
||||
auto compound = cf.create(comp_id);
|
||||
if (compound != nullptr)
|
||||
{
|
||||
if (compound->is_base() or compound->is_peptide())
|
||||
type = "polymer";
|
||||
else if (compound->is_water())
|
||||
type = "water";
|
||||
else
|
||||
{
|
||||
if (db["pdbx_entity_branch_link"].contains("entity_id"_key == entity_id))
|
||||
type = "branched";
|
||||
else
|
||||
type = "non-polymer";
|
||||
}
|
||||
}
|
||||
|
||||
if (type.empty())
|
||||
throw std::runtime_error("Entity without type and cannot determine what it should be");
|
||||
|
||||
entity["type"] = type;
|
||||
}
|
||||
|
||||
if (type == "polymer")
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (std::string comp_id : db["pdbx_poly_seq_scheme"].find<std::string>("entity_id"_key == entity_id, "mon_id"))
|
||||
{
|
||||
auto compound = cf.create(comp_id);
|
||||
if (compound)
|
||||
formula_weight += compound->formula_weight();
|
||||
// else if (cif::VERBOSE > 0)
|
||||
// std::clog << "missing information for compound " + comp_id << '\n';
|
||||
++n;
|
||||
}
|
||||
|
||||
formula_weight -= (n - 1) * 18.015;
|
||||
}
|
||||
else if (type == "water")
|
||||
formula_weight = 18.015;
|
||||
else if (type == "branched")
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (std::string comp_id : db["pdbx_entity_branch_list"].find<std::string>("entity_id"_key == entity_id, "comp_id"))
|
||||
{
|
||||
auto compound = cf.create(comp_id);
|
||||
if (compound)
|
||||
formula_weight += compound->formula_weight();
|
||||
// else if (cif::VERBOSE > 0)
|
||||
// std::clog << "missing information for compound " + comp_id << '\n';
|
||||
++n;
|
||||
}
|
||||
|
||||
formula_weight -= (n - 1) * 18.015;
|
||||
}
|
||||
else if (type == "non-polymer")
|
||||
{
|
||||
auto comp_id = db["pdbx_nonpoly_scheme"].find_first<std::optional<std::string>>("entity_id"_key == entity_id, "mon_id");
|
||||
if (comp_id.has_value())
|
||||
{
|
||||
auto compound = cf.create(*comp_id);
|
||||
if (not compound)
|
||||
{
|
||||
// std::cerr << "missing information for compound " << *comp_id << "\n";
|
||||
continue;
|
||||
}
|
||||
formula_weight = compound->formula_weight();
|
||||
}
|
||||
}
|
||||
|
||||
if (formula_weight > 0)
|
||||
entity.assign({ { "formula_weight", formula_weight, 3 } });
|
||||
}
|
||||
}
|
||||
|
||||
void createEntityIDs(datablock &db)
|
||||
{
|
||||
// Suppose the file does not have entity ID's. We have to make up some
|
||||
@@ -114,11 +205,11 @@ void createEntityIDs(datablock &db)
|
||||
std::vector<residue_key_type> waters;
|
||||
|
||||
for (residue_key_type k : atom_site.rows<std::optional<std::string>,
|
||||
std::optional<int>,
|
||||
std::optional<std::string>,
|
||||
std::optional<std::string>,
|
||||
std::optional<int>,
|
||||
std::optional<std::string>>(
|
||||
std::optional<int>,
|
||||
std::optional<std::string>,
|
||||
std::optional<std::string>,
|
||||
std::optional<int>,
|
||||
std::optional<std::string>>(
|
||||
"auth_asym_id", "auth_seq_id", "auth_comp_id",
|
||||
"label_asym_id", "label_seq_id", "label_comp_id"))
|
||||
{
|
||||
@@ -147,11 +238,11 @@ void createEntityIDs(datablock &db)
|
||||
lastSeqID = seq_id;
|
||||
}
|
||||
|
||||
std::map<size_t, std::string> entity_ids;
|
||||
std::map<std::size_t, std::string> entity_ids;
|
||||
|
||||
atom_site.add_item("label_entity_id");
|
||||
|
||||
for (size_t i = 0; i < entities.size(); ++i)
|
||||
for (std::size_t i = 0; i < entities.size(); ++i)
|
||||
{
|
||||
if (entity_ids.contains(i))
|
||||
continue;
|
||||
@@ -159,14 +250,14 @@ void createEntityIDs(datablock &db)
|
||||
auto entity_id = std::to_string(i + 1);
|
||||
entity_ids[i] = entity_id;
|
||||
|
||||
for (size_t j = i + 1; j < entities.size(); ++j)
|
||||
for (std::size_t j = i + 1; j < entities.size(); ++j)
|
||||
{
|
||||
if (entities[i] == entities[j])
|
||||
entity_ids[j] = entity_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t ix = 0; auto &e : entities)
|
||||
for (std::size_t ix = 0; auto &e : entities)
|
||||
{
|
||||
auto k = e.front();
|
||||
const auto &entity_id = entity_ids[ix++];
|
||||
@@ -325,7 +416,7 @@ void checkChemCompRecords(datablock &db)
|
||||
items.emplace_back(item{ "formula_weight", compound->formula_weight() });
|
||||
|
||||
if (not items.empty())
|
||||
chem_comp_entry.assign(std::move(items));
|
||||
chem_comp_entry.assign(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,6 +439,12 @@ void checkAtomRecords(datablock &db)
|
||||
if (atom_site.contains(key("label_seq_id") < 0))
|
||||
fixNegativeSeqID(atom_site);
|
||||
|
||||
std::set<int> polymer_entities;
|
||||
for (int id : db["entity"].find<int>("type"_key == "polymer", "id"))
|
||||
polymer_entities.insert(id);
|
||||
|
||||
std::set<std::string> missingCompounds;
|
||||
|
||||
for (auto row : atom_site)
|
||||
{
|
||||
residue_key_type k = row.get<std::optional<std::string>,
|
||||
@@ -378,20 +475,32 @@ void checkAtomRecords(datablock &db)
|
||||
std::string asym_id = get_asym_id(k);
|
||||
std::string comp_id = get_comp_id(k);
|
||||
|
||||
bool is_peptide = cf.is_peptide(comp_id);
|
||||
if (missingCompounds.contains(comp_id))
|
||||
continue;
|
||||
|
||||
bool is_polymer = polymer_entities.contains(row["label_entity_id"].as<int>());
|
||||
auto compound = cf.create(comp_id);
|
||||
|
||||
if (not compound)
|
||||
throw std::runtime_error("Missing compound information for " + comp_id);
|
||||
{
|
||||
missingCompounds.insert(comp_id);
|
||||
// if (cif::VERBOSE > 0)
|
||||
// std::cerr << "Missing compound information for " << comp_id << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto chem_comp_entry = chem_comp.find_first("id"_key == comp_id);
|
||||
|
||||
std::optional<bool> non_std;
|
||||
if (cf.is_monomer(comp_id))
|
||||
non_std = cf.is_std_monomer(comp_id);
|
||||
|
||||
if (not chem_comp_entry)
|
||||
{
|
||||
chem_comp.emplace({ //
|
||||
{ "id", comp_id },
|
||||
{ "type", compound->type() },
|
||||
{ "mon_nstd_flag", cf.is_std_monomer(comp_id) ? "y" : "n" },
|
||||
{ "mon_nstd_flag", non_std },
|
||||
{ "name", compound->name() },
|
||||
{ "formula", compound->formula() },
|
||||
{ "formula_weight", compound->formula_weight() } });
|
||||
@@ -402,8 +511,8 @@ void checkAtomRecords(datablock &db)
|
||||
|
||||
if (not chem_comp_entry["type"])
|
||||
items.emplace_back(item{ "type", compound->type() });
|
||||
if (not chem_comp_entry["mon_nstd_flag"])
|
||||
items.emplace_back(item{ "mon_nstd_flag", cf.is_std_monomer(comp_id) ? "y" : "n" });
|
||||
if (not chem_comp_entry["mon_nstd_flag"] and non_std.has_value())
|
||||
items.emplace_back(item{ "mon_nstd_flag", non_std });
|
||||
if (not chem_comp_entry["name"])
|
||||
items.emplace_back(item{ "name", compound->name() });
|
||||
if (not chem_comp_entry["formula"])
|
||||
@@ -412,23 +521,21 @@ void checkAtomRecords(datablock &db)
|
||||
items.emplace_back(item{ "formula_weight", compound->formula_weight() });
|
||||
|
||||
if (not items.empty())
|
||||
chem_comp_entry.assign(std::move(items));
|
||||
chem_comp_entry.assign(items);
|
||||
}
|
||||
|
||||
if (is_peptide and not has_seq_id(k))
|
||||
if (is_polymer and not has_seq_id(k))
|
||||
throw std::runtime_error("atom_site record has peptide comp_id but no sequence number, cannot continue");
|
||||
|
||||
int seq_id = get_seq_id(k);
|
||||
|
||||
if (row["label_seq_id"].empty())
|
||||
if (is_polymer and row["label_seq_id"].empty() and cf.is_monomer(comp_id))
|
||||
row["label_seq_id"] = std::to_string(seq_id);
|
||||
|
||||
if (row["label_atom_id"].empty())
|
||||
row["label_atom_id"] = row["auth_atom_id"].text();
|
||||
if (row["label_asym_id"].empty())
|
||||
row["label_asym_id"] = row["auth_asym_id"].text();
|
||||
if (row["label_seq_id"].empty())
|
||||
row["label_seq_id"] = row["auth_seq_id"].text();
|
||||
if (row["label_comp_id"].empty())
|
||||
row["label_comp_id"] = row["auth_comp_id"].text();
|
||||
if (row["label_atom_id"].empty())
|
||||
@@ -448,14 +555,14 @@ void checkAtomRecords(datablock &db)
|
||||
|
||||
float v;
|
||||
auto s = row.get<std::string>(item_name);
|
||||
if (auto [ptr, ec] = cif::from_chars(s.data(), s.data() + s.length(), v); ec != std::errc())
|
||||
if (auto [ptr, ec] = cif::from_chars(s.data(), s.data() + s.length(), v); (bool)ec)
|
||||
continue;
|
||||
|
||||
if (s.length() < prec + 1 or s[s.length() - prec - 1] != '.')
|
||||
{
|
||||
char b[12];
|
||||
|
||||
if (auto [ptr, ec] = cif::to_chars(b, b + sizeof(b), v, cif::chars_format::fixed, prec); ec == std::errc())
|
||||
if (auto [ptr, ec] = cif::to_chars(b, b + sizeof(b), v, cif::chars_format::fixed, prec); (bool)ec)
|
||||
row.assign(item_name, { b, static_cast<std::string::size_type>(ptr - b) }, false, false);
|
||||
}
|
||||
}
|
||||
@@ -517,21 +624,21 @@ void checkAtomAnisotropRecords(datablock &db)
|
||||
{
|
||||
if (cif::VERBOSE and std::exchange(warnReplaceTypeSymbol, false))
|
||||
std::clog << "Replacing type_symbol in atom_site_anisotrop record(s)\n";
|
||||
row["type_symbol"] != parent["type_symbol"].text();
|
||||
row["type_symbol"] = parent["type_symbol"].text();
|
||||
}
|
||||
|
||||
if (row["pdbx_auth_alt_id"].empty())
|
||||
if (row["pdbx_auth_alt_id"].empty() and not parent["pdbx_auth_alt_id"].empty())
|
||||
row["pdbx_auth_alt_id"] = parent["pdbx_auth_alt_id"].text();
|
||||
if (row["pdbx_label_seq_id"].empty())
|
||||
if (row["pdbx_label_seq_id"].empty() and not parent["label_seq_id"].empty())
|
||||
row["pdbx_label_seq_id"] = parent["label_seq_id"].text();
|
||||
if (row["pdbx_label_asym_id"].empty())
|
||||
if (row["pdbx_label_asym_id"].empty() and not parent["label_asym_id"].empty())
|
||||
row["pdbx_label_asym_id"] = parent["label_asym_id"].text();
|
||||
if (row["pdbx_label_atom_id"].empty())
|
||||
if (row["pdbx_label_atom_id"].empty() and not parent["label_atom_id"].empty())
|
||||
row["pdbx_label_atom_id"] = parent["label_atom_id"].text();
|
||||
if (row["pdbx_label_comp_id"].empty())
|
||||
if (row["pdbx_label_comp_id"].empty() and not parent["label_comp_id"].empty())
|
||||
row["pdbx_label_comp_id"] = parent["label_comp_id"].text();
|
||||
if (row["pdbx_PDB_model_num"].empty())
|
||||
row["pdbx_PDB_model_num"] = parent["pdbx_PDB_model_num"].text();
|
||||
// if (row["pdbx_PDB_model_num"].empty() and not parent["pdbx_PDB_model_num"].empty())
|
||||
// row["pdbx_PDB_model_num"] = parent["pdbx_PDB_model_num"].text();
|
||||
}
|
||||
|
||||
if (not to_be_deleted.empty())
|
||||
@@ -670,6 +777,7 @@ void createEntity(datablock &db)
|
||||
void createEntityPoly(datablock &db)
|
||||
{
|
||||
using namespace literals;
|
||||
using namespace std::literals;
|
||||
|
||||
auto &cf = compound_factory::instance();
|
||||
|
||||
@@ -696,7 +804,7 @@ void createEntityPoly(datablock &db)
|
||||
auto c = cf.create(comp_id);
|
||||
|
||||
std::string letter;
|
||||
char letter_can;
|
||||
char letter_can{};
|
||||
|
||||
// TODO: Perhaps we should improve this...
|
||||
if (type != "other")
|
||||
@@ -705,7 +813,11 @@ void createEntityPoly(datablock &db)
|
||||
if (cf.is_base(comp_id))
|
||||
{
|
||||
c_type = "polydeoxyribonucleotide";
|
||||
letter = letter_can = compound_factory::kBaseMap.at(comp_id);
|
||||
letter_can = compound_factory::kBaseMap.at(comp_id);
|
||||
if (comp_id.length() == 1)
|
||||
letter = letter_can;
|
||||
else
|
||||
letter = '(' + letter_can + ')';
|
||||
}
|
||||
else if (cf.is_peptide(comp_id))
|
||||
{
|
||||
@@ -737,6 +849,18 @@ void createEntityPoly(datablock &db)
|
||||
|
||||
non_std_monomer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// c_type = "other";
|
||||
|
||||
letter_can = c->one_letter_code();
|
||||
if (letter_can == 0)
|
||||
letter_can = 'X';
|
||||
|
||||
letter = '(' + comp_id + ')';
|
||||
|
||||
non_std_monomer = true;
|
||||
}
|
||||
|
||||
if (type.empty())
|
||||
type = c_type;
|
||||
@@ -792,7 +916,7 @@ void createEntityPoly(datablock &db)
|
||||
|
||||
entity_poly.emplace({ //
|
||||
{ "entity_id", entity_id },
|
||||
{ "type", type },
|
||||
{ "type", type.empty() ? "other"s : type },
|
||||
{ "nstd_linkage", non_std_linkage },
|
||||
{ "nstd_monomer", non_std_monomer },
|
||||
{ "pdbx_seq_one_letter_code", entity_seq },
|
||||
@@ -803,7 +927,7 @@ void createEntityPoly(datablock &db)
|
||||
|
||||
void createEntityPolySeq(datablock &db)
|
||||
{
|
||||
if (db.get("entity_poly") == nullptr)
|
||||
if (auto cat = db.get("entity_poly"); cat == nullptr or cat->empty())
|
||||
createEntityPoly(db);
|
||||
|
||||
using namespace literals;
|
||||
@@ -854,7 +978,10 @@ void createEntityPolySeq(datablock &db)
|
||||
|
||||
void createPdbxPolySeqScheme(datablock &db)
|
||||
{
|
||||
if (db.get("entity_poly_seq") == nullptr)
|
||||
if (auto cat = db.get("entity_poly"); cat == nullptr or cat->empty())
|
||||
createEntityPoly(db);
|
||||
|
||||
if (auto cat = db.get("entity_poly_seq"); cat == nullptr or cat->empty())
|
||||
createEntityPolySeq(db);
|
||||
|
||||
using namespace literals;
|
||||
@@ -912,6 +1039,10 @@ void comparePolySeqSchemes(datablock &db)
|
||||
auto &ndb_poly_seq_scheme = db["ndb_poly_seq_scheme"];
|
||||
auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"];
|
||||
|
||||
// Don't bother if ndb_poly_seq_scheme is empty
|
||||
if (ndb_poly_seq_scheme.empty())
|
||||
return;
|
||||
|
||||
// Since often ndb_poly_seq_scheme only contains an id and mon_id item
|
||||
// we assume that it should match the accompanying pdbx_poly_seq
|
||||
|
||||
@@ -980,7 +1111,247 @@ void comparePolySeqSchemes(datablock &db)
|
||||
}
|
||||
}
|
||||
|
||||
bool reconstruct_pdbx(file &file, std::string_view dictionary)
|
||||
void createPdbxEntityNonpoly(datablock &db)
|
||||
{
|
||||
using namespace literals;
|
||||
|
||||
auto &atom_site = db["atom_site"];
|
||||
auto &entity = db["entity"];
|
||||
auto &pdbx_entity_nonpoly = db["pdbx_entity_nonpoly"];
|
||||
|
||||
for (const auto &[entity_id, type] : entity.find<std::string, std::string>("type"_key == "water" or "type"_key == "non-polymer", "id", "type"))
|
||||
{
|
||||
for (auto comp_id : atom_site.find<std::string>("label_entity_id"_key == entity_id, "label_comp_id"))
|
||||
{
|
||||
if (auto test_comp_id = pdbx_entity_nonpoly.find_first<std::optional<std::string>>("entity_id"_key == entity_id, "comp_id"); test_comp_id.has_value())
|
||||
{
|
||||
if (*test_comp_id != comp_id)
|
||||
throw std::runtime_error("Inconsistent pdbx_entity_nonpoly record for entity " + entity_id + ", expected comp_id " + comp_id);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == "water")
|
||||
pdbx_entity_nonpoly.emplace({ //
|
||||
{ "entity_id", entity_id },
|
||||
{ "name", "water" },
|
||||
{ "comp_id", comp_id }
|
||||
});
|
||||
else
|
||||
{
|
||||
auto c = cif::compound_factory::instance().create(comp_id);
|
||||
|
||||
std::string name = c ? c->name() : ".";
|
||||
|
||||
pdbx_entity_nonpoly.emplace({ //
|
||||
{ "entity_id", entity_id },
|
||||
{ "name", name },
|
||||
{ "comp_id", comp_id }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createPdbxNonpolyScheme(datablock &db)
|
||||
{
|
||||
using namespace literals;
|
||||
|
||||
createPdbxEntityNonpoly(db);
|
||||
|
||||
auto &pdbx_entity_nonpoly = db["pdbx_entity_nonpoly"];
|
||||
auto &pdbx_nonpoly_scheme = db["pdbx_nonpoly_scheme"];
|
||||
auto &atom_site = db["atom_site"];
|
||||
|
||||
for (const auto &[entity_id, comp_id] : pdbx_entity_nonpoly.rows<std::string,std::string>("entity_id", "comp_id"))
|
||||
{
|
||||
for (int ndb_nr = 1; auto row : atom_site.find("label_entity_id"_key == entity_id and "label_comp_id"_key == comp_id))
|
||||
{
|
||||
// Skip existing records
|
||||
auto linked = atom_site.get_children(row, pdbx_nonpoly_scheme);
|
||||
if (not linked.empty())
|
||||
continue;
|
||||
|
||||
int num = row.get<int>("auth_seq_id");
|
||||
|
||||
pdbx_nonpoly_scheme.emplace({//
|
||||
|
||||
{ "asym_id", row.get<std::string>("label_asym_id") },
|
||||
{ "entity_id", entity_id },
|
||||
{ "mon_id", comp_id },
|
||||
{ "ndb_seq_num", ndb_nr++ },
|
||||
{ "pdb_seq_num", num },
|
||||
{ "auth_seq_num", num },
|
||||
{ "pdb_mon_id", row.get<std::string>("auth_comp_id") },
|
||||
{ "auth_mon_id", row.get<std::string>("auth_comp_id") },
|
||||
{ "pdb_strand_id", row.get<std::string>("auth_asym_id") },
|
||||
{ "pdb_ins_code", row.get<std::string>("pdbx_PDB_ins_code") }
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createPdbxBranchScheme(datablock &db)
|
||||
{
|
||||
using namespace literals;
|
||||
|
||||
createPdbxEntityNonpoly(db);
|
||||
|
||||
auto &entity = db["entity"];
|
||||
auto &pdbx_branch_scheme = db["pdbx_branch_scheme"];
|
||||
auto &pdbx_entity_branch_list = db["pdbx_entity_branch_list"];
|
||||
auto &atom_site = db["atom_site"];
|
||||
|
||||
for (const auto entity_id : entity.find<std::string>("type"_key == "branched", "id"))
|
||||
{
|
||||
for (const auto &[comp_id, asym_id, auth_seq_id] : atom_site.find<std::string, std::string, std::optional<int>>("label_entity_id"_key == entity_id, "label_comp_id", "label_asym_id", "auth_seq_id"))
|
||||
{
|
||||
if (not auth_seq_id.has_value())
|
||||
throw std::runtime_error("Missing auth_seq_id on sugar atom");
|
||||
|
||||
int num = *auth_seq_id;
|
||||
|
||||
if (not pdbx_entity_branch_list.contains("entity_id"_key == entity_id and "num"_key == num))
|
||||
{
|
||||
pdbx_entity_branch_list.emplace({
|
||||
// clang-format off
|
||||
|
||||
{ "entity_id", entity_id },
|
||||
{ "comp_id", comp_id },
|
||||
{ "num", num },
|
||||
|
||||
// clang-format on
|
||||
});
|
||||
}
|
||||
|
||||
if (not pdbx_branch_scheme.contains("entity_id"_key == entity_id and "asym_id"_key == asym_id and "num"_key == num))
|
||||
{
|
||||
pdbx_branch_scheme.emplace({
|
||||
// clang-format off
|
||||
{ "asym_id", asym_id },
|
||||
{ "entity_id", entity_id },
|
||||
{ "mon_id", comp_id },
|
||||
{ "num", num },
|
||||
{ "pdb_asym_id", asym_id },
|
||||
{ "pdb_mon_id", comp_id },
|
||||
{ "pdb_seq_num", num }
|
||||
// clang-format on
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reconstruct_index_for_category(const validator &validator, category &cat, datablock &db)
|
||||
{
|
||||
auto cv = validator.get_validator_for_category(cat.name());
|
||||
|
||||
enum class State
|
||||
{
|
||||
Start,
|
||||
MissingKeys,
|
||||
DuplicateKeys
|
||||
} state = State::Start;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// See if we can build an index
|
||||
try
|
||||
{
|
||||
cat.set_validator(&validator, db);
|
||||
}
|
||||
catch (const missing_key_error &ex)
|
||||
{
|
||||
if (state == State::MissingKeys)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Repairing failed for category " << cat.name() << ", missing keys remain: " << ex.what() << '\n';
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
state = State::MissingKeys;
|
||||
|
||||
auto key = ex.get_key();
|
||||
|
||||
if (cif::VERBOSE > 1)
|
||||
std::clog << "Need to add key " << key << " to category " << cat.name() << '\n';
|
||||
|
||||
for (auto row : cat)
|
||||
{
|
||||
auto ord = row.get<std::string>(key.c_str());
|
||||
if (ord.empty())
|
||||
row.assign({ //
|
||||
{ key, cat.get_unique_value(key) } });
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
catch (const duplicate_key_error &ex)
|
||||
{
|
||||
if (state == State::DuplicateKeys)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Repairing failed for category " << cat.name() << ", duplicate keys remain: " << ex.what() << '\n';
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
state = State::DuplicateKeys;
|
||||
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Attempt to fix " << cat.name() << " failed: " << ex.what() << '\n';
|
||||
|
||||
// replace items that do not define a relation to a parent
|
||||
|
||||
std::set<std::string> replaceableKeys;
|
||||
for (auto key : cv->m_keys)
|
||||
{
|
||||
bool replaceable = true;
|
||||
for (auto lv : validator.get_links_for_child(cat.name()))
|
||||
{
|
||||
if (find(lv->m_child_keys.begin(), lv->m_child_keys.end(), key) != lv->m_child_keys.end())
|
||||
{
|
||||
replaceable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceable)
|
||||
replaceableKeys.insert(key);
|
||||
}
|
||||
|
||||
if (replaceableKeys.empty())
|
||||
throw std::runtime_error("Cannot repair category " + cat.name() + " since it contains duplicate keys that cannot be replaced");
|
||||
|
||||
for (auto key : replaceableKeys)
|
||||
{
|
||||
for (auto row : cat)
|
||||
row.assign(key, cat.get_unique_value(key), false, false);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool reconstruct_pdbx(file &file)
|
||||
{
|
||||
if (file.empty())
|
||||
throw std::runtime_error("Cannot reconstruct PDBx, file seems to be empty");
|
||||
|
||||
auto &db = file.front();
|
||||
|
||||
if (auto ac = db.get("audit_conform"); ac != nullptr)
|
||||
return reconstruct_pdbx(file, validator_factory::instance().get(*ac));
|
||||
else
|
||||
return reconstruct_pdbx(file, validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
}
|
||||
|
||||
bool reconstruct_pdbx(file &file, const validator &validator)
|
||||
{
|
||||
if (file.empty())
|
||||
throw std::runtime_error("Cannot reconstruct PDBx, file seems to be empty");
|
||||
@@ -991,15 +1362,13 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
|
||||
// ... and any additional datablock will contain compound information
|
||||
cif::compound_source cs(file);
|
||||
|
||||
if (db.get("atom_site") == nullptr)
|
||||
if (auto cat = db.get("atom_site"); cat == nullptr or cat->empty())
|
||||
throw std::runtime_error("Cannot reconstruct PDBx file, atom data missing");
|
||||
|
||||
auto &validator = validator_factory::instance()[dictionary];
|
||||
|
||||
std::string entry_id;
|
||||
|
||||
// Phenix files do not have an entry record
|
||||
if (db.get("entry") == nullptr)
|
||||
if (auto cat = db.get("entry"); cat == nullptr or cat->empty())
|
||||
{
|
||||
entry_id = db.name();
|
||||
category entry("entry");
|
||||
@@ -1064,7 +1433,7 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
|
||||
iv->m_type != nullptr and
|
||||
iv->m_type->m_primitive_type == cif::DDL_PrimitiveType::Numb;
|
||||
|
||||
for (size_t ix = 0; auto row : cat)
|
||||
for (std::size_t ix = 0; auto row : cat)
|
||||
{
|
||||
if (number)
|
||||
row.assign(key, std::to_string(++ix), false, false);
|
||||
@@ -1135,95 +1504,7 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
|
||||
}
|
||||
}
|
||||
|
||||
enum class State
|
||||
{
|
||||
Start,
|
||||
MissingKeys,
|
||||
DuplicateKeys
|
||||
} state = State::Start;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// See if we can build an index
|
||||
try
|
||||
{
|
||||
cat.set_validator(&validator, db);
|
||||
}
|
||||
catch (const missing_key_error &ex)
|
||||
{
|
||||
if (state == State::MissingKeys)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Repairing failed for category " << cat.name() << ", missing keys remain: " << ex.what() << '\n';
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
state = State::MissingKeys;
|
||||
|
||||
auto key = ex.get_key();
|
||||
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Need to add key " << key << " to category " << cat.name() << '\n';
|
||||
|
||||
for (auto row : cat)
|
||||
{
|
||||
auto ord = row.get<std::string>(key.c_str());
|
||||
if (ord.empty())
|
||||
row.assign({ //
|
||||
{ key, cat.get_unique_value(key) } });
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
catch (const duplicate_key_error &ex)
|
||||
{
|
||||
if (state == State::DuplicateKeys)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Repairing failed for category " << cat.name() << ", duplicate keys remain: " << ex.what() << '\n';
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
state = State::DuplicateKeys;
|
||||
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Attempt to fix " << cat.name() << " failed: " << ex.what() << '\n';
|
||||
|
||||
// replace items that do not define a relation to a parent
|
||||
|
||||
std::set<std::string> replaceableKeys;
|
||||
for (auto key : cv->m_keys)
|
||||
{
|
||||
bool replaceable = true;
|
||||
for (auto lv : validator.get_links_for_child(cat.name()))
|
||||
{
|
||||
if (find(lv->m_child_keys.begin(), lv->m_child_keys.end(), key) != lv->m_child_keys.end())
|
||||
{
|
||||
replaceable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceable)
|
||||
replaceableKeys.insert(key);
|
||||
}
|
||||
|
||||
if (replaceableKeys.empty())
|
||||
throw std::runtime_error("Cannot repair category " + cat.name() + " since it contains duplicate keys that cannot be replaced");
|
||||
|
||||
for (auto key : replaceableKeys)
|
||||
{
|
||||
for (auto row : cat)
|
||||
row.assign(key, cat.get_unique_value(key), false, false);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
reconstruct_index_for_category(validator, cat, db);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
@@ -1246,31 +1527,146 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
|
||||
|
||||
db["chem_comp"].reorder_by_index();
|
||||
|
||||
file.load_dictionary(dictionary);
|
||||
db.set_validator(&validator);
|
||||
|
||||
if (db.get("atom_site_anisotrop"))
|
||||
checkAtomAnisotropRecords(db);
|
||||
|
||||
// Now create any missing categories
|
||||
// Next make sure we have struct_asym records
|
||||
if (db.get("struct_asym") == nullptr)
|
||||
if (auto cat = db.get("struct_asym"); cat == nullptr or cat->empty())
|
||||
createStructAsym(db);
|
||||
|
||||
if (db.get("entity") == nullptr)
|
||||
if (auto cat = db.get("entity"); cat == nullptr or cat->empty())
|
||||
createEntity(db);
|
||||
|
||||
if (db.get("pdbx_poly_seq_scheme") == nullptr)
|
||||
if (auto cat = db.get("pdbx_poly_seq_scheme"); cat == nullptr or cat->empty())
|
||||
createPdbxPolySeqScheme(db);
|
||||
|
||||
if (db.get("ndb_poly_seq_scheme") != nullptr)
|
||||
if (auto cat = db.get("ndb_poly_seq_scheme"); cat == nullptr or cat->empty())
|
||||
comparePolySeqSchemes(db);
|
||||
|
||||
createPdbxNonpolyScheme(db);
|
||||
|
||||
// Create a minimal set of branch records
|
||||
createPdbxBranchScheme(db);
|
||||
|
||||
// fill in missing formula_weight, e.g.
|
||||
checkEntities(db);
|
||||
|
||||
// skip unknown categories for now
|
||||
bool valid = true;
|
||||
for (auto &cat : db)
|
||||
valid = valid and (cat.get_cat_validator() == nullptr or cat.is_valid());
|
||||
|
||||
return valid and is_valid_pdbx_file(file, dictionary);
|
||||
return valid and is_valid_pdbx_file(file, validator);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void fixup_pdbx(file &file)
|
||||
{
|
||||
if (file.empty())
|
||||
throw std::runtime_error("Cannot reconstruct PDBx, file seems to be empty");
|
||||
|
||||
auto &db = file.front();
|
||||
|
||||
if (auto ac = db.get("audit_conform"); ac != nullptr)
|
||||
fixup_pdbx(file, validator_factory::instance().get(*ac));
|
||||
else
|
||||
fixup_pdbx(file, validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
}
|
||||
|
||||
void fixup_pdbx(file &file, const validator &validator)
|
||||
{
|
||||
if (file.empty())
|
||||
throw std::runtime_error("Cannot reconstruct PDBx, file seems to be empty");
|
||||
|
||||
// assuming the first datablock contains the entry ...
|
||||
auto &db = file.front();
|
||||
|
||||
if (auto cat = db.get("atom_site"); cat == nullptr or cat->empty())
|
||||
throw std::runtime_error("Cannot reconstruct PDBx file, atom data missing");
|
||||
|
||||
// ... and any additional datablock will contain compound information
|
||||
cif::compound_source cs(file);
|
||||
|
||||
// Be silent about missing compound info in fixup
|
||||
auto &cf = compound_factory::instance();
|
||||
bool save_report = cf.get_report_missing();
|
||||
cf.set_report_missing(cif::VERBOSE > 1);
|
||||
|
||||
std::string entry_id;
|
||||
|
||||
// Phenix files do not have an entry record
|
||||
if (auto cat = db.get("entry"); cat == nullptr or cat->empty())
|
||||
{
|
||||
entry_id = db.name();
|
||||
category entry("entry");
|
||||
entry.emplace({ { "id", entry_id } });
|
||||
db.emplace_back(std::move(entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &entry = db["entry"];
|
||||
if (entry.size() != 1)
|
||||
throw std::runtime_error("Unexpected size of entry category");
|
||||
|
||||
entry_id = entry.front().get<std::string>("id");
|
||||
}
|
||||
|
||||
// Start with chem_comp, it is often missing many fields
|
||||
// that can easily be filled in.
|
||||
checkChemCompRecords(db);
|
||||
|
||||
// If the data is really horrible, it might not contain entities
|
||||
if (not db["atom_site"].find_first(key("label_entity_id") != null))
|
||||
createEntityIDs(db);
|
||||
|
||||
// Now see if atom records make sense at all, but in a silent way, this time
|
||||
checkAtomRecords(db);
|
||||
|
||||
db["chem_comp"].reorder_by_index();
|
||||
|
||||
// See if we can easily reconstruct missing data fields in order to create an index
|
||||
for (auto &cat : db)
|
||||
{
|
||||
try
|
||||
{
|
||||
cat.set_validator(&validator, db);
|
||||
}
|
||||
catch (const missing_key_error &)
|
||||
{
|
||||
reconstruct_index_for_category(validator, cat, db);
|
||||
}
|
||||
}
|
||||
|
||||
db.set_validator(&validator);
|
||||
|
||||
// Now create any missing categories
|
||||
// Next make sure we have struct_asym records
|
||||
if (auto cat = db.get("struct_asym"); cat == nullptr or cat->empty())
|
||||
createStructAsym(db);
|
||||
|
||||
if (auto cat = db.get("entity"); cat == nullptr or cat->empty())
|
||||
createEntity(db);
|
||||
|
||||
if (auto cat = db.get("pdbx_poly_seq_scheme"); cat == nullptr or cat->empty())
|
||||
createPdbxPolySeqScheme(db);
|
||||
|
||||
if (auto cat = db.get("ndb_poly_seq_scheme"); cat == nullptr or cat->empty())
|
||||
comparePolySeqSchemes(db);
|
||||
|
||||
createPdbxNonpolyScheme(db);
|
||||
|
||||
// Create a minimal set of branch records
|
||||
createPdbxBranchScheme(db);
|
||||
|
||||
// fill in missing formula_weight, e.g.
|
||||
checkEntities(db);
|
||||
|
||||
// That's it
|
||||
cf.set_report_missing(save_report);
|
||||
}
|
||||
|
||||
} // namespace cif::pdb
|
||||
|
||||
@@ -48,7 +48,7 @@ condition get_parents_condition(const validator &validator, row_handle rh, const
|
||||
{
|
||||
condition cond;
|
||||
|
||||
for (size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
|
||||
for (std::size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
|
||||
{
|
||||
auto childValue = rh[link->m_child_keys[ix]];
|
||||
|
||||
@@ -61,17 +61,15 @@ condition get_parents_condition(const validator &validator, row_handle rh, const
|
||||
result = std::move(result) or std::move(cond);
|
||||
}
|
||||
}
|
||||
else if (cif::VERBOSE > 0)
|
||||
std::cerr << "warning: no child to parent links were found for child " << childName << " and parent " << parentName << '\n';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
|
||||
bool is_valid_pdbx_file(const file &file, const validator &v)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool result = is_valid_pdbx_file(file, dictionary, ec);
|
||||
return result and ec == std::errc();
|
||||
bool result = is_valid_pdbx_file(file, v, ec);
|
||||
return result and not (bool)ec;
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file, std::error_code &ec)
|
||||
@@ -80,42 +78,23 @@ bool is_valid_pdbx_file(const file &file, std::error_code &ec)
|
||||
|
||||
if (file.empty())
|
||||
ec = make_error_code(validation_error::empty_file);
|
||||
else if (auto ac = file.front().get("audit_conform"); ac != nullptr)
|
||||
result = is_valid_pdbx_file(file, validator_factory::instance().get(*ac), ec);
|
||||
else
|
||||
{
|
||||
std::string dictionary = "mmcif_pdbx";
|
||||
|
||||
for (auto &db : file)
|
||||
{
|
||||
auto audit_conform = db.get("audit_conform");
|
||||
if (audit_conform == nullptr)
|
||||
continue;
|
||||
|
||||
if (not audit_conform->empty())
|
||||
{
|
||||
auto specified_dict = audit_conform->front()["dict_name"];
|
||||
if (not specified_dict.empty())
|
||||
dictionary = specified_dict.as<std::string>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
result = is_valid_pdbx_file(file, dictionary, ec);
|
||||
}
|
||||
result = is_valid_pdbx_file(file, validator_factory::instance().get("mmcif_pdbx.dic"), ec);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::error_code &ec)
|
||||
bool is_valid_pdbx_file(const file &file, const validator &validator, std::error_code &ec)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
bool result = true;
|
||||
bool result = true, warned_missing_parents = false;
|
||||
|
||||
try
|
||||
{
|
||||
auto &cf = cif::compound_factory::instance();
|
||||
auto &validator = cif::validator_factory::instance().operator[](dictionary);
|
||||
|
||||
if (file.empty())
|
||||
throw std::runtime_error("Empty file");
|
||||
@@ -148,10 +127,18 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
|
||||
if (not cf.is_monomer(comp_id))
|
||||
continue;
|
||||
|
||||
auto p = pdbx_poly_seq_scheme.find(get_parents_condition(validator, r, pdbx_poly_seq_scheme));
|
||||
auto cond = get_parents_condition(validator, r, pdbx_poly_seq_scheme);
|
||||
if (not cond)
|
||||
{
|
||||
if (VERBOSE > 0 and std::exchange(warned_missing_parents, true) == false)
|
||||
std::cerr << "warning: missing links for atom_site/pdbx_poly_seq_scheme\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto p = pdbx_poly_seq_scheme.find(std::move(cond));
|
||||
if (p.size() != 1)
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
if (VERBOSE > 0)
|
||||
std::clog << "In atom_site record: " << r["id"].text() << '\n';
|
||||
throw std::runtime_error("For each monomer in atom_site there should be exactly one pdbx_poly_seq_scheme record");
|
||||
}
|
||||
@@ -189,6 +176,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
|
||||
for (auto asym_id : struct_asym.find<std::string>("entity_id"_key == entity_id, "id"))
|
||||
{
|
||||
if (pdbx_poly_seq_scheme.count(
|
||||
"entity_id"_key == entity_id and
|
||||
"asym_id"_key == asym_id and
|
||||
"mon_id"_key == mon_id and
|
||||
"seq_id"_key == num and
|
||||
@@ -202,6 +190,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
|
||||
for (const auto &[seq_id, mon_id, hetero] : pdbx_poly_seq_scheme.find<int, std::string, bool>("entity_id"_key == entity_id, "seq_id", "mon_id", "hetero"))
|
||||
{
|
||||
if (entity_poly_seq.count(
|
||||
"entity_id"_key == entity_id and
|
||||
"mon_id"_key == mon_id and
|
||||
"num"_key == seq_id and
|
||||
"hetero"_key == hetero) != 1)
|
||||
@@ -291,7 +280,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
|
||||
|
||||
if (not seq.has_value())
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
if (VERBOSE > 0)
|
||||
std::clog << "Warning: entity_poly has no sequence for entity_id " << entity_id << '\n';
|
||||
}
|
||||
else
|
||||
@@ -304,8 +293,8 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
|
||||
|
||||
if (not seq_can.has_value())
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Warning: entity_poly has no sequence for entity_id " << entity_id << '\n';
|
||||
if (VERBOSE > 1)
|
||||
std::clog << "Warning: entity_poly has no canonical sequence for entity_id " << entity_id << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -321,16 +310,16 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
result = false;
|
||||
if (cif::VERBOSE > 0)
|
||||
if (VERBOSE > 0)
|
||||
std::clog << ex.what() << '\n';
|
||||
ec = make_error_code(validation_error::not_valid_pdbx);
|
||||
}
|
||||
|
||||
if (not result and ec == std::errc())
|
||||
if (not result and (bool)ec)
|
||||
ec = make_error_code(validation_error::not_valid_pdbx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif::pdb
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include "symop_table_data.hpp"
|
||||
|
||||
#include <Eigen/Eigenvalues>
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -103,15 +103,15 @@ sym_op::sym_op(std::string_view s)
|
||||
auto b = s.data();
|
||||
auto e = b + s.length();
|
||||
|
||||
int rnri = 256; // default to unexisting number
|
||||
int rnri = 256; // default to unexisting number
|
||||
auto r = std::from_chars(b, e, rnri);
|
||||
|
||||
|
||||
m_nr = static_cast<uint8_t>(rnri);
|
||||
m_ta = r.ptr[1] - '0';
|
||||
m_tb = r.ptr[2] - '0';
|
||||
m_tc = r.ptr[3] - '0';
|
||||
|
||||
if (r.ec != std::errc() or rnri > 192 or r.ptr[0] != '_' or m_ta > 9 or m_tb > 9 or m_tc > 9)
|
||||
if ((bool)r.ec or rnri > 192 or r.ptr[0] != '_' or m_ta > 9 or m_tb > 9 or m_tc > 9)
|
||||
throw std::invalid_argument("Could not convert string into sym_op");
|
||||
}
|
||||
|
||||
@@ -119,16 +119,16 @@ std::string sym_op::string() const
|
||||
{
|
||||
char b[9];
|
||||
auto r = std::to_chars(b, b + sizeof(b), m_nr);
|
||||
if (r.ec != std::errc() or r.ptr > b + 4)
|
||||
if ((bool)r.ec or r.ptr > b + 4)
|
||||
throw std::runtime_error("Could not write out symmetry operation to string");
|
||||
|
||||
|
||||
*r.ptr++ = '_';
|
||||
*r.ptr++ = '0' + m_ta;
|
||||
*r.ptr++ = '0' + m_tb;
|
||||
*r.ptr++ = '0' + m_tc;
|
||||
*r.ptr = 0;
|
||||
|
||||
return { b, static_cast<size_t>(r.ptr - b) };
|
||||
return { b, static_cast<std::size_t>(r.ptr - b) };
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -163,41 +163,16 @@ transformation::transformation(const matrix3x3<float> &r, const cif::point &t)
|
||||
|
||||
void transformation::try_create_quaternion()
|
||||
{
|
||||
float Qxx = m_rotation(0, 0);
|
||||
float Qxy = m_rotation(0, 1);
|
||||
float Qxz = m_rotation(0, 2);
|
||||
float Qyx = m_rotation(1, 0);
|
||||
float Qyy = m_rotation(1, 1);
|
||||
float Qyz = m_rotation(1, 2);
|
||||
float Qzx = m_rotation(2, 0);
|
||||
float Qzy = m_rotation(2, 1);
|
||||
float Qzz = m_rotation(2, 2);
|
||||
Eigen::Matrix3f rot;
|
||||
|
||||
Eigen::Matrix4f em;
|
||||
rot << m_rotation(0, 0), m_rotation(0, 1), m_rotation(0, 2),
|
||||
m_rotation(1, 0), m_rotation(1, 1), m_rotation(1, 2),
|
||||
m_rotation(2, 0), m_rotation(2, 1), m_rotation(2, 2);
|
||||
|
||||
em << Qxx - Qyy - Qzz, Qyx + Qxy, Qzx + Qxz, Qzy - Qyz,
|
||||
Qyx + Qxy, Qyy - Qxx - Qzz, Qzy + Qyz, Qxz - Qzx,
|
||||
Qzx + Qxz, Qzy + Qyz, Qzz - Qxx - Qyy, Qyx - Qxy,
|
||||
Qzy - Qyz, Qxz - Qzx, Qyx - Qxy, Qxx + Qyy + Qzz;
|
||||
|
||||
Eigen::EigenSolver<Eigen::Matrix4f> es(em / 3);
|
||||
|
||||
auto ev = es.eigenvalues();
|
||||
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
if (rot * rot.transpose() == Eigen::Matrix3f::Identity() and rot.determinant() == 1)
|
||||
{
|
||||
if (std::abs(ev[j].real() - 1) > 0.01)
|
||||
continue;
|
||||
|
||||
auto col = es.eigenvectors().col(j);
|
||||
|
||||
m_q = normalize(cif::quaternion{
|
||||
static_cast<float>(col(3).real()),
|
||||
static_cast<float>(col(0).real()),
|
||||
static_cast<float>(col(1).real()),
|
||||
static_cast<float>(col(2).real()) });
|
||||
|
||||
break;
|
||||
Eigen::Quaternionf qe(rot);
|
||||
m_q = normalize(cif::quaternion{ qe.w(), qe.x(), qe.y(), qe.z() });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +196,7 @@ transformation inverse(const transformation &t)
|
||||
spacegroup::spacegroup(int nr)
|
||||
: m_nr(nr)
|
||||
{
|
||||
const size_t N = kSymopNrTableSize;
|
||||
const std::size_t N = kSymopNrTableSize;
|
||||
int32_t L = 0, R = static_cast<int32_t>(N - 1);
|
||||
while (L <= R)
|
||||
{
|
||||
@@ -234,7 +209,7 @@ spacegroup::spacegroup(int nr)
|
||||
|
||||
m_index = L;
|
||||
|
||||
for (size_t i = L; i < N and kSymopNrTable[i].spacegroup() == m_nr; ++i)
|
||||
for (std::size_t i = L; i < N and kSymopNrTable[i].spacegroup() == m_nr; ++i)
|
||||
emplace_back(kSymopNrTable[i].symop().data());
|
||||
}
|
||||
|
||||
@@ -297,7 +272,7 @@ point spacegroup::operator()(const point &pt, const cell &c, sym_op symop) const
|
||||
{
|
||||
if (symop.m_nr < 1 or symop.m_nr > size())
|
||||
throw std::out_of_range("symmetry operator number out of range");
|
||||
|
||||
|
||||
transformation t = at(symop.m_nr - 1);
|
||||
|
||||
t.m_translation.m_x += symop.m_ta - 5;
|
||||
@@ -316,7 +291,7 @@ point spacegroup::inverse(const point &pt, const cell &c, sym_op symop) const
|
||||
{
|
||||
if (symop.m_nr < 1 or symop.m_nr > size())
|
||||
throw std::out_of_range("symmetry operator number out of range");
|
||||
|
||||
|
||||
transformation t = at(symop.m_nr - 1);
|
||||
|
||||
t.m_translation.m_x += symop.m_ta - 5;
|
||||
@@ -343,7 +318,7 @@ int get_space_group_number(std::string_view spacegroup)
|
||||
|
||||
int result = 0;
|
||||
|
||||
const size_t N = kNrOfSpaceGroups;
|
||||
const std::size_t N = kNrOfSpaceGroups;
|
||||
int32_t L = 0, R = static_cast<int32_t>(N - 1);
|
||||
while (L <= R)
|
||||
{
|
||||
@@ -365,7 +340,7 @@ int get_space_group_number(std::string_view spacegroup)
|
||||
// not found, see if we can find a match based on xHM name
|
||||
if (result == 0)
|
||||
{
|
||||
for (size_t i = 0; i < kNrOfSpaceGroups; ++i)
|
||||
for (std::size_t i = 0; i < kNrOfSpaceGroups; ++i)
|
||||
{
|
||||
auto &sp = kSpaceGroups[i];
|
||||
if (sp.xHM == spacegroup)
|
||||
@@ -395,7 +370,7 @@ int get_space_group_number(std::string_view spacegroup, space_group_name type)
|
||||
|
||||
if (type == space_group_name::full)
|
||||
{
|
||||
const size_t N = kNrOfSpaceGroups;
|
||||
const std::size_t N = kNrOfSpaceGroups;
|
||||
int32_t L = 0, R = static_cast<int32_t>(N - 1);
|
||||
while (L <= R)
|
||||
{
|
||||
@@ -450,13 +425,13 @@ int get_space_group_number(const datablock &db)
|
||||
|
||||
if (_symmetry.size() != 1)
|
||||
throw std::runtime_error("Could not find a unique symmetry in this mmCIF file");
|
||||
|
||||
|
||||
return _symmetry.front().get<int>("Int_Tables_number");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<float,point,sym_op> crystal::closest_symmetry_copy(point a, point b) const
|
||||
std::tuple<float, point, sym_op> crystal::closest_symmetry_copy(point a, point b) const
|
||||
{
|
||||
if (m_cell.get_a() == 0 or m_cell.get_b() == 0 or m_cell.get_c() == 0)
|
||||
throw std::runtime_error("Invalid cell, contains a dimension that is zero");
|
||||
@@ -475,7 +450,7 @@ std::tuple<float,point,sym_op> crystal::closest_symmetry_copy(point a, point b)
|
||||
|
||||
a = orthogonal(fa, m_cell);
|
||||
|
||||
for (size_t i = 0; i < m_spacegroup.size(); ++i)
|
||||
for (std::size_t i = 0; i < m_spacegroup.size(); ++i)
|
||||
{
|
||||
sym_op s(static_cast<uint8_t>(i + 1));
|
||||
auto &t = m_spacegroup[i];
|
||||
@@ -491,7 +466,7 @@ std::tuple<float,point,sym_op> crystal::closest_symmetry_copy(point a, point b)
|
||||
while (fsb.m_x + 0.5f < fa.m_x)
|
||||
{
|
||||
fsb.m_x += 1;
|
||||
s.m_ta += 1;
|
||||
s.m_ta += 1;
|
||||
}
|
||||
|
||||
while (fsb.m_y - 0.5f > fa.m_y)
|
||||
@@ -503,7 +478,7 @@ std::tuple<float,point,sym_op> crystal::closest_symmetry_copy(point a, point b)
|
||||
while (fsb.m_y + 0.5f < fa.m_y)
|
||||
{
|
||||
fsb.m_y += 1;
|
||||
s.m_tb += 1;
|
||||
s.m_tb += 1;
|
||||
}
|
||||
|
||||
while (fsb.m_z - 0.5f > fa.m_z)
|
||||
@@ -515,7 +490,7 @@ std::tuple<float,point,sym_op> crystal::closest_symmetry_copy(point a, point b)
|
||||
while (fsb.m_z + 0.5f < fa.m_z)
|
||||
{
|
||||
fsb.m_z += 1;
|
||||
s.m_tc += 1;
|
||||
s.m_tc += 1;
|
||||
}
|
||||
|
||||
auto p = orthogonal(fsb, m_cell);
|
||||
|
||||
@@ -280,7 +280,7 @@ int main(int argc, char* const argv[])
|
||||
if (std::isdigit(line[0])) // start of new spacegroup
|
||||
{
|
||||
auto r = std::from_chars(line.data(), line.data() + line.length(), sgnr);
|
||||
if (r.ec != std::errc())
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("Error parsing symop.lib file");
|
||||
rnr = 1;
|
||||
continue;
|
||||
@@ -426,7 +426,7 @@ const space_group kSpaceGroups[] =
|
||||
out << R"(
|
||||
};
|
||||
|
||||
const size_t kNrOfSpaceGroups = sizeof(kSpaceGroups) / sizeof(space_group);
|
||||
const std::size_t kNrOfSpaceGroups = sizeof(kSpaceGroups) / sizeof(space_group);
|
||||
|
||||
const symop_datablock kSymopNrTable[] = {
|
||||
)";
|
||||
@@ -450,7 +450,7 @@ const symop_datablock kSymopNrTable[] = {
|
||||
|
||||
out << R"(};
|
||||
|
||||
const size_t kSymopNrTableSize = sizeof(kSymopNrTable) / sizeof(symop_datablock);
|
||||
const std::size_t kSymopNrTableSize = sizeof(kSymopNrTable) / sizeof(symop_datablock);
|
||||
|
||||
} // namespace mmcif
|
||||
)";
|
||||
|
||||
@@ -361,7 +361,7 @@ const space_group kSpaceGroups[] =
|
||||
|
||||
};
|
||||
|
||||
const size_t kNrOfSpaceGroups = sizeof(kSpaceGroups) / sizeof(space_group);
|
||||
const std::size_t kNrOfSpaceGroups = sizeof(kSpaceGroups) / sizeof(space_group);
|
||||
|
||||
const symop_datablock kSymopNrTable[] = {
|
||||
// P 1
|
||||
@@ -5286,6 +5286,6 @@ const symop_datablock kSymopNrTable[] = {
|
||||
{ 5005, 4, { -1, 0, 0, 0, 1, 0, 0, 0,-1, 1, 2, 0, 0, 1, 2, } },
|
||||
};
|
||||
|
||||
const size_t kSymopNrTableSize = sizeof(kSymopNrTable) / sizeof(symop_datablock);
|
||||
const std::size_t kSymopNrTableSize = sizeof(kSymopNrTable) / sizeof(symop_datablock);
|
||||
|
||||
} // namespace mmcif
|
||||
|
||||
212
src/text.cpp
212
src/text.cpp
@@ -35,24 +35,24 @@ namespace cif
|
||||
// --------------------------------------------------------------------
|
||||
// This really makes a difference, having our own tolower routines
|
||||
|
||||
const uint8_t kCharToLowerMap[256] =
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
|
||||
const uint8_t kCharToLowerMap[256] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -69,7 +69,7 @@ bool iequals(const char *a, const char *b)
|
||||
{
|
||||
bool result = true;
|
||||
for (; result and *a and *b; ++a, ++b)
|
||||
result = tolower(*a) == tolower(*b);
|
||||
result = kCharToLowerMap[uint8_t(*a)] == kCharToLowerMap[uint8_t(*b)];
|
||||
|
||||
return result and *a == *b;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ int icompare(std::string_view a, std::string_view b)
|
||||
auto ai = a.begin(), bi = b.begin();
|
||||
|
||||
for (; d == 0 and ai != a.end() and bi != b.end(); ++ai, ++bi)
|
||||
d = tolower(*ai) - tolower(*bi);
|
||||
d = (int)kCharToLowerMap[uint8_t(*ai)] - (int)kCharToLowerMap[uint8_t(*bi)];
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
@@ -98,7 +98,7 @@ int icompare(const char *a, const char *b)
|
||||
int d = 0;
|
||||
|
||||
for (; d == 0 and *a != 0 and *b != 0; ++a, ++b)
|
||||
d = tolower(*a) - tolower(*b);
|
||||
d = (int)kCharToLowerMap[uint8_t(*a)] - (int)kCharToLowerMap[uint8_t(*b)];
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
@@ -171,7 +171,7 @@ std::string trim_right_copy(std::string_view s)
|
||||
e = pe;
|
||||
}
|
||||
|
||||
return {s.begin(), e};
|
||||
return { s.begin(), e };
|
||||
}
|
||||
|
||||
std::string trim_left_copy(std::string_view s)
|
||||
@@ -185,27 +185,46 @@ std::string trim_left_copy(std::string_view s)
|
||||
b = std::next(b);
|
||||
}
|
||||
|
||||
return {b, s.end()};
|
||||
return { b, s.end() };
|
||||
}
|
||||
|
||||
void trim_left(std::string &s)
|
||||
{
|
||||
auto b = s.begin();
|
||||
while (b != s.end())
|
||||
auto in = s.begin(), out = s.begin();
|
||||
|
||||
while (in != s.end() and std::isspace(*in))
|
||||
++in;
|
||||
|
||||
if (in == s.end())
|
||||
s.clear();
|
||||
else if (in != out)
|
||||
{
|
||||
if (not std::isspace(*b))
|
||||
break;
|
||||
|
||||
b = std::next(b);
|
||||
while (in != s.end())
|
||||
*out++ = *in++;
|
||||
s.erase(out, s.end());
|
||||
}
|
||||
|
||||
s.erase(s.begin(), b);
|
||||
}
|
||||
|
||||
void trim(std::string &s)
|
||||
{
|
||||
trim_right(s);
|
||||
trim_left(s);
|
||||
auto in = s.begin(), out = s.begin(), end = s.end();
|
||||
|
||||
while (end != s.begin() and std::isspace(*(end - 1)))
|
||||
--end;
|
||||
|
||||
while (in != end and std::isspace(*in))
|
||||
++in;
|
||||
|
||||
if (in == end)
|
||||
s.clear();
|
||||
else if (in != out)
|
||||
{
|
||||
while (in != end)
|
||||
*out++ = *in++;
|
||||
s.erase(out, s.end());
|
||||
}
|
||||
else if (end != s.end())
|
||||
s.erase(end, s.end());
|
||||
}
|
||||
|
||||
std::string trim_copy(std::string_view s)
|
||||
@@ -220,14 +239,14 @@ std::tuple<std::string, std::string> split_item_name(std::string_view item_name)
|
||||
if (item_name.empty())
|
||||
throw std::runtime_error("empty item_name");
|
||||
if (item_name[0] != '_')
|
||||
throw std::runtime_error("item_name '" + std::string { item_name } + "' does not start with underscore");
|
||||
throw std::runtime_error("item_name '" + std::string{ item_name } + "' does not start with underscore");
|
||||
|
||||
auto s = item_name.find('.');
|
||||
if (s == std::string::npos)
|
||||
// throw std::runtime_error("item_name does not contain dot (" + std::string{ item_name } + ')');
|
||||
return std::tuple<std::string, std::string>{ "", item_name.substr(1) };
|
||||
else
|
||||
return std::tuple<std::string, std::string>{item_name.substr(1, s - 1), item_name.substr(s + 1)};
|
||||
return std::tuple<std::string, std::string>{ item_name.substr(1, s - 1), item_name.substr(s + 1) };
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -242,8 +261,7 @@ std::string cif_id_for_number(int number)
|
||||
result += static_cast<char>('A' + r);
|
||||
|
||||
number = (number - r) / 26 - 1;
|
||||
}
|
||||
while (number >= 0);
|
||||
} while (number >= 0);
|
||||
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
@@ -298,29 +316,29 @@ enum LineBreakClass
|
||||
kLBC_Unknown
|
||||
};
|
||||
|
||||
const LineBreakClass kASCII_LBTable[128] =
|
||||
{
|
||||
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_CombiningMark, kLBC_BreakAfter, kLBC_LineFeed, kLBC_MandatoryBreak, kLBC_MandatoryBreak, kLBC_CarriageReturn, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_Space, kLBC_Exlamation, kLBC_Quotation, kLBC_Alphabetic, kLBC_PrefixNumeric, kLBC_PostfixNumeric, kLBC_Alphabetic, kLBC_Quotation,
|
||||
kLBC_OpenPunctuation, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_PrefixNumeric,
|
||||
const LineBreakClass kASCII_LBTable[128] = {
|
||||
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_CombiningMark, kLBC_BreakAfter, kLBC_LineFeed, kLBC_MandatoryBreak, kLBC_MandatoryBreak, kLBC_CarriageReturn, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
|
||||
kLBC_Space, kLBC_Exlamation, kLBC_Quotation, kLBC_Alphabetic, kLBC_PrefixNumeric, kLBC_PostfixNumeric, kLBC_Alphabetic, kLBC_Quotation,
|
||||
kLBC_OpenPunctuation, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_PrefixNumeric,
|
||||
|
||||
// comma treated differently here, it is not a numeric separator in PDB
|
||||
kLBC_SymbolAllowingBreakAfter /* kLBC_InfixNumericSeparator */,
|
||||
// comma treated differently here, it is not a numeric separator in PDB
|
||||
kLBC_SymbolAllowingBreakAfter /* kLBC_InfixNumericSeparator */,
|
||||
|
||||
kLBC_Hyphen, kLBC_InfixNumericSeparator, kLBC_SymbolAllowingBreakAfter,
|
||||
kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric,
|
||||
kLBC_Numeric, kLBC_Numeric, kLBC_InfixNumericSeparator, kLBC_InfixNumericSeparator, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Exlamation,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_PrefixNumeric, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_BreakAfter, kLBC_ClosePunctuation, kLBC_Alphabetic, kLBC_CombiningMark};
|
||||
kLBC_Hyphen, kLBC_InfixNumericSeparator, kLBC_SymbolAllowingBreakAfter,
|
||||
kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric,
|
||||
kLBC_Numeric, kLBC_Numeric, kLBC_InfixNumericSeparator, kLBC_InfixNumericSeparator, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Exlamation,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_PrefixNumeric, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
|
||||
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_BreakAfter, kLBC_ClosePunctuation, kLBC_Alphabetic, kLBC_CombiningMark
|
||||
};
|
||||
|
||||
std::string::const_iterator nextLineBreak(std::string::const_iterator text, std::string::const_iterator end)
|
||||
{
|
||||
@@ -338,33 +356,33 @@ std::string::const_iterator nextLineBreak(std::string::const_iterator text, std:
|
||||
|
||||
const breakAction brkTable[27][27] = {
|
||||
// OP CL CP QU GL NS EX SY IS PR PO NU AL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT
|
||||
/* OP */ {PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, CPB, PBK, PBK, PBK, PBK, PBK, PBK},
|
||||
/* CL */ {DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* CP */ {DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* QU */ {PBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
|
||||
/* GL */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
|
||||
/* NS */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* EX */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* SY */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* IS */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* PR */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, IBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
|
||||
/* PO */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* NU */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* AL */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* ID */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* IN */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* HY */ {DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* BA */ {DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* BB */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
|
||||
/* B2 */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, PBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* ZW */ {DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* CM */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
|
||||
/* WJ */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
|
||||
/* H2 */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK},
|
||||
/* H3 */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK},
|
||||
/* JL */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, DBK},
|
||||
/* JV */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK},
|
||||
/* JT */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK},
|
||||
/* OP */ { PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, CPB, PBK, PBK, PBK, PBK, PBK, PBK },
|
||||
/* CL */ { DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* CP */ { DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* QU */ { PBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
|
||||
/* GL */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
|
||||
/* NS */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* EX */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* SY */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* IS */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* PR */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, IBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
|
||||
/* PO */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* NU */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* AL */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* ID */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* IN */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* HY */ { DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* BA */ { DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* BB */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
|
||||
/* B2 */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, PBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* ZW */ { DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* CM */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
|
||||
/* WJ */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
|
||||
/* H2 */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK },
|
||||
/* H3 */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK },
|
||||
/* JL */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, DBK },
|
||||
/* JV */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK },
|
||||
/* JT */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK },
|
||||
};
|
||||
|
||||
uint8_t ch = static_cast<uint8_t>(*text);
|
||||
@@ -415,10 +433,10 @@ std::string::const_iterator nextLineBreak(std::string::const_iterator text, std:
|
||||
return text;
|
||||
}
|
||||
|
||||
std::vector<std::string> wrapLine(const std::string &text, size_t width)
|
||||
std::vector<std::string> wrapLine(const std::string &text, std::size_t width)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::vector<size_t> offsets = {0};
|
||||
std::vector<std::size_t> offsets = { 0 };
|
||||
|
||||
auto b = text.begin();
|
||||
while (b != text.end())
|
||||
@@ -430,18 +448,18 @@ std::vector<std::string> wrapLine(const std::string &text, size_t width)
|
||||
b = e;
|
||||
}
|
||||
|
||||
size_t count = offsets.size() - 1;
|
||||
std::size_t count = offsets.size() - 1;
|
||||
|
||||
std::vector<size_t> minima(count + 1, 1000000);
|
||||
std::vector<std::size_t> minima(count + 1, 1000000);
|
||||
minima[0] = 0;
|
||||
std::vector<size_t> breaks(count + 1, 0);
|
||||
std::vector<std::size_t> breaks(count + 1, 0);
|
||||
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
size_t j = i + 1;
|
||||
std::size_t j = i + 1;
|
||||
while (j <= count)
|
||||
{
|
||||
size_t w = offsets[j] - offsets[i];
|
||||
std::size_t w = offsets[j] - offsets[i];
|
||||
|
||||
if (w > width)
|
||||
break;
|
||||
@@ -449,7 +467,7 @@ std::vector<std::string> wrapLine(const std::string &text, size_t width)
|
||||
while (w > 0 and isspace(text[offsets[i] + w - 1]))
|
||||
--w;
|
||||
|
||||
size_t cost = minima[i];
|
||||
std::size_t cost = minima[i];
|
||||
if (j < count) // last line may be shorter
|
||||
cost += (width - w) * (width - w);
|
||||
|
||||
@@ -463,10 +481,10 @@ std::vector<std::string> wrapLine(const std::string &text, size_t width)
|
||||
}
|
||||
}
|
||||
|
||||
size_t j = count;
|
||||
std::size_t j = count;
|
||||
while (j > 0)
|
||||
{
|
||||
size_t i = breaks[j];
|
||||
std::size_t i = breaks[j];
|
||||
result.push_back(text.substr(offsets[i], offsets[j] - offsets[i]));
|
||||
j = i;
|
||||
}
|
||||
@@ -476,7 +494,7 @@ std::vector<std::string> wrapLine(const std::string &text, size_t width)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> word_wrap(const std::string &text, size_t width)
|
||||
std::vector<std::string> word_wrap(const std::string &text, std::size_t width)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
for (auto p : cif::split<std::string>(text, "\n"))
|
||||
|
||||
@@ -63,9 +63,9 @@ std::string get_version_nr()
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) or defined(__MINGW32__)
|
||||
}
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
#include <libloaderapi.h>
|
||||
#include <wincon.h>
|
||||
|
||||
@@ -215,7 +215,7 @@ const char* kSpinner[] = {
|
||||
".", "o", "O", "0", "@", "*", " "
|
||||
};
|
||||
|
||||
const size_t kSpinnerCount = sizeof(kSpinner) / sizeof(char*);
|
||||
const std::size_t kSpinnerCount = sizeof(kSpinner) / sizeof(char*);
|
||||
|
||||
const int kSpinnerTimeInterval = 100;
|
||||
|
||||
@@ -235,7 +235,7 @@ void progress_bar_impl::print_progress()
|
||||
float progress = static_cast<float>(m_consumed) / m_max_value;
|
||||
|
||||
if (width < kMinBarWidth)
|
||||
std::cout << (100 * progress) << '%' << std::endl;
|
||||
std::cout << (100 * progress) << "%\n";
|
||||
else
|
||||
{
|
||||
uint32_t bar_width = 7 * width / 10;
|
||||
@@ -329,7 +329,7 @@ void progress_bar_impl::print_done()
|
||||
if (msg.length() < width)
|
||||
msg += std::string(width - msg.length(), ' ');
|
||||
|
||||
std::cout << '\r' << msg << std::endl;
|
||||
std::cout << '\r' << msg << '\n';
|
||||
}
|
||||
|
||||
progress_bar::progress_bar(int64_t inMax, const std::string &inAction)
|
||||
@@ -877,6 +877,21 @@ class resource_pool
|
||||
|
||||
resource_pool::resource_pool()
|
||||
{
|
||||
// directories are searched in reverse order
|
||||
|
||||
// As a last resort, try the location that might have been
|
||||
// used during installation, works only when running on an
|
||||
// OS with a proc file system.
|
||||
|
||||
std::error_code ec;
|
||||
if (auto exefile = fs::read_symlink("/proc/self/exe", ec); not ec and exefile.parent_path().filename() == "bin")
|
||||
{
|
||||
auto install_prefix = exefile.parent_path().parent_path();
|
||||
auto data_dir = install_prefix / "share" / "libcifpp";
|
||||
if (fs::exists(data_dir, ec))
|
||||
pushDir(data_dir);
|
||||
}
|
||||
|
||||
#if defined(DATA_DIR)
|
||||
pushDir(DATA_DIR);
|
||||
#endif
|
||||
|
||||
381
src/validate.cpp
381
src/validate.cpp
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "cif++/validate.hpp"
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
@@ -35,16 +36,11 @@
|
||||
|
||||
// The validator depends on regular expressions. Unfortunately,
|
||||
// the implementation of std::regex in g++ is buggy and crashes
|
||||
// on reading the pdbx dictionary. Therefore, in case g++ is used
|
||||
// the code will use boost::regex instead.
|
||||
// on reading the pdbx dictionary. We used to use boost regex
|
||||
// instead but using pcre2 is even easier and faster.
|
||||
|
||||
#if USE_BOOST_REGEX
|
||||
# include <boost/regex.hpp>
|
||||
using boost::regex;
|
||||
#else
|
||||
# include <regex>
|
||||
using std::regex;
|
||||
#endif
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -55,33 +51,84 @@ validation_exception::validation_exception(std::error_code ec)
|
||||
}
|
||||
|
||||
validation_exception::validation_exception(std::error_code ec, std::string_view category)
|
||||
: runtime_error(
|
||||
(std::ostringstream{} << ec.message() << "; category: " << std::quoted(category)).str())
|
||||
: runtime_error((ec.message() + "; category: ").append(category))
|
||||
{
|
||||
}
|
||||
|
||||
validation_exception::validation_exception(std::error_code ec, std::string_view category, std::string_view item)
|
||||
: runtime_error(
|
||||
(std::ostringstream{} << ec.message() << "; category: " << std::quoted(category) << "; item: " << std::quoted(item)).str())
|
||||
: runtime_error((ec.message() + "; category: ").append(category).append("; item: ").append(item))
|
||||
{
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
struct regex_impl : public regex
|
||||
// struct regex_impl : public regex
|
||||
// {
|
||||
// regex_impl(std::string_view rx)
|
||||
// : regex(rx.begin(), rx.end(), regex::extended | regex::optimize)
|
||||
// {
|
||||
// }
|
||||
// };
|
||||
|
||||
struct regex_impl
|
||||
{
|
||||
regex_impl(std::string_view rx)
|
||||
: regex(rx.begin(), rx.end(), regex::extended | regex::optimize)
|
||||
{
|
||||
}
|
||||
regex_impl(std::string_view rx);
|
||||
~regex_impl();
|
||||
|
||||
regex_impl(const regex_impl &) = delete;
|
||||
regex_impl &operator=(const regex_impl &) = delete;
|
||||
|
||||
bool match(std::string_view v) const;
|
||||
|
||||
private:
|
||||
|
||||
pcre2_code *m_rx = nullptr;
|
||||
pcre2_match_data *m_data = nullptr;
|
||||
};
|
||||
|
||||
regex_impl::regex_impl(std::string_view rx)
|
||||
{
|
||||
int err_code;
|
||||
size_t err_offset;
|
||||
m_rx = pcre2_compile((PCRE2_SPTR)rx.data(), rx.length(), 0, &err_code, &err_offset, nullptr);
|
||||
if (m_rx == nullptr)
|
||||
{
|
||||
PCRE2_UCHAR buffer[256];
|
||||
int n = pcre2_get_error_message(err_code, buffer, sizeof(buffer));
|
||||
|
||||
throw std::runtime_error(std::string("PCRE2 compilation failed: ") + std::string{ (char *)buffer, (char *)buffer + n });
|
||||
}
|
||||
|
||||
m_data = pcre2_match_data_create_from_pattern(m_rx, nullptr);
|
||||
}
|
||||
|
||||
regex_impl::~regex_impl()
|
||||
{
|
||||
if (m_data)
|
||||
pcre2_match_data_free(m_data);
|
||||
|
||||
if (m_rx)
|
||||
pcre2_code_free(m_rx);
|
||||
}
|
||||
|
||||
bool regex_impl::match(std::string_view v) const
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (int rc = pcre2_match(m_rx, (PCRE2_SPTR)v.data(), v.length(), 0, 0, m_data, nullptr); rc >= 0)
|
||||
result = true;
|
||||
else if (rc != PCRE2_ERROR_NOMATCH)
|
||||
std::cerr << "Error matching with pcre\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
DDL_PrimitiveType map_to_primitive_type(std::string_view s, std::error_code &ec) noexcept
|
||||
{
|
||||
ec = {};
|
||||
DDL_PrimitiveType result;
|
||||
DDL_PrimitiveType result = DDL_PrimitiveType::Char;
|
||||
if (iequals(s, "char"))
|
||||
result = DDL_PrimitiveType::Char;
|
||||
else if (iequals(s, "uchar"))
|
||||
@@ -111,9 +158,15 @@ type_validator::type_validator(std::string_view name, DDL_PrimitiveType type, st
|
||||
{
|
||||
}
|
||||
|
||||
type_validator::type_validator(const type_validator &tv)
|
||||
: m_name(tv.m_name)
|
||||
, m_primitive_type(tv.m_primitive_type)
|
||||
, m_rx(tv.m_rx)
|
||||
{
|
||||
}
|
||||
|
||||
type_validator::~type_validator()
|
||||
{
|
||||
delete m_rx;
|
||||
}
|
||||
|
||||
int type_validator::compare(std::string_view a, std::string_view b) const
|
||||
@@ -140,7 +193,7 @@ int type_validator::compare(std::string_view a, std::string_view b) const
|
||||
ra = selected_charconv<double>::from_chars(a.data(), a.data() + a.length(), da);
|
||||
rb = selected_charconv<double>::from_chars(b.data(), b.data() + b.length(), db);
|
||||
|
||||
if (ra.ec == std::errc() and rb.ec == std::errc())
|
||||
if (not(bool) ra.ec and not(bool) rb.ec)
|
||||
{
|
||||
auto d = da - db;
|
||||
if (std::abs(d) > std::numeric_limits<double>::epsilon())
|
||||
@@ -151,7 +204,7 @@ int type_validator::compare(std::string_view a, std::string_view b) const
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
else if (ra.ec == std::errc())
|
||||
else if ((bool)ra.ec)
|
||||
result = 1;
|
||||
else
|
||||
result = -1;
|
||||
@@ -224,17 +277,17 @@ void item_validator::operator()(std::string_view value) const
|
||||
|
||||
bool item_validator::validate_value(std::string_view value, std::error_code &ec) const noexcept
|
||||
{
|
||||
ec = {};
|
||||
ec.clear();
|
||||
|
||||
if (not value.empty() and value != "?" and value != ".")
|
||||
{
|
||||
if (m_type != nullptr and not regex_match(value.begin(), value.end(), *m_type->m_rx))
|
||||
if (m_type != nullptr and not m_type->m_rx->match(value))
|
||||
ec = make_error_code(validation_error::value_does_not_match_rx);
|
||||
else if (not m_enums.empty() and m_enums.count(std::string{ value }) == 0)
|
||||
ec = make_error_code(validation_error::value_is_not_in_enumeration_list);
|
||||
}
|
||||
|
||||
return ec == std::errc();
|
||||
return not(bool) ec;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -244,7 +297,7 @@ void category_validator::add_item_validator(item_validator &&v)
|
||||
if (v.m_mandatory)
|
||||
m_mandatory_items.insert(v.m_item_name);
|
||||
|
||||
v.m_category = this;
|
||||
v.m_category = m_name;
|
||||
|
||||
auto r = m_item_validators.insert(std::move(v));
|
||||
if (not r.second and VERBOSE >= 4)
|
||||
@@ -286,6 +339,29 @@ const item_validator *category_validator::get_validator_for_aliased_item(std::st
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator::validator(const validator &rhs)
|
||||
: m_audit_conform(rhs.m_audit_conform)
|
||||
, m_strict(rhs.m_strict)
|
||||
, m_type_validators(rhs.m_type_validators)
|
||||
, m_category_validators(rhs.m_category_validators)
|
||||
, m_link_validators(rhs.m_link_validators)
|
||||
{
|
||||
}
|
||||
|
||||
void swap(validator &a, validator &b) noexcept
|
||||
{
|
||||
std::swap(a.m_audit_conform, b.m_audit_conform);
|
||||
std::swap(a.m_strict, b.m_strict);
|
||||
std::swap(a.m_type_validators, b.m_type_validators);
|
||||
std::swap(a.m_category_validators, b.m_category_validators);
|
||||
std::swap(a.m_link_validators, b.m_link_validators);
|
||||
}
|
||||
|
||||
void validator::parse(std::istream &is)
|
||||
{
|
||||
parse_dictionary(*this, is);
|
||||
}
|
||||
|
||||
void validator::add_type_validator(type_validator &&v)
|
||||
{
|
||||
auto r = m_type_validators.insert(std::move(v));
|
||||
@@ -355,7 +431,7 @@ void validator::add_link_validator(link_validator &&v)
|
||||
if (ccv == nullptr)
|
||||
throw std::runtime_error("unknown child category " + v.m_child_category);
|
||||
|
||||
for (size_t i = 0; i < v.m_parent_keys.size(); ++i)
|
||||
for (std::size_t i = 0; i < v.m_parent_keys.size(); ++i)
|
||||
{
|
||||
auto piv = pcv->get_validator_for_item(v.m_parent_keys[i]);
|
||||
|
||||
@@ -403,23 +479,63 @@ void validator::report_error(std::error_code ec, bool fatal) const
|
||||
{
|
||||
if (m_strict or fatal)
|
||||
throw validation_exception(ec);
|
||||
else
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ec.message() << '\n';
|
||||
}
|
||||
|
||||
void validator::report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal) const
|
||||
{
|
||||
auto ex = item.empty() ?
|
||||
validation_exception(ec, category) :
|
||||
validation_exception(ec, category, item);
|
||||
auto ex = item.empty() ? validation_exception(ec, category) : validation_exception(ec, category, item);
|
||||
|
||||
if (m_strict or fatal)
|
||||
throw ex;
|
||||
else
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ex.what() << '\n';
|
||||
}
|
||||
|
||||
void validator::fill_audit_conform(category &audit_conform) const
|
||||
{
|
||||
audit_conform.clear();
|
||||
audit_conform.emplace(m_audit_conform.begin(), m_audit_conform.end());
|
||||
}
|
||||
|
||||
bool validator::matches_audit_conform(const category &audit_conform) const
|
||||
{
|
||||
if (audit_conform.empty())
|
||||
return false;
|
||||
|
||||
auto ai = m_audit_conform.begin();
|
||||
auto bi = audit_conform.begin();
|
||||
|
||||
while (ai != m_audit_conform.end() and bi != audit_conform.end())
|
||||
{
|
||||
const auto &[name_a, version_a] = ai->get<std::string, std::optional<std::string>>("dict_name", "dict_version");
|
||||
const auto &[name_b, version_b] = bi->get<std::string, std::optional<std::string>>("dict_name", "dict_version");
|
||||
|
||||
++ai;
|
||||
++bi;
|
||||
|
||||
if (name_a != name_b)
|
||||
return false;
|
||||
|
||||
if (not version_b.has_value() or not version_a.has_value())
|
||||
continue;
|
||||
|
||||
if (validator_factory::check_version(name_a, *version_b, *version_a) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return ai == m_audit_conform.end() and bi == audit_conform.end();
|
||||
}
|
||||
|
||||
void validator::append_audit_conform(const std::string &name, const std::optional<std::string> &version)
|
||||
{
|
||||
m_audit_conform.emplace({ //
|
||||
{ "dict_name", name },
|
||||
{ "dict_version", version } });
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator_factory &validator_factory::instance()
|
||||
@@ -428,101 +544,122 @@ validator_factory &validator_factory::instance()
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
const validator &validator_factory::operator[](std::string_view dictionary_name)
|
||||
const validator &validator_factory::get(std::string_view dictionary_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
category audit_conform("audit_conform");
|
||||
for (auto part : cif::split(dictionary_name, ";", true))
|
||||
audit_conform.emplace({ { "dict_name", part } });
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
{
|
||||
if (iequals(validator.name(), dictionary_name))
|
||||
return validator;
|
||||
}
|
||||
|
||||
// not found, try to see if it helps if we tweak the name a little
|
||||
|
||||
// too bad clang version 10 did not have a constructor for std::filesystem::path that accepts a std::string_view
|
||||
std::filesystem::path dictionary(dictionary_name.data(), dictionary_name.data() + dictionary_name.length());
|
||||
|
||||
if (dictionary.extension() != ".dic")
|
||||
{
|
||||
auto dict_name = dictionary.filename().string() + ".dic";
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
{
|
||||
if (iequals(validator.name(), dict_name))
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
||||
// not found, add it
|
||||
auto data = load_resource(dictionary_name);
|
||||
|
||||
if (not data and dictionary.extension().string() != ".dic")
|
||||
data = load_resource(dictionary.parent_path() / (dictionary.filename().string() + ".dic"));
|
||||
|
||||
if (data)
|
||||
construct_validator(dictionary_name, *data);
|
||||
else
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
// might be a compressed dictionary on disk
|
||||
std::filesystem::path p = dictionary;
|
||||
if (p.extension() == ".dic")
|
||||
p = p.parent_path() / (p.filename().string() + ".gz");
|
||||
else
|
||||
p = p.parent_path() / (p.filename().string() + ".dic.gz");
|
||||
|
||||
#if defined(CACHE_DIR) or defined(DATA_DIR)
|
||||
if (not std::filesystem::exists(p, ec) or ec)
|
||||
{
|
||||
for (const char *dir : {
|
||||
# if defined(CACHE_DIR)
|
||||
CACHE_DIR,
|
||||
# endif
|
||||
# if defined(DATA_DIR)
|
||||
DATA_DIR
|
||||
# endif
|
||||
})
|
||||
{
|
||||
auto p2 = std::filesystem::path(dir) / p;
|
||||
if (std::filesystem::exists(p2, ec) and not ec)
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (std::filesystem::exists(p, ec) and not ec)
|
||||
{
|
||||
gzio::ifstream in(p);
|
||||
|
||||
if (not in.is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
construct_validator(dictionary_name, in);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
|
||||
}
|
||||
|
||||
return m_validators.back();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
std::string msg = "Error while loading dictionary ";
|
||||
msg += dictionary_name;
|
||||
std::throw_with_nested(std::runtime_error(msg));
|
||||
}
|
||||
return get(audit_conform);
|
||||
}
|
||||
|
||||
const validator &validator_factory::construct_validator(std::string_view name, std::istream &is)
|
||||
const validator &validator_factory::get(const category &audit_conform)
|
||||
{
|
||||
return m_validators.emplace_back(parse_dictionary(name, is));
|
||||
if (audit_conform.empty())
|
||||
throw std::runtime_error("Empty audit_conform category, cannot create a validator");
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// Check existing first
|
||||
for (auto &v : m_validators)
|
||||
{
|
||||
if (v.matches_audit_conform(audit_conform))
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the audit conform contains only one record, this is easy
|
||||
if (audit_conform.size() == 1)
|
||||
{
|
||||
const auto &[name, version] = audit_conform.front().get<std::string, std::optional<std::string>>("dict_name", "dict_version");
|
||||
return m_validators.emplace_back(construct_validator(name, version));
|
||||
}
|
||||
|
||||
// A new, merged dictionary
|
||||
|
||||
std::optional<validator> v;
|
||||
for (const auto &[name, version] : audit_conform.rows<std::string, std::optional<std::string>>("dict_name", "dict_version"))
|
||||
{
|
||||
if (not v)
|
||||
v = construct_validator(name, version);
|
||||
else
|
||||
{
|
||||
auto data = load_resource(name);
|
||||
if (not data)
|
||||
throw std::runtime_error("Could not load dictionary " + std::string{ name });
|
||||
|
||||
v->parse(*data);
|
||||
}
|
||||
}
|
||||
|
||||
if (not v)
|
||||
throw std::runtime_error("Missing dictionary information?");
|
||||
|
||||
return m_validators.emplace_back(std::move(*v));
|
||||
}
|
||||
|
||||
validator validator_factory::construct_validator(std::string_view name, std::optional<std::string> version)
|
||||
{
|
||||
auto data = load_resource(name);
|
||||
if (not data and name == "mmcif_pdbx_v50")
|
||||
data = load_resource("mmcif_pdbx.dic");
|
||||
|
||||
if (not data)
|
||||
throw std::runtime_error("Could not load dictionary " + std::string{ name });
|
||||
|
||||
validator v;
|
||||
v.parse(*data);
|
||||
|
||||
if (version.has_value() and VERBOSE >= 0 and
|
||||
not v.matches_audit_conform(category{ "audit_conform", //
|
||||
{ { "dict_name", name }, { "dict_version", version } } }))
|
||||
{
|
||||
std::clog << "Invalid dictionary?\n";
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool validator_factory::check_version(std::string_view name, std::string_view expected, std::string_view found)
|
||||
{
|
||||
bool result = true;
|
||||
auto el = cif::split(expected, ".");
|
||||
auto fl = cif::split(found, ".");
|
||||
|
||||
auto eli = el.begin();
|
||||
auto fli = fl.begin();
|
||||
|
||||
while (eli != el.end() and fli != fl.end())
|
||||
{
|
||||
int e_int, f_int;
|
||||
if (auto [ptr, ec] = std::from_chars(eli->data(), eli->data() + eli->length(), e_int); ec != std::errc{})
|
||||
{
|
||||
std::clog << "Could not parse requested version string for dictionary " << std::quoted(expected) << "\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto [ptr, ec] = std::from_chars(fli->data(), fli->data() + fli->length(), f_int); ec != std::errc{})
|
||||
{
|
||||
std::clog << "Could not parse version string in dictionary " << name << " " << std::quoted(found) << "\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (f_int > e_int) // newer version, assume this is ok
|
||||
break;
|
||||
|
||||
if (f_int < e_int)
|
||||
{
|
||||
std::clog << "The version in dictionary " << name << " is lower than requested, this may cause validation errors\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
++eli;
|
||||
++fli;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
2770
test/1cbs-dssp.cif
Normal file
2770
test/1cbs-dssp.cif
Normal file
File diff suppressed because it is too large
Load Diff
76
test/CMakeLists.txt
Normal file
76
test/CMakeLists.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
# We're using the older version 2 of Catch2
|
||||
|
||||
if(NOT(Catch2_FOUND OR TARGET Catch2))
|
||||
find_package(Catch2 QUIET)
|
||||
|
||||
if(NOT Catch2_FOUND)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v2.13.9)
|
||||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
|
||||
set(Catch2_VERSION "2.13.9")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(
|
||||
APPEND
|
||||
CIFPP_tests
|
||||
unit-v2
|
||||
unit-3d
|
||||
model
|
||||
query
|
||||
rename-compound
|
||||
sugar
|
||||
spinner
|
||||
# reconstruction
|
||||
validate-pdbx
|
||||
)
|
||||
|
||||
add_library(test-main OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/test-main.cpp")
|
||||
|
||||
target_link_libraries(test-main cifpp::cifpp Catch2::Catch2)
|
||||
|
||||
if("${Catch2_VERSION}" VERSION_LESS 3.0.0)
|
||||
target_compile_definitions(test-main PUBLIC CATCH22=1)
|
||||
else()
|
||||
target_compile_definitions(test-main PUBLIC CATCH22=0)
|
||||
endif()
|
||||
|
||||
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
|
||||
set(CIFPP_TEST "${CIFPP_TEST}-test")
|
||||
set(CIFPP_TEST_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${CIFPP_TEST}.cpp")
|
||||
|
||||
add_executable(
|
||||
${CIFPP_TEST} ${CIFPP_TEST_SOURCE} $<TARGET_OBJECTS:test-main>)
|
||||
|
||||
if(${Catch2_VERSION} VERSION_GREATER_EQUAL 3.0.0)
|
||||
target_compile_definitions(${CIFPP_TEST} PUBLIC CATCH22=0)
|
||||
else()
|
||||
target_compile_definitions(${CIFPP_TEST} PUBLIC CATCH22=1)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${CIFPP_TEST} PRIVATE cifpp::cifpp Catch2::Catch2)
|
||||
target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
if(MSVC)
|
||||
# Specify unwind semantics so that MSVC knowns how to handle exceptions
|
||||
target_compile_options(${CIFPP_TEST} PRIVATE /EHsc)
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
"run-${CIFPP_TEST}"
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch ${CIFPP_TEST})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_test(NAME ${CIFPP_TEST} COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endforeach()
|
||||
822
test/brak.pdb
Normal file
822
test/brak.pdb
Normal file
@@ -0,0 +1,822 @@
|
||||
REMARK 001 design 0 N 3 RMSD 1.605
|
||||
MODEL 1
|
||||
ATOM 1 N MET A 1 -24.216 -7.571 -1.155 1.00 31.87 N
|
||||
ATOM 2 CA MET A 1 -22.971 -7.756 -0.416 1.00 31.87 C
|
||||
ATOM 3 C MET A 1 -21.814 -7.051 -1.114 1.00 31.87 C
|
||||
ATOM 4 CB MET A 1 -22.656 -9.245 -0.256 1.00 31.87 C
|
||||
ATOM 5 O MET A 1 -21.516 -7.338 -2.275 1.00 31.87 O
|
||||
ATOM 6 CG MET A 1 -22.779 -9.747 1.174 1.00 31.87 C
|
||||
ATOM 7 SD MET A 1 -22.473 -11.551 1.314 1.00 31.87 S
|
||||
ATOM 8 CE MET A 1 -22.597 -11.758 3.112 1.00 31.87 C
|
||||
ATOM 9 N LYS A 2 -21.652 -5.596 -0.909 1.00 33.06 N
|
||||
ATOM 10 CA LYS A 2 -21.035 -4.320 -0.554 1.00 33.06 C
|
||||
ATOM 11 C LYS A 2 -19.531 -4.475 -0.351 1.00 33.06 C
|
||||
ATOM 12 CB LYS A 2 -21.678 -3.747 0.710 1.00 33.06 C
|
||||
ATOM 13 O LYS A 2 -19.087 -5.326 0.423 1.00 33.06 O
|
||||
ATOM 14 CG LYS A 2 -22.957 -2.963 0.453 1.00 33.06 C
|
||||
ATOM 15 CD LYS A 2 -23.454 -2.275 1.717 1.00 33.06 C
|
||||
ATOM 16 CE LYS A 2 -24.810 -1.615 1.500 1.00 33.06 C
|
||||
ATOM 17 NZ LYS A 2 -25.284 -0.906 2.725 1.00 33.06 N
|
||||
ATOM 18 N ILE A 3 -18.889 -4.065 -1.586 1.00 34.22 N
|
||||
ATOM 19 CA ILE A 3 -17.539 -3.550 -1.381 1.00 34.22 C
|
||||
ATOM 20 C ILE A 3 -17.331 -2.297 -2.229 1.00 34.22 C
|
||||
ATOM 21 CB ILE A 3 -16.471 -4.612 -1.721 1.00 34.22 C
|
||||
ATOM 22 O ILE A 3 -17.508 -2.330 -3.449 1.00 34.22 O
|
||||
ATOM 23 CG1 ILE A 3 -16.524 -5.766 -0.713 1.00 34.22 C
|
||||
ATOM 24 CG2 ILE A 3 -15.075 -3.982 -1.759 1.00 34.22 C
|
||||
ATOM 25 CD1 ILE A 3 -15.743 -7.000 -1.142 1.00 34.22 C
|
||||
ATOM 26 N ILE A 4 -17.776 -0.985 -1.831 1.00 40.18 N
|
||||
ATOM 27 CA ILE A 4 -17.255 0.212 -1.181 1.00 40.18 C
|
||||
ATOM 28 C ILE A 4 -16.631 1.136 -2.224 1.00 40.18 C
|
||||
ATOM 29 CB ILE A 4 -16.218 -0.142 -0.091 1.00 40.18 C
|
||||
ATOM 30 O ILE A 4 -15.717 0.736 -2.949 1.00 40.18 O
|
||||
ATOM 31 CG1 ILE A 4 -16.844 -1.063 0.963 1.00 40.18 C
|
||||
ATOM 32 CG2 ILE A 4 -15.658 1.128 0.555 1.00 40.18 C
|
||||
ATOM 33 CD1 ILE A 4 -15.839 -1.662 1.937 1.00 40.18 C
|
||||
ATOM 34 N GLU A 5 -17.325 2.198 -2.769 1.00 38.95 N
|
||||
ATOM 35 CA GLU A 5 -17.243 3.640 -2.553 1.00 38.95 C
|
||||
ATOM 36 C GLU A 5 -15.944 4.019 -1.848 1.00 38.95 C
|
||||
ATOM 37 CB GLU A 5 -18.445 4.131 -1.741 1.00 38.95 C
|
||||
ATOM 38 O GLU A 5 -15.602 3.445 -0.812 1.00 38.95 O
|
||||
ATOM 39 CG GLU A 5 -19.296 5.162 -2.466 1.00 38.95 C
|
||||
ATOM 40 CD GLU A 5 -20.407 5.738 -1.602 1.00 38.95 C
|
||||
ATOM 41 OE1 GLU A 5 -20.194 6.791 -0.960 1.00 38.95 O
|
||||
ATOM 42 OE2 GLU A 5 -21.500 5.129 -1.566 1.00 38.95 O
|
||||
ATOM 43 N LYS A 6 -14.697 4.048 -2.514 1.00 40.24 N
|
||||
ATOM 44 CA LYS A 6 -13.793 5.173 -2.294 1.00 40.24 C
|
||||
ATOM 45 C LYS A 6 -12.348 4.784 -2.593 1.00 40.24 C
|
||||
ATOM 46 CB LYS A 6 -13.911 5.684 -0.857 1.00 40.24 C
|
||||
ATOM 47 O LYS A 6 -11.769 3.946 -1.899 1.00 40.24 O
|
||||
ATOM 48 CG LYS A 6 -14.799 6.911 -0.707 1.00 40.24 C
|
||||
ATOM 49 CD LYS A 6 -14.696 7.508 0.690 1.00 40.24 C
|
||||
ATOM 50 CE LYS A 6 -15.689 8.645 0.887 1.00 40.24 C
|
||||
ATOM 51 NZ LYS A 6 -15.523 9.301 2.219 1.00 40.24 N
|
||||
ATOM 52 N TYR A 7 -12.096 4.360 -3.877 1.00 55.19 N
|
||||
ATOM 53 CA TYR A 7 -10.695 4.330 -4.282 1.00 55.19 C
|
||||
ATOM 54 C TYR A 7 -9.919 5.478 -3.647 1.00 55.19 C
|
||||
ATOM 55 CB TYR A 7 -10.574 4.398 -5.807 1.00 55.19 C
|
||||
ATOM 56 O TYR A 7 -10.324 6.639 -3.746 1.00 55.19 O
|
||||
ATOM 57 CG TYR A 7 -11.069 3.159 -6.511 1.00 55.19 C
|
||||
ATOM 58 CD1 TYR A 7 -10.245 2.047 -6.669 1.00 55.19 C
|
||||
ATOM 59 CD2 TYR A 7 -12.361 3.097 -7.021 1.00 55.19 C
|
||||
ATOM 60 CE1 TYR A 7 -10.696 0.903 -7.319 1.00 55.19 C
|
||||
ATOM 61 CE2 TYR A 7 -12.823 1.958 -7.673 1.00 55.19 C
|
||||
ATOM 62 OH TYR A 7 -12.437 -0.262 -8.461 1.00 55.19 O
|
||||
ATOM 63 CZ TYR A 7 -11.985 0.868 -7.817 1.00 55.19 C
|
||||
ATOM 64 N VAL A 8 -9.308 5.253 -2.484 1.00 55.50 N
|
||||
ATOM 65 CA VAL A 8 -8.469 6.226 -1.792 1.00 55.50 C
|
||||
ATOM 66 C VAL A 8 -7.196 6.476 -2.597 1.00 55.50 C
|
||||
ATOM 67 CB VAL A 8 -8.112 5.754 -0.364 1.00 55.50 C
|
||||
ATOM 68 O VAL A 8 -6.488 5.534 -2.960 1.00 55.50 O
|
||||
ATOM 69 CG1 VAL A 8 -7.215 6.774 0.333 1.00 55.50 C
|
||||
ATOM 70 CG2 VAL A 8 -9.381 5.509 0.450 1.00 55.50 C
|
||||
ATOM 71 N PHE A 9 -7.225 7.625 -3.250 1.00 66.91 N
|
||||
ATOM 72 CA PHE A 9 -6.004 8.094 -3.895 1.00 66.91 C
|
||||
ATOM 73 C PHE A 9 -4.934 8.414 -2.858 1.00 66.91 C
|
||||
ATOM 74 CB PHE A 9 -6.289 9.330 -4.754 1.00 66.91 C
|
||||
ATOM 75 O PHE A 9 -5.089 9.345 -2.065 1.00 66.91 O
|
||||
ATOM 76 CG PHE A 9 -6.868 9.009 -6.105 1.00 66.91 C
|
||||
ATOM 77 CD1 PHE A 9 -6.039 8.797 -7.200 1.00 66.91 C
|
||||
ATOM 78 CD2 PHE A 9 -8.243 8.920 -6.281 1.00 66.91 C
|
||||
ATOM 79 CE1 PHE A 9 -6.572 8.499 -8.452 1.00 66.91 C
|
||||
ATOM 80 CE2 PHE A 9 -8.783 8.623 -7.530 1.00 66.91 C
|
||||
ATOM 81 CZ PHE A 9 -7.946 8.414 -8.614 1.00 66.91 C
|
||||
ATOM 82 N LEU A 10 -4.065 7.388 -2.607 1.00 72.14 N
|
||||
ATOM 83 CA LEU A 10 -2.967 7.542 -1.658 1.00 72.14 C
|
||||
ATOM 84 C LEU A 10 -2.342 8.929 -1.771 1.00 72.14 C
|
||||
ATOM 85 CB LEU A 10 -1.902 6.469 -1.893 1.00 72.14 C
|
||||
ATOM 86 O LEU A 10 -1.903 9.499 -0.770 1.00 72.14 O
|
||||
ATOM 87 CG LEU A 10 -2.222 5.069 -1.365 1.00 72.14 C
|
||||
ATOM 88 CD1 LEU A 10 -1.258 4.046 -1.957 1.00 72.14 C
|
||||
ATOM 89 CD2 LEU A 10 -2.165 5.045 0.158 1.00 72.14 C
|
||||
ATOM 90 N ALA A 11 -2.498 9.659 -2.947 1.00 69.94 N
|
||||
ATOM 91 CA ALA A 11 -1.847 10.939 -3.211 1.00 69.94 C
|
||||
ATOM 92 C ALA A 11 -2.571 12.080 -2.501 1.00 69.94 C
|
||||
ATOM 93 CB ALA A 11 -1.786 11.206 -4.713 1.00 69.94 C
|
||||
ATOM 94 O ALA A 11 -1.971 13.117 -2.207 1.00 69.94 O
|
||||
ATOM 95 N GLU A 12 -3.713 11.866 -1.974 1.00 76.23 N
|
||||
ATOM 96 CA GLU A 12 -4.520 12.921 -1.368 1.00 76.23 C
|
||||
ATOM 97 C GLU A 12 -4.620 12.741 0.144 1.00 76.23 C
|
||||
ATOM 98 CB GLU A 12 -5.920 12.951 -1.987 1.00 76.23 C
|
||||
ATOM 99 O GLU A 12 -5.178 13.590 0.841 1.00 76.23 O
|
||||
ATOM 100 CG GLU A 12 -5.939 13.391 -3.444 1.00 76.23 C
|
||||
ATOM 101 CD GLU A 12 -7.343 13.548 -4.005 1.00 76.23 C
|
||||
ATOM 102 OE1 GLU A 12 -7.904 14.665 -3.935 1.00 76.23 O
|
||||
ATOM 103 OE2 GLU A 12 -7.888 12.544 -4.518 1.00 76.23 O
|
||||
ATOM 104 N LEU A 13 -3.986 11.682 0.620 1.00 82.70 N
|
||||
ATOM 105 CA LEU A 13 -4.106 11.386 2.043 1.00 82.70 C
|
||||
ATOM 106 C LEU A 13 -2.951 12.001 2.826 1.00 82.70 C
|
||||
ATOM 107 CB LEU A 13 -4.146 9.873 2.274 1.00 82.70 C
|
||||
ATOM 108 O LEU A 13 -1.826 12.073 2.327 1.00 82.70 O
|
||||
ATOM 109 CG LEU A 13 -5.347 9.129 1.688 1.00 82.70 C
|
||||
ATOM 110 CD1 LEU A 13 -5.171 7.623 1.857 1.00 82.70 C
|
||||
ATOM 111 CD2 LEU A 13 -6.640 9.598 2.346 1.00 82.70 C
|
||||
ATOM 112 N SER A 14 -3.339 12.631 3.947 1.00 86.03 N
|
||||
ATOM 113 CA SER A 14 -2.328 13.121 4.878 1.00 86.03 C
|
||||
ATOM 114 C SER A 14 -1.680 11.974 5.645 1.00 86.03 C
|
||||
ATOM 115 CB SER A 14 -2.942 14.120 5.859 1.00 86.03 C
|
||||
ATOM 116 O SER A 14 -2.161 10.839 5.599 1.00 86.03 O
|
||||
ATOM 117 OG SER A 14 -3.526 15.211 5.168 1.00 86.03 O
|
||||
ATOM 118 N ASP A 15 -0.488 12.215 6.359 1.00 86.85 N
|
||||
ATOM 119 CA ASP A 15 0.221 11.246 7.189 1.00 86.85 C
|
||||
ATOM 120 C ASP A 15 -0.734 10.542 8.149 1.00 86.85 C
|
||||
ATOM 121 CB ASP A 15 1.345 11.930 7.971 1.00 86.85 C
|
||||
ATOM 122 O ASP A 15 -0.647 9.327 8.340 1.00 86.85 O
|
||||
ATOM 123 CG ASP A 15 2.418 12.521 7.074 1.00 86.85 C
|
||||
ATOM 124 OD1 ASP A 15 3.279 11.766 6.575 1.00 86.85 O
|
||||
ATOM 125 OD2 ASP A 15 2.403 13.754 6.867 1.00 86.85 O
|
||||
ATOM 126 N GLU A 16 -1.606 11.353 8.835 1.00 86.30 N
|
||||
ATOM 127 CA GLU A 16 -2.590 10.797 9.760 1.00 86.30 C
|
||||
ATOM 128 C GLU A 16 -3.555 9.859 9.041 1.00 86.30 C
|
||||
ATOM 129 CB GLU A 16 -3.366 11.918 10.456 1.00 86.30 C
|
||||
ATOM 130 O GLU A 16 -3.871 8.780 9.545 1.00 86.30 O
|
||||
ATOM 131 CG GLU A 16 -2.547 12.688 11.481 1.00 86.30 C
|
||||
ATOM 132 CD GLU A 16 -3.342 13.770 12.194 1.00 86.30 C
|
||||
ATOM 133 OE1 GLU A 16 -3.925 13.489 13.266 1.00 86.30 O
|
||||
ATOM 134 OE2 GLU A 16 -3.384 14.908 11.676 1.00 86.30 O
|
||||
ATOM 135 N GLU A 17 -4.022 10.266 7.880 1.00 87.05 N
|
||||
ATOM 136 CA GLU A 17 -4.956 9.466 7.093 1.00 87.05 C
|
||||
ATOM 137 C GLU A 17 -4.305 8.172 6.613 1.00 87.05 C
|
||||
ATOM 138 CB GLU A 17 -5.477 10.268 5.898 1.00 87.05 C
|
||||
ATOM 139 O GLU A 17 -4.937 7.114 6.618 1.00 87.05 O
|
||||
ATOM 140 CG GLU A 17 -6.410 11.407 6.281 1.00 87.05 C
|
||||
ATOM 141 CD GLU A 17 -7.322 11.844 5.146 1.00 87.05 C
|
||||
ATOM 142 OE1 GLU A 17 -8.505 11.433 5.125 1.00 87.05 O
|
||||
ATOM 143 OE2 GLU A 17 -6.850 12.602 4.270 1.00 87.05 O
|
||||
ATOM 144 N LEU A 18 -3.057 8.282 6.290 1.00 88.16 N
|
||||
ATOM 145 CA LEU A 18 -2.291 7.120 5.855 1.00 88.16 C
|
||||
ATOM 146 C LEU A 18 -2.194 6.084 6.970 1.00 88.16 C
|
||||
ATOM 147 CB LEU A 18 -0.889 7.539 5.407 1.00 88.16 C
|
||||
ATOM 148 O LEU A 18 -2.374 4.888 6.730 1.00 88.16 O
|
||||
ATOM 149 CG LEU A 18 -0.785 8.201 4.032 1.00 88.16 C
|
||||
ATOM 150 CD1 LEU A 18 0.627 8.730 3.803 1.00 88.16 C
|
||||
ATOM 151 CD2 LEU A 18 -1.179 7.219 2.934 1.00 88.16 C
|
||||
ATOM 152 N LYS A 19 -1.979 6.558 8.141 1.00 87.30 N
|
||||
ATOM 153 CA LYS A 19 -1.908 5.682 9.308 1.00 87.30 C
|
||||
ATOM 154 C LYS A 19 -3.243 4.984 9.553 1.00 87.30 C
|
||||
ATOM 155 CB LYS A 19 -1.495 6.474 10.549 1.00 87.30 C
|
||||
ATOM 156 O LYS A 19 -3.280 3.787 9.843 1.00 87.30 O
|
||||
ATOM 157 CG LYS A 19 -0.007 6.781 10.620 1.00 87.30 C
|
||||
ATOM 158 CD LYS A 19 0.352 7.515 11.906 1.00 87.30 C
|
||||
ATOM 159 CE LYS A 19 1.818 7.927 11.926 1.00 87.30 C
|
||||
ATOM 160 NZ LYS A 19 2.176 8.639 13.189 1.00 87.30 N
|
||||
ATOM 161 N LYS A 20 -4.246 5.781 9.525 1.00 88.15 N
|
||||
ATOM 162 CA LYS A 20 -5.586 5.234 9.715 1.00 88.15 C
|
||||
ATOM 163 C LYS A 20 -5.907 4.185 8.654 1.00 88.15 C
|
||||
ATOM 164 CB LYS A 20 -6.631 6.350 9.682 1.00 88.15 C
|
||||
ATOM 165 O LYS A 20 -6.511 3.153 8.956 1.00 88.15 O
|
||||
ATOM 166 CG LYS A 20 -6.661 7.208 10.937 1.00 88.15 C
|
||||
ATOM 167 CD LYS A 20 -7.772 8.249 10.877 1.00 88.15 C
|
||||
ATOM 168 CE LYS A 20 -7.774 9.138 12.113 1.00 88.15 C
|
||||
ATOM 169 NZ LYS A 20 -8.875 10.146 12.069 1.00 88.15 N
|
||||
ATOM 170 N LEU A 21 -5.444 4.518 7.462 1.00 86.41 N
|
||||
ATOM 171 CA LEU A 21 -5.662 3.611 6.341 1.00 86.41 C
|
||||
ATOM 172 C LEU A 21 -4.974 2.271 6.583 1.00 86.41 C
|
||||
ATOM 173 CB LEU A 21 -5.148 4.234 5.040 1.00 86.41 C
|
||||
ATOM 174 O LEU A 21 -5.577 1.214 6.385 1.00 86.41 O
|
||||
ATOM 175 CG LEU A 21 -5.364 3.417 3.765 1.00 86.41 C
|
||||
ATOM 176 CD1 LEU A 21 -6.842 3.400 3.391 1.00 86.41 C
|
||||
ATOM 177 CD2 LEU A 21 -4.524 3.976 2.622 1.00 86.41 C
|
||||
ATOM 178 N VAL A 22 -3.737 2.304 6.914 1.00 87.19 N
|
||||
ATOM 179 CA VAL A 22 -2.953 1.109 7.205 1.00 87.19 C
|
||||
ATOM 180 C VAL A 22 -3.627 0.307 8.316 1.00 87.19 C
|
||||
ATOM 181 CB VAL A 22 -1.504 1.464 7.609 1.00 87.19 C
|
||||
ATOM 182 O VAL A 22 -3.719 -0.921 8.236 1.00 87.19 O
|
||||
ATOM 183 CG1 VAL A 22 -0.752 0.218 8.073 1.00 87.19 C
|
||||
ATOM 184 CG2 VAL A 22 -0.774 2.130 6.444 1.00 87.19 C
|
||||
ATOM 185 N GLU A 23 -4.070 0.928 9.305 1.00 88.34 N
|
||||
ATOM 186 CA GLU A 23 -4.790 0.285 10.400 1.00 88.34 C
|
||||
ATOM 187 C GLU A 23 -6.050 -0.414 9.897 1.00 88.34 C
|
||||
ATOM 188 CB GLU A 23 -5.151 1.308 11.480 1.00 88.34 C
|
||||
ATOM 189 O GLU A 23 -6.364 -1.525 10.328 1.00 88.34 O
|
||||
ATOM 190 CG GLU A 23 -3.959 1.792 12.292 1.00 88.34 C
|
||||
ATOM 191 CD GLU A 23 -4.356 2.595 13.521 1.00 88.34 C
|
||||
ATOM 192 OE1 GLU A 23 -4.486 2.004 14.616 1.00 88.34 O
|
||||
ATOM 193 OE2 GLU A 23 -4.539 3.826 13.386 1.00 88.34 O
|
||||
ATOM 194 N GLU A 24 -6.671 0.256 9.129 1.00 87.82 N
|
||||
ATOM 195 CA GLU A 24 -7.883 -0.315 8.549 1.00 87.82 C
|
||||
ATOM 196 C GLU A 24 -7.569 -1.568 7.737 1.00 87.82 C
|
||||
ATOM 197 CB GLU A 24 -8.595 0.717 7.670 1.00 87.82 C
|
||||
ATOM 198 O GLU A 24 -8.334 -2.535 7.758 1.00 87.82 O
|
||||
ATOM 199 CG GLU A 24 -9.372 1.763 8.456 1.00 87.82 C
|
||||
ATOM 200 CD GLU A 24 -10.598 1.200 9.157 1.00 87.82 C
|
||||
ATOM 201 OE1 GLU A 24 -10.544 0.974 10.387 1.00 87.82 O
|
||||
ATOM 202 OE2 GLU A 24 -11.621 0.982 8.469 1.00 87.82 O
|
||||
ATOM 203 N TRP A 25 -6.452 -1.421 6.925 1.00 87.98 N
|
||||
ATOM 204 CA TRP A 25 -6.008 -2.576 6.152 1.00 87.98 C
|
||||
ATOM 205 C TRP A 25 -5.804 -3.789 7.054 1.00 87.98 C
|
||||
ATOM 206 CB TRP A 25 -4.712 -2.256 5.403 1.00 87.98 C
|
||||
ATOM 207 O TRP A 25 -6.237 -4.895 6.724 1.00 87.98 O
|
||||
ATOM 208 CG TRP A 25 -4.867 -1.219 4.332 1.00 87.98 C
|
||||
ATOM 209 CD1 TRP A 25 -6.030 -0.819 3.734 1.00 87.98 C
|
||||
ATOM 210 CD2 TRP A 25 -3.820 -0.453 3.727 1.00 87.98 C
|
||||
ATOM 211 CE2 TRP A 25 -4.422 0.394 2.770 1.00 87.98 C
|
||||
ATOM 212 CE3 TRP A 25 -2.431 -0.399 3.902 1.00 87.98 C
|
||||
ATOM 213 NE1 TRP A 25 -5.769 0.151 2.794 1.00 87.98 N
|
||||
ATOM 214 CH2 TRP A 25 -2.324 1.317 2.182 1.00 87.98 C
|
||||
ATOM 215 CZ2 TRP A 25 -3.681 1.285 1.990 1.00 87.98 C
|
||||
ATOM 216 CZ3 TRP A 25 -1.695 0.488 3.125 1.00 87.98 C
|
||||
ATOM 217 N ILE A 26 -5.164 -3.521 8.121 1.00 86.80 N
|
||||
ATOM 218 CA ILE A 26 -4.842 -4.578 9.074 1.00 86.80 C
|
||||
ATOM 219 C ILE A 26 -6.123 -5.095 9.724 1.00 86.80 C
|
||||
ATOM 220 CB ILE A 26 -3.855 -4.082 10.155 1.00 86.80 C
|
||||
ATOM 221 O ILE A 26 -6.287 -6.302 9.913 1.00 86.80 O
|
||||
ATOM 222 CG1 ILE A 26 -2.511 -3.706 9.519 1.00 86.80 C
|
||||
ATOM 223 CG2 ILE A 26 -3.667 -5.144 11.243 1.00 86.80 C
|
||||
ATOM 224 CD1 ILE A 26 -1.549 -3.010 10.471 1.00 86.80 C
|
||||
ATOM 225 N LYS A 27 -7.085 -4.130 10.074 1.00 88.23 N
|
||||
ATOM 226 CA LYS A 27 -8.358 -4.482 10.697 1.00 88.23 C
|
||||
ATOM 227 C LYS A 27 -9.231 -5.292 9.743 1.00 88.23 C
|
||||
ATOM 228 CB LYS A 27 -9.101 -3.224 11.147 1.00 88.23 C
|
||||
ATOM 229 O LYS A 27 -9.857 -6.273 10.148 1.00 88.23 O
|
||||
ATOM 230 CG LYS A 27 -10.280 -3.498 12.070 1.00 88.23 C
|
||||
ATOM 231 CD LYS A 27 -10.890 -2.206 12.597 1.00 88.23 C
|
||||
ATOM 232 CE LYS A 27 -12.096 -2.477 13.486 1.00 88.23 C
|
||||
ATOM 233 NZ LYS A 27 -12.726 -1.212 13.967 1.00 88.23 N
|
||||
ATOM 234 N SER A 28 -9.257 -4.866 8.486 1.00 88.60 N
|
||||
ATOM 235 CA SER A 28 -10.097 -5.462 7.453 1.00 88.60 C
|
||||
ATOM 236 C SER A 28 -9.499 -6.767 6.939 1.00 88.60 C
|
||||
ATOM 237 CB SER A 28 -10.292 -4.488 6.290 1.00 88.60 C
|
||||
ATOM 238 O SER A 28 -10.208 -7.598 6.366 1.00 88.60 O
|
||||
ATOM 239 OG SER A 28 -11.021 -3.347 6.707 1.00 88.60 O
|
||||
ATOM 240 N LYS A 29 -8.274 -7.060 7.266 1.00 87.22 N
|
||||
ATOM 241 CA LYS A 29 -7.552 -8.279 6.911 1.00 87.22 C
|
||||
ATOM 242 C LYS A 29 -7.546 -8.493 5.400 1.00 87.22 C
|
||||
ATOM 243 CB LYS A 29 -8.169 -9.491 7.609 1.00 87.22 C
|
||||
ATOM 244 O LYS A 29 -7.336 -9.612 4.927 1.00 87.22 O
|
||||
ATOM 245 CG LYS A 29 -7.958 -9.511 9.116 1.00 87.22 C
|
||||
ATOM 246 CD LYS A 29 -8.508 -10.787 9.741 1.00 87.22 C
|
||||
ATOM 247 CE LYS A 29 -8.322 -10.795 11.252 1.00 87.22 C
|
||||
ATOM 248 NZ LYS A 29 -8.836 -12.056 11.866 1.00 87.22 N
|
||||
ATOM 249 N GLU A 30 -7.995 -7.561 4.711 1.00 90.12 N
|
||||
ATOM 250 CA GLU A 30 -7.955 -7.620 3.253 1.00 90.12 C
|
||||
ATOM 251 C GLU A 30 -7.715 -6.239 2.650 1.00 90.12 C
|
||||
ATOM 252 CB GLU A 30 -9.254 -8.215 2.703 1.00 90.12 C
|
||||
ATOM 253 O GLU A 30 -8.286 -5.248 3.110 1.00 90.12 O
|
||||
ATOM 254 CG GLU A 30 -9.273 -8.357 1.188 1.00 90.12 C
|
||||
ATOM 255 CD GLU A 30 -10.542 -9.008 0.662 1.00 90.12 C
|
||||
ATOM 256 OE1 GLU A 30 -11.585 -8.321 0.575 1.00 90.12 O
|
||||
ATOM 257 OE2 GLU A 30 -10.494 -10.215 0.335 1.00 90.12 O
|
||||
ATOM 258 N VAL A 31 -6.835 -6.090 1.610 1.00 86.60 N
|
||||
ATOM 259 CA VAL A 31 -6.583 -4.828 0.922 1.00 86.60 C
|
||||
ATOM 260 C VAL A 31 -6.313 -5.090 -0.558 1.00 86.60 C
|
||||
ATOM 261 CB VAL A 31 -5.397 -4.064 1.553 1.00 86.60 C
|
||||
ATOM 262 O VAL A 31 -5.684 -6.090 -0.912 1.00 86.60 O
|
||||
ATOM 263 CG1 VAL A 31 -4.102 -4.859 1.404 1.00 86.60 C
|
||||
ATOM 264 CG2 VAL A 31 -5.255 -2.682 0.919 1.00 86.60 C
|
||||
ATOM 265 N THR A 32 -6.886 -4.281 -1.455 1.00 86.60 N
|
||||
ATOM 266 CA THR A 32 -6.648 -4.386 -2.890 1.00 86.60 C
|
||||
ATOM 267 C THR A 32 -5.875 -3.173 -3.400 1.00 86.60 C
|
||||
ATOM 268 CB THR A 32 -7.971 -4.518 -3.667 1.00 86.60 C
|
||||
ATOM 269 O THR A 32 -6.311 -2.033 -3.224 1.00 86.60 O
|
||||
ATOM 270 CG2 THR A 32 -7.715 -4.710 -5.159 1.00 86.60 C
|
||||
ATOM 271 OG1 THR A 32 -8.700 -5.647 -3.170 1.00 86.60 O
|
||||
ATOM 272 N PHE A 33 -4.627 -3.379 -3.960 1.00 85.17 N
|
||||
ATOM 273 CA PHE A 33 -3.825 -2.315 -4.552 1.00 85.17 C
|
||||
ATOM 274 C PHE A 33 -4.096 -2.201 -6.048 1.00 85.17 C
|
||||
ATOM 275 CB PHE A 33 -2.333 -2.565 -4.307 1.00 85.17 C
|
||||
ATOM 276 O PHE A 33 -4.048 -3.198 -6.771 1.00 85.17 O
|
||||
ATOM 277 CG PHE A 33 -1.918 -2.397 -2.870 1.00 85.17 C
|
||||
ATOM 278 CD1 PHE A 33 -1.696 -1.132 -2.340 1.00 85.17 C
|
||||
ATOM 279 CD2 PHE A 33 -1.750 -3.504 -2.050 1.00 85.17 C
|
||||
ATOM 280 CE1 PHE A 33 -1.312 -0.973 -1.011 1.00 85.17 C
|
||||
ATOM 281 CE2 PHE A 33 -1.366 -3.354 -0.720 1.00 85.17 C
|
||||
ATOM 282 CZ PHE A 33 -1.146 -2.087 -0.203 1.00 85.17 C
|
||||
ATOM 283 N VAL A 34 -4.488 -1.033 -6.377 1.00 79.71 N
|
||||
ATOM 284 CA VAL A 34 -4.738 -0.771 -7.791 1.00 79.71 C
|
||||
ATOM 285 C VAL A 34 -3.582 0.033 -8.380 1.00 79.71 C
|
||||
ATOM 286 CB VAL A 34 -6.072 -0.020 -8.002 1.00 79.71 C
|
||||
ATOM 287 O VAL A 34 -3.285 1.137 -7.917 1.00 79.71 O
|
||||
ATOM 288 CG1 VAL A 34 -6.363 0.156 -9.491 1.00 79.71 C
|
||||
ATOM 289 CG2 VAL A 34 -7.216 -0.762 -7.314 1.00 79.71 C
|
||||
ATOM 290 N ILE A 35 -2.823 -0.596 -9.337 1.00 77.12 N
|
||||
ATOM 291 CA ILE A 35 -1.721 0.099 -9.993 1.00 77.12 C
|
||||
ATOM 292 C ILE A 35 -2.004 0.218 -11.489 1.00 77.12 C
|
||||
ATOM 293 CB ILE A 35 -0.376 -0.624 -9.757 1.00 77.12 C
|
||||
ATOM 294 O ILE A 35 -2.768 -0.572 -12.047 1.00 77.12 O
|
||||
ATOM 295 CG1 ILE A 35 -0.441 -2.059 -10.291 1.00 77.12 C
|
||||
ATOM 296 CG2 ILE A 35 -0.007 -0.608 -8.271 1.00 77.12 C
|
||||
ATOM 297 CD1 ILE A 35 0.916 -2.740 -10.402 1.00 77.12 C
|
||||
ATOM 298 N SER A 36 -1.599 1.325 -11.947 1.00 72.93 N
|
||||
ATOM 299 CA SER A 36 -1.731 1.517 -13.387 1.00 72.93 C
|
||||
ATOM 300 C SER A 36 -0.484 1.040 -14.125 1.00 72.93 C
|
||||
ATOM 301 CB SER A 36 -1.994 2.988 -13.711 1.00 72.93 C
|
||||
ATOM 302 O SER A 36 0.613 1.040 -13.564 1.00 72.93 O
|
||||
ATOM 303 OG SER A 36 -1.967 3.208 -15.110 1.00 72.93 O
|
||||
ATOM 304 N SER A 37 -0.670 0.403 -15.236 1.00 69.39 N
|
||||
ATOM 305 CA SER A 37 0.426 -0.073 -16.073 1.00 69.39 C
|
||||
ATOM 306 C SER A 37 1.372 1.064 -16.443 1.00 69.39 C
|
||||
ATOM 307 CB SER A 37 -0.115 -0.731 -17.343 1.00 69.39 C
|
||||
ATOM 308 O SER A 37 2.505 0.823 -16.867 1.00 69.39 O
|
||||
ATOM 309 OG SER A 37 -1.045 0.119 -17.992 1.00 69.39 O
|
||||
ATOM 310 N ALA A 38 0.862 2.297 -16.248 1.00 67.39 N
|
||||
ATOM 311 CA ALA A 38 1.656 3.492 -16.525 1.00 67.39 C
|
||||
ATOM 312 C ALA A 38 2.561 3.834 -15.344 1.00 67.39 C
|
||||
ATOM 313 CB ALA A 38 0.745 4.672 -16.853 1.00 67.39 C
|
||||
ATOM 314 O ALA A 38 3.386 4.746 -15.431 1.00 67.39 O
|
||||
ATOM 315 N ASP A 39 2.279 3.071 -14.251 1.00 72.75 N
|
||||
ATOM 316 CA ASP A 39 3.057 3.298 -13.037 1.00 72.75 C
|
||||
ATOM 317 C ASP A 39 4.501 2.833 -13.215 1.00 72.75 C
|
||||
ATOM 318 CB ASP A 39 2.417 2.580 -11.847 1.00 72.75 C
|
||||
ATOM 319 O ASP A 39 4.780 1.959 -14.039 1.00 72.75 O
|
||||
ATOM 320 CG ASP A 39 1.183 3.292 -11.320 1.00 72.75 C
|
||||
ATOM 321 OD1 ASP A 39 1.293 4.454 -10.874 1.00 72.75 O
|
||||
ATOM 322 OD2 ASP A 39 0.091 2.684 -11.348 1.00 72.75 O
|
||||
ATOM 323 N SER A 40 5.475 3.562 -12.768 1.00 72.73 N
|
||||
ATOM 324 CA SER A 40 6.908 3.286 -12.803 1.00 72.73 C
|
||||
ATOM 325 C SER A 40 7.256 2.065 -11.958 1.00 72.73 C
|
||||
ATOM 326 CB SER A 40 7.700 4.499 -12.314 1.00 72.73 C
|
||||
ATOM 327 O SER A 40 6.491 1.677 -11.073 1.00 72.73 O
|
||||
ATOM 328 OG SER A 40 7.410 5.640 -13.101 1.00 72.73 O
|
||||
ATOM 329 N GLU A 41 8.265 1.200 -12.472 1.00 83.34 N
|
||||
ATOM 330 CA GLU A 41 8.802 0.051 -11.749 1.00 83.34 C
|
||||
ATOM 331 C GLU A 41 8.950 0.356 -10.261 1.00 83.34 C
|
||||
ATOM 332 CB GLU A 41 10.152 -0.371 -12.336 1.00 83.34 C
|
||||
ATOM 333 O GLU A 41 8.722 -0.515 -9.418 1.00 83.34 O
|
||||
ATOM 334 CG GLU A 41 10.046 -1.058 -13.689 1.00 83.34 C
|
||||
ATOM 335 CD GLU A 41 11.377 -1.586 -14.200 1.00 83.34 C
|
||||
ATOM 336 OE1 GLU A 41 11.690 -2.775 -13.962 1.00 83.34 O
|
||||
ATOM 337 OE2 GLU A 41 12.113 -0.805 -14.842 1.00 83.34 O
|
||||
ATOM 338 N GLU A 42 9.164 1.541 -9.996 1.00 85.29 N
|
||||
ATOM 339 CA GLU A 42 9.324 1.965 -8.608 1.00 85.29 C
|
||||
ATOM 340 C GLU A 42 8.026 1.793 -7.825 1.00 85.29 C
|
||||
ATOM 341 CB GLU A 42 9.789 3.422 -8.541 1.00 85.29 C
|
||||
ATOM 342 O GLU A 42 8.031 1.257 -6.715 1.00 85.29 O
|
||||
ATOM 343 CG GLU A 42 10.241 3.861 -7.156 1.00 85.29 C
|
||||
ATOM 344 CD GLU A 42 11.177 5.059 -7.182 1.00 85.29 C
|
||||
ATOM 345 OE1 GLU A 42 10.689 6.208 -7.276 1.00 85.29 O
|
||||
ATOM 346 OE2 GLU A 42 12.408 4.847 -7.108 1.00 85.29 O
|
||||
ATOM 347 N ILE A 43 6.916 2.343 -8.302 1.00 82.81 N
|
||||
ATOM 348 CA ILE A 43 5.610 2.254 -7.658 1.00 82.81 C
|
||||
ATOM 349 C ILE A 43 5.202 0.789 -7.519 1.00 82.81 C
|
||||
ATOM 350 CB ILE A 43 4.537 3.036 -8.447 1.00 82.81 C
|
||||
ATOM 351 O ILE A 43 4.717 0.370 -6.465 1.00 82.81 O
|
||||
ATOM 352 CG1 ILE A 43 4.822 4.541 -8.387 1.00 82.81 C
|
||||
ATOM 353 CG2 ILE A 43 3.137 2.722 -7.911 1.00 82.81 C
|
||||
ATOM 354 CD1 ILE A 43 3.876 5.384 -9.232 1.00 82.81 C
|
||||
ATOM 355 N LYS A 44 5.549 -0.013 -8.535 1.00 83.23 N
|
||||
ATOM 356 CA LYS A 44 5.294 -1.450 -8.502 1.00 83.23 C
|
||||
ATOM 357 C LYS A 44 6.064 -2.118 -7.366 1.00 83.23 C
|
||||
ATOM 358 CB LYS A 44 5.667 -2.093 -9.838 1.00 83.23 C
|
||||
ATOM 359 O LYS A 44 5.511 -2.944 -6.636 1.00 83.23 O
|
||||
ATOM 360 CG LYS A 44 4.624 -1.902 -10.929 1.00 83.23 C
|
||||
ATOM 361 CD LYS A 44 4.985 -2.679 -12.189 1.00 83.23 C
|
||||
ATOM 362 CE LYS A 44 4.004 -2.398 -13.320 1.00 83.23 C
|
||||
ATOM 363 NZ LYS A 44 4.334 -3.183 -14.547 1.00 83.23 N
|
||||
ATOM 364 N LYS A 45 7.296 -1.791 -7.304 1.00 88.48 N
|
||||
ATOM 365 CA LYS A 45 8.146 -2.345 -6.255 1.00 88.48 C
|
||||
ATOM 366 C LYS A 45 7.628 -1.967 -4.870 1.00 88.48 C
|
||||
ATOM 367 CB LYS A 45 9.589 -1.867 -6.424 1.00 88.48 C
|
||||
ATOM 368 O LYS A 45 7.601 -2.800 -3.962 1.00 88.48 O
|
||||
ATOM 369 CG LYS A 45 10.363 -2.605 -7.506 1.00 88.48 C
|
||||
ATOM 370 CD LYS A 45 11.819 -2.159 -7.554 1.00 88.48 C
|
||||
ATOM 371 CE LYS A 45 12.582 -2.860 -8.670 1.00 88.48 C
|
||||
ATOM 372 NZ LYS A 45 14.014 -2.437 -8.712 1.00 88.48 N
|
||||
ATOM 373 N LEU A 46 7.267 -0.760 -4.707 1.00 90.20 N
|
||||
ATOM 374 CA LEU A 46 6.764 -0.277 -3.426 1.00 90.20 C
|
||||
ATOM 375 C LEU A 46 5.478 -1.001 -3.040 1.00 90.20 C
|
||||
ATOM 376 CB LEU A 46 6.516 1.233 -3.481 1.00 90.20 C
|
||||
ATOM 377 O LEU A 46 5.308 -1.401 -1.886 1.00 90.20 O
|
||||
ATOM 378 CG LEU A 46 7.756 2.126 -3.413 1.00 90.20 C
|
||||
ATOM 379 CD1 LEU A 46 7.391 3.567 -3.755 1.00 90.20 C
|
||||
ATOM 380 CD2 LEU A 46 8.398 2.045 -2.033 1.00 90.20 C
|
||||
ATOM 381 N VAL A 47 4.634 -1.055 -3.956 1.00 87.72 N
|
||||
ATOM 382 CA VAL A 47 3.355 -1.724 -3.743 1.00 87.72 C
|
||||
ATOM 383 C VAL A 47 3.592 -3.184 -3.363 1.00 87.72 C
|
||||
ATOM 384 CB VAL A 47 2.454 -1.638 -4.995 1.00 87.72 C
|
||||
ATOM 385 O VAL A 47 2.953 -3.705 -2.446 1.00 87.72 O
|
||||
ATOM 386 CG1 VAL A 47 1.201 -2.494 -4.819 1.00 87.72 C
|
||||
ATOM 387 CG2 VAL A 47 2.077 -0.186 -5.282 1.00 87.72 C
|
||||
ATOM 388 N GLU A 48 4.453 -3.832 -4.059 1.00 89.12 N
|
||||
ATOM 389 CA GLU A 48 4.817 -5.214 -3.761 1.00 89.12 C
|
||||
ATOM 390 C GLU A 48 5.366 -5.347 -2.344 1.00 89.12 C
|
||||
ATOM 391 CB GLU A 48 5.843 -5.729 -4.774 1.00 89.12 C
|
||||
ATOM 392 O GLU A 48 5.015 -6.283 -1.622 1.00 89.12 O
|
||||
ATOM 393 CG GLU A 48 5.260 -6.014 -6.150 1.00 89.12 C
|
||||
ATOM 394 CD GLU A 48 6.211 -6.777 -7.058 1.00 89.12 C
|
||||
ATOM 395 OE1 GLU A 48 6.128 -8.025 -7.112 1.00 89.12 O
|
||||
ATOM 396 OE2 GLU A 48 7.046 -6.122 -7.721 1.00 89.12 O
|
||||
ATOM 397 N GLU A 49 6.263 -4.525 -2.078 1.00 92.03 N
|
||||
ATOM 398 CA GLU A 49 6.825 -4.532 -0.731 1.00 92.03 C
|
||||
ATOM 399 C GLU A 49 5.738 -4.339 0.322 1.00 92.03 C
|
||||
ATOM 400 CB GLU A 49 7.894 -3.445 -0.589 1.00 92.03 C
|
||||
ATOM 401 O GLU A 49 5.730 -5.026 1.346 1.00 92.03 O
|
||||
ATOM 402 CG GLU A 49 9.203 -3.773 -1.292 1.00 92.03 C
|
||||
ATOM 403 CD GLU A 49 10.340 -2.840 -0.909 1.00 92.03 C
|
||||
ATOM 404 OE1 GLU A 49 10.970 -3.054 0.152 1.00 92.03 O
|
||||
ATOM 405 OE2 GLU A 49 10.603 -1.886 -1.675 1.00 92.03 O
|
||||
ATOM 406 N ASN A 50 4.950 -3.304 0.106 1.00 90.05 N
|
||||
ATOM 407 CA ASN A 50 3.830 -3.068 1.010 1.00 90.05 C
|
||||
ATOM 408 C ASN A 50 2.960 -4.313 1.161 1.00 90.05 C
|
||||
ATOM 409 CB ASN A 50 2.987 -1.887 0.524 1.00 90.05 C
|
||||
ATOM 410 O ASN A 50 2.539 -4.651 2.269 1.00 90.05 O
|
||||
ATOM 411 CG ASN A 50 3.539 -0.550 0.978 1.00 90.05 C
|
||||
ATOM 412 ND2 ASN A 50 4.277 0.116 0.098 1.00 90.05 N
|
||||
ATOM 413 OD1 ASN A 50 3.305 -0.120 2.110 1.00 90.05 O
|
||||
ATOM 414 N ALA A 51 2.704 -4.904 0.020 1.00 89.43 N
|
||||
ATOM 415 CA ALA A 51 1.897 -6.121 -0.004 1.00 89.43 C
|
||||
ATOM 416 C ALA A 51 2.538 -7.220 0.839 1.00 89.43 C
|
||||
ATOM 417 CB ALA A 51 1.701 -6.602 -1.439 1.00 89.43 C
|
||||
ATOM 418 O ALA A 51 1.849 -7.920 1.585 1.00 89.43 O
|
||||
ATOM 419 N GLU A 52 3.815 -7.414 0.696 1.00 91.12 N
|
||||
ATOM 420 CA GLU A 52 4.547 -8.437 1.437 1.00 91.12 C
|
||||
ATOM 421 C GLU A 52 4.436 -8.213 2.942 1.00 91.12 C
|
||||
ATOM 422 CB GLU A 52 6.018 -8.457 1.015 1.00 91.12 C
|
||||
ATOM 423 O GLU A 52 4.209 -9.158 3.700 1.00 91.12 O
|
||||
ATOM 424 CG GLU A 52 6.248 -9.005 -0.387 1.00 91.12 C
|
||||
ATOM 425 CD GLU A 52 7.720 -9.166 -0.733 1.00 91.12 C
|
||||
ATOM 426 OE1 GLU A 52 8.313 -10.215 -0.392 1.00 91.12 O
|
||||
ATOM 427 OE2 GLU A 52 8.285 -8.235 -1.350 1.00 91.12 O
|
||||
ATOM 428 N ILE A 53 4.609 -7.008 3.402 1.00 91.89 N
|
||||
ATOM 429 CA ILE A 53 4.531 -6.669 4.819 1.00 91.89 C
|
||||
ATOM 430 C ILE A 53 3.112 -6.910 5.330 1.00 91.89 C
|
||||
ATOM 431 CB ILE A 53 4.950 -5.204 5.074 1.00 91.89 C
|
||||
ATOM 432 O ILE A 53 2.921 -7.486 6.403 1.00 91.89 O
|
||||
ATOM 433 CG1 ILE A 53 6.419 -4.994 4.686 1.00 91.89 C
|
||||
ATOM 434 CG2 ILE A 53 4.710 -4.819 6.536 1.00 91.89 C
|
||||
ATOM 435 CD1 ILE A 53 6.878 -3.544 4.762 1.00 91.89 C
|
||||
ATOM 436 N LEU A 54 2.220 -6.422 4.598 1.00 90.60 N
|
||||
ATOM 437 CA LEU A 54 0.817 -6.592 4.960 1.00 90.60 C
|
||||
ATOM 438 C LEU A 54 0.454 -8.071 5.048 1.00 90.60 C
|
||||
ATOM 439 CB LEU A 54 -0.087 -5.892 3.942 1.00 90.60 C
|
||||
ATOM 440 O LEU A 54 -0.274 -8.482 5.955 1.00 90.60 O
|
||||
ATOM 441 CG LEU A 54 -0.161 -4.367 4.036 1.00 90.60 C
|
||||
ATOM 442 CD1 LEU A 54 -0.837 -3.792 2.797 1.00 90.60 C
|
||||
ATOM 443 CD2 LEU A 54 -0.900 -3.944 5.301 1.00 90.60 C
|
||||
ATOM 444 N GLU A 55 0.909 -8.858 4.086 1.00 90.94 N
|
||||
ATOM 445 CA GLU A 55 0.715 -10.305 4.103 1.00 90.94 C
|
||||
ATOM 446 C GLU A 55 1.303 -10.926 5.367 1.00 90.94 C
|
||||
ATOM 447 CB GLU A 55 1.342 -10.946 2.862 1.00 90.94 C
|
||||
ATOM 448 O GLU A 55 0.712 -11.837 5.950 1.00 90.94 O
|
||||
ATOM 449 CG GLU A 55 0.549 -10.716 1.584 1.00 90.94 C
|
||||
ATOM 450 CD GLU A 55 0.996 -11.603 0.432 1.00 90.94 C
|
||||
ATOM 451 OE1 GLU A 55 0.436 -12.710 0.266 1.00 90.94 O
|
||||
ATOM 452 OE2 GLU A 55 1.915 -11.187 -0.308 1.00 90.94 O
|
||||
ATOM 453 N LYS A 56 2.477 -10.439 5.689 1.00 90.58 N
|
||||
ATOM 454 CA LYS A 56 3.128 -10.914 6.907 1.00 90.58 C
|
||||
ATOM 455 C LYS A 56 2.303 -10.564 8.143 1.00 90.58 C
|
||||
ATOM 456 CB LYS A 56 4.533 -10.324 7.031 1.00 90.58 C
|
||||
ATOM 457 O LYS A 56 2.287 -11.317 9.119 1.00 90.58 O
|
||||
ATOM 458 CG LYS A 56 5.551 -10.945 6.085 1.00 90.58 C
|
||||
ATOM 459 CD LYS A 56 6.949 -10.393 6.327 1.00 90.58 C
|
||||
ATOM 460 CE LYS A 56 7.967 -11.008 5.376 1.00 90.58 C
|
||||
ATOM 461 NZ LYS A 56 9.350 -10.516 5.651 1.00 90.58 N
|
||||
ATOM 462 N LEU A 57 1.666 -9.472 8.081 1.00 89.28 N
|
||||
ATOM 463 CA LEU A 57 0.843 -8.979 9.180 1.00 89.28 C
|
||||
ATOM 464 C LEU A 57 -0.522 -9.661 9.185 1.00 89.28 C
|
||||
ATOM 465 CB LEU A 57 0.668 -7.462 9.080 1.00 89.28 C
|
||||
ATOM 466 O LEU A 57 -1.332 -9.430 10.085 1.00 89.28 O
|
||||
ATOM 467 CG LEU A 57 1.906 -6.615 9.381 1.00 89.28 C
|
||||
ATOM 468 CD1 LEU A 57 1.651 -5.157 9.016 1.00 89.28 C
|
||||
ATOM 469 CD2 LEU A 57 2.298 -6.744 10.849 1.00 89.28 C
|
||||
ATOM 470 N GLY A 58 -0.801 -10.562 8.254 1.00 89.24 N
|
||||
ATOM 471 CA GLY A 58 -2.043 -11.316 8.202 1.00 89.24 C
|
||||
ATOM 472 C GLY A 58 -3.109 -10.651 7.352 1.00 89.24 C
|
||||
ATOM 473 O GLY A 58 -4.304 -10.868 7.563 1.00 89.24 O
|
||||
ATOM 474 N VAL A 59 -2.742 -9.745 6.559 1.00 90.59 N
|
||||
ATOM 475 CA VAL A 59 -3.658 -9.015 5.689 1.00 90.59 C
|
||||
ATOM 476 C VAL A 59 -3.626 -9.615 4.285 1.00 90.59 C
|
||||
ATOM 477 CB VAL A 59 -3.312 -7.511 5.634 1.00 90.59 C
|
||||
ATOM 478 O VAL A 59 -2.551 -9.854 3.730 1.00 90.59 O
|
||||
ATOM 479 CG1 VAL A 59 -4.305 -6.760 4.750 1.00 90.59 C
|
||||
ATOM 480 CG2 VAL A 59 -3.290 -6.917 7.042 1.00 90.59 C
|
||||
ATOM 481 N LYS A 60 -4.796 -10.038 3.669 1.00 91.31 N
|
||||
ATOM 482 CA LYS A 60 -4.890 -10.525 2.295 1.00 91.31 C
|
||||
ATOM 483 C LYS A 60 -4.751 -9.380 1.296 1.00 91.31 C
|
||||
ATOM 484 CB LYS A 60 -6.215 -11.256 2.074 1.00 91.31 C
|
||||
ATOM 485 O LYS A 60 -5.554 -8.444 1.300 1.00 91.31 O
|
||||
ATOM 486 CG LYS A 60 -6.280 -12.039 0.771 1.00 91.31 C
|
||||
ATOM 487 CD LYS A 60 -7.562 -12.856 0.673 1.00 91.31 C
|
||||
ATOM 488 CE LYS A 60 -7.618 -13.657 -0.621 1.00 91.31 C
|
||||
ATOM 489 NZ LYS A 60 -8.859 -14.483 -0.707 1.00 91.31 N
|
||||
ATOM 490 N VAL A 61 -3.640 -9.388 0.542 1.00 90.50 N
|
||||
ATOM 491 CA VAL A 61 -3.325 -8.295 -0.373 1.00 90.50 C
|
||||
ATOM 492 C VAL A 61 -3.627 -8.719 -1.808 1.00 90.50 C
|
||||
ATOM 493 CB VAL A 61 -1.849 -7.856 -0.246 1.00 90.50 C
|
||||
ATOM 494 O VAL A 61 -3.177 -9.776 -2.258 1.00 90.50 O
|
||||
ATOM 495 CG1 VAL A 61 -1.548 -6.696 -1.192 1.00 90.50 C
|
||||
ATOM 496 CG2 VAL A 61 -1.531 -7.470 1.197 1.00 90.50 C
|
||||
ATOM 497 N LYS A 62 -4.464 -7.942 -2.568 1.00 89.89 N
|
||||
ATOM 498 CA LYS A 62 -4.755 -8.135 -3.986 1.00 89.89 C
|
||||
ATOM 499 C LYS A 62 -4.271 -6.948 -4.813 1.00 89.89 C
|
||||
ATOM 500 CB LYS A 62 -6.254 -8.348 -4.202 1.00 89.89 C
|
||||
ATOM 501 O LYS A 62 -4.598 -5.799 -4.510 1.00 89.89 O
|
||||
ATOM 502 CG LYS A 62 -6.615 -8.835 -5.598 1.00 89.89 C
|
||||
ATOM 503 CD LYS A 62 -8.100 -9.156 -5.711 1.00 89.89 C
|
||||
ATOM 504 CE LYS A 62 -8.454 -9.686 -7.094 1.00 89.89 C
|
||||
ATOM 505 NZ LYS A 62 -9.906 -10.018 -7.205 1.00 89.89 N
|
||||
ATOM 506 N VAL A 63 -3.369 -7.174 -5.795 1.00 85.66 N
|
||||
ATOM 507 CA VAL A 63 -2.847 -6.112 -6.649 1.00 85.66 C
|
||||
ATOM 508 C VAL A 63 -3.490 -6.198 -8.032 1.00 85.66 C
|
||||
ATOM 509 CB VAL A 63 -1.309 -6.185 -6.772 1.00 85.66 C
|
||||
ATOM 510 O VAL A 63 -3.359 -7.211 -8.723 1.00 85.66 O
|
||||
ATOM 511 CG1 VAL A 63 -0.779 -5.034 -7.625 1.00 85.66 C
|
||||
ATOM 512 CG2 VAL A 63 -0.663 -6.171 -5.388 1.00 85.66 C
|
||||
ATOM 513 N VAL A 64 -4.304 -5.230 -8.309 1.00 83.17 N
|
||||
ATOM 514 CA VAL A 64 -5.001 -5.174 -9.589 1.00 83.17 C
|
||||
ATOM 515 C VAL A 64 -4.339 -4.137 -10.494 1.00 83.17 C
|
||||
ATOM 516 CB VAL A 64 -6.499 -4.843 -9.406 1.00 83.17 C
|
||||
ATOM 517 O VAL A 64 -4.094 -3.004 -10.073 1.00 83.17 O
|
||||
ATOM 518 CG1 VAL A 64 -7.221 -4.843 -10.753 1.00 83.17 C
|
||||
ATOM 519 CG2 VAL A 64 -7.152 -5.836 -8.447 1.00 83.17 C
|
||||
ATOM 520 N GLU A 65 -3.914 -4.576 -11.655 1.00 82.38 N
|
||||
ATOM 521 CA GLU A 65 -3.300 -3.697 -12.646 1.00 82.38 C
|
||||
ATOM 522 C GLU A 65 -4.341 -3.154 -13.621 1.00 82.38 C
|
||||
ATOM 523 CB GLU A 65 -2.198 -4.434 -13.410 1.00 82.38 C
|
||||
ATOM 524 O GLU A 65 -5.007 -3.922 -14.318 1.00 82.38 O
|
||||
ATOM 525 CG GLU A 65 -1.357 -3.531 -14.300 1.00 82.38 C
|
||||
ATOM 526 CD GLU A 65 -0.228 -4.266 -15.005 1.00 82.38 C
|
||||
ATOM 527 OE1 GLU A 65 -0.445 -4.784 -16.124 1.00 82.38 O
|
||||
ATOM 528 OE2 GLU A 65 0.884 -4.325 -14.433 1.00 82.38 O
|
||||
ATOM 529 N LEU A 66 -4.731 -1.848 -13.511 1.00 73.61 N
|
||||
ATOM 530 CA LEU A 66 -5.704 -1.232 -14.407 1.00 73.61 C
|
||||
ATOM 531 C LEU A 66 -5.031 -0.737 -15.682 1.00 73.61 C
|
||||
ATOM 532 CB LEU A 66 -6.417 -0.072 -13.708 1.00 73.61 C
|
||||
ATOM 533 O LEU A 66 -3.927 -0.189 -15.634 1.00 73.61 O
|
||||
ATOM 534 CG LEU A 66 -7.425 -0.450 -12.622 1.00 73.61 C
|
||||
ATOM 535 CD1 LEU A 66 -7.847 0.787 -11.836 1.00 73.61 C
|
||||
ATOM 536 CD2 LEU A 66 -8.638 -1.141 -13.234 1.00 73.61 C
|
||||
ATOM 537 N GLY A 67 -5.215 -1.540 -16.831 1.00 61.81 N
|
||||
ATOM 538 CA GLY A 67 -4.761 -1.145 -18.155 1.00 61.81 C
|
||||
ATOM 539 C GLY A 67 -5.505 0.056 -18.708 1.00 61.81 C
|
||||
ATOM 540 O GLY A 67 -6.738 0.065 -18.746 1.00 61.81 O
|
||||
ATOM 541 N GLY A 68 -5.090 1.390 -18.491 1.00 60.96 N
|
||||
ATOM 542 CA GLY A 68 -5.697 2.625 -18.962 1.00 60.96 C
|
||||
ATOM 543 C GLY A 68 -4.768 3.820 -18.865 1.00 60.96 C
|
||||
ATOM 544 O GLY A 68 -3.738 3.760 -18.191 1.00 60.96 O
|
||||
ATOM 545 N GLU A 69 -4.531 4.607 -19.986 1.00 63.19 N
|
||||
ATOM 546 CA GLU A 69 -3.769 5.840 -20.158 1.00 63.19 C
|
||||
ATOM 547 C GLU A 69 -3.863 6.725 -18.918 1.00 63.19 C
|
||||
ATOM 548 CB GLU A 69 -4.257 6.607 -21.389 1.00 63.19 C
|
||||
ATOM 549 O GLU A 69 -4.938 6.870 -18.332 1.00 63.19 O
|
||||
ATOM 550 CG GLU A 69 -3.142 7.015 -22.341 1.00 63.19 C
|
||||
ATOM 551 CD GLU A 69 -3.653 7.632 -23.634 1.00 63.19 C
|
||||
ATOM 552 OE1 GLU A 69 -3.936 8.852 -23.654 1.00 63.19 O
|
||||
ATOM 553 OE2 GLU A 69 -3.771 6.890 -24.634 1.00 63.19 O
|
||||
ATOM 554 N LEU A 70 -2.763 6.805 -18.127 1.00 62.85 N
|
||||
ATOM 555 CA LEU A 70 -2.656 7.713 -16.990 1.00 62.85 C
|
||||
ATOM 556 C LEU A 70 -3.013 9.139 -17.398 1.00 62.85 C
|
||||
ATOM 557 CB LEU A 70 -1.242 7.676 -16.406 1.00 62.85 C
|
||||
ATOM 558 O LEU A 70 -2.495 9.653 -18.391 1.00 62.85 O
|
||||
ATOM 559 CG LEU A 70 -0.896 6.460 -15.544 1.00 62.85 C
|
||||
ATOM 560 CD1 LEU A 70 0.611 6.230 -15.534 1.00 62.85 C
|
||||
ATOM 561 CD2 LEU A 70 -1.425 6.642 -14.126 1.00 62.85 C
|
||||
ATOM 562 N ASP A 71 -4.382 9.504 -17.115 1.00 67.78 N
|
||||
ATOM 563 CA ASP A 71 -4.779 10.889 -17.347 1.00 67.78 C
|
||||
ATOM 564 C ASP A 71 -3.796 11.859 -16.695 1.00 67.78 C
|
||||
ATOM 565 CB ASP A 71 -6.193 11.139 -16.819 1.00 67.78 C
|
||||
ATOM 566 O ASP A 71 -3.070 11.487 -15.770 1.00 67.78 O
|
||||
ATOM 567 CG ASP A 71 -6.996 12.083 -17.696 1.00 67.78 C
|
||||
ATOM 568 OD1 ASP A 71 -7.054 13.295 -17.394 1.00 67.78 O
|
||||
ATOM 569 OD2 ASP A 71 -7.578 11.611 -18.697 1.00 67.78 O
|
||||
ATOM 570 N GLU A 72 -3.069 12.841 -17.280 1.00 66.31 N
|
||||
ATOM 571 CA GLU A 72 -2.192 13.936 -16.876 1.00 66.31 C
|
||||
ATOM 572 C GLU A 72 -2.299 14.205 -15.378 1.00 66.31 C
|
||||
ATOM 573 CB GLU A 72 -2.521 15.207 -17.663 1.00 66.31 C
|
||||
ATOM 574 O GLU A 72 -1.296 14.487 -14.719 1.00 66.31 O
|
||||
ATOM 575 CG GLU A 72 -1.767 15.327 -18.980 1.00 66.31 C
|
||||
ATOM 576 CD GLU A 72 -2.109 16.590 -19.754 1.00 66.31 C
|
||||
ATOM 577 OE1 GLU A 72 -1.474 17.642 -19.511 1.00 66.31 O
|
||||
ATOM 578 OE2 GLU A 72 -3.020 16.529 -20.609 1.00 66.31 O
|
||||
ATOM 579 N LEU A 73 -3.365 13.942 -14.773 1.00 66.33 N
|
||||
ATOM 580 CA LEU A 73 -3.564 14.142 -13.342 1.00 66.33 C
|
||||
ATOM 581 C LEU A 73 -2.893 13.032 -12.539 1.00 66.33 C
|
||||
ATOM 582 CB LEU A 73 -5.058 14.196 -13.010 1.00 66.33 C
|
||||
ATOM 583 O LEU A 73 -2.291 13.292 -11.495 1.00 66.33 O
|
||||
ATOM 584 CG LEU A 73 -5.727 15.567 -13.115 1.00 66.33 C
|
||||
ATOM 585 CD1 LEU A 73 -7.205 15.411 -13.456 1.00 66.33 C
|
||||
ATOM 586 CD2 LEU A 73 -5.551 16.349 -11.818 1.00 66.33 C
|
||||
ATOM 587 N THR A 74 -2.894 11.771 -13.049 1.00 65.78 N
|
||||
ATOM 588 CA THR A 74 -2.225 10.632 -12.430 1.00 65.78 C
|
||||
ATOM 589 C THR A 74 -0.710 10.750 -12.575 1.00 65.78 C
|
||||
ATOM 590 CB THR A 74 -2.699 9.303 -13.046 1.00 65.78 C
|
||||
ATOM 591 O THR A 74 0.035 10.429 -11.646 1.00 65.78 O
|
||||
ATOM 592 CG2 THR A 74 -2.057 8.111 -12.344 1.00 65.78 C
|
||||
ATOM 593 OG1 THR A 74 -4.124 9.206 -12.920 1.00 65.78 O
|
||||
ATOM 594 N LEU A 75 -0.311 11.344 -13.746 1.00 68.90 N
|
||||
ATOM 595 CA LEU A 75 1.107 11.593 -13.982 1.00 68.90 C
|
||||
ATOM 596 C LEU A 75 1.625 12.698 -13.068 1.00 68.90 C
|
||||
ATOM 597 CB LEU A 75 1.348 11.970 -15.446 1.00 68.90 C
|
||||
ATOM 598 O LEU A 75 2.740 12.610 -12.550 1.00 68.90 O
|
||||
ATOM 599 CG LEU A 75 1.401 10.812 -16.445 1.00 68.90 C
|
||||
ATOM 600 CD1 LEU A 75 1.017 11.297 -17.839 1.00 68.90 C
|
||||
ATOM 601 CD2 LEU A 75 2.788 10.179 -16.456 1.00 68.90 C
|
||||
ATOM 602 N LYS A 76 0.708 13.698 -12.805 1.00 71.32 N
|
||||
ATOM 603 CA LYS A 76 1.071 14.813 -11.936 1.00 71.32 C
|
||||
ATOM 604 C LYS A 76 1.146 14.372 -10.477 1.00 71.32 C
|
||||
ATOM 605 CB LYS A 76 0.068 15.959 -12.086 1.00 71.32 C
|
||||
ATOM 606 O LYS A 76 1.991 14.854 -9.720 1.00 71.32 O
|
||||
ATOM 607 CG LYS A 76 0.514 17.260 -11.436 1.00 71.32 C
|
||||
ATOM 608 CD LYS A 76 -0.488 18.381 -11.684 1.00 71.32 C
|
||||
ATOM 609 CE LYS A 76 -0.066 19.672 -10.996 1.00 71.32 C
|
||||
ATOM 610 NZ LYS A 76 -1.069 20.760 -11.197 1.00 71.32 N
|
||||
ATOM 611 N HIS A 77 0.420 13.365 -10.189 1.00 75.38 N
|
||||
ATOM 612 CA HIS A 77 0.315 12.913 -8.807 1.00 75.38 C
|
||||
ATOM 613 C HIS A 77 1.167 11.672 -8.567 1.00 75.38 C
|
||||
ATOM 614 CB HIS A 77 -1.144 12.626 -8.446 1.00 75.38 C
|
||||
ATOM 615 O HIS A 77 1.146 11.101 -7.474 1.00 75.38 O
|
||||
ATOM 616 CG HIS A 77 -1.983 13.857 -8.316 1.00 75.38 C
|
||||
ATOM 617 CD2 HIS A 77 -1.961 14.855 -7.401 1.00 75.38 C
|
||||
ATOM 618 ND1 HIS A 77 -2.994 14.166 -9.199 1.00 75.38 N
|
||||
ATOM 619 CE1 HIS A 77 -3.559 15.304 -8.833 1.00 75.38 C
|
||||
ATOM 620 NE2 HIS A 77 -2.951 15.743 -7.744 1.00 75.38 N
|
||||
ATOM 621 N LYS A 78 1.936 11.316 -9.653 1.00 73.17 N
|
||||
ATOM 622 CA LYS A 78 2.824 10.158 -9.610 1.00 73.17 C
|
||||
ATOM 623 C LYS A 78 3.862 10.302 -8.500 1.00 73.17 C
|
||||
ATOM 624 CB LYS A 78 3.521 9.965 -10.957 1.00 73.17 C
|
||||
ATOM 625 O LYS A 78 4.117 9.353 -7.755 1.00 73.17 O
|
||||
ATOM 626 CG LYS A 78 4.245 8.633 -11.095 1.00 73.17 C
|
||||
ATOM 627 CD LYS A 78 4.838 8.461 -12.487 1.00 73.17 C
|
||||
ATOM 628 CE LYS A 78 5.641 7.172 -12.598 1.00 73.17 C
|
||||
ATOM 629 NZ LYS A 78 6.222 6.996 -13.963 1.00 73.17 N
|
||||
ATOM 630 N GLU A 79 4.467 11.425 -8.459 1.00 82.01 N
|
||||
ATOM 631 CA GLU A 79 5.451 11.676 -7.410 1.00 82.01 C
|
||||
ATOM 632 C GLU A 79 4.810 11.619 -6.027 1.00 82.01 C
|
||||
ATOM 633 CB GLU A 79 6.127 13.034 -7.621 1.00 82.01 C
|
||||
ATOM 634 O GLU A 79 5.388 11.062 -5.091 1.00 82.01 O
|
||||
ATOM 635 CG GLU A 79 7.125 13.052 -8.769 1.00 82.01 C
|
||||
ATOM 636 CD GLU A 79 7.967 14.317 -8.812 1.00 82.01 C
|
||||
ATOM 637 OE1 GLU A 79 9.088 14.320 -8.254 1.00 82.01 O
|
||||
ATOM 638 OE2 GLU A 79 7.502 15.314 -9.408 1.00 82.01 O
|
||||
ATOM 639 N LYS A 80 3.748 12.178 -5.930 1.00 81.73 N
|
||||
ATOM 640 CA LYS A 80 3.031 12.190 -4.659 1.00 81.73 C
|
||||
ATOM 641 C LYS A 80 2.604 10.781 -4.255 1.00 81.73 C
|
||||
ATOM 642 CB LYS A 80 1.808 13.105 -4.740 1.00 81.73 C
|
||||
ATOM 643 O LYS A 80 2.693 10.412 -3.082 1.00 81.73 O
|
||||
ATOM 644 CG LYS A 80 2.129 14.583 -4.570 1.00 81.73 C
|
||||
ATOM 645 CD LYS A 80 0.863 15.427 -4.516 1.00 81.73 C
|
||||
ATOM 646 CE LYS A 80 1.184 16.914 -4.444 1.00 81.73 C
|
||||
ATOM 647 NZ LYS A 80 -0.055 17.744 -4.351 1.00 81.73 N
|
||||
ATOM 648 N ILE A 81 2.180 10.044 -5.166 1.00 80.10 N
|
||||
ATOM 649 CA ILE A 81 1.790 8.655 -4.957 1.00 80.10 C
|
||||
ATOM 650 C ILE A 81 2.993 7.848 -4.473 1.00 80.10 C
|
||||
ATOM 651 CB ILE A 81 1.208 8.030 -6.245 1.00 80.10 C
|
||||
ATOM 652 O ILE A 81 2.875 7.039 -3.550 1.00 80.10 O
|
||||
ATOM 653 CG1 ILE A 81 -0.130 8.688 -6.600 1.00 80.10 C
|
||||
ATOM 654 CG2 ILE A 81 1.050 6.515 -6.087 1.00 80.10 C
|
||||
ATOM 655 CD1 ILE A 81 -0.679 8.279 -7.960 1.00 80.10 C
|
||||
ATOM 656 N LEU A 82 4.081 8.122 -5.134 1.00 83.52 N
|
||||
ATOM 657 CA LEU A 82 5.328 7.478 -4.739 1.00 83.52 C
|
||||
ATOM 658 C LEU A 82 5.679 7.813 -3.294 1.00 83.52 C
|
||||
ATOM 659 CB LEU A 82 6.470 7.905 -5.666 1.00 83.52 C
|
||||
ATOM 660 O LEU A 82 5.984 6.919 -2.501 1.00 83.52 O
|
||||
ATOM 661 CG LEU A 82 7.813 7.204 -5.456 1.00 83.52 C
|
||||
ATOM 662 CD1 LEU A 82 7.738 5.760 -5.939 1.00 83.52 C
|
||||
ATOM 663 CD2 LEU A 82 8.927 7.957 -6.174 1.00 83.52 C
|
||||
ATOM 664 N GLU A 83 5.694 9.021 -2.968 1.00 87.96 N
|
||||
ATOM 665 CA GLU A 83 6.011 9.477 -1.618 1.00 87.96 C
|
||||
ATOM 666 C GLU A 83 5.056 8.873 -0.593 1.00 87.96 C
|
||||
ATOM 667 CB GLU A 83 5.967 11.005 -1.542 1.00 87.96 C
|
||||
ATOM 668 O GLU A 83 5.488 8.386 0.454 1.00 87.96 O
|
||||
ATOM 669 CG GLU A 83 6.496 11.571 -0.233 1.00 87.96 C
|
||||
ATOM 670 CD GLU A 83 6.453 13.090 -0.175 1.00 87.96 C
|
||||
ATOM 671 OE1 GLU A 83 5.424 13.652 0.264 1.00 87.96 O
|
||||
ATOM 672 OE2 GLU A 83 7.456 13.723 -0.573 1.00 87.96 O
|
||||
ATOM 673 N LYS A 84 3.752 8.925 -0.931 1.00 87.17 N
|
||||
ATOM 674 CA LYS A 84 2.749 8.416 0.000 1.00 87.17 C
|
||||
ATOM 675 C LYS A 84 2.865 6.903 0.160 1.00 87.17 C
|
||||
ATOM 676 CB LYS A 84 1.342 8.787 -0.470 1.00 87.17 C
|
||||
ATOM 677 O LYS A 84 2.708 6.376 1.264 1.00 87.17 O
|
||||
ATOM 678 CG LYS A 84 1.031 10.274 -0.383 1.00 87.17 C
|
||||
ATOM 679 CD LYS A 84 0.932 10.739 1.064 1.00 87.17 C
|
||||
ATOM 680 CE LYS A 84 0.563 12.214 1.154 1.00 87.17 C
|
||||
ATOM 681 NZ LYS A 84 0.580 12.705 2.564 1.00 87.17 N
|
||||
ATOM 682 N THR A 85 3.075 6.194 -0.878 1.00 86.48 N
|
||||
ATOM 683 CA THR A 85 3.277 4.749 -0.859 1.00 86.48 C
|
||||
ATOM 684 C THR A 85 4.478 4.381 0.007 1.00 86.48 C
|
||||
ATOM 685 CB THR A 85 3.478 4.195 -2.282 1.00 86.48 C
|
||||
ATOM 686 O THR A 85 4.438 3.396 0.747 1.00 86.48 O
|
||||
ATOM 687 CG2 THR A 85 3.571 2.673 -2.271 1.00 86.48 C
|
||||
ATOM 688 OG1 THR A 85 2.371 4.589 -3.103 1.00 86.48 O
|
||||
ATOM 689 N LYS A 86 5.560 5.179 -0.120 1.00 89.61 N
|
||||
ATOM 690 CA LYS A 86 6.738 4.988 0.722 1.00 89.61 C
|
||||
ATOM 691 C LYS A 86 6.390 5.146 2.199 1.00 89.61 C
|
||||
ATOM 692 CB LYS A 86 7.840 5.975 0.335 1.00 89.61 C
|
||||
ATOM 693 O LYS A 86 6.864 4.379 3.040 1.00 89.61 O
|
||||
ATOM 694 CG LYS A 86 8.596 5.594 -0.930 1.00 89.61 C
|
||||
ATOM 695 CD LYS A 86 9.745 6.555 -1.205 1.00 89.61 C
|
||||
ATOM 696 CE LYS A 86 10.475 6.201 -2.494 1.00 89.61 C
|
||||
ATOM 697 NZ LYS A 86 11.592 7.151 -2.777 1.00 89.61 N
|
||||
ATOM 698 N LEU A 87 5.725 6.133 2.442 1.00 90.63 N
|
||||
ATOM 699 CA LEU A 87 5.303 6.398 3.814 1.00 90.63 C
|
||||
ATOM 700 C LEU A 87 4.520 5.217 4.379 1.00 90.63 C
|
||||
ATOM 701 CB LEU A 87 4.449 7.667 3.877 1.00 90.63 C
|
||||
ATOM 702 O LEU A 87 4.736 4.815 5.524 1.00 90.63 O
|
||||
ATOM 703 CG LEU A 87 4.127 8.198 5.274 1.00 90.63 C
|
||||
ATOM 704 CD1 LEU A 87 5.400 8.666 5.971 1.00 90.63 C
|
||||
ATOM 705 CD2 LEU A 87 3.108 9.330 5.195 1.00 90.63 C
|
||||
ATOM 706 N VAL A 88 3.611 4.770 3.617 1.00 89.50 N
|
||||
ATOM 707 CA VAL A 88 2.818 3.610 4.012 1.00 89.50 C
|
||||
ATOM 708 C VAL A 88 3.741 2.436 4.330 1.00 89.50 C
|
||||
ATOM 709 CB VAL A 88 1.808 3.212 2.913 1.00 89.50 C
|
||||
ATOM 710 O VAL A 88 3.547 1.739 5.328 1.00 89.50 O
|
||||
ATOM 711 CG1 VAL A 88 1.118 1.895 3.265 1.00 89.50 C
|
||||
ATOM 712 CG2 VAL A 88 0.777 4.321 2.708 1.00 89.50 C
|
||||
ATOM 713 N LEU A 89 4.633 2.181 3.505 1.00 90.95 N
|
||||
ATOM 714 CA LEU A 89 5.629 1.136 3.718 1.00 90.95 C
|
||||
ATOM 715 C LEU A 89 6.348 1.334 5.048 1.00 90.95 C
|
||||
ATOM 716 CB LEU A 89 6.644 1.123 2.572 1.00 90.95 C
|
||||
ATOM 717 O LEU A 89 6.528 0.380 5.809 1.00 90.95 O
|
||||
ATOM 718 CG LEU A 89 7.716 0.033 2.629 1.00 90.95 C
|
||||
ATOM 719 CD1 LEU A 89 7.069 -1.348 2.620 1.00 90.95 C
|
||||
ATOM 720 CD2 LEU A 89 8.691 0.180 1.466 1.00 90.95 C
|
||||
ATOM 721 N GLU A 90 6.858 2.505 5.268 1.00 91.77 N
|
||||
ATOM 722 CA GLU A 90 7.540 2.813 6.521 1.00 91.77 C
|
||||
ATOM 723 C GLU A 90 6.648 2.516 7.723 1.00 91.77 C
|
||||
ATOM 724 CB GLU A 90 7.985 4.278 6.545 1.00 91.77 C
|
||||
ATOM 725 O GLU A 90 7.113 1.982 8.731 1.00 91.77 O
|
||||
ATOM 726 CG GLU A 90 9.127 4.590 5.589 1.00 91.77 C
|
||||
ATOM 727 CD GLU A 90 10.319 5.241 6.271 1.00 91.77 C
|
||||
ATOM 728 OE1 GLU A 90 11.320 4.540 6.544 1.00 91.77 O
|
||||
ATOM 729 OE2 GLU A 90 10.252 6.462 6.535 1.00 91.77 O
|
||||
ATOM 730 N ILE A 91 5.411 2.885 7.569 1.00 90.84 N
|
||||
ATOM 731 CA ILE A 91 4.447 2.638 8.635 1.00 90.84 C
|
||||
ATOM 732 C ILE A 91 4.287 1.135 8.849 1.00 90.84 C
|
||||
ATOM 733 CB ILE A 91 3.078 3.283 8.321 1.00 90.84 C
|
||||
ATOM 734 O ILE A 91 4.286 0.660 9.987 1.00 90.84 O
|
||||
ATOM 735 CG1 ILE A 91 3.208 4.810 8.263 1.00 90.84 C
|
||||
ATOM 736 CG2 ILE A 91 2.031 2.861 9.356 1.00 90.84 C
|
||||
ATOM 737 CD1 ILE A 91 1.989 5.514 7.684 1.00 90.84 C
|
||||
ATOM 738 N LEU A 92 4.083 0.438 7.825 1.00 90.22 N
|
||||
ATOM 739 CA LEU A 92 3.929 -1.012 7.890 1.00 90.22 C
|
||||
ATOM 740 C LEU A 92 5.163 -1.662 8.506 1.00 90.22 C
|
||||
ATOM 741 CB LEU A 92 3.677 -1.587 6.494 1.00 90.22 C
|
||||
ATOM 742 O LEU A 92 5.045 -2.579 9.322 1.00 90.22 O
|
||||
ATOM 743 CG LEU A 92 2.300 -1.314 5.887 1.00 90.22 C
|
||||
ATOM 744 CD1 LEU A 92 2.262 -1.772 4.432 1.00 90.22 C
|
||||
ATOM 745 CD2 LEU A 92 1.211 -2.006 6.699 1.00 90.22 C
|
||||
ATOM 746 N LYS A 93 6.355 -1.270 8.049 1.00 89.96 N
|
||||
ATOM 747 CA LYS A 93 7.611 -1.791 8.582 1.00 89.96 C
|
||||
ATOM 748 C LYS A 93 7.703 -1.568 10.089 1.00 89.96 C
|
||||
ATOM 749 CB LYS A 93 8.803 -1.137 7.881 1.00 89.96 C
|
||||
ATOM 750 O LYS A 93 8.149 -2.450 10.826 1.00 89.96 O
|
||||
ATOM 751 CG LYS A 93 9.068 -1.672 6.481 1.00 89.96 C
|
||||
ATOM 752 CD LYS A 93 10.333 -1.070 5.884 1.00 89.96 C
|
||||
ATOM 753 CE LYS A 93 10.606 -1.615 4.488 1.00 89.96 C
|
||||
ATOM 754 NZ LYS A 93 11.842 -1.022 3.894 1.00 89.96 N
|
||||
ATOM 755 N GLU A 94 7.401 -0.356 10.430 1.00 91.25 N
|
||||
ATOM 756 CA GLU A 94 7.387 -0.032 11.853 1.00 91.25 C
|
||||
ATOM 757 C GLU A 94 6.457 -0.965 12.623 1.00 91.25 C
|
||||
ATOM 758 CB GLU A 94 6.968 1.425 12.069 1.00 91.25 C
|
||||
ATOM 759 O GLU A 94 6.797 -1.429 13.713 1.00 91.25 O
|
||||
ATOM 760 CG GLU A 94 8.067 2.432 11.765 1.00 91.25 C
|
||||
ATOM 761 CD GLU A 94 7.783 3.817 12.324 1.00 91.25 C
|
||||
ATOM 762 OE1 GLU A 94 8.221 4.116 13.459 1.00 91.25 O
|
||||
ATOM 763 OE2 GLU A 94 7.116 4.610 11.623 1.00 91.25 O
|
||||
ATOM 764 N ARG A 95 5.355 -1.225 12.075 1.00 85.31 N
|
||||
ATOM 765 CA ARG A 95 4.398 -2.127 12.709 1.00 85.31 C
|
||||
ATOM 766 C ARG A 95 4.938 -3.553 12.756 1.00 85.31 C
|
||||
ATOM 767 CB ARG A 95 3.059 -2.098 11.969 1.00 85.31 C
|
||||
ATOM 768 O ARG A 95 4.712 -4.276 13.728 1.00 85.31 O
|
||||
ATOM 769 CG ARG A 95 2.304 -0.786 12.115 1.00 85.31 C
|
||||
ATOM 770 CD ARG A 95 1.648 -0.662 13.483 1.00 85.31 C
|
||||
ATOM 771 NE ARG A 95 0.780 0.509 13.560 1.00 85.31 N
|
||||
ATOM 772 NH1 ARG A 95 -1.032 -0.634 14.424 1.00 85.31 N
|
||||
ATOM 773 NH2 ARG A 95 -1.174 1.620 14.033 1.00 85.31 N
|
||||
ATOM 774 CZ ARG A 95 -0.474 0.496 14.006 1.00 85.31 C
|
||||
ATOM 775 N LEU A 96 5.431 -3.928 11.737 1.00 87.53 N
|
||||
ATOM 776 CA LEU A 96 6.039 -5.251 11.646 1.00 87.53 C
|
||||
ATOM 777 C LEU A 96 7.142 -5.415 12.687 1.00 87.53 C
|
||||
ATOM 778 CB LEU A 96 6.605 -5.486 10.244 1.00 87.53 C
|
||||
ATOM 779 O LEU A 96 7.260 -6.471 13.311 1.00 87.53 O
|
||||
ATOM 780 CG LEU A 96 7.106 -6.899 9.943 1.00 87.53 C
|
||||
ATOM 781 CD1 LEU A 96 5.938 -7.879 9.903 1.00 87.53 C
|
||||
ATOM 782 CD2 LEU A 96 7.877 -6.925 8.627 1.00 87.53 C
|
||||
ATOM 783 N LYS A 97 8.035 -4.458 12.855 1.00 87.68 N
|
||||
ATOM 784 CA LYS A 97 9.111 -4.470 13.842 1.00 87.68 C
|
||||
ATOM 785 C LYS A 97 8.555 -4.573 15.260 1.00 87.68 C
|
||||
ATOM 786 CB LYS A 97 9.976 -3.216 13.709 1.00 87.68 C
|
||||
ATOM 787 O LYS A 97 9.131 -5.256 16.109 1.00 87.68 O
|
||||
ATOM 788 CG LYS A 97 10.961 -3.264 12.550 1.00 87.68 C
|
||||
ATOM 789 CD LYS A 97 11.875 -2.045 12.542 1.00 87.68 C
|
||||
ATOM 790 CE LYS A 97 12.840 -2.076 11.365 1.00 87.68 C
|
||||
ATOM 791 NZ LYS A 97 13.742 -0.886 11.356 1.00 87.68 N
|
||||
ATOM 792 N GLU A 98 7.395 -3.949 15.535 1.00 85.16 N
|
||||
ATOM 793 CA GLU A 98 6.766 -3.985 16.852 1.00 85.16 C
|
||||
ATOM 794 C GLU A 98 6.185 -5.364 17.149 1.00 85.16 C
|
||||
ATOM 795 CB GLU A 98 5.671 -2.920 16.954 1.00 85.16 C
|
||||
ATOM 796 O GLU A 98 6.174 -5.804 18.300 1.00 85.16 O
|
||||
ATOM 797 CG GLU A 98 6.201 -1.494 16.993 1.00 85.16 C
|
||||
ATOM 798 CD GLU A 98 5.199 -0.496 17.550 1.00 85.16 C
|
||||
ATOM 799 OE1 GLU A 98 5.207 -0.247 18.777 1.00 85.16 O
|
||||
ATOM 800 OE2 GLU A 98 4.397 0.041 16.753 1.00 85.16 O
|
||||
ATOM 801 N LYS A 99 5.862 -6.201 16.145 1.00 71.59 N
|
||||
ATOM 802 CA LYS A 99 5.236 -7.516 16.249 1.00 71.59 C
|
||||
ATOM 803 C LYS A 99 6.285 -8.620 16.338 1.00 71.59 C
|
||||
ATOM 804 CB LYS A 99 4.311 -7.766 15.057 1.00 71.59 C
|
||||
ATOM 805 O LYS A 99 6.031 -9.682 16.910 1.00 71.59 O
|
||||
ATOM 806 CG LYS A 99 2.886 -7.276 15.266 1.00 71.59 C
|
||||
ATOM 807 CD LYS A 99 1.932 -7.876 14.240 1.00 71.59 C
|
||||
ATOM 808 CE LYS A 99 0.499 -7.420 14.474 1.00 71.59 C
|
||||
ATOM 809 NZ LYS A 99 -0.480 -8.264 13.726 1.00 71.59 N
|
||||
ATOM 810 N GLU A 100 7.534 -8.377 16.016 1.00 69.93 N
|
||||
ATOM 811 CA GLU A 100 8.637 -9.325 16.142 1.00 69.93 C
|
||||
ATOM 812 C GLU A 100 9.233 -9.296 17.546 1.00 69.93 C
|
||||
ATOM 813 CB GLU A 100 9.723 -9.028 15.104 1.00 69.93 C
|
||||
ATOM 814 O GLU A 100 9.551 -10.343 18.113 1.00 69.93 O
|
||||
ATOM 815 CG GLU A 100 9.683 -9.948 13.892 1.00 69.93 C
|
||||
ATOM 816 CD GLU A 100 10.905 -9.814 12.998 1.00 69.93 C
|
||||
ATOM 817 OE1 GLU A 100 11.866 -10.601 13.160 1.00 69.93 O
|
||||
ATOM 818 OE2 GLU A 100 10.903 -8.915 12.128 1.00 69.93 O
|
||||
ENDMDL
|
||||
END
|
||||
1867
test/dssp-extension.dic
Normal file
1867
test/dssp-extension.dic
Normal file
File diff suppressed because it is too large
Load Diff
@@ -26,19 +26,17 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::file operator""_cf(const char *text, size_t length)
|
||||
cif::file operator""_cf(const char *text, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -55,8 +53,8 @@ TEST_CASE("create_nonpoly_1")
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
cif::file file;
|
||||
file.load_dictionary("mmcif_pdbx.dic");
|
||||
file.emplace("TEST"); // create a datablock
|
||||
auto &&[dbi, ignore] = file.emplace("TEST"); // create a datablock
|
||||
dbi->set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
cif::mm::structure structure(file);
|
||||
|
||||
@@ -84,7 +82,7 @@ _atom_site.pdbx_formal_charge
|
||||
# that's enough to test with
|
||||
)"_cf;
|
||||
|
||||
atoms.load_dictionary("mmcif_pdbx.dic");
|
||||
atoms.front().set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
auto &hem_data = atoms["HEM"];
|
||||
auto &atom_site = hem_data["atom_site"];
|
||||
@@ -161,14 +159,14 @@ _struct_asym.details ?
|
||||
_atom_type.symbol C
|
||||
)"_cf;
|
||||
|
||||
expected.load_dictionary("mmcif_pdbx.dic");
|
||||
expected.front().set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
if (not(expected.front() == structure.get_datablock()))
|
||||
{
|
||||
REQUIRE(false);
|
||||
std::cout << expected.front() << '\n'
|
||||
std::cerr << expected.front() << '\n'
|
||||
<< '\n'
|
||||
<< structure.get_datablock() << '\n';
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,8 +177,8 @@ TEST_CASE("create_nonpoly_2")
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
cif::file file;
|
||||
file.load_dictionary("mmcif_pdbx.dic");
|
||||
file.emplace("TEST"); // create a datablock
|
||||
auto &&[dbi, ignore] = file.emplace("TEST"); // create a datablock
|
||||
dbi->set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
cif::mm::structure structure(file);
|
||||
|
||||
@@ -272,7 +270,7 @@ _struct_asym.details ?
|
||||
_atom_type.symbol C
|
||||
)"_cf;
|
||||
|
||||
expected.load_dictionary("mmcif_pdbx.dic");
|
||||
expected.front().set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
REQUIRE(expected.front() == structure.get_datablock());
|
||||
|
||||
@@ -356,7 +354,7 @@ _struct_asym.details ?
|
||||
#
|
||||
)"_cf;
|
||||
|
||||
data.load_dictionary("mmcif_pdbx.dic");
|
||||
data.front().set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
cif::mm::structure s(data);
|
||||
|
||||
@@ -433,3 +431,169 @@ TEST_CASE("remove_residue_1")
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Tests for structure_open_options
|
||||
|
||||
TEST_CASE("options_1")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
const std::filesystem::path example(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
cif::file file(example.string());
|
||||
|
||||
auto &cf = cif::compound_factory::instance();
|
||||
|
||||
SECTION("skip_water")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .skip_water = true });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK_FALSE(a.is_water());
|
||||
}
|
||||
|
||||
SECTION("skip_hetatom")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .skip_hetatom = true });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK((a.is_water() or cf.is_peptide(a.get_label_comp_id()) or cf.is_base(a.get_label_comp_id())));
|
||||
}
|
||||
|
||||
SECTION("selected_asyms")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .asyms = { "A" } });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK(a.get_label_asym_id() == "A");
|
||||
}
|
||||
|
||||
SECTION("min-b-factor")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .min_b_factor = 20.f });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK(a.get_property_float("B_iso_or_equiv") >= 20.f);
|
||||
}
|
||||
|
||||
SECTION("max-b-factor")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .max_b_factor = 20.f });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK(a.get_property_float("B_iso_or_equiv") <= 20.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("options_2")
|
||||
{
|
||||
|
||||
auto data = R"(
|
||||
data_TEST
|
||||
#
|
||||
_pdbx_nonpoly_scheme.asym_id A
|
||||
_pdbx_nonpoly_scheme.ndb_seq_num 1
|
||||
_pdbx_nonpoly_scheme.entity_id 1
|
||||
_pdbx_nonpoly_scheme.mon_id HEM
|
||||
_pdbx_nonpoly_scheme.pdb_seq_num 1
|
||||
_pdbx_nonpoly_scheme.auth_seq_num 1
|
||||
_pdbx_nonpoly_scheme.pdb_mon_id HEM
|
||||
_pdbx_nonpoly_scheme.auth_mon_id HEM
|
||||
_pdbx_nonpoly_scheme.pdb_strand_id A
|
||||
_pdbx_nonpoly_scheme.pdb_ins_code .
|
||||
#
|
||||
loop_
|
||||
_atom_site.id
|
||||
_atom_site.auth_asym_id
|
||||
_atom_site.label_alt_id
|
||||
_atom_site.label_asym_id
|
||||
_atom_site.label_atom_id
|
||||
_atom_site.label_comp_id
|
||||
_atom_site.label_entity_id
|
||||
_atom_site.label_seq_id
|
||||
_atom_site.type_symbol
|
||||
_atom_site.group_PDB
|
||||
_atom_site.pdbx_PDB_ins_code
|
||||
_atom_site.Cartn_x
|
||||
_atom_site.Cartn_y
|
||||
_atom_site.Cartn_z
|
||||
_atom_site.occupancy
|
||||
_atom_site.B_iso_or_equiv
|
||||
_atom_site.pdbx_formal_charge
|
||||
_atom_site.auth_seq_id
|
||||
_atom_site.auth_comp_id
|
||||
_atom_site.auth_atom_id
|
||||
_atom_site.pdbx_PDB_model_num
|
||||
1 A A A CHA HEM 1 . C HETATM ? -5.248 39.769 -0.250 0.75 7.67 ? 1 HEM CHA 1
|
||||
3 A A A CHB HEM 1 . C HETATM ? -3.774 36.790 3.280 0.75 7.05 ? 1 HEM CHB 1
|
||||
2 A A A CHC HEM 1 . C HETATM ? -2.879 33.328 0.013 0.75 7.69 ? 1 HEM CHC 1
|
||||
4 A A A CHD HEM 1 . C HETATM ? -4.342 36.262 -3.536 0.75 8.00 ? 1 HEM CHD 1
|
||||
5 A B A CHA HEM 1 . C HETATM ? -5.248 39.769 -0.250 0.25 7.67 ? 1 HEM CHA 1
|
||||
6 A B A CHB HEM 1 . C HETATM ? -3.774 36.790 3.280 0.25 7.05 ? 1 HEM CHB 1
|
||||
7 A B A CHC HEM 1 . C HETATM ? -2.879 33.328 0.013 0.25 7.69 ? 1 HEM CHC 1
|
||||
8 A B A CHD HEM 1 . C HETATM ? -4.342 36.262 -3.536 0.25 8.00 ? 1 HEM CHD 1
|
||||
#
|
||||
_chem_comp.id HEM
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_chem_comp.formula 'C34 H32 Fe N4 O4'
|
||||
_chem_comp.formula_weight 616.487000
|
||||
#
|
||||
_pdbx_entity_nonpoly.entity_id 1
|
||||
_pdbx_entity_nonpoly.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_pdbx_entity_nonpoly.comp_id HEM
|
||||
#
|
||||
_entity.id 1
|
||||
_entity.type non-polymer
|
||||
_entity.pdbx_description 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_entity.formula_weight 616.487000
|
||||
#
|
||||
_struct_asym.id A
|
||||
_struct_asym.entity_id 1
|
||||
_struct_asym.pdbx_blank_PDB_chainid_flag N
|
||||
_struct_asym.pdbx_modified N
|
||||
_struct_asym.details ?
|
||||
#
|
||||
)"_cf;
|
||||
|
||||
data.front().set_validator(&cif::validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
SECTION("max")
|
||||
{
|
||||
cif::mm::structure s(data, 1, {
|
||||
.occupancy_mode = cif::mm::occupancy_policy::MAX
|
||||
});
|
||||
|
||||
REQUIRE(s.atoms().size() == 4);
|
||||
CHECK(s.atoms().front().get_label_alt_id() == "A");
|
||||
}
|
||||
|
||||
SECTION("min")
|
||||
{
|
||||
cif::mm::structure s(data, 1, {
|
||||
.occupancy_mode = cif::mm::occupancy_policy::MIN
|
||||
});
|
||||
|
||||
REQUIRE(s.atoms().size() == 4);
|
||||
CHECK(s.atoms().front().get_label_alt_id() == "B");
|
||||
}
|
||||
|
||||
SECTION("unoccupied")
|
||||
{
|
||||
cif::mm::structure s(data, 1, {
|
||||
.occupancy_mode = cif::mm::occupancy_policy::UNOCCUPIED
|
||||
});
|
||||
|
||||
CHECK(s.atoms().empty());
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2025 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
|
||||
@@ -24,37 +24,31 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
TEST_CASE("fmt_1")
|
||||
TEST_CASE("q-1")
|
||||
{
|
||||
std::ostringstream os;
|
||||
using namespace cif::literals;
|
||||
|
||||
std::string world("world");
|
||||
os << cif::format("Hello, %-10.10s, the magic number is %d and pi is %g", world, 42, cif::kPI);
|
||||
REQUIRE(os.str() == "Hello, world , the magic number is 42 and pi is 3.14159");
|
||||
cif::compound_factory::instance().push_dictionary(gTestDir / "REA.cif");
|
||||
|
||||
cif::file a = cif::pdb::read(gTestDir / "pdb1cbs.ent.gz");
|
||||
auto &pdbx_poly_seq_scheme = a.front()["pdbx_poly_seq_scheme"];
|
||||
REQUIRE_FALSE(pdbx_poly_seq_scheme.empty());
|
||||
|
||||
SECTION("s-11")
|
||||
{
|
||||
CHECK(pdbx_poly_seq_scheme.count("asym_id"_key == "A") == 137);
|
||||
|
||||
CHECK(pdbx_poly_seq_scheme.count("asym_id"_key == "A" and "entity_id"_key == 1 and "seq_id"_key == 1 and "mon_id"_key == "PRO") == 1);
|
||||
|
||||
CHECK(pdbx_poly_seq_scheme.count("asym_id"_key == "A" and "entity_id"_key == 1 and "seq_id"_key == 1 and "mon_id"_key == "PRO" and "hetero"_key == false) == 1);
|
||||
}
|
||||
|
||||
|
||||
REQUIRE(cif::format("Hello, %-10.10s, the magic number is %d and pi is %g", world, 42, cif::kPI).str() ==
|
||||
"Hello, world , the magic number is 42 and pi is 3.14159");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("clr_1")
|
||||
{
|
||||
using namespace cif::colour;
|
||||
|
||||
std::cout << "Hello, " << cif::coloured("world!", white, red, cif::colour::regular) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", white, red, bold) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", black, red) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", white, green) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", white, blue) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", blue, white) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", red, white, bold) << '\n';
|
||||
}
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
@@ -56,7 +54,7 @@ TEST_CASE("reconstruct")
|
||||
|
||||
std::error_code ec;
|
||||
CHECK_FALSE(cif::pdb::is_valid_pdbx_file(f, ec));
|
||||
CHECK(ec != std::errc{});
|
||||
CHECK((bool)ec);
|
||||
|
||||
CHECK(cif::pdb::reconstruct_pdbx(f));
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
@@ -1,6 +1,32 @@
|
||||
#include "cif++/utilities.hpp"
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2024 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
@@ -26,19 +26,17 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::file operator""_cf(const char* text, size_t length)
|
||||
cif::file operator""_cf(const char* text, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char* text, size_t length)
|
||||
membuf(char* text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -133,7 +131,7 @@ TEST_CASE("sugar_name_1")
|
||||
// auto &db = s.get_datablock();
|
||||
// auto &as = db["atom_site"];
|
||||
|
||||
// for (size_t i = 0; i < 2; ++i)
|
||||
// for (std::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);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#define CATCH_CONFIG_RUNNER 1
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
std::filesystem::path gTestDir = std::filesystem::current_path();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -12,7 +11,13 @@ int main(int argc, char *argv[])
|
||||
Catch::Session session; // There must be exactly one instance
|
||||
|
||||
// Build a new parser on top of Catch2's
|
||||
#if CATCH22
|
||||
using namespace Catch::clara;
|
||||
#else
|
||||
// Build a new parser on top of Catch2's
|
||||
using namespace Catch::Clara;
|
||||
#endif
|
||||
|
||||
auto cli = session.cli() // Get Catch2's command line parser
|
||||
| Opt(gTestDir, "data-dir") // bind variable to a new option, with a hint string
|
||||
["-D"]["--data-dir"] // the option names it will respond to
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2024 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
|
||||
|
||||
#if CATCH22
|
||||
#include <catch2/catch.hpp>
|
||||
#else
|
||||
#include <catch2/catch_all.hpp>
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
extern std::filesystem::path gTestDir;
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++.hpp>
|
||||
@@ -36,11 +34,11 @@
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::file operator""_cf(const char *text, size_t length)
|
||||
cif::file operator""_cf(const char *text, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -92,7 +90,7 @@ TEST_CASE("t1")
|
||||
|
||||
const auto &&[angle, axis] = cif::quaternion_to_angle_axis(q2);
|
||||
|
||||
REQUIRE_THAT(std::fmod(360 + angle, 360), Catch::Matchers::WithinRel(std::fmod(360 - angle0, 360), 0.01));
|
||||
CHECK_THAT(std::fmod(360 + angle, 360), Catch::Matchers::WithinRel(std::fmod(360 - angle0, 360), 0.01));
|
||||
|
||||
for (auto &p : p1)
|
||||
p.rotate(q2);
|
||||
@@ -118,7 +116,7 @@ TEST_CASE("t2")
|
||||
|
||||
auto &&[angle, axis] = cif::quaternion_to_angle_axis(q);
|
||||
|
||||
REQUIRE_THAT(angle, Catch::Matchers::WithinRel(45.f, 0.01f));
|
||||
CHECK_THAT(angle, Catch::Matchers::WithinRel(45.f, 0.01f));
|
||||
}
|
||||
|
||||
TEST_CASE("t3")
|
||||
@@ -142,7 +140,7 @@ TEST_CASE("t3")
|
||||
|
||||
double a = cif::angle(v, p[0], p[1]);
|
||||
|
||||
REQUIRE_THAT(a, Catch::Matchers::WithinRel(45.f, 0.01f));
|
||||
CHECK_THAT(a, Catch::Matchers::WithinRel(45.f, 0.01f));
|
||||
}
|
||||
|
||||
TEST_CASE("dh_q_0")
|
||||
@@ -150,39 +148,37 @@ TEST_CASE("dh_q_0")
|
||||
cif::point axis(1, 0, 0);
|
||||
|
||||
cif::point p(1, 1, 0);
|
||||
|
||||
cif::point t[3] =
|
||||
{
|
||||
|
||||
cif::point t[3] = {
|
||||
{ 0, 1, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 1, 0, 0 }
|
||||
};
|
||||
|
||||
auto a = cif::dihedral_angle(t[0], t[1], t[2], p);
|
||||
REQUIRE_THAT(a, Catch::Matchers::WithinRel(0, 0.01f));
|
||||
CHECK_THAT(a, Catch::Matchers::WithinRel(0.f, 0.01f));
|
||||
|
||||
auto q = cif::construct_from_angle_axis(90, axis);
|
||||
|
||||
p.rotate(q);
|
||||
|
||||
REQUIRE_THAT(p.m_x, Catch::Matchers::WithinRel(1, 0.01f));
|
||||
REQUIRE_THAT(p.m_y, Catch::Matchers::WithinRel(0, 0.01f));
|
||||
REQUIRE_THAT(p.m_z, Catch::Matchers::WithinRel(1, 0.01f));
|
||||
REQUIRE(std::abs(p.m_x - 1.f) < 0.01f);
|
||||
REQUIRE(std::abs(p.m_y - 0.f) < 0.01f);
|
||||
REQUIRE(std::abs(p.m_z - 1.f) < 0.01f);
|
||||
|
||||
a = cif::dihedral_angle(t[0], t[1], t[2], p);
|
||||
REQUIRE_THAT(a, Catch::Matchers::WithinRel(90, 0.01f));
|
||||
REQUIRE(std::abs(a - 90.f) < 0.01f);
|
||||
|
||||
q = cif::construct_from_angle_axis(-90, axis);
|
||||
|
||||
p.rotate(q);
|
||||
|
||||
REQUIRE_THAT(p.m_x, Catch::Matchers::WithinRel(1, 0.01f));
|
||||
REQUIRE_THAT(p.m_y, Catch::Matchers::WithinRel(1, 0.01f));
|
||||
REQUIRE_THAT(p.m_z, Catch::Matchers::WithinRel(0, 0.01f));
|
||||
REQUIRE(std::abs(p.m_x - 1.f) < 0.01f);
|
||||
REQUIRE(std::abs(p.m_y - 1.f) < 0.01f);
|
||||
REQUIRE(std::abs(p.m_z - 0.f) < 0.01f);
|
||||
|
||||
a = cif::dihedral_angle(t[0], t[1], t[2], p);
|
||||
REQUIRE_THAT(a, Catch::Matchers::WithinRel(0, 0.01f));
|
||||
|
||||
REQUIRE(std::abs(a - 0.f) < 0.01f);
|
||||
}
|
||||
|
||||
TEST_CASE("dh_q_1")
|
||||
@@ -224,78 +220,119 @@ TEST_CASE("dh_q_1")
|
||||
pts[3].rotate(q, pts[2]);
|
||||
|
||||
auto dh = cif::dihedral_angle(pts[0], pts[1], pts[2], pts[3]);
|
||||
REQUIRE_THAT(dh, Catch::Matchers::WithinRel(angle, 0.1f));
|
||||
CHECK_THAT(dh, Catch::Matchers::WithinRel(angle, 0.1f));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("m2q_0, *utf::tolerance(0.001f)")
|
||||
// TEST_CASE("m2q_0")
|
||||
// {
|
||||
// for (std::size_t i = 0; i < cif::kSymopNrTableSize; ++i)
|
||||
// {
|
||||
// auto d = cif::kSymopNrTable[i].symop().data();
|
||||
|
||||
// cif::matrix3x3<float> rot;
|
||||
// float Qxx = rot(0, 0) = d[0];
|
||||
// float Qxy = rot(0, 1) = d[1];
|
||||
// float Qxz = rot(0, 2) = d[2];
|
||||
// float Qyx = rot(1, 0) = d[3];
|
||||
// float Qyy = rot(1, 1) = d[4];
|
||||
// float Qyz = rot(1, 2) = d[5];
|
||||
// float Qzx = rot(2, 0) = d[6];
|
||||
// float Qzy = rot(2, 1) = d[7];
|
||||
// float Qzz = rot(2, 2) = d[8];
|
||||
|
||||
// Eigen::Matrix4f em;
|
||||
|
||||
// em << Qxx - Qyy - Qzz, Qyx + Qxy, Qzx + Qxz, Qzy - Qyz,
|
||||
// Qyx + Qxy, Qyy - Qxx - Qzz, Qzy + Qyz, Qxz - Qzx,
|
||||
// Qzx + Qxz, Qzy + Qyz, Qzz - Qxx - Qyy, Qyx - Qxy,
|
||||
// Qzy - Qyz, Qxz - Qzx, Qyx - Qxy, Qxx + Qyy + Qzz;
|
||||
|
||||
// Eigen::EigenSolver<Eigen::Matrix4f> es(em / 3);
|
||||
|
||||
// auto ev = es.eigenvalues();
|
||||
|
||||
// std::size_t bestJ = 0;
|
||||
// float bestEV = -1;
|
||||
|
||||
// for (std::size_t j = 0; j < 4; ++j)
|
||||
// {
|
||||
// if (bestEV < ev[j].real())
|
||||
// {
|
||||
// bestEV = ev[j].real();
|
||||
// bestJ = j;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (std::abs(bestEV - 1) > 0.01)
|
||||
// continue; // not a rotation matrix
|
||||
|
||||
// auto col = es.eigenvectors().col(bestJ);
|
||||
|
||||
// auto q = normalize(cif::quaternion{
|
||||
// static_cast<float>(col(3).real()),
|
||||
// static_cast<float>(col(0).real()),
|
||||
// static_cast<float>(col(1).real()),
|
||||
// static_cast<float>(col(2).real()) });
|
||||
|
||||
// cif::point p1{ 1, 1, 1 };
|
||||
// cif::point p2 = p1;
|
||||
// p2.rotate(q);
|
||||
|
||||
// cif::point p3 = rot * p1;
|
||||
|
||||
// CHECK_THAT(p2.m_x, Catch::Matchers::WithinRel(p3.m_x, 0.01f));
|
||||
// CHECK_THAT(p2.m_y, Catch::Matchers::WithinRel(p3.m_y, 0.01f));
|
||||
// CHECK_THAT(p2.m_z, Catch::Matchers::WithinRel(p3.m_z, 0.01f));
|
||||
// }
|
||||
// }
|
||||
|
||||
TEST_CASE("m2q_0a")
|
||||
{
|
||||
for (size_t i = 0; i < cif::kSymopNrTableSize; ++i)
|
||||
for (std::size_t i = 0; i < cif::kSymopNrTableSize; ++i)
|
||||
{
|
||||
auto d = cif::kSymopNrTable[i].symop().data();
|
||||
|
||||
cif::matrix3x3<float> rot;
|
||||
float Qxx = rot(0, 0) = d[0];
|
||||
float Qxy = rot(0, 1) = d[1];
|
||||
float Qxz = rot(0, 2) = d[2];
|
||||
float Qyx = rot(1, 0) = d[3];
|
||||
float Qyy = rot(1, 1) = d[4];
|
||||
float Qyz = rot(1, 2) = d[5];
|
||||
float Qzx = rot(2, 0) = d[6];
|
||||
float Qzy = rot(2, 1) = d[7];
|
||||
float Qzz = rot(2, 2) = d[8];
|
||||
Eigen::Matrix3f rot;
|
||||
rot << d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8];
|
||||
|
||||
Eigen::Matrix4f em;
|
||||
// check to see if this matrix contains a true rotation
|
||||
if (rot * rot.transpose() != Eigen::Matrix3f::Identity() or rot.determinant() != 1)
|
||||
continue;
|
||||
|
||||
em << Qxx - Qyy - Qzz, Qyx + Qxy, Qzx + Qxz, Qzy - Qyz,
|
||||
Qyx + Qxy, Qyy - Qxx - Qzz, Qzy + Qyz, Qxz - Qzx,
|
||||
Qzx + Qxz, Qzy + Qyz, Qzz - Qxx - Qyy, Qyx - Qxy,
|
||||
Qzy - Qyz, Qxz - Qzx, Qyx - Qxy, Qxx + Qyy + Qzz;
|
||||
Eigen::Quaternionf qe(rot);
|
||||
|
||||
Eigen::EigenSolver<Eigen::Matrix4f> es(em / 3);
|
||||
auto q = normalize(cif::quaternion{ qe.w(), qe.x(), qe.y(), qe.z() });
|
||||
|
||||
auto ev = es.eigenvalues();
|
||||
|
||||
size_t bestJ = 0;
|
||||
float bestEV = -1;
|
||||
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
{
|
||||
if (bestEV < ev[j].real())
|
||||
{
|
||||
bestEV = ev[j].real();
|
||||
bestJ = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::abs(bestEV - 1) > 0.01)
|
||||
continue; // not a rotation matrix
|
||||
|
||||
auto col = es.eigenvectors().col(bestJ);
|
||||
|
||||
auto q = normalize(cif::quaternion{
|
||||
static_cast<float>(col(3).real()),
|
||||
static_cast<float>(col(0).real()),
|
||||
static_cast<float>(col(1).real()),
|
||||
static_cast<float>(col(2).real()) });
|
||||
|
||||
cif::point p1{ 1, 1, 1 };
|
||||
cif::point p2 = p1;
|
||||
p2.rotate(q);
|
||||
|
||||
cif::point p3 = rot * p1;
|
||||
cif::matrix3x3<float> rot_c({
|
||||
static_cast<float>(d[0]),
|
||||
static_cast<float>(d[1]),
|
||||
static_cast<float>(d[2]),
|
||||
static_cast<float>(d[3]),
|
||||
static_cast<float>(d[4]),
|
||||
static_cast<float>(d[5]),
|
||||
static_cast<float>(d[6]),
|
||||
static_cast<float>(d[7]),
|
||||
static_cast<float>(d[8])
|
||||
});
|
||||
|
||||
REQUIRE_THAT(p2.m_x, Catch::Matchers::WithinRel(p3.m_x, 0.01f));
|
||||
REQUIRE_THAT(p2.m_y, Catch::Matchers::WithinRel(p3.m_y, 0.01f));
|
||||
REQUIRE_THAT(p2.m_z, Catch::Matchers::WithinRel(p3.m_z, 0.01f));
|
||||
cif::point p3 = rot_c * p1;
|
||||
|
||||
CHECK_THAT(p2.m_x, Catch::Matchers::WithinRel(p3.m_x, 0.01f));
|
||||
CHECK_THAT(p2.m_y, Catch::Matchers::WithinRel(p3.m_y, 0.01f));
|
||||
CHECK_THAT(p2.m_z, Catch::Matchers::WithinRel(p3.m_z, 0.01f));
|
||||
}
|
||||
}
|
||||
|
||||
// "TEST_CASE(m2q_1, *utf::tolerance(0.001f)")
|
||||
// "TEST_CASE(m2q_1")
|
||||
// {
|
||||
// for (size_t i = 0; i < cif::kSymopNrTableSize; ++i)
|
||||
// for (std::size_t i = 0; i < cif::kSymopNrTableSize; ++i)
|
||||
// {
|
||||
// auto d = cif::kSymopNrTable[i].symop().data();
|
||||
|
||||
@@ -319,10 +356,10 @@ TEST_CASE("m2q_0, *utf::tolerance(0.001f)")
|
||||
|
||||
// auto &&[ev, em] = cif::eigen(m * (1/3.0f), false);
|
||||
|
||||
// size_t bestJ = 0;
|
||||
// std::size_t bestJ = 0;
|
||||
// float bestEV = -1;
|
||||
|
||||
// for (size_t j = 0; j < 4; ++j)
|
||||
// for (std::size_t j = 0; j < 4; ++j)
|
||||
// {
|
||||
// if (bestEV < ev[j])
|
||||
// {
|
||||
@@ -339,7 +376,7 @@ TEST_CASE("m2q_0, *utf::tolerance(0.001f)")
|
||||
// static_cast<float>(em(bestJ, 0)),
|
||||
// static_cast<float>(em(bestJ, 1)),
|
||||
// static_cast<float>(em(bestJ, 2)) });
|
||||
|
||||
|
||||
// cif::point p1{ 1, 1, 1 };
|
||||
// cif::point p2 = p1;
|
||||
// p2.rotate(q);
|
||||
@@ -362,15 +399,15 @@ TEST_CASE("symm_1")
|
||||
|
||||
cif::point f = fractional(p, c);
|
||||
|
||||
REQUIRE_THAT(f.m_x, Catch::Matchers::WithinRel(0.1f, 0.01f));
|
||||
REQUIRE_THAT(f.m_y, Catch::Matchers::WithinRel(0.1f, 0.01f));
|
||||
REQUIRE_THAT(f.m_z, Catch::Matchers::WithinRel(0.1f, 0.01f));
|
||||
CHECK_THAT(f.m_x, Catch::Matchers::WithinRel(0.1f, 0.01f));
|
||||
CHECK_THAT(f.m_y, Catch::Matchers::WithinRel(0.1f, 0.01f));
|
||||
CHECK_THAT(f.m_z, Catch::Matchers::WithinRel(0.1f, 0.01f));
|
||||
|
||||
cif::point o = orthogonal(f, c);
|
||||
|
||||
REQUIRE_THAT(o.m_x, Catch::Matchers::WithinRel(1.f, 0.01f));
|
||||
REQUIRE_THAT(o.m_y, Catch::Matchers::WithinRel(1.f, 0.01f));
|
||||
REQUIRE_THAT(o.m_z, Catch::Matchers::WithinRel(1.f, 0.01f));
|
||||
CHECK_THAT(o.m_x, Catch::Matchers::WithinRel(1.f, 0.01f));
|
||||
CHECK_THAT(o.m_y, Catch::Matchers::WithinRel(1.f, 0.01f));
|
||||
CHECK_THAT(o.m_z, Catch::Matchers::WithinRel(1.f, 0.01f));
|
||||
}
|
||||
|
||||
TEST_CASE("symm_2")
|
||||
@@ -392,33 +429,33 @@ TEST_CASE("symm_3")
|
||||
REQUIRE(sg.get_name() == "P 21 21 2");
|
||||
}
|
||||
|
||||
TEST_CASE("symm_4, *utf::tolerance(0.1f)")
|
||||
TEST_CASE("symm_4")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
// based on 2b8h
|
||||
auto sg = cif::spacegroup(154); // p 32 2 1
|
||||
auto c = cif::cell(107.516, 107.516, 338.487, 90.00, 90.00, 120.00);
|
||||
|
||||
cif::point a{ -8.688, 79.351, 10.439 }; // O6 NAG A 500
|
||||
cif::point b{ -35.356, 33.693, -3.236 }; // CG2 THR D 400
|
||||
cif::point sb( -6.916, 79.34, 3.236); // 4_565 copy of b
|
||||
|
||||
REQUIRE_THAT(distance(a, sg(a, c, "1_455"_symop)), Catch::Matchers::WithinRel(static_cast<float>(c.get_a()), 0.01f));
|
||||
REQUIRE_THAT(distance(a, sg(a, c, "1_545"_symop)), Catch::Matchers::WithinRel(static_cast<float>(c.get_b()), 0.01f));
|
||||
REQUIRE_THAT(distance(a, sg(a, c, "1_554"_symop)), Catch::Matchers::WithinRel(static_cast<float>(c.get_c()), 0.01f));
|
||||
cif::point a{ -8.688, 79.351, 10.439 }; // O6 NAG A 500
|
||||
cif::point b{ -35.356, 33.693, -3.236 }; // CG2 THR D 400
|
||||
cif::point sb(-6.916, 79.34, 3.236); // 4_565 copy of b
|
||||
|
||||
CHECK_THAT(distance(a, sg(a, c, "1_455"_symop)), Catch::Matchers::WithinRel(static_cast<float>(c.get_a()), 0.01f));
|
||||
CHECK_THAT(distance(a, sg(a, c, "1_545"_symop)), Catch::Matchers::WithinRel(static_cast<float>(c.get_b()), 0.01f));
|
||||
CHECK_THAT(distance(a, sg(a, c, "1_554"_symop)), Catch::Matchers::WithinRel(static_cast<float>(c.get_c()), 0.01f));
|
||||
|
||||
auto sb2 = sg(b, c, "4_565"_symop);
|
||||
REQUIRE_THAT(sb.m_x, Catch::Matchers::WithinRel(sb2.m_x, 0.01f));
|
||||
REQUIRE_THAT(sb.m_y, Catch::Matchers::WithinRel(sb2.m_y, 0.01f));
|
||||
REQUIRE_THAT(sb.m_z, Catch::Matchers::WithinRel(sb2.m_z, 0.01f));
|
||||
CHECK_THAT(sb.m_x, Catch::Matchers::WithinRel(sb2.m_x, 0.01f));
|
||||
CHECK_THAT(sb.m_y, Catch::Matchers::WithinRel(sb2.m_y, 0.01f));
|
||||
CHECK_THAT(sb.m_z, Catch::Matchers::WithinRel(sb2.m_z, 0.01f));
|
||||
|
||||
REQUIRE_THAT(distance(a, sb2), Catch::Matchers::WithinRel(7.42f, 0.01f));
|
||||
CHECK_THAT(distance(a, sb2), Catch::Matchers::WithinRel(7.42f, 0.01f));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("symm_4wvp_1, *utf::tolerance(0.1f)")
|
||||
TEST_CASE("symm_4wvp_1")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
@@ -429,25 +466,24 @@ TEST_CASE("symm_4wvp_1, *utf::tolerance(0.1f)")
|
||||
|
||||
cif::crystal c(db);
|
||||
|
||||
cif::point p{ -78.722, 98.528, 11.994 };
|
||||
cif::point p{ -78.722, 98.528, 11.994 };
|
||||
auto a = s.get_residue("A", 10, "").get_atom_by_atom_id("O");
|
||||
|
||||
auto sp1 = c.symmetry_copy(a.get_location(), "2_565"_symop);
|
||||
REQUIRE_THAT(sp1.m_x, Catch::Matchers::WithinAbs(p.m_x, 0.5f));
|
||||
REQUIRE_THAT(sp1.m_y, Catch::Matchers::WithinAbs(p.m_y, 0.5f));
|
||||
REQUIRE_THAT(sp1.m_z, Catch::Matchers::WithinAbs(p.m_z, 0.5f));
|
||||
CHECK_THAT(sp1.m_x, Catch::Matchers::WithinAbs(p.m_x, 0.5f));
|
||||
CHECK_THAT(sp1.m_y, Catch::Matchers::WithinAbs(p.m_y, 0.5f));
|
||||
CHECK_THAT(sp1.m_z, Catch::Matchers::WithinAbs(p.m_z, 0.5f));
|
||||
|
||||
const auto &[d, sp2, so] = c.closest_symmetry_copy(p, a.get_location());
|
||||
|
||||
REQUIRE(d < 1);
|
||||
|
||||
REQUIRE_THAT(sp2.m_x, Catch::Matchers::WithinAbs(p.m_x, 0.5f));
|
||||
REQUIRE_THAT(sp2.m_y, Catch::Matchers::WithinAbs(p.m_y, 0.5f));
|
||||
REQUIRE_THAT(sp2.m_z, Catch::Matchers::WithinAbs(p.m_z, 0.5f));
|
||||
|
||||
CHECK_THAT(sp2.m_x, Catch::Matchers::WithinAbs(p.m_x, 0.5f));
|
||||
CHECK_THAT(sp2.m_y, Catch::Matchers::WithinAbs(p.m_y, 0.5f));
|
||||
CHECK_THAT(sp2.m_z, Catch::Matchers::WithinAbs(p.m_z, 0.5f));
|
||||
}
|
||||
|
||||
TEST_CASE("symm_2bi3_1, *utf::tolerance(0.1f)")
|
||||
TEST_CASE("symm_2bi3_1")
|
||||
{
|
||||
cif::file f(gTestDir / "2bi3.cif.gz");
|
||||
|
||||
@@ -457,18 +493,15 @@ TEST_CASE("symm_2bi3_1, *utf::tolerance(0.1f)")
|
||||
cif::crystal c(db);
|
||||
|
||||
auto struct_conn = db["struct_conn"];
|
||||
for (const auto &[
|
||||
asym1, seqid1, authseqid1, atomid1, symm1,
|
||||
asym2, seqid2, authseqid2, atomid2, symm2,
|
||||
dist] : struct_conn.find<
|
||||
std::string,int,std::string,std::string,std::string,
|
||||
std::string,int,std::string,std::string,std::string,
|
||||
float>(
|
||||
cif::key("ptnr1_symmetry") != "1_555" or cif::key("ptnr2_symmetry") != "1_555",
|
||||
"ptnr1_label_asym_id", "ptnr1_label_seq_id", "ptnr1_auth_seq_id", "ptnr1_label_atom_id", "ptnr1_symmetry",
|
||||
"ptnr2_label_asym_id", "ptnr2_label_seq_id", "ptnr2_auth_seq_id", "ptnr2_label_atom_id", "ptnr2_symmetry",
|
||||
"pdbx_dist_value"
|
||||
))
|
||||
for (const auto &[asym1, seqid1, authseqid1, atomid1, symm1,
|
||||
asym2, seqid2, authseqid2, atomid2, symm2,
|
||||
dist] : struct_conn.find<std::string, int, std::string, std::string, std::string,
|
||||
std::string, int, std::string, std::string, std::string,
|
||||
float>(
|
||||
cif::key("ptnr1_symmetry") != "1_555" or cif::key("ptnr2_symmetry") != "1_555",
|
||||
"ptnr1_label_asym_id", "ptnr1_label_seq_id", "ptnr1_auth_seq_id", "ptnr1_label_atom_id", "ptnr1_symmetry",
|
||||
"ptnr2_label_asym_id", "ptnr2_label_seq_id", "ptnr2_auth_seq_id", "ptnr2_label_atom_id", "ptnr2_symmetry",
|
||||
"pdbx_dist_value"))
|
||||
{
|
||||
auto &r1 = s.get_residue(asym1, seqid1, authseqid1);
|
||||
auto &r2 = s.get_residue(asym2, seqid2, authseqid2);
|
||||
@@ -479,22 +512,22 @@ TEST_CASE("symm_2bi3_1, *utf::tolerance(0.1f)")
|
||||
auto sa1 = c.symmetry_copy(a1.get_location(), cif::sym_op(symm1));
|
||||
auto sa2 = c.symmetry_copy(a2.get_location(), cif::sym_op(symm2));
|
||||
|
||||
REQUIRE_THAT(cif::distance(sa1, sa2), Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
CHECK_THAT(cif::distance(sa1, sa2), Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
|
||||
auto pa1 = a1.get_location();
|
||||
|
||||
const auto &[d, p, so] = c.closest_symmetry_copy(pa1, a2.get_location());
|
||||
|
||||
REQUIRE_THAT(p.m_x, Catch::Matchers::WithinAbs(sa2.m_x, 0.5f));
|
||||
REQUIRE_THAT(p.m_y, Catch::Matchers::WithinAbs(sa2.m_y, 0.5f));
|
||||
REQUIRE_THAT(p.m_z, Catch::Matchers::WithinAbs(sa2.m_z, 0.5f));
|
||||
CHECK_THAT(p.m_x, Catch::Matchers::WithinAbs(sa2.m_x, 0.5f));
|
||||
CHECK_THAT(p.m_y, Catch::Matchers::WithinAbs(sa2.m_y, 0.5f));
|
||||
CHECK_THAT(p.m_z, Catch::Matchers::WithinAbs(sa2.m_z, 0.5f));
|
||||
|
||||
REQUIRE_THAT(d, Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
CHECK_THAT(d, Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
REQUIRE(so.string() == symm2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("symm_2bi3_1a, *utf::tolerance(0.1f)")
|
||||
TEST_CASE("symm_2bi3_1a")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
@@ -506,43 +539,40 @@ TEST_CASE("symm_2bi3_1a, *utf::tolerance(0.1f)")
|
||||
auto struct_conn = db["struct_conn"];
|
||||
auto atom_site = db["atom_site"];
|
||||
|
||||
for (const auto &[
|
||||
asym1, seqid1, authseqid1, atomid1, symm1,
|
||||
asym2, seqid2, authseqid2, atomid2, symm2,
|
||||
dist] : struct_conn.find<
|
||||
std::string,std::optional<int>,std::string,std::string,std::string,
|
||||
std::string,std::optional<int>,std::string,std::string,std::string,
|
||||
float>(
|
||||
cif::key("ptnr1_symmetry") != "1_555" or cif::key("ptnr2_symmetry") != "1_555",
|
||||
"ptnr1_label_asym_id", "ptnr1_label_seq_id", "ptnr1_auth_seq_id", "ptnr1_label_atom_id", "ptnr1_symmetry",
|
||||
"ptnr2_label_asym_id", "ptnr2_label_seq_id", "ptnr2_auth_seq_id", "ptnr2_label_atom_id", "ptnr2_symmetry",
|
||||
"pdbx_dist_value"
|
||||
))
|
||||
for (const auto &[asym1, seqid1, authseqid1, atomid1, symm1,
|
||||
asym2, seqid2, authseqid2, atomid2, symm2,
|
||||
dist] : struct_conn.find<std::string, std::optional<int>, std::string, std::string, std::string,
|
||||
std::string, std::optional<int>, std::string, std::string, std::string,
|
||||
float>(
|
||||
cif::key("ptnr1_symmetry") != "1_555" or cif::key("ptnr2_symmetry") != "1_555",
|
||||
"ptnr1_label_asym_id", "ptnr1_label_seq_id", "ptnr1_auth_seq_id", "ptnr1_label_atom_id", "ptnr1_symmetry",
|
||||
"ptnr2_label_asym_id", "ptnr2_label_seq_id", "ptnr2_auth_seq_id", "ptnr2_label_atom_id", "ptnr2_symmetry",
|
||||
"pdbx_dist_value"))
|
||||
{
|
||||
cif::point p1 = atom_site.find1<float,float,float>(
|
||||
cif::point p1 = atom_site.find1<float, float, float>(
|
||||
"label_asym_id"_key == asym1 and "label_seq_id"_key == seqid1 and "auth_seq_id"_key == authseqid1 and "label_atom_id"_key == atomid1,
|
||||
"cartn_x", "cartn_y", "cartn_z");
|
||||
cif::point p2 = atom_site.find1<float,float,float>(
|
||||
cif::point p2 = atom_site.find1<float, float, float>(
|
||||
"label_asym_id"_key == asym2 and "label_seq_id"_key == seqid2 and "auth_seq_id"_key == authseqid2 and "label_atom_id"_key == atomid2,
|
||||
"cartn_x", "cartn_y", "cartn_z");
|
||||
|
||||
auto sa1 = c.symmetry_copy(p1, cif::sym_op(symm1));
|
||||
auto sa2 = c.symmetry_copy(p2, cif::sym_op(symm2));
|
||||
|
||||
REQUIRE_THAT(cif::distance(sa1, sa2), Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
CHECK_THAT(cif::distance(sa1, sa2), Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
|
||||
const auto &[d, p, so] = c.closest_symmetry_copy(p1, p2);
|
||||
|
||||
REQUIRE_THAT(p.m_x, Catch::Matchers::WithinAbs(sa2.m_x, 0.5f));
|
||||
REQUIRE_THAT(p.m_y, Catch::Matchers::WithinAbs(sa2.m_y, 0.5f));
|
||||
REQUIRE_THAT(p.m_z, Catch::Matchers::WithinAbs(sa2.m_z, 0.5f));
|
||||
CHECK_THAT(p.m_x, Catch::Matchers::WithinAbs(sa2.m_x, 0.5f));
|
||||
CHECK_THAT(p.m_y, Catch::Matchers::WithinAbs(sa2.m_y, 0.5f));
|
||||
CHECK_THAT(p.m_z, Catch::Matchers::WithinAbs(sa2.m_z, 0.5f));
|
||||
|
||||
REQUIRE_THAT(d, Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
CHECK_THAT(d, Catch::Matchers::WithinAbs(dist, 0.5f));
|
||||
REQUIRE(so.string() == symm2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("symm_3bwh_1, *utf::tolerance(0.1f)")
|
||||
TEST_CASE("symm_3bwh_1")
|
||||
{
|
||||
cif::file f(gTestDir / "3bwh.cif.gz");
|
||||
|
||||
@@ -557,15 +587,15 @@ TEST_CASE("symm_3bwh_1, *utf::tolerance(0.1f)")
|
||||
{
|
||||
if (a1 == a2)
|
||||
continue;
|
||||
|
||||
const auto&[ d, p, so ] = c.closest_symmetry_copy(a1.get_location(), a2.get_location());
|
||||
|
||||
REQUIRE_THAT(d, Catch::Matchers::WithinAbs(distance(a1.get_location(), p), 0.5f));
|
||||
const auto &[d, p, so] = c.closest_symmetry_copy(a1.get_location(), a2.get_location());
|
||||
|
||||
CHECK_THAT(d, Catch::Matchers::WithinAbs(distance(a1.get_location(), p), 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("volume_3bwh_1, *utf::tolerance(0.1f)")
|
||||
TEST_CASE("volume_3bwh_1")
|
||||
{
|
||||
cif::file f(gTestDir / "1juh.cif.gz");
|
||||
|
||||
@@ -573,6 +603,5 @@ TEST_CASE("volume_3bwh_1, *utf::tolerance(0.1f)")
|
||||
|
||||
cif::crystal c(db);
|
||||
|
||||
REQUIRE_THAT(c.get_cell().get_volume(), Catch::Matchers::WithinRel(741009.625f, 0.01f));
|
||||
CHECK_THAT(c.get_cell().get_volume(), Catch::Matchers::WithinRel(741009.625f, 0.01f));
|
||||
}
|
||||
|
||||
|
||||
@@ -26,21 +26,17 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::file operator""_cf(const char *text, size_t length)
|
||||
cif::file operator""_cf(const char *text, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -52,6 +48,47 @@ cif::file operator""_cf(const char *text, size_t length)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("text_1")
|
||||
{
|
||||
CHECK(cif::iequals("TEST", "test"));
|
||||
CHECK(cif::iequals(std::string_view{"TEST"}, std::string_view{"test"}));
|
||||
|
||||
CHECK(cif::icompare("TEST", "test") == 0);
|
||||
CHECK(cif::icompare(std::string_view{"TEST"}, std::string_view{"test"}) == 0);
|
||||
|
||||
CHECK(cif::icompare("TEST1", "test") > 0);
|
||||
CHECK(cif::icompare(std::string_view{"TEST1"}, std::string_view{"test"}) > 0);
|
||||
|
||||
CHECK(cif::icompare("aap", "noot") < 0);
|
||||
CHECK(cif::icompare(std::string_view{"aap"}, std::string_view{"noot"}) < 0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("from_chars_1")
|
||||
{
|
||||
auto f = R"(data_TEST
|
||||
#
|
||||
loop_
|
||||
_test.v
|
||||
616.487
|
||||
616.487000
|
||||
)"_cf;
|
||||
|
||||
auto &db = f.front();
|
||||
auto &c = db.front();
|
||||
|
||||
auto r1 = c.front();
|
||||
REQUIRE(r1.get<double>("v") == 616.487);
|
||||
REQUIRE(r1["v"].compare(616.487) == 0);
|
||||
|
||||
auto r2 = c.back();
|
||||
REQUIRE(r2.get<double>("v") == 616.487);
|
||||
REQUIRE(r2["v"].compare(616.487) == 0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("id_1")
|
||||
{
|
||||
REQUIRE(cif::cif_id_for_number(0) == "A");
|
||||
@@ -103,7 +140,7 @@ TEST_CASE("cc_1")
|
||||
float tv;
|
||||
const auto &[ptr, ec] = cif::from_chars(txt.data(), txt.data() + txt.length(), tv);
|
||||
|
||||
REQUIRE(ec == std::errc());
|
||||
CHECK_FALSE((bool)ec);
|
||||
REQUIRE(tv == val);
|
||||
if (ch != 0)
|
||||
REQUIRE(*ptr == ch);
|
||||
@@ -121,7 +158,7 @@ TEST_CASE("cc_2")
|
||||
char buffer[64];
|
||||
const auto &[ptr, ec] = cif::to_chars(buffer, buffer + sizeof(buffer), val, cif::chars_format::fixed, prec);
|
||||
|
||||
REQUIRE(ec == std::errc());
|
||||
CHECK_FALSE((bool)ec);
|
||||
|
||||
REQUIRE(buffer == test);
|
||||
}
|
||||
@@ -242,7 +279,7 @@ TEST_CASE("r_2")
|
||||
{
|
||||
cif::category c("foo");
|
||||
|
||||
for (size_t i = 1; i < 256; ++i)
|
||||
for (std::size_t i = 1; i < 256; ++i)
|
||||
{
|
||||
c.emplace({ { "id", i },
|
||||
{ "txt", std::string(i, 'x') } });
|
||||
@@ -539,7 +576,7 @@ _test.value
|
||||
REQUIRE(not t.empty());
|
||||
REQUIRE(t.front()["name"].as<std::string>() == "aap");
|
||||
|
||||
auto t2 = test.find(cif::key("value") == 1.2f);
|
||||
auto t2 = test.find(cif::key("value") == 1.2);
|
||||
REQUIRE(not t2.empty());
|
||||
REQUIRE(t2.front()["name"].as<std::string>() == "mies");
|
||||
}
|
||||
@@ -574,6 +611,28 @@ _test.value
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("compare-with-float")
|
||||
{
|
||||
auto f = R"(data_TEST
|
||||
#
|
||||
loop_
|
||||
_test.id
|
||||
_test.value
|
||||
1 1.0
|
||||
2 2.0
|
||||
3 3.0
|
||||
4 ?
|
||||
5 .
|
||||
)"_cf;
|
||||
|
||||
auto &db = f.front();
|
||||
auto &cat = db["test"];
|
||||
|
||||
CHECK(cat.find_first<int>(cif::key("value") == 1.0, "id") == 1);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("sw_1")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
@@ -702,7 +761,7 @@ save__cat_2.desc
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -710,10 +769,9 @@ save__cat_2.desc
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -737,36 +795,60 @@ _cat_2.desc
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
SECTION("one")
|
||||
{
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
|
||||
REQUIRE(cat1.size() == 3);
|
||||
REQUIRE(cat2.size() == 3);
|
||||
REQUIRE(cat1.size() == 3);
|
||||
REQUIRE(cat2.size() == 3);
|
||||
|
||||
cat1.erase(cif::key("id") == 1);
|
||||
cat1.erase(cif::key("id") == 1);
|
||||
|
||||
REQUIRE(cat1.size() == 2);
|
||||
REQUIRE(cat2.size() == 1);
|
||||
REQUIRE(cat1.size() == 2);
|
||||
REQUIRE(cat2.size() == 1);
|
||||
|
||||
// REQUIRE_THROWS_AS(cat2.emplace({
|
||||
// { "id", 4 },
|
||||
// { "parent_id", 4 },
|
||||
// { "desc", "moet fout gaan" }
|
||||
// }), std::exception);
|
||||
// REQUIRE_THROWS_AS(cat2.emplace({
|
||||
// { "id", 4 },
|
||||
// { "parent_id", 4 },
|
||||
// { "desc", "moet fout gaan" }
|
||||
// }), std::exception);
|
||||
|
||||
REQUIRE_THROWS_AS(cat2.emplace({ { "id", "vijf" }, // <- invalid value
|
||||
{ "parent_id", 2 },
|
||||
{ "desc", "moet fout gaan" } }),
|
||||
std::exception);
|
||||
REQUIRE_THROWS_AS(cat2.emplace({ { "id", "vijf" }, // <- invalid value
|
||||
{ "parent_id", 2 },
|
||||
{ "desc", "moet fout gaan" } }),
|
||||
std::exception);
|
||||
}
|
||||
|
||||
// SECTION("two")
|
||||
// {
|
||||
// auto &cat1 = f.front()["cat_1"];
|
||||
// auto &cat2 = f.front()["cat_2"];
|
||||
|
||||
// cat1.update_value(cif::all(), "id", [](std::string_view v) -> std::string
|
||||
// {
|
||||
// int vi;
|
||||
// auto [ec, ptr] = std::from_chars(v.data(), v.data() + v.length(), vi);
|
||||
// return std::to_string(vi + 1);
|
||||
// });
|
||||
|
||||
// REQUIRE(cat1.find1<std::string>(cif::key("id") == 2, "name") == "Aap");
|
||||
// REQUIRE(cat1.find1<std::string>(cif::key("id") == 3, "name") == "Noot");
|
||||
// REQUIRE(cat1.find1<std::string>(cif::key("id") == 4, "name") == "Mies");
|
||||
|
||||
// REQUIRE(cat2.find1<int>(cif::key("id") == 1, "parent_id") == 2);
|
||||
// REQUIRE(cat2.find1<int>(cif::key("id") == 2, "parent_id") == 2);
|
||||
// REQUIRE(cat2.find1<int>(cif::key("id") == 3, "parent_id") == 3);
|
||||
// }
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -831,7 +913,7 @@ save__cat_1.c
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -839,10 +921,9 @@ save__cat_1.c
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -858,14 +939,14 @@ mies Mies
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
|
||||
@@ -993,7 +1074,7 @@ save__cat_2.desc
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -1001,10 +1082,9 @@ save__cat_2.desc
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1031,14 +1111,14 @@ _cat_2.desc
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
@@ -1196,7 +1276,7 @@ save__cat_2.parent_id3
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -1204,10 +1284,9 @@ save__cat_2.parent_id3
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1244,14 +1323,14 @@ _cat_2.parent_id3
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
@@ -1417,7 +1496,7 @@ cat_2 3 cat_2:cat_1:3
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -1425,10 +1504,9 @@ cat_2 3 cat_2:cat_1:3
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1458,14 +1536,14 @@ _cat_2.parent_id3
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
@@ -1657,7 +1735,7 @@ cat_2 1 cat_2:cat_1:1
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -1665,10 +1743,9 @@ cat_2 1 cat_2:cat_1:1
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1698,14 +1775,14 @@ _cat_2.parent_id_2
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
// auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
@@ -2053,7 +2130,7 @@ cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -2061,10 +2138,9 @@ cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -2099,14 +2175,14 @@ _cat_3.num
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
@@ -2338,7 +2414,7 @@ cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -2346,10 +2422,9 @@ cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -2384,14 +2459,14 @@ _cat_3.num
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
auto &cat2 = f.front()["cat_2"];
|
||||
@@ -2545,11 +2620,11 @@ _cat_3.num
|
||||
// bonded.insert({atom_id_1, atom_id_2});
|
||||
// }
|
||||
|
||||
// for (size_t i = 0; i + 1 < atoms.size(); ++i)
|
||||
// for (std::size_t i = 0; i + 1 < atoms.size(); ++i)
|
||||
// {
|
||||
// auto label_i = atoms[i].labelAtomID();
|
||||
|
||||
// for (size_t j = i + 1; j < atoms.size(); ++j)
|
||||
// for (std::size_t j = i + 1; j < atoms.size(); ++j)
|
||||
// {
|
||||
// auto label_j = atoms[j].labelAtomID();
|
||||
|
||||
@@ -2570,7 +2645,7 @@ _cat_3.num
|
||||
|
||||
// auto &poly = structure.polymers().front();
|
||||
|
||||
// for (size_t i = 0; i + 1 < poly.size(); ++i)
|
||||
// for (std::size_t i = 0; i + 1 < poly.size(); ++i)
|
||||
// {
|
||||
// auto C = poly[i].atomByID("C");
|
||||
// auto N = poly[i + 1].atomByID("N");
|
||||
@@ -2672,7 +2747,7 @@ boo.data_.whatever
|
||||
|
||||
REQUIRE(test1.size() == sizeof(kS) / sizeof(T));
|
||||
|
||||
size_t i = 0;
|
||||
std::size_t i = 0;
|
||||
for (auto r : test1)
|
||||
{
|
||||
auto text = r.get<std::string>("text");
|
||||
@@ -2728,7 +2803,7 @@ There it was!)",
|
||||
|
||||
REQUIRE(test1.size() == sizeof(kS) / sizeof(T));
|
||||
|
||||
size_t i = 0;
|
||||
std::size_t i = 0;
|
||||
for (auto r : test1)
|
||||
{
|
||||
auto text = r.get<std::string>("text");
|
||||
@@ -2935,7 +3010,7 @@ save__cat_1.name
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -2943,10 +3018,9 @@ save__cat_1.name
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -2962,14 +3036,14 @@ _cat_1.name
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
REQUIRE(f.is_valid());
|
||||
|
||||
@@ -3130,7 +3204,7 @@ save__cat_1.name
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -3138,10 +3212,9 @@ save__cat_1.name
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto &validator = cif::validator_factory::instance().construct_validator("test_dict.dic", is_dict);
|
||||
auto &validator = cif::validator_factory::instance().add(cif::validator(is_dict));
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -3161,26 +3234,28 @@ _cat_1.name
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
REQUIRE(f.is_valid());
|
||||
CHECK(f.is_valid());
|
||||
|
||||
std::stringstream ss;
|
||||
ss << f;
|
||||
|
||||
cif::file f2(ss);
|
||||
REQUIRE(f2.is_valid());
|
||||
REQUIRE(f2.empty() == false);
|
||||
f2.front().load_dictionary();
|
||||
CHECK(f2.is_valid());
|
||||
|
||||
auto &audit_conform = f2.front()["audit_conform"];
|
||||
REQUIRE(audit_conform.front()["dict_name"].as<std::string>() == "test_dict.dic");
|
||||
REQUIRE(audit_conform.front()["dict_version"].as<float>() == 1.0);
|
||||
CHECK(audit_conform.front()["dict_name"].as<std::string>() == "test_dict.dic");
|
||||
CHECK(audit_conform.front()["dict_version"].as<float>() == 1.0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -3237,7 +3312,7 @@ save__cat_1.id_2
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -3245,10 +3320,9 @@ save__cat_1.id_2
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test", is_dict);
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -3266,14 +3340,14 @@ _cat_1.id_2
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, size_t length)
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.load(is_data, validator);
|
||||
|
||||
auto &cat1 = f.front()["cat_1"];
|
||||
|
||||
@@ -3281,10 +3355,10 @@ _cat_1.id_2
|
||||
using test_tuple_type = std::tuple<key_type,bool>;
|
||||
|
||||
test_tuple_type TESTS[] = {
|
||||
{ {{"id", 1}, {"id_2", 10}}, true },
|
||||
{ {{"id_2", 10}, {"id", 1}}, true },
|
||||
{ {{"id", 1}, {"id_2", 20}}, false },
|
||||
{ {{"id", 3} }, true },
|
||||
{ {{"id", "1"}, {"id_2", "10"}}, true },
|
||||
{ {{"id_2", "10"}, {"id", "1"}}, true },
|
||||
{ {{"id", "1"}, {"id_2", "20"}}, false },
|
||||
{ {{"id", "3"} }, true },
|
||||
};
|
||||
|
||||
for (const auto &[key, test] : TESTS)
|
||||
@@ -3412,7 +3486,7 @@ TEST_CASE("compound_test_1")
|
||||
cif::compound_factory::instance().push_dictionary(gTestDir / "REA_v2.cif");
|
||||
auto compound = cif::compound_factory::instance().create("REA_v2");
|
||||
REQUIRE(compound != nullptr);
|
||||
REQUIRE(compound->id() == "REA_v2");
|
||||
REQUIRE(cif::iequals(compound->id(), "REA_v2"));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -3450,7 +3524,7 @@ ATOM 7 CD PRO A 1 15.762 13.216 43.724 1.00 30.71 C)"
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -3486,4 +3560,11 @@ TEST_CASE("pdb2cif_formula_weight")
|
||||
|
||||
fw = a.front()["entity"].find1<float>(cif::key("id") == 3, "formula_weight");
|
||||
CHECK(fw == 18.015f);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("update_values_with_provider")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -26,19 +26,17 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::file operator""_cf(const char *text, size_t length)
|
||||
cif::file operator""_cf(const char *text, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -281,6 +279,20 @@ A 1 5 GLY 5 5 5 GLY GLY A . n
|
||||
|
||||
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("extended-dictionary-1")
|
||||
{
|
||||
cif::add_file_resource("dssp-extension.dic", gTestDir / "dssp-extension.dic");
|
||||
|
||||
cif::VERBOSE = 2;
|
||||
|
||||
auto f = cif::pdb::read(gTestDir / "1cbs-dssp.cif");
|
||||
CHECK(f.is_valid());
|
||||
}
|
||||
|
||||
TEST_CASE("brak")
|
||||
{
|
||||
auto f = cif::pdb::read(gTestDir / "brak.pdb");
|
||||
CHECK(f.is_valid());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user