mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-05 14:34:21 +08:00
Compare commits
158 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50df250415 | ||
|
|
2409fc5b7b | ||
|
|
8a1184a24c | ||
|
|
d2fbc54765 | ||
|
|
1bcb26ba75 | ||
|
|
32f4749d84 | ||
|
|
da12be879a | ||
|
|
94a38ad4e8 | ||
|
|
20ef79a172 | ||
|
|
92bf25476e | ||
|
|
b55e074dd7 | ||
|
|
7b654a837d | ||
|
|
ae9d247d22 | ||
|
|
16b7deafe8 | ||
|
|
f2cfe28458 | ||
|
|
2e8a52949e | ||
|
|
441e142767 | ||
|
|
bf9bdd2aae | ||
|
|
ce14593f0b | ||
|
|
1c02a451e1 | ||
|
|
448855a2d3 | ||
|
|
8ac8e89f2b | ||
|
|
2281f59401 | ||
|
|
4cb0673370 | ||
|
|
76c5706f7c | ||
|
|
2bf4284ff4 | ||
|
|
d9e2fc97f3 | ||
|
|
85dfdf4174 | ||
|
|
1bede3efda | ||
|
|
505f0fdd31 | ||
|
|
eed7ec3a4a | ||
|
|
fdb057e0e2 | ||
|
|
3fddd1a628 | ||
|
|
2440706b87 | ||
|
|
cf628fa95c | ||
|
|
2b0b47d20d | ||
|
|
a8abf2804f | ||
|
|
22d7757949 | ||
|
|
0b0d170c96 | ||
|
|
1e8e9adf62 | ||
|
|
0f03fc31e0 | ||
|
|
518432e0fb | ||
|
|
10ef3464ef | ||
|
|
226abbd577 | ||
|
|
8d66f42ab1 | ||
|
|
0f14d06f9a | ||
|
|
c53be78496 | ||
|
|
a38f31ce48 | ||
|
|
1258bd5047 | ||
|
|
d25cbeb14c | ||
|
|
9b60a07fb6 | ||
|
|
c0dd41ce50 | ||
|
|
4cff92bbcc | ||
|
|
9aa8a223c7 | ||
|
|
fb59adcfdd | ||
|
|
4acca8a3e3 | ||
|
|
c1030d2b08 | ||
|
|
16a185c6c0 | ||
|
|
174e818bd0 | ||
|
|
7f829bf5df | ||
|
|
71908282bb | ||
|
|
db3ae446af | ||
|
|
bc7d291307 | ||
|
|
cfd4702279 | ||
|
|
54eefb546d | ||
|
|
6af0d96a4e | ||
|
|
eb50bee4a3 | ||
|
|
b6143f3652 | ||
|
|
348aa7afb6 | ||
|
|
66912b68cc | ||
|
|
84dd218758 | ||
|
|
106ae38976 | ||
|
|
f1a52245ea | ||
|
|
cea38e5bb2 | ||
|
|
ed5aac358c | ||
|
|
5eb128251e | ||
|
|
cfa46ec954 | ||
|
|
07cc60e264 | ||
|
|
90973dc547 | ||
|
|
12e3d71b00 | ||
|
|
9addc8f873 | ||
|
|
343465cef0 | ||
|
|
bec5159415 | ||
|
|
f8da8360e6 | ||
|
|
fb2ad7b75d | ||
|
|
24aa7a70e5 | ||
|
|
5ade3d6cdd | ||
|
|
0d8e548ffc | ||
|
|
b09650812f | ||
|
|
acc9ad5c08 | ||
|
|
67b6c4bd27 | ||
|
|
7a1d3dbdfa | ||
|
|
4bf10df0c5 | ||
|
|
d84faad109 | ||
|
|
e01ace7ea4 | ||
|
|
e004e1591e | ||
|
|
4613084e1b | ||
|
|
637b795a8f | ||
|
|
4de981a3c0 | ||
|
|
15db026e27 | ||
|
|
d88d520553 | ||
|
|
46cd98ea1d | ||
|
|
d10328d891 | ||
|
|
e418a17256 | ||
|
|
627d3b9df2 | ||
|
|
ba28ade414 | ||
|
|
7c11130357 | ||
|
|
151915beea | ||
|
|
4f9aacb338 | ||
|
|
1f8e491ddc | ||
|
|
05cfa92182 | ||
|
|
e8031aeb49 | ||
|
|
85885406aa | ||
|
|
636f17d78d | ||
|
|
29559a5339 | ||
|
|
19f2fd75c9 | ||
|
|
8a60bae335 | ||
|
|
fa5ff60550 | ||
|
|
f6e0568964 | ||
|
|
fa27a11fea | ||
|
|
19706559cb | ||
|
|
0a06a0a51d | ||
|
|
b045177734 | ||
|
|
7ee5fa8765 | ||
|
|
3e690048a6 | ||
|
|
7ec3bfea9f | ||
|
|
098f3fd496 | ||
|
|
5476eef049 | ||
|
|
33c1eea9a1 | ||
|
|
d3432ed87c | ||
|
|
f05363ea93 | ||
|
|
77389c20a4 | ||
|
|
7c5f1ba85e | ||
|
|
e7c34cc15c | ||
|
|
72fd03a6b2 | ||
|
|
61f464ae4d | ||
|
|
19cdf66f10 | ||
|
|
0c036df6a8 | ||
|
|
4c1b9d83d1 | ||
|
|
b976b4657b | ||
|
|
eba04950d5 | ||
|
|
0c70df27ec | ||
|
|
d83f34722b | ||
|
|
652b6021d3 | ||
|
|
7fe9c87b6e | ||
|
|
9b2ae6d7fd | ||
|
|
8fd5b9a34b | ||
|
|
dffbf52d04 | ||
|
|
57ac5f0112 | ||
|
|
d5a71b0b24 | ||
|
|
d95b7be2e4 | ||
|
|
2f0a23f56a | ||
|
|
13b218f643 | ||
|
|
92a836ecdc | ||
|
|
c88a46f155 | ||
|
|
8882a34984 | ||
|
|
2d4a1731d9 | ||
|
|
be1e3073f1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ CMakeSettings.json
|
||||
msvc/
|
||||
src/revision.hpp
|
||||
test/test-create_sugar_?.cif
|
||||
Testing/
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "gxrio"]
|
||||
path = gxrio
|
||||
url = https://github.com/mhekkel/gxrio.git
|
||||
112
CMakeLists.txt
112
CMakeLists.txt
@@ -25,7 +25,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# set the project name
|
||||
project(cifpp VERSION 5.0.2 LANGUAGES CXX)
|
||||
project(cifpp VERSION 5.1.0 LANGUAGES CXX)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -35,11 +35,15 @@ include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(Dart)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
set(CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
# set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
||||
elseif(MSVC)
|
||||
@@ -86,6 +90,7 @@ if(BUILD_FOR_CCP4)
|
||||
list(APPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/share/libcifpp")
|
||||
|
||||
if(WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
@@ -98,11 +103,22 @@ if(MSVC)
|
||||
add_compile_options(/permissive-)
|
||||
|
||||
macro(get_WIN32_WINNT version)
|
||||
if(WIN32 AND CMAKE_SYSTEM_VERSION)
|
||||
if(CMAKE_SYSTEM_VERSION)
|
||||
set(ver ${CMAKE_SYSTEM_VERSION})
|
||||
string(REPLACE "." "" ver ${ver})
|
||||
string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver})
|
||||
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
|
||||
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
|
||||
|
||||
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
|
||||
if("${verMajor}" MATCHES "10")
|
||||
set(verMajor "A")
|
||||
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
|
||||
endif()
|
||||
|
||||
# Remove all remaining '.' characters.
|
||||
string(REPLACE "." "" ver ${ver})
|
||||
|
||||
# Prepend each digit with a zero.
|
||||
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
|
||||
set(${version} "0x${ver}")
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -153,23 +169,32 @@ if(MSVC)
|
||||
set(_ZLIB_x86 "(x86)")
|
||||
set(_ZLIB_SEARCH_NORMAL
|
||||
PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]"
|
||||
"$ENV{ProgramFiles}/zlib"
|
||||
"$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
|
||||
"$ENV{ProgramFiles}/zlib"
|
||||
"$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
|
||||
unset(_ZLIB_x86)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_NORMAL)
|
||||
|
||||
foreach(search ${_ZLIB_SEARCHES})
|
||||
find_library(ZLIB_LIBRARY NAMES zlibstatic NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib)
|
||||
find_library(ZLIB_LIBRARY NAMES zlibstatic NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
find_package(Eigen3 REQUIRED)
|
||||
|
||||
include(FindFilesystem)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
|
||||
|
||||
include(FindAtomic)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPATOMIC_LIBRARY})
|
||||
|
||||
if(MSVC)
|
||||
# this dependency can go once MSVC supports std::experimental::is_detected
|
||||
find_package(zeep 5.1.8 REQUIRED)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES zeep::zeep)
|
||||
endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
include(VersionString)
|
||||
write_version_header(${PROJECT_SOURCE_DIR}/src/ "LibCIFPP")
|
||||
@@ -181,12 +206,12 @@ if(CIFPP_RECREATE_SYMOP_DATA)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
COMMAND $<TARGET_FILE:symop-map-generator> $ENV{CLIBD}/syminfo.lib ${PROJECT_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
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib" "$ENV{CLIBD}/symop.lib"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -224,7 +249,6 @@ set(project_headers
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/datablock.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/file.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/validate.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/list.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/iterator.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/parser.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/forward_decl.hpp
|
||||
@@ -249,6 +273,7 @@ set(project_headers
|
||||
|
||||
add_library(cifpp ${project_sources} ${project_headers} ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
add_library(cifpp::cifpp ALIAS cifpp)
|
||||
generate_export_header(cifpp EXPORT_FILE_NAME cif++/exports.hpp)
|
||||
|
||||
if(BOOST_REGEX)
|
||||
target_compile_definitions(cifpp PRIVATE USE_BOOST_REGEX=1 BOOST_REGEX_STANDALONE=1)
|
||||
@@ -263,7 +288,7 @@ set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(cifpp
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include;${PROJECT_BINARY_DIR};${EIGEN3_INCLUDE_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
|
||||
@@ -299,19 +324,17 @@ if(CIFPP_DOWNLOAD_CCD)
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
set(CIFPP_CACHE_DIR "/var/cache/libcifpp" CACHE STRING "The cache directory to use")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
endif()
|
||||
|
||||
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
|
||||
set(SHARE_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING "The directory containing the provided data files")
|
||||
|
||||
# Installation directories
|
||||
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp")
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
|
||||
if(UNIX)
|
||||
set(CIFPP_CACHE_DIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
|
||||
set(CIFPP_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
|
||||
endif()
|
||||
|
||||
# Install rules
|
||||
install(TARGETS cifpp
|
||||
EXPORT cifppTargets
|
||||
@@ -345,6 +368,12 @@ install(
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${PROJECT_BINARY_DIR}/cif++/exports.hpp
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cif++
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
@@ -353,13 +382,23 @@ install(FILES
|
||||
DESTINATION ${CIFPP_DATA_DIR}
|
||||
)
|
||||
|
||||
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/cifppConfig.cmake.in)
|
||||
|
||||
configure_package_config_file(
|
||||
${CONFIG_TEMPLATE_FILE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfig.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
|
||||
PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR SHARE_INSTALL_DIR
|
||||
PATH_VARS CIFPP_DATA_DIR
|
||||
)
|
||||
|
||||
install(FILES
|
||||
@@ -402,8 +441,7 @@ if(ENABLE_TESTING)
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
|
||||
list(APPEND CIFPP_tests unit-v2 unit-3d format model rename-compound sugar
|
||||
)
|
||||
list(APPEND CIFPP_tests unit-v2 unit-3d format model rename-compound sugar spinner)
|
||||
|
||||
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
|
||||
set(CIFPP_TEST "${CIFPP_TEST}-test")
|
||||
@@ -422,18 +460,22 @@ if(ENABLE_TESTING)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${PROJECT_SOURCE_DIR}/test)
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
|
||||
add_test(NAME ${CIFPP_TEST}
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${PROJECT_SOURCE_DIR}/test)
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
message("Will install in ${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
# Optionally install the update scripts for CCD and dictionary files
|
||||
if(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
set(CIFPP_CRON_DIR "$ENV{DESTDIR}/etc/cron.weekly")
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/cron.weekly")
|
||||
elseif(UNIX) # assume all others are like FreeBSD...
|
||||
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/periodic/weekly")
|
||||
else()
|
||||
message(FATAL_ERROR "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(
|
||||
@@ -443,15 +485,15 @@ if(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CIFPP_CACHE_DIR})
|
||||
install(DIRECTORY DESTINATION "$ENV{DESTDIR}/etc/libcifpp/cache-update.d")
|
||||
install(DIRECTORY DESTINATION "${CIFPP_ETC_DIR}/libcifpp/cache-update.d")
|
||||
|
||||
# a config to, to make it complete
|
||||
if(NOT EXISTS "$ENV{DESTDIR}/etc/libcifpp.conf")
|
||||
if(NOT EXISTS "${CIFPP_ETC_DIR}/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 "$ENV{DESTDIR}/etc")
|
||||
install(CODE "message(\"A configuration file has been written to $ENV{DESTDIR}/etc/libcifpp.conf, please edit this file to enable automatic updates\")")
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf DESTINATION "${CIFPP_ETC_DIR}")
|
||||
install(CODE "message(\"A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
@@ -462,7 +504,7 @@ 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 "/data/components.cif;/build;/.vscode;/.git;/regex")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "/data/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)
|
||||
|
||||
95
README.md
95
README.md
@@ -3,18 +3,78 @@ libcifpp
|
||||
|
||||
This library contains code to work with mmCIF and PDB files.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
```c++
|
||||
// A simple program counting residues with an OXT atom
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
exit(1);
|
||||
|
||||
// Read file, can be PDB or mmCIF and can even be compressed with gzip.
|
||||
cif::file file = cif::pdb::read(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto &db = file.front();
|
||||
auto &atom_site = db["atom_site"];
|
||||
auto n = atom_site.find(cif::key("label_atom_id") == "OXT").size();
|
||||
|
||||
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;
|
||||
|
||||
for (const auto &[asym, comp, seqnr] :
|
||||
atom_site.find<std::string, std::string, int>(
|
||||
cif::key("label_atom_id") == "OXT",
|
||||
"label_asym_id", "label_comp_id", "label_seq_id"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
The code for this library was written in C++17. You therefore need a
|
||||
recent compiler to build it. For the development gcc 9.3 and clang 9.0
|
||||
recent compiler to build it. For the development gcc 9.4 and clang 9.0
|
||||
have been used as well as MSVC version 2019.
|
||||
|
||||
Other requirements are:
|
||||
|
||||
- [mrc](https://github.com/mhekkel/mrc), a resource compiler that
|
||||
allows including data files into the executable making them easier to
|
||||
install. Strictly this is optional, but at the expense of functionality.
|
||||
install. Strictly speaking this is optional, but at the expense of
|
||||
functionality.
|
||||
- [libeigen](https://eigen.tuxfamily.org/index.php?title=Main_Page), a
|
||||
library to do amongst others matrix calculations. This usually can be
|
||||
installed using your package manager, in Debian/Ubuntu it is called
|
||||
`libeigen3-dev`
|
||||
- zlib, the development version of this library. On Debian/Ubuntu this
|
||||
is the package `zlib1g-dev`.
|
||||
- [boost](https://www.boost.org). The boost libraries are only needed if
|
||||
you want to build the testing code.
|
||||
|
||||
When building using MS Visual Studio, you will also need [libzeep](https://github.com/mhekkel/libzeep)
|
||||
since MSVC does not yet provide a C++ template required by libcifpp.
|
||||
|
||||
Building
|
||||
--------
|
||||
@@ -22,25 +82,20 @@ Building
|
||||
This library uses [cmake](https://cmake.org). The usual way of building
|
||||
and installing is to create a `build` directory and run cmake there.
|
||||
|
||||
On linux e.g. you would issue the following commands:
|
||||
On linux e.g. you would issue the following commands to build and install
|
||||
libcifpp in your `$HOME/.local` folder:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/PDB-REDO/libcifpp.git --recurse-submodules
|
||||
cd libcifpp
|
||||
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
git clone https://github.com/PDB-REDO/libcifpp.git
|
||||
cd libcifpp
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
ctest -C Release
|
||||
cmake --install .
|
||||
```
|
||||
|
||||
This checks out the source code from github, creates a new directory
|
||||
where cmake stores its files. Run a configure, build the code and run
|
||||
tests. And then it installs the library and auxiliary files.
|
||||
|
||||
The default is to install everything in `$HOME/.local` on Linux and
|
||||
`%LOCALAPPDATA%` on Windows (the AppData/Local folder in your home directory).
|
||||
You can change this by specifying the prefix with the
|
||||
[CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/v3.21/variable/CMAKE_INSTALL_PREFIX.html)
|
||||
variable.
|
||||
where cmake stores its files. Run a configure, build the code and then
|
||||
it installs the library and auxiliary files.
|
||||
|
||||
If you want to run the tests before installing, you should add `-DENABLE_TESTING=ON`
|
||||
to the first cmake command.
|
||||
|
||||
43
changelog
43
changelog
@@ -1,3 +1,46 @@
|
||||
Version 5.1
|
||||
- New parser, optimised for speed
|
||||
- Fix in unique ID generator
|
||||
|
||||
Version 5.0.10
|
||||
- Fix in progress_bar, was using too much CPU
|
||||
- Optimised mmCIF parser
|
||||
|
||||
Version 5.0.9
|
||||
- Fix in dihedral angle calculations
|
||||
- Added create_water to model
|
||||
- Writing twin domain info in PDB files and more PDB fixes
|
||||
- remove_atom improved (remove struct_conn records)
|
||||
- Added a specialisation for category::find1<std::optional>
|
||||
- fix memory leak in category
|
||||
|
||||
Version 5.0.8
|
||||
- implemented find_first, find_min, find_max and count in category
|
||||
- find1 now throws an exception if condition does not not exactly match one row
|
||||
- Change in writing out PDB files, now looking up the original auth_seq_num
|
||||
via the pdbx_xxx_scheme categories based on the atom_site.auth_seq_num ->
|
||||
pdbx_xxx_scheme.pdb_seq_num relationship.
|
||||
- fix memory leak in category
|
||||
|
||||
Version 5.0.7.1
|
||||
- Use the implementation from zeep for std::experimental::is_detected
|
||||
|
||||
Version 5.0.7
|
||||
- Reintroduce exports file. For DLL's
|
||||
|
||||
Version 5.0.6
|
||||
- Fix file::contains, using iequals
|
||||
- Fix is_cis
|
||||
|
||||
Version 5.0.5
|
||||
- Fix code to work on 32 bit machines
|
||||
|
||||
Version 5.0.4
|
||||
- Revert removal of CIFPP_SHARE_DIR export
|
||||
|
||||
Version 5.0.3
|
||||
- Fix installation of libcifpp into the correct locations
|
||||
|
||||
Version 5.0.2
|
||||
- Fix export of CISPEP records in PDB format
|
||||
- Better support for exporting package_source
|
||||
|
||||
@@ -4,12 +4,13 @@ include(CMakeFindDependencyMacro)
|
||||
find_dependency(Threads)
|
||||
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
find_dependency(LibLZMA REQUIRED)
|
||||
|
||||
if(MSVC)
|
||||
find_dependency(zeep REQUIRED)
|
||||
endif()
|
||||
|
||||
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
|
||||
|
||||
set_and_check(CIFPP_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
set_and_check(CIFPP_LIBRARY_DIR "@PACKAGE_LIBRARY_INSTALL_DIR@")
|
||||
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_SHARE_INSTALL_DIR@")
|
||||
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")
|
||||
|
||||
check_required_components(cifpp)
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
cif::file file;
|
||||
file.load("1cbs.cif.gz");
|
||||
if (argc != 2)
|
||||
exit(1);
|
||||
|
||||
auto& db = file.front();
|
||||
cif::file file = cif::pdb::read(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto &db = file.front();
|
||||
auto &atom_site = db["atom_site"];
|
||||
auto n = atom_site.find(cif::key("label_atom_id") == "OXT").size();
|
||||
|
||||
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;
|
||||
|
||||
for (const auto& [asym, comp, seqnr]: atom_site.find<std::string,std::string,int>(
|
||||
cif::key("label_atom_id") == "OXT", "label_asym_id", "label_comp_id", "label_seq_id"))
|
||||
<< "residues with an OXT are:" << std::endl;
|
||||
|
||||
for (const auto &[asym, comp, seqnr] : atom_site.find<std::string, std::string, int>(
|
||||
cif::key("label_atom_id") == "OXT", "label_asym_id", "label_comp_id", "label_seq_id"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
|
||||
}
|
||||
|
||||
@@ -26,15 +26,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++/utilities.hpp>
|
||||
#include <cif++/file.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include <cif++/format.hpp>
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/format.hpp"
|
||||
|
||||
#include <cif++/compound.hpp>
|
||||
#include <cif++/point.hpp>
|
||||
#include <cif++/symmetry.hpp>
|
||||
#include "cif++/compound.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/symmetry.hpp"
|
||||
|
||||
#include <cif++/model.hpp>
|
||||
#include "cif++/model.hpp"
|
||||
|
||||
#include <cif++/pdb/io.hpp>
|
||||
#include "cif++/pdb/io.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
@@ -204,7 +204,7 @@ struct atom_type_info
|
||||
float radii[kRadiusTypeCount];
|
||||
};
|
||||
|
||||
extern const atom_type_info kKnownAtoms[];
|
||||
extern CIFPP_EXPORT const atom_type_info kKnownAtoms[];
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// AtomTypeTraits
|
||||
@@ -270,6 +270,10 @@ class atom_type_traits
|
||||
const SFData &wksf(int charge = 0) const;
|
||||
const SFData &elsf() const;
|
||||
|
||||
// Clipper doesn't like atoms with charges that do not have a scattering factor. And
|
||||
// rightly so, but we need to know in advance if this is the case
|
||||
bool has_sf(int charge) const;
|
||||
|
||||
private:
|
||||
const struct atom_type_info *m_info;
|
||||
};
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <cif++/forward_decl.hpp>
|
||||
|
||||
#include <cif++/condition.hpp>
|
||||
#include <cif++/iterator.hpp>
|
||||
#include <cif++/row.hpp>
|
||||
#include <cif++/validate.hpp>
|
||||
|
||||
// TODO: implement all of:
|
||||
// https://en.cppreference.com/w/cpp/named_req/Container
|
||||
// https://en.cppreference.com/w/cpp/named_req/SequenceContainer
|
||||
@@ -49,9 +49,26 @@ class duplicate_key_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
duplicate_key_error(const std::string &msg)
|
||||
: std::runtime_error(msg) {}
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class multiple_results_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
multiple_results_error()
|
||||
: std::runtime_error("query should have returned exactly one row")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// These should be moved elsewhere, one day.
|
||||
|
||||
template<typename _Tp> inline constexpr bool is_optional_v = false;
|
||||
template<typename _Tp> inline constexpr bool is_optional_v<std::optional<_Tp>> = true;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class category
|
||||
@@ -109,52 +126,52 @@ class category
|
||||
|
||||
reference front()
|
||||
{
|
||||
return {*this, *m_head};
|
||||
return { *this, *m_head };
|
||||
}
|
||||
|
||||
const_reference front() const
|
||||
{
|
||||
return {const_cast<category &>(*this), const_cast<row &>(*m_head)};
|
||||
return { const_cast<category &>(*this), const_cast<row &>(*m_head) };
|
||||
}
|
||||
|
||||
reference back()
|
||||
{
|
||||
return {*this, *m_tail};
|
||||
return { *this, *m_tail };
|
||||
}
|
||||
|
||||
const_reference back() const
|
||||
{
|
||||
return {const_cast<category &>(*this), const_cast<row &>(*m_tail)};
|
||||
return { const_cast<category &>(*this), const_cast<row &>(*m_tail) };
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return {*this, m_head};
|
||||
return { *this, m_head };
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return {*this, nullptr};
|
||||
return { *this, nullptr };
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return {*this, m_head};
|
||||
return { *this, m_head };
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return {*this, nullptr};
|
||||
return { *this, nullptr };
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return {*this, m_head};
|
||||
return { *this, m_head };
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return {*this, nullptr};
|
||||
return { *this, nullptr };
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
@@ -189,64 +206,64 @@ class category
|
||||
iterator_proxy<const category, Ts...> rows(Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
return iterator_proxy<const category, Ts...>(*this, begin(), {names...});
|
||||
return iterator_proxy<const category, Ts...>(*this, begin(), { names... });
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
iterator_proxy<category, Ts...> rows(Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
return iterator_proxy<category, Ts...>(*this, begin(), {names...});
|
||||
return iterator_proxy<category, Ts...>(*this, begin(), { names... });
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
conditional_iterator_proxy<category> find(condition &&cond)
|
||||
{
|
||||
return find(begin(), std::forward<condition>(cond));
|
||||
return find(begin(), std::move(cond));
|
||||
}
|
||||
|
||||
conditional_iterator_proxy<category> find(iterator pos, condition &&cond)
|
||||
{
|
||||
return {*this, pos, std::forward<condition>(cond)};
|
||||
return { *this, pos, std::move(cond) };
|
||||
}
|
||||
|
||||
conditional_iterator_proxy<const category> find(condition &&cond) const
|
||||
{
|
||||
return find(cbegin(), std::forward<condition>(cond));
|
||||
return find(cbegin(), std::move(cond));
|
||||
}
|
||||
|
||||
conditional_iterator_proxy<const category> find(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
return conditional_iterator_proxy<const category>{*this, pos, std::forward<condition>(cond)};
|
||||
return conditional_iterator_proxy<const category>{ *this, pos, std::move(cond) };
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<category, Ts...> find(condition &&cond, Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
return find<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Ns>(names)...);
|
||||
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<const category, Ts...> find(condition &&cond, Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
return find<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Ns>(names)...);
|
||||
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<category, Ts...> find(const_iterator pos, condition &&cond, Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
return {*this, pos, std::forward<condition>(cond), std::forward<Ns>(names)...};
|
||||
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<const category, Ts...> find(const_iterator pos, condition &&cond, Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
return {*this, pos, std::forward<condition>(cond), std::forward<Ns>(names)...};
|
||||
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -254,40 +271,63 @@ class category
|
||||
|
||||
row_handle find1(condition &&cond)
|
||||
{
|
||||
return find1(begin(), std::forward<condition>(cond));
|
||||
return find1(begin(), std::move(cond));
|
||||
}
|
||||
|
||||
row_handle find1(iterator pos, condition &&cond)
|
||||
{
|
||||
auto h = find(pos, std::forward<condition>(cond));
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
return h.size() != 1 ? row_handle{} : *h.begin();
|
||||
if (h.size() != 1)
|
||||
throw multiple_results_error();
|
||||
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
const row_handle find1(condition &&cond) const
|
||||
{
|
||||
return find1(cbegin(), std::forward<condition>(cond));
|
||||
return find1(cbegin(), std::move(cond));
|
||||
}
|
||||
|
||||
const row_handle find1(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
auto h = find(pos, std::forward<condition>(cond));
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
return h.size() != 1 ? row_handle{} : *h.begin();
|
||||
if (h.size() != 1)
|
||||
throw multiple_results_error();
|
||||
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T find1(condition &&cond, const char *column) const
|
||||
{
|
||||
return find1<T>(cbegin(), std::forward<condition>(cond), column);
|
||||
return find1<T>(cbegin(), std::move(cond), column);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, std::enable_if_t<not is_optional_v<T>, int> = 0>
|
||||
T find1(const_iterator pos, condition &&cond, const char *column) const
|
||||
{
|
||||
auto h = find<T>(pos, std::forward<condition>(cond), column);
|
||||
auto h = find<T>(pos, std::move(cond), column);
|
||||
|
||||
return h.size() == 1 ? *h.begin() : T{};
|
||||
if (h.size() != 1)
|
||||
throw multiple_results_error();
|
||||
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<is_optional_v<T>, int> = 0>
|
||||
T find1(const_iterator pos, condition &&cond, const char *column) const
|
||||
{
|
||||
auto h = find<typename T::value_type>(pos, std::move(cond), column);
|
||||
|
||||
if (h.size() > 1)
|
||||
throw multiple_results_error();
|
||||
|
||||
if (h.empty())
|
||||
return {};
|
||||
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
@@ -295,16 +335,119 @@ class category
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
|
||||
return find1<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Cs>(columns)...);
|
||||
return find1<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(columns)...);
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find1(const_iterator pos, condition &&cond, Cs... columns) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
auto h = find<Ts...>(pos, std::forward<condition>(cond), std::forward<Cs>(columns)...);
|
||||
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(columns)...);
|
||||
|
||||
return h.size() == 1 ? *h.begin() : std::tuple<Ts...>{};
|
||||
if (h.size() != 1)
|
||||
throw multiple_results_error();
|
||||
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// if you want only a first hit
|
||||
|
||||
row_handle find_first(condition &&cond)
|
||||
{
|
||||
return find_first(begin(), std::move(cond));
|
||||
}
|
||||
|
||||
row_handle find_first(iterator pos, condition &&cond)
|
||||
{
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
return h.empty() ? row_handle{} : *h.begin();
|
||||
}
|
||||
|
||||
const row_handle find_first(condition &&cond) const
|
||||
{
|
||||
return find_first(cbegin(), std::move(cond));
|
||||
}
|
||||
|
||||
const row_handle find_first(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
return h.empty() ? row_handle{} : *h.begin();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T find_first(condition &&cond, const char *column) const
|
||||
{
|
||||
return find_first<T>(cbegin(), std::move(cond), column);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T find_first(const_iterator pos, condition &&cond, const char *column) const
|
||||
{
|
||||
auto h = find<T>(pos, std::move(cond), column);
|
||||
|
||||
return h.empty() ? T{} : *h.begin();
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find_first(condition &&cond, Cs... columns) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
|
||||
return find_first<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(columns)...);
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find_first(const_iterator pos, condition &&cond, Cs... columns) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(columns)...);
|
||||
|
||||
return h.empty() ? std::tuple<Ts...>{} : *h.begin();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_max(const char *column, condition &&cond) const
|
||||
{
|
||||
T result = std::numeric_limits<T>::min();
|
||||
|
||||
for (auto v : find<T>(std::move(cond), column))
|
||||
{
|
||||
if (result < v)
|
||||
result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_max(const char *column) const
|
||||
{
|
||||
return find_max<T>(column, all());
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_min(const char *column, condition &&cond) const
|
||||
{
|
||||
T result = std::numeric_limits<T>::max();
|
||||
|
||||
for (auto v : find<T>(std::move(cond), column))
|
||||
{
|
||||
if (result > v)
|
||||
result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_min(const char *column) const
|
||||
{
|
||||
return find_min<T>(column, all());
|
||||
}
|
||||
|
||||
bool exists(condition &&cond) const
|
||||
@@ -335,6 +478,31 @@ class category
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t count(condition &&cond) const
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
if (cond)
|
||||
{
|
||||
cond.prepare(*this);
|
||||
|
||||
auto sh = cond.single();
|
||||
|
||||
if (sh.has_value() and *sh)
|
||||
result = 1;
|
||||
else
|
||||
{
|
||||
for (auto r : *this)
|
||||
{
|
||||
if (cond(r))
|
||||
++result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
bool has_children(row_handle r) const;
|
||||
@@ -486,7 +654,7 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void sort(std::function<int(row_handle,row_handle)> f);
|
||||
void sort(std::function<int(row_handle, row_handle)> f);
|
||||
void reorder_by_index();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -583,7 +751,7 @@ class category
|
||||
void swap_item(uint16_t column_ix, row_handle &a, row_handle &b);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
std::string m_name;
|
||||
std::vector<item_column> m_columns;
|
||||
const validator *m_validator = nullptr;
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
/// \file This file contains the definition for the class compound, encapsulating
|
||||
/// the information found for compounds in the CCD.
|
||||
|
||||
#include "cif++/atom_type.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include <cif++/atom_type.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -75,6 +75,11 @@ struct compound_atom
|
||||
bool leaving_atom = false;
|
||||
bool stereo_config = false;
|
||||
float x, y, z;
|
||||
|
||||
point get_location() const
|
||||
{
|
||||
return { x, y, z };
|
||||
}
|
||||
};
|
||||
|
||||
/// --------------------------------------------------------------------
|
||||
@@ -114,6 +119,7 @@ class compound
|
||||
compound_atom get_atom_by_atom_id(const std::string &atom_id) const;
|
||||
|
||||
bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const;
|
||||
float bond_length(const std::string &atomId_1, const std::string &atomId_2) const;
|
||||
|
||||
bool is_water() const
|
||||
{
|
||||
@@ -173,7 +179,7 @@ class compound_factory
|
||||
|
||||
~compound_factory();
|
||||
|
||||
static const std::map<std::string, char> kAAMap, kBaseMap;
|
||||
static CIFPP_EXPORT const std::map<std::string, char> kAAMap, kBaseMap;
|
||||
|
||||
private:
|
||||
compound_factory();
|
||||
@@ -188,4 +194,4 @@ class compound_factory
|
||||
std::shared_ptr<compound_factory_impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace pdbx
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
|
||||
#include <cif++/row.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace detail
|
||||
virtual bool test(row_handle) const = 0;
|
||||
virtual void str(std::ostream &) const = 0;
|
||||
virtual std::optional<row_handle> single() const { return {}; };
|
||||
|
||||
virtual bool equals([[maybe_unused]] const condition_impl *rhs) const { return false; }
|
||||
};
|
||||
|
||||
struct all_condition_impl : public condition_impl
|
||||
@@ -145,7 +147,6 @@ class condition
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void optimise(condition_impl *&impl);
|
||||
|
||||
condition_impl *m_impl;
|
||||
@@ -181,6 +182,33 @@ namespace detail
|
||||
uint16_t m_item_ix = 0;
|
||||
};
|
||||
|
||||
struct key_is_not_empty_condition_impl : public condition_impl
|
||||
{
|
||||
key_is_not_empty_condition_impl(const std::string &item_tag)
|
||||
: m_item_tag(item_tag)
|
||||
{
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
return not r[m_item_ix].empty();
|
||||
}
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << " IS NOT NULL";
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
uint16_t m_item_ix = 0;
|
||||
};
|
||||
|
||||
struct key_equals_condition_impl : public condition_impl
|
||||
{
|
||||
key_equals_condition_impl(item &&i)
|
||||
@@ -193,9 +221,7 @@ namespace detail
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
return m_single_hit.has_value() ?
|
||||
*m_single_hit == r :
|
||||
r[m_item_ix].compare(m_value, m_icase) == 0;
|
||||
return m_single_hit.has_value() ? *m_single_hit == r : r[m_item_ix].compare(m_value, m_icase) == 0;
|
||||
}
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
@@ -208,6 +234,20 @@ namespace detail
|
||||
return m_single_hit;
|
||||
}
|
||||
|
||||
virtual bool equals(const condition_impl *rhs) const override
|
||||
{
|
||||
if (typeid(*rhs) == typeid(key_equals_condition_impl))
|
||||
{
|
||||
auto ri = static_cast<const key_equals_condition_impl *>(rhs);
|
||||
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
|
||||
return m_single_hit == ri->m_single_hit;
|
||||
else
|
||||
// watch out, both m_item_ix might be the same while tags might be diffent (in case they both do not exist in the category)
|
||||
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_tag == ri->m_item_tag;
|
||||
}
|
||||
return this == rhs;
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
uint16_t m_item_ix = 0;
|
||||
bool m_icase = false;
|
||||
@@ -244,7 +284,7 @@ namespace detail
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL";
|
||||
os << '(' << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL)";
|
||||
}
|
||||
|
||||
virtual std::optional<row_handle> single() const override
|
||||
@@ -252,12 +292,26 @@ namespace detail
|
||||
return m_single_hit;
|
||||
}
|
||||
|
||||
virtual bool equals(const condition_impl *rhs) const override
|
||||
{
|
||||
if (typeid(*rhs) == typeid(key_equals_or_empty_condition_impl))
|
||||
{
|
||||
auto ri = static_cast<const key_equals_or_empty_condition_impl *>(rhs);
|
||||
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
|
||||
return m_single_hit == ri->m_single_hit;
|
||||
else
|
||||
// watch out, both m_item_ix might be the same while tags might be diffent (in case they both do not exist in the category)
|
||||
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_tag == ri->m_item_tag;
|
||||
}
|
||||
return this == rhs;
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
uint16_t m_item_ix = 0;
|
||||
std::string m_value;
|
||||
bool m_icase = false;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
};
|
||||
};
|
||||
|
||||
struct key_compare_condition_impl : public condition_impl
|
||||
{
|
||||
@@ -409,29 +463,53 @@ namespace detail
|
||||
// case they make up an indexed tuple.
|
||||
struct and_condition_impl : public condition_impl
|
||||
{
|
||||
and_condition_impl() = default;
|
||||
|
||||
and_condition_impl(condition &&a, condition &&b)
|
||||
{
|
||||
mSub.emplace_back(std::exchange(a.m_impl, nullptr));
|
||||
mSub.emplace_back(std::exchange(b.m_impl, nullptr));
|
||||
if (typeid(*a.m_impl) == typeid(*this))
|
||||
{
|
||||
and_condition_impl *ai = static_cast<and_condition_impl *>(a.m_impl);
|
||||
|
||||
std::swap(m_sub, ai->m_sub);
|
||||
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
|
||||
}
|
||||
else if (typeid(*b.m_impl) == typeid(*this))
|
||||
{
|
||||
and_condition_impl *bi = static_cast<and_condition_impl *>(b.m_impl);
|
||||
|
||||
std::swap(m_sub, bi->m_sub);
|
||||
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
|
||||
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
~and_condition_impl()
|
||||
{
|
||||
for (auto sub : mSub)
|
||||
for (auto sub : m_sub)
|
||||
delete sub;
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override;
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
for (auto &sub : m_sub)
|
||||
sub = sub->prepare(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto sub : mSub)
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (sub->test(r))
|
||||
continue;
|
||||
|
||||
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
@@ -444,7 +522,7 @@ namespace detail
|
||||
os << '(';
|
||||
|
||||
bool first = true;
|
||||
for (auto sub : mSub)
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
@@ -461,7 +539,7 @@ namespace detail
|
||||
{
|
||||
std::optional<row_handle> result;
|
||||
|
||||
for (auto sub : mSub)
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
auto s = sub->single();
|
||||
|
||||
@@ -470,7 +548,7 @@ namespace detail
|
||||
result = s;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (s == result)
|
||||
continue;
|
||||
|
||||
@@ -481,56 +559,100 @@ namespace detail
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<condition_impl *> mSub;
|
||||
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
|
||||
|
||||
std::vector<condition_impl *> m_sub;
|
||||
};
|
||||
|
||||
struct or_condition_impl : public condition_impl
|
||||
{
|
||||
or_condition_impl(condition &&a, condition &&b)
|
||||
: mA(nullptr)
|
||||
, mB(nullptr)
|
||||
{
|
||||
std::swap(mA, a.m_impl);
|
||||
std::swap(mB, b.m_impl);
|
||||
if (typeid(*a.m_impl) == typeid(*this))
|
||||
{
|
||||
or_condition_impl *ai = static_cast<or_condition_impl *>(a.m_impl);
|
||||
|
||||
std::swap(m_sub, ai->m_sub);
|
||||
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
|
||||
}
|
||||
else if (typeid(*b.m_impl) == typeid(*this))
|
||||
{
|
||||
or_condition_impl *bi = static_cast<or_condition_impl *>(b.m_impl);
|
||||
|
||||
std::swap(m_sub, bi->m_sub);
|
||||
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
|
||||
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
~or_condition_impl()
|
||||
{
|
||||
delete mA;
|
||||
delete mB;
|
||||
for (auto sub : m_sub)
|
||||
delete sub;
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
return mA->test(r) or mB->test(r);
|
||||
bool result = false;
|
||||
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (not sub->test(r))
|
||||
continue;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
bool first = true;
|
||||
|
||||
os << '(';
|
||||
mA->str(os);
|
||||
os << ") OR (";
|
||||
mB->str(os);
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
os << " OR ";
|
||||
sub->str(os);
|
||||
}
|
||||
os << ')';
|
||||
}
|
||||
|
||||
virtual std::optional<row_handle> single() const override
|
||||
{
|
||||
auto sa = mA->single();
|
||||
auto sb = mB->single();
|
||||
|
||||
if (sa.has_value() and sb.has_value() and sa != sb)
|
||||
sa.reset();
|
||||
else if (not sa.has_value())
|
||||
sa = sb;
|
||||
std::optional<row_handle> result;
|
||||
|
||||
return sa;
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
auto s = sub->single();
|
||||
|
||||
if (not result.has_value())
|
||||
{
|
||||
result = s;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s == result)
|
||||
continue;
|
||||
|
||||
result.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
condition_impl *mA;
|
||||
condition_impl *mB;
|
||||
std::vector<condition_impl *> m_sub;
|
||||
};
|
||||
|
||||
struct not_condition_impl : public condition_impl
|
||||
@@ -569,7 +691,7 @@ namespace detail
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline condition operator&&(condition &&a, condition &&b)
|
||||
inline condition operator and(condition &&a, condition &&b)
|
||||
{
|
||||
if (a.m_impl and b.m_impl)
|
||||
return condition(new detail::and_condition_impl(std::move(a), std::move(b)));
|
||||
@@ -578,12 +700,35 @@ inline condition operator&&(condition &&a, condition &&b)
|
||||
return condition(std::move(b));
|
||||
}
|
||||
|
||||
inline condition operator||(condition &&a, condition &&b)
|
||||
inline condition operator or(condition &&a, condition &&b)
|
||||
{
|
||||
if (a.m_impl and b.m_impl)
|
||||
{
|
||||
if (typeid(*a.m_impl) == typeid(detail::key_equals_condition_impl) and
|
||||
typeid(*b.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_condition_impl *>(a.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(b.m_impl);
|
||||
|
||||
if (ci->m_item_tag == ce->m_item_tag)
|
||||
return condition(new detail::key_equals_or_empty_condition_impl(ci));
|
||||
}
|
||||
else if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
|
||||
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_condition_impl *>(b.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(a.m_impl);
|
||||
|
||||
if (ci->m_item_tag == ce->m_item_tag)
|
||||
return condition(new detail::key_equals_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
|
||||
}
|
||||
|
||||
if (a.m_impl)
|
||||
return condition(std::move(a));
|
||||
|
||||
return condition(std::move(b));
|
||||
}
|
||||
|
||||
@@ -706,7 +851,12 @@ inline condition operator==(const key &key, const empty_type &)
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
|
||||
}
|
||||
|
||||
inline condition operator !(condition &&rhs)
|
||||
inline condition operator!=(const key &key, const empty_type &)
|
||||
{
|
||||
return condition(new detail::key_is_not_empty_condition_impl(key.m_item_tag));
|
||||
}
|
||||
|
||||
inline condition operator not(condition &&rhs)
|
||||
{
|
||||
return condition(new detail::not_condition_impl(std::move(rhs)));
|
||||
}
|
||||
@@ -741,4 +891,4 @@ namespace literals
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++/forward_decl.hpp>
|
||||
|
||||
#include <cif++/category.hpp>
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -45,11 +44,10 @@ class datablock : public std::list<category>
|
||||
{
|
||||
}
|
||||
|
||||
datablock(const datablock &) = default;
|
||||
|
||||
datablock(const datablock &);
|
||||
datablock(datablock &&) = default;
|
||||
|
||||
datablock &operator=(const datablock &) = default;
|
||||
datablock &operator=(const datablock &);
|
||||
datablock &operator=(datablock &&) = default;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -89,7 +87,7 @@ class datablock : public std::list<category>
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
bool operator==(const datablock &rhs) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++/validate.hpp>
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
validator parse_dictionary(std::string_view name, std::istream &is);
|
||||
void extend_dictionary(validator &v, std::istream &is);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <cif++/datablock.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
/// whether to use a compressions/decompression algorithm is
|
||||
/// based on the extension of the \a filename argument.
|
||||
|
||||
// This is a stripped down version of the gzio library from
|
||||
// https://github.com/mhekkel/gzio.git
|
||||
// This is a stripped down version of the gxrio library from
|
||||
// https://github.com/mhekkel/gxrio.git
|
||||
// Most notably, the lzma support has been removed since getting
|
||||
// that to work in Windows proved to be too much work.
|
||||
|
||||
@@ -128,15 +128,15 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
std::swap(m_zstream, rhs.m_zstream);
|
||||
std::swap(m_gzheader, rhs.m_gzheader);
|
||||
|
||||
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.begin());
|
||||
this->setg(m_out_buffer.data(), m_out_buffer.data() + m_out_buffer.size(), p);
|
||||
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.data());
|
||||
this->setg(m_out_buffer.data(), m_out_buffer.data(), p);
|
||||
|
||||
if (m_zstream and m_zstream->avail_in > 0)
|
||||
{
|
||||
auto next_in_offset = m_zstream->next_in - rhs.m_in_buffer.data();
|
||||
std::copy(rhs.m_in_buffer.begin() + next_in_offset,
|
||||
rhs.m_in_buffer.begin() + next_in_offset + m_zstream->avail_in,
|
||||
m_in_buffer.begin());
|
||||
std::copy(rhs.m_in_buffer.data() + next_in_offset,
|
||||
rhs.m_in_buffer.data() + next_in_offset + m_zstream->avail_in,
|
||||
m_in_buffer.data());
|
||||
m_zstream->next_in = m_in_buffer.data();
|
||||
}
|
||||
}
|
||||
@@ -151,15 +151,15 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
std::swap(m_zstream, rhs.m_zstream);
|
||||
std::swap(m_gzheader, rhs.m_gzheader);
|
||||
|
||||
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.begin());
|
||||
this->setg(m_out_buffer.data(), m_out_buffer.data() + m_out_buffer.size(), p);
|
||||
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.data());
|
||||
this->setg(m_out_buffer.data(), m_out_buffer.data(), p);
|
||||
|
||||
if (m_zstream and m_zstream->avail_in > 0)
|
||||
{
|
||||
auto next_in_offset = m_zstream->next_in - reinterpret_cast<unsigned char *>(rhs.m_in_buffer.data());
|
||||
std::copy(rhs.m_in_buffer.begin() + next_in_offset,
|
||||
rhs.m_in_buffer.begin() + next_in_offset + m_zstream->avail_in,
|
||||
m_in_buffer.begin());
|
||||
std::copy(rhs.m_in_buffer.data() + next_in_offset,
|
||||
rhs.m_in_buffer.data() + next_in_offset + m_zstream->avail_in,
|
||||
m_in_buffer.data());
|
||||
m_zstream->next_in = reinterpret_cast<unsigned char *>(m_in_buffer.data());
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/forward_decl.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
@@ -35,9 +41,6 @@
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include <cif++/forward_decl.hpp>
|
||||
#include <cif++/text.hpp>
|
||||
|
||||
/// \file item.hpp
|
||||
/// This file contains the declaration of item but also the item_value and item_handle
|
||||
/// These handle the storage of and access to the data for a single data field.
|
||||
@@ -45,8 +48,6 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
extern int VERBOSE;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief item is a transient class that is used to pass data into rows
|
||||
/// but it also takes care of formatting data.
|
||||
@@ -194,6 +195,7 @@ struct item_value
|
||||
/// \brief constructor
|
||||
item_value(std::string_view text)
|
||||
: m_length(text.length())
|
||||
, m_storage(0)
|
||||
{
|
||||
if (m_length >= kBufferSize)
|
||||
{
|
||||
@@ -210,7 +212,7 @@ struct item_value
|
||||
|
||||
item_value(item_value &&rhs)
|
||||
: m_length(std::exchange(rhs.m_length, 0))
|
||||
, m_data(std::exchange(rhs.m_data, nullptr))
|
||||
, m_storage(std::exchange(rhs.m_storage, 0))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -219,7 +221,7 @@ struct item_value
|
||||
if (this != &rhs)
|
||||
{
|
||||
m_length = std::exchange(rhs.m_length, m_length);
|
||||
m_data = std::exchange(rhs.m_data, m_data);
|
||||
m_storage = std::exchange(rhs.m_storage, m_storage);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -228,7 +230,7 @@ struct item_value
|
||||
{
|
||||
if (m_length >= kBufferSize)
|
||||
delete[] m_data;
|
||||
m_data = nullptr;
|
||||
m_storage = 0;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
@@ -245,6 +247,7 @@ struct item_value
|
||||
{
|
||||
char m_local_data[8];
|
||||
char *m_data;
|
||||
uint64_t m_storage;
|
||||
};
|
||||
|
||||
static constexpr size_t kBufferSize = sizeof(m_local_data);
|
||||
@@ -257,9 +260,6 @@ struct item_value
|
||||
}
|
||||
};
|
||||
|
||||
// static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes");
|
||||
static_assert(sizeof(item_value) == 16, "sizeof(item_value) should be 16 bytes");
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Transient object to access stored data
|
||||
|
||||
@@ -354,7 +354,7 @@ struct item_handle
|
||||
{
|
||||
}
|
||||
|
||||
static const item_handle s_null_item;
|
||||
static CIFPP_EXPORT const item_handle s_null_item;
|
||||
|
||||
friend void swap(item_handle a, item_handle b)
|
||||
{
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++/row.hpp>
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template<typename Allocator = std::allocator<void>>
|
||||
class list
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
struct list_item
|
||||
{
|
||||
list_item *m_next = nullptr;
|
||||
};
|
||||
|
||||
using list_item_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<list_item>;
|
||||
using list_item_allocator_traits = std::allocator_traits<item_allocator_type>;
|
||||
|
||||
list_item_allocator_traits::pointer get_item()
|
||||
{
|
||||
list_item_allocator_type ia(get_allocator());
|
||||
return list_item_allocator_traits::allocate(ia, 1);
|
||||
}
|
||||
|
||||
template<typename ...Arguments>
|
||||
list_item *create_list_item(uint16_t column_ix, Arguments... args)
|
||||
{
|
||||
auto p = this->get_item();
|
||||
list_item_allocator_type ia(get_allocator());
|
||||
list_item_allocator_traits::construct(ia, p, std::forward<Arguments>(args)...);
|
||||
return p;
|
||||
}
|
||||
|
||||
void delete_list_item(list_item *iv)
|
||||
{
|
||||
list_item_allocator_type ia(get_allocator());
|
||||
list_item_allocator_traits::destroy(ia, iv);
|
||||
list_item_allocator_traits::deallocate(ia, iv, 1);
|
||||
}
|
||||
|
||||
list_item *m_head = nullptr, *m_tail = nullptr;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cif
|
||||
531
include/cif++/matrix.hpp
Normal file
531
include/cif++/matrix.hpp
Normal file
@@ -0,0 +1,531 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2023 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
// --------------------------------------------------------------------
|
||||
// We're using expression templates here
|
||||
|
||||
template <typename M>
|
||||
class matrix_expression
|
||||
{
|
||||
public:
|
||||
constexpr uint32_t dim_m() const { return static_cast<const M &>(*this).dim_m(); }
|
||||
constexpr uint32_t dim_n() const { return static_cast<const M &>(*this).dim_n(); }
|
||||
|
||||
constexpr auto &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
return static_cast<M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
constexpr auto operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return static_cast<const M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
void swap_row(uint32_t r1, uint32_t r2)
|
||||
{
|
||||
for (uint32_t c = 0; c < dim_m(); ++c)
|
||||
{
|
||||
auto v = operator()(r1, c);
|
||||
operator()(r1, c) = operator()(r2, c);
|
||||
operator()(r2, c) = v;
|
||||
}
|
||||
}
|
||||
|
||||
void swap_col(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
for (uint32_t r = 0; r < dim_n(); ++r)
|
||||
{
|
||||
auto &a = operator()(r, c1);
|
||||
auto &b = operator()(r, c2);
|
||||
std::swap(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const matrix_expression &m)
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (size_t i = 0; i < m.dim_m(); ++i)
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (size_t j = 0; j < m.dim_n(); ++j)
|
||||
{
|
||||
os << m(i, j);
|
||||
if (j + 1 < m.dim_n())
|
||||
os << ", ";
|
||||
}
|
||||
|
||||
if (i + 1 < m.dim_m())
|
||||
os << ", ";
|
||||
|
||||
os << ']';
|
||||
}
|
||||
|
||||
os << ']';
|
||||
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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 = float>
|
||||
class matrix : public matrix_expression<matrix<F>>
|
||||
{
|
||||
public:
|
||||
using value_type = F;
|
||||
|
||||
template <typename M2>
|
||||
matrix(const matrix_expression<M2> &m)
|
||||
: m_m(m.dim_m())
|
||||
, m_n(m.dim_n())
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_m; ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < m_n; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
matrix(size_t m, size_t n, value_type v = 0)
|
||||
: m_m(m)
|
||||
, m_n(n)
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
matrix() = default;
|
||||
matrix(matrix &&m) = default;
|
||||
matrix(const matrix &m) = default;
|
||||
matrix &operator=(matrix &&m) = default;
|
||||
matrix &operator=(const matrix &m) = default;
|
||||
|
||||
constexpr size_t dim_m() const { return m_m; }
|
||||
constexpr size_t dim_n() const { return m_n; }
|
||||
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_m = 0, m_n = 0;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// special case, 3x3 matrix
|
||||
|
||||
template <typename F, size_t M, size_t N>
|
||||
class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
{
|
||||
public:
|
||||
using value_type = F;
|
||||
|
||||
static constexpr size_t kSize = M * N;
|
||||
|
||||
template <typename M2>
|
||||
matrix_fixed(const M2 &m)
|
||||
{
|
||||
assert(M == m.dim_m() and N == m.dim_n());
|
||||
for (uint32_t i = 0; i < M; ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < N; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
matrix_fixed(value_type v = 0)
|
||||
{
|
||||
m_data.fill(v);
|
||||
}
|
||||
|
||||
matrix_fixed(const F (&v)[kSize])
|
||||
{
|
||||
fill(v, std::make_index_sequence<kSize>{});
|
||||
}
|
||||
|
||||
matrix_fixed(matrix_fixed &&m) = default;
|
||||
matrix_fixed(const matrix_fixed &m) = default;
|
||||
matrix_fixed &operator=(matrix_fixed &&m) = default;
|
||||
matrix_fixed &operator=(const matrix_fixed &m) = default;
|
||||
|
||||
template<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; }
|
||||
constexpr size_t dim_n() const { return N; }
|
||||
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
return m_data[i * N + j];
|
||||
}
|
||||
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
return m_data[i * N + j];
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<value_type, M * N> m_data;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
using matrix3x3 = matrix_fixed<F, 3, 3>;
|
||||
|
||||
template <typename F>
|
||||
using matrix4x4 = matrix_fixed<F, 4, 4>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename F = float>
|
||||
class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
{
|
||||
public:
|
||||
using value_type = F;
|
||||
|
||||
symmetric_matrix(uint32_t n, value_type v = 0)
|
||||
: m_n(n)
|
||||
, m_data((m_n * (m_n + 1)) / 2)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
symmetric_matrix() = default;
|
||||
symmetric_matrix(symmetric_matrix &&m) = default;
|
||||
symmetric_matrix(const symmetric_matrix &m) = default;
|
||||
symmetric_matrix &operator=(symmetric_matrix &&m) = default;
|
||||
symmetric_matrix &operator=(const symmetric_matrix &m) = default;
|
||||
|
||||
constexpr uint32_t dim_m() const { return m_n; }
|
||||
constexpr uint32_t dim_n() const { return m_n; }
|
||||
|
||||
constexpr value_type operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
: m_data[(i * (i + 1)) / 2 + j];
|
||||
}
|
||||
|
||||
constexpr value_type &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
assert(j < m_n);
|
||||
return m_data[(j * (j + 1)) / 2 + i];
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename F, size_t M>
|
||||
class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F, M>>
|
||||
{
|
||||
public:
|
||||
using value_type = F;
|
||||
|
||||
symmetric_matrix_fixed(value_type v = 0)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
symmetric_matrix_fixed(symmetric_matrix_fixed &&m) = default;
|
||||
symmetric_matrix_fixed(const symmetric_matrix_fixed &m) = default;
|
||||
symmetric_matrix_fixed &operator=(symmetric_matrix_fixed &&m) = default;
|
||||
symmetric_matrix_fixed &operator=(const symmetric_matrix_fixed &m) = default;
|
||||
|
||||
constexpr uint32_t dim_m() const { return M; }
|
||||
constexpr uint32_t dim_n() const { return M; }
|
||||
|
||||
constexpr value_type operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
: m_data[(i * (i + 1)) / 2 + j];
|
||||
}
|
||||
|
||||
constexpr value_type &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
assert(j < M);
|
||||
return m_data[(j * (j + 1)) / 2 + i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<value_type, (M * (M + 1)) / 2> m_data;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
using symmetric_matrix3x3 = symmetric_matrix_fixed<F, 3>;
|
||||
|
||||
template <typename F>
|
||||
using symmetric_matrix4x4 = symmetric_matrix_fixed<F, 4>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename F = float>
|
||||
class identity_matrix : public matrix_expression<identity_matrix<F>>
|
||||
{
|
||||
public:
|
||||
using value_type = F;
|
||||
|
||||
identity_matrix(uint32_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr uint32_t dim_m() const { return m_n; }
|
||||
constexpr uint32_t dim_n() const { return m_n; }
|
||||
|
||||
constexpr value_type operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i == j ? 1 : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// matrix functions, implemented as expression templates
|
||||
|
||||
template <typename M1, typename M2>
|
||||
class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
|
||||
{
|
||||
public:
|
||||
matrix_subtraction(const M1 &m1, const M2 &m2)
|
||||
: m_m1(m1)
|
||||
, m_m2(m2)
|
||||
{
|
||||
assert(m_m1.dim_m() == m_m2.dim_m());
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
constexpr uint32_t dim_m() const { return m_m1.dim_m(); }
|
||||
constexpr uint32_t dim_n() const { return m_m1.dim_n(); }
|
||||
|
||||
constexpr auto operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M1 &m_m1;
|
||||
const M2 &m_m2;
|
||||
};
|
||||
|
||||
template <typename M1, typename M2>
|
||||
auto operator-(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
|
||||
{
|
||||
return matrix_subtraction(m1, m2);
|
||||
}
|
||||
|
||||
template <typename M1, typename M2>
|
||||
class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_multiplication<M1, M2>>
|
||||
{
|
||||
public:
|
||||
matrix_matrix_multiplication(const M1 &m1, const M2 &m2)
|
||||
: m_m1(m1)
|
||||
, m_m2(m2)
|
||||
{
|
||||
assert(m1.dim_m() == m2.dim_n());
|
||||
}
|
||||
|
||||
constexpr uint32_t dim_m() const { return m_m1.dim_m(); }
|
||||
constexpr uint32_t dim_n() const { return m_m1.dim_n(); }
|
||||
|
||||
constexpr auto operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
using value_type = decltype(m_m1(0, 0));
|
||||
|
||||
value_type result = {};
|
||||
|
||||
for (uint32_t k = 0; k < m_m1.dim_m(); ++k)
|
||||
result += m_m1(i, k) * m_m2(k, j);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const M1 &m_m1;
|
||||
const M2 &m_m2;
|
||||
};
|
||||
|
||||
template <typename M, typename T>
|
||||
class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_multiplication<M, T>>
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
matrix_scalar_multiplication(const M &m, value_type v)
|
||||
: m_m(m)
|
||||
, m_v(v)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr uint32_t dim_m() const { return m_m.dim_m(); }
|
||||
constexpr uint32_t dim_n() const { return m_m.dim_n(); }
|
||||
|
||||
constexpr auto operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
value_type m_v;
|
||||
};
|
||||
|
||||
template <typename M1, typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
auto operator*(const matrix_expression<M1> &m, T v)
|
||||
{
|
||||
return matrix_scalar_multiplication(m, v);
|
||||
}
|
||||
|
||||
template <typename M1, typename M2, std::enable_if_t<not std::is_floating_point_v<M2>, int> = 0>
|
||||
auto operator*(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
|
||||
{
|
||||
return matrix_matrix_multiplication(m1, m2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename M>
|
||||
auto determinant(const M &m);
|
||||
|
||||
template <typename F = float>
|
||||
auto determinant(const matrix3x3<F> &m)
|
||||
{
|
||||
return (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
|
||||
m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
|
||||
m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
M inverse(const M &m);
|
||||
|
||||
template <typename F = float>
|
||||
matrix3x3<F> inverse(const matrix3x3<F> &m)
|
||||
{
|
||||
F det = determinant(m);
|
||||
|
||||
matrix3x3<F> result;
|
||||
|
||||
result(0, 0) = (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) / det;
|
||||
result(1, 0) = (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) / det;
|
||||
result(2, 0) = (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)) / det;
|
||||
result(0, 1) = (m(2, 1) * m(0, 2) - m(2, 2) * m(0, 1)) / det;
|
||||
result(1, 1) = (m(2, 2) * m(0, 0) - m(2, 0) * m(0, 2)) / det;
|
||||
result(2, 1) = (m(2, 0) * m(0, 1) - m(2, 1) * m(0, 0)) / det;
|
||||
result(0, 2) = (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) / det;
|
||||
result(1, 2) = (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) / det;
|
||||
result(2, 2) = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) / det;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename M>
|
||||
class matrix_cofactors : public matrix_expression<matrix_cofactors<M>>
|
||||
{
|
||||
public:
|
||||
matrix_cofactors(const M &m)
|
||||
: m_m(m)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr uint32_t dim_m() const { return m_m.dim_m(); }
|
||||
constexpr uint32_t dim_n() const { return m_m.dim_n(); }
|
||||
|
||||
constexpr auto operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
const 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];
|
||||
|
||||
auto result =
|
||||
m_m(ix[0], iy[0]) * m_m(ix[1], iy[1]) * m_m(ix[2], iy[2]) +
|
||||
m_m(ix[0], iy[1]) * m_m(ix[1], iy[2]) * m_m(ix[2], iy[0]) +
|
||||
m_m(ix[0], iy[2]) * m_m(ix[1], iy[0]) * m_m(ix[2], iy[1]) -
|
||||
m_m(ix[0], iy[2]) * m_m(ix[1], iy[1]) * m_m(ix[2], iy[0]) -
|
||||
m_m(ix[0], iy[1]) * m_m(ix[1], iy[0]) * m_m(ix[2], iy[2]) -
|
||||
m_m(ix[0], iy[0]) * m_m(ix[1], iy[2]) * m_m(ix[2], iy[1]);
|
||||
|
||||
return (i + j) % 2 == 1 ? -result : result;
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <numeric>
|
||||
#include "cif++/atom_type.hpp"
|
||||
|
||||
#include <cif++/atom_type.hpp>
|
||||
#include <numeric>
|
||||
|
||||
#if __cpp_lib_format
|
||||
#include <format>
|
||||
@@ -50,7 +50,7 @@ class atom
|
||||
private:
|
||||
struct atom_impl : public std::enable_shared_from_this<atom_impl>
|
||||
{
|
||||
atom_impl(datablock &db, std::string_view id)
|
||||
atom_impl(const datablock &db, std::string_view id)
|
||||
: m_db(db)
|
||||
, m_cat(db["atom_site"])
|
||||
, m_id(id)
|
||||
@@ -101,17 +101,17 @@ class atom
|
||||
row_handle row_aniso()
|
||||
{
|
||||
auto cat = m_db.get("atom_site_anisotrop");
|
||||
return cat ? cat->find1(key("id") == m_id) : row_handle{};
|
||||
return cat ? cat->operator[]({ {"id", m_id} }) : row_handle{};
|
||||
}
|
||||
|
||||
const row_handle row_aniso() const
|
||||
{
|
||||
auto cat = m_db.get("atom_site_anisotrop");
|
||||
return cat ? cat->find1(key("id") == m_id) : row_handle{};
|
||||
return cat ? cat->operator[]({ {"id", m_id} }) : row_handle{};
|
||||
}
|
||||
|
||||
const datablock &m_db;
|
||||
category &m_cat;
|
||||
const category &m_cat;
|
||||
std::string m_id;
|
||||
point m_location;
|
||||
std::string m_symop = "1_555";
|
||||
@@ -130,7 +130,7 @@ class atom
|
||||
{
|
||||
}
|
||||
|
||||
atom(datablock &db, row_handle &row)
|
||||
atom(const datablock &db, const row_handle &row)
|
||||
: atom(std::make_shared<atom_impl>(db, row["id"].as<std::string>()))
|
||||
{
|
||||
}
|
||||
@@ -216,6 +216,14 @@ class atom
|
||||
set_location(loc);
|
||||
}
|
||||
|
||||
/// \brief rotate the coordinates of this atom by \a q around point \a p
|
||||
void rotate(quaternion q, point p)
|
||||
{
|
||||
auto loc = get_location();
|
||||
loc.rotate(q, p);
|
||||
set_location(loc);
|
||||
}
|
||||
|
||||
/// \brief Translate and rotate the position of this atom by \a t and \a q
|
||||
void translate_and_rotate(point t, quaternion q)
|
||||
{
|
||||
@@ -321,13 +329,6 @@ class atom
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const atom &atom);
|
||||
|
||||
// /// \brief Synchronize data with underlying cif data
|
||||
// void sync()
|
||||
// {
|
||||
// if (m_impl)
|
||||
// m_impl->prefetch();
|
||||
// }
|
||||
|
||||
private:
|
||||
friend class structure;
|
||||
|
||||
@@ -341,25 +342,6 @@ class atom
|
||||
std::shared_ptr<atom_impl> m_impl;
|
||||
};
|
||||
|
||||
// template <>
|
||||
// inline std::string atom::get_property<std::string>(const std::string_view name) const
|
||||
// {
|
||||
// return get_property(name);
|
||||
// }
|
||||
|
||||
// template <>
|
||||
// inline int atom::get_property<int>(const std::string_view name) const
|
||||
// {
|
||||
// auto v = impl().get_property(name);
|
||||
// return v.empty() ? 0 : stoi(v);
|
||||
// }
|
||||
|
||||
// template <>
|
||||
// inline float atom::get_property<float>(const std::string_view name) const
|
||||
// {
|
||||
// return stof(impl().get_property(name));
|
||||
// }
|
||||
|
||||
inline void swap(atom &a, atom &b)
|
||||
{
|
||||
a.swap(b);
|
||||
@@ -394,7 +376,7 @@ class residue
|
||||
friend class structure;
|
||||
|
||||
// constructor
|
||||
residue(const structure &structure, const std::string &compoundID,
|
||||
residue(structure &structure, const std::string &compoundID,
|
||||
const std::string &asymID, int seqID,
|
||||
const std::string &authAsymID, const std::string &authSeqID,
|
||||
const std::string &pdbInsCode)
|
||||
@@ -408,6 +390,8 @@ class residue
|
||||
{
|
||||
}
|
||||
|
||||
residue(structure &structure, const std::vector<atom> &atoms);
|
||||
|
||||
residue(const residue &rhs) = delete;
|
||||
residue &operator=(const residue &rhs) = delete;
|
||||
|
||||
@@ -430,7 +414,7 @@ class residue
|
||||
const std::string &get_compound_id() const { return m_compound_id; }
|
||||
void set_compound_id(const std::string &id) { m_compound_id = id; }
|
||||
|
||||
const structure *get_structure() const { return m_structure; }
|
||||
structure *get_structure() const { return m_structure; }
|
||||
|
||||
// const compound &compound() const;
|
||||
|
||||
@@ -487,7 +471,7 @@ class residue
|
||||
protected:
|
||||
residue() {}
|
||||
|
||||
const structure *m_structure = nullptr;
|
||||
structure *m_structure = nullptr;
|
||||
std::string m_compound_id, m_asym_id;
|
||||
int m_seq_id = 0;
|
||||
std::string m_auth_asym_id, m_auth_seq_id, m_pdb_ins_code;
|
||||
@@ -571,7 +555,7 @@ class monomer : public residue
|
||||
class polymer : public std::vector<monomer>
|
||||
{
|
||||
public:
|
||||
polymer(const structure &s, const std::string &entityID, const std::string &asymID, const std::string &auth_asym_id);
|
||||
polymer(structure &s, const std::string &entityID, const std::string &asymID, const std::string &auth_asym_id);
|
||||
|
||||
polymer(const polymer &) = delete;
|
||||
polymer &operator=(const polymer &) = delete;
|
||||
@@ -579,7 +563,7 @@ class polymer : public std::vector<monomer>
|
||||
// monomer &getBySeqID(int seqID);
|
||||
// const monomer &getBySeqID(int seqID) const;
|
||||
|
||||
const structure *get_structure() const { return m_structure; }
|
||||
structure *get_structure() const { return m_structure; }
|
||||
|
||||
std::string get_asym_id() const { return m_asym_id; }
|
||||
std::string get_auth_asym_id() const { return m_auth_asym_id; } // The PDB chain ID, actually
|
||||
@@ -588,7 +572,7 @@ class polymer : public std::vector<monomer>
|
||||
// int Distance(const monomer &a, const monomer &b) const;
|
||||
|
||||
private:
|
||||
const structure *m_structure;
|
||||
structure *m_structure;
|
||||
std::string m_entity_id;
|
||||
std::string m_asym_id;
|
||||
std::string m_auth_asym_id;
|
||||
@@ -602,7 +586,7 @@ class branch;
|
||||
class sugar : public residue
|
||||
{
|
||||
public:
|
||||
sugar(const branch &branch, const std::string &compoundID,
|
||||
sugar(branch &branch, const std::string &compoundID,
|
||||
const std::string &asymID, int authSeqID);
|
||||
|
||||
sugar(sugar &&rhs);
|
||||
@@ -629,27 +613,44 @@ class sugar : public residue
|
||||
return result;
|
||||
}
|
||||
|
||||
cif::mm::atom add_atom(row_initializer atom_info);
|
||||
|
||||
private:
|
||||
const branch *m_branch;
|
||||
branch *m_branch;
|
||||
atom m_link;
|
||||
};
|
||||
|
||||
class branch : public std::vector<sugar>
|
||||
{
|
||||
public:
|
||||
branch(structure &structure, const std::string &asymID);
|
||||
branch(structure &structure, const std::string &asym_id, const std::string &entity_id);
|
||||
|
||||
branch(const branch &) = delete;
|
||||
branch &operator=(const branch &) = delete;
|
||||
|
||||
branch(branch &&) = default;
|
||||
branch &operator=(branch &&) = default;
|
||||
|
||||
void link_atoms();
|
||||
|
||||
std::string name() const;
|
||||
float weight() const;
|
||||
std::string get_asym_id() const { return m_asym_id; }
|
||||
std::string get_entity_id() const { return m_entity_id; }
|
||||
|
||||
structure &get_structure() { return *m_structure; }
|
||||
const structure &get_structure() const { return *m_structure; }
|
||||
structure &get_structure() const { return *m_structure; }
|
||||
|
||||
sugar &getSugarByNum(int nr);
|
||||
const sugar &getSugarByNum(int nr) const;
|
||||
sugar &get_sugar_by_num(int nr);
|
||||
|
||||
const sugar &get_sugar_by_num(int nr) const
|
||||
{
|
||||
return const_cast<branch *>(this)->get_sugar_by_num(nr);
|
||||
}
|
||||
|
||||
sugar &construct_sugar(const std::string &compound_id);
|
||||
sugar &construct_sugar(const std::string &compound_id, const std::string &atom_id,
|
||||
int linked_sugar_nr, const std::string &linked_atom_id);
|
||||
|
||||
private:
|
||||
friend sugar;
|
||||
@@ -657,40 +658,9 @@ class branch : public std::vector<sugar>
|
||||
std::string name(const sugar &s) const;
|
||||
|
||||
structure *m_structure;
|
||||
std::string m_asym_id;
|
||||
std::string m_asym_id, m_entity_id;
|
||||
};
|
||||
|
||||
// // --------------------------------------------------------------------
|
||||
// // file is a reference to the data stored in e.g. the cif file.
|
||||
// // This object is not copyable.
|
||||
|
||||
// class File : public file
|
||||
// {
|
||||
// public:
|
||||
// File() {}
|
||||
|
||||
// // File(const std::filesystem::path &path)
|
||||
// // {
|
||||
// // load(path);
|
||||
// // }
|
||||
|
||||
// // File(const char *data, size_t length)
|
||||
// // {
|
||||
// // load(data, length);
|
||||
// // }
|
||||
|
||||
// File(const File &) = delete;
|
||||
// File &operator=(const File &) = delete;
|
||||
|
||||
// // void load(const std::filesystem::path &p) override;
|
||||
// // void save(const std::filesystem::path &p) override;
|
||||
|
||||
// // using file::load;
|
||||
// // using file::save;
|
||||
|
||||
// datablock &data() { return front(); }
|
||||
// };
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
enum class StructureOpenOptions
|
||||
@@ -698,7 +668,7 @@ enum class StructureOpenOptions
|
||||
SkipHydrogen = 1 << 0
|
||||
};
|
||||
|
||||
inline bool operator&(StructureOpenOptions a, StructureOpenOptions b)
|
||||
constexpr inline bool operator&(StructureOpenOptions a, StructureOpenOptions b)
|
||||
{
|
||||
return static_cast<int>(a) bitand static_cast<int>(b);
|
||||
}
|
||||
@@ -751,6 +721,7 @@ class structure
|
||||
|
||||
const std::vector<residue> &non_polymers() const { return m_non_polymers; }
|
||||
|
||||
bool has_atom_id(const std::string &id) const;
|
||||
atom get_atom_by_id(const std::string &id) const;
|
||||
// atom getAtomByLocation(point pt, float maxDistance) const;
|
||||
|
||||
@@ -763,6 +734,9 @@ class structure
|
||||
/// \brief Return the atom closest to point \a p with atom type \a type in a residue of type \a res_type
|
||||
atom get_atom_by_position_and_type(point p, std::string_view type, std::string_view res_type) const;
|
||||
|
||||
/// \brief Create a non-poly residue based on atoms already present in this structure.
|
||||
residue &create_residue(const std::vector<atom> &atoms);
|
||||
|
||||
/// \brief Get a non-poly residue for an asym with id \a asymID
|
||||
residue &get_residue(const std::string &asymID)
|
||||
{
|
||||
@@ -820,10 +794,7 @@ class structure
|
||||
///
|
||||
/// \param asym_id The asym ID
|
||||
/// \param seq_id The sequence ID
|
||||
void remove_residue(const std::string &asym_id, int seq_id, const std::string &auth_seq_id)
|
||||
{
|
||||
remove_residue(get_residue(asym_id, seq_id, auth_seq_id));
|
||||
}
|
||||
void remove_residue(const std::string &asym_id, int seq_id, const std::string &auth_seq_id);
|
||||
|
||||
/// \brief Create a new non-polymer entity, returns new ID
|
||||
/// \param mon_id The mon_id for the new nonpoly, must be an existing and known compound from CCD
|
||||
@@ -846,6 +817,15 @@ class structure
|
||||
/// \return The newly create asym ID
|
||||
std::string create_non_poly(const std::string &entity_id, std::vector<row_initializer> atoms);
|
||||
|
||||
/// \brief Create a new water with atom constructed from info in \a atom_info
|
||||
/// This method creates a new atom record filled with info from the info.
|
||||
///
|
||||
/// \param atom The set of item data containing the data for the atoms.
|
||||
void create_water(row_initializer atom);
|
||||
|
||||
/// \brief Create a new and empty (sugar) branch
|
||||
branch &create_branch();
|
||||
|
||||
/// \brief Create a new (sugar) branch with one first NAG containing atoms constructed from \a atoms
|
||||
branch &create_branch(std::vector<row_initializer> atoms);
|
||||
|
||||
@@ -893,6 +873,18 @@ class structure
|
||||
|
||||
void validate_atoms() const;
|
||||
|
||||
// TODO: make this protected?
|
||||
|
||||
void load_atoms_for_model(StructureOpenOptions options);
|
||||
|
||||
template <typename... Args>
|
||||
atom &emplace_atom(Args&... args)
|
||||
{
|
||||
return emplace_atom(atom{ std::forward<Args>(args)... });
|
||||
}
|
||||
|
||||
atom &emplace_atom(atom &&atom);
|
||||
|
||||
private:
|
||||
friend polymer;
|
||||
friend residue;
|
||||
@@ -903,16 +895,6 @@ class structure
|
||||
|
||||
void load_data();
|
||||
|
||||
void load_atoms_for_model(StructureOpenOptions options);
|
||||
|
||||
template <typename... Args>
|
||||
atom &emplace_atom(Args... args)
|
||||
{
|
||||
return emplace_atom(atom{ std::forward<Args>(args)... });
|
||||
}
|
||||
|
||||
atom &emplace_atom(atom &&atom);
|
||||
|
||||
void remove_atom(atom &a, bool removeFromResidue);
|
||||
void remove_sugar(sugar &sugar);
|
||||
|
||||
@@ -925,4 +907,11 @@ class structure
|
||||
std::vector<residue> m_non_polymers;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
/// Some people believe that simply dumping some atom records is enough.
|
||||
/// \param db The cif::datablock that hopefully contains some valid data
|
||||
void reconstruct_pdbx(datablock &db);
|
||||
|
||||
} // namespace cif::mm
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <cif++/row.hpp>
|
||||
#include <map>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -53,8 +53,6 @@ class sac_parser
|
||||
public:
|
||||
using datablock_index = std::map<std::string, std::size_t>;
|
||||
|
||||
sac_parser(std::istream &is, bool init = true);
|
||||
|
||||
virtual ~sac_parser() = default;
|
||||
|
||||
enum CharTraitsMask : uint8_t
|
||||
@@ -65,9 +63,14 @@ class sac_parser
|
||||
kAnyPrintMask = 1 << 3
|
||||
};
|
||||
|
||||
static bool is_white(int ch)
|
||||
static constexpr bool is_space(int ch)
|
||||
{
|
||||
return std::isspace(ch) or ch == '#';
|
||||
return ch == ' ' or ch == '\t' or ch == '\r' or ch == '\n';
|
||||
}
|
||||
|
||||
static constexpr bool is_white(int ch)
|
||||
{
|
||||
return is_space(ch) or ch == '#';
|
||||
}
|
||||
|
||||
static constexpr bool is_ordinary(int ch)
|
||||
@@ -91,26 +94,7 @@ class sac_parser
|
||||
(ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kAnyPrintMask) != 0);
|
||||
}
|
||||
|
||||
static bool is_unquoted_string(std::string_view text)
|
||||
{
|
||||
auto s = text.begin();
|
||||
|
||||
bool result = is_ordinary(*s++);
|
||||
while (result and s != text.end())
|
||||
{
|
||||
result = is_non_blank(*s);
|
||||
++s;
|
||||
}
|
||||
|
||||
// but be careful it does not contain e.g. stop_
|
||||
if (result)
|
||||
{
|
||||
static const std::regex reservedRx(R"((^(?:data|save)|.*(?:loop|stop|global))_.+)", std::regex_constants::icase);
|
||||
result = not std::regex_match(text.begin(), text.end(), reservedRx);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
static bool is_unquoted_string(std::string_view text);
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t kCharTraitsTable[128] = {
|
||||
@@ -132,7 +116,8 @@ class sac_parser
|
||||
DATA,
|
||||
LOOP,
|
||||
GLOBAL,
|
||||
SAVE,
|
||||
SAVE_,
|
||||
SAVE_NAME,
|
||||
STOP,
|
||||
Tag,
|
||||
Value
|
||||
@@ -147,7 +132,8 @@ class sac_parser
|
||||
case CIFToken::DATA: return "DATA";
|
||||
case CIFToken::LOOP: return "LOOP";
|
||||
case CIFToken::GLOBAL: return "GLOBAL";
|
||||
case CIFToken::SAVE: return "SAVE";
|
||||
case CIFToken::SAVE_: return "SAVE";
|
||||
case CIFToken::SAVE_NAME: return "SAVE+name";
|
||||
case CIFToken::STOP: return "STOP";
|
||||
case CIFToken::Tag: return "Tag";
|
||||
case CIFToken::Value: return "Value";
|
||||
@@ -155,41 +141,13 @@ class sac_parser
|
||||
}
|
||||
}
|
||||
|
||||
enum class CIFValue
|
||||
{
|
||||
Int,
|
||||
Float,
|
||||
Numeric,
|
||||
String,
|
||||
TextField,
|
||||
Inapplicable,
|
||||
Unknown
|
||||
};
|
||||
|
||||
static constexpr const char *get_value_name(CIFValue type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CIFValue::Int: return "Int";
|
||||
case CIFValue::Float: return "Float";
|
||||
case CIFValue::Numeric: return "Numeric";
|
||||
case CIFValue::String: return "String";
|
||||
case CIFValue::TextField: return "TextField";
|
||||
case CIFValue::Inapplicable: return "Inapplicable";
|
||||
case CIFValue::Unknown: return "Unknown";
|
||||
default: return "Invalid type parameter";
|
||||
}
|
||||
}
|
||||
|
||||
// get_next_char takes a char from the buffer, or if it is empty
|
||||
// from the istream. This function also does carriage/linefeed
|
||||
// translation.
|
||||
// get_next_char takes the next character from the istream.
|
||||
// This function also does carriage/linefeed translation.
|
||||
int get_next_char();
|
||||
|
||||
// Put the last read character back into the istream
|
||||
void retract();
|
||||
|
||||
int restart(int start);
|
||||
|
||||
CIFToken get_next_token();
|
||||
|
||||
void match(CIFToken token);
|
||||
@@ -204,6 +162,9 @@ class sac_parser
|
||||
void parse_file();
|
||||
|
||||
protected:
|
||||
|
||||
sac_parser(std::istream &is, bool init = true);
|
||||
|
||||
void parse_global();
|
||||
|
||||
void parse_datablock();
|
||||
@@ -226,13 +187,14 @@ class sac_parser
|
||||
|
||||
// production methods, these are pure virtual here
|
||||
|
||||
virtual void produce_datablock(const std::string &name) = 0;
|
||||
virtual void produce_category(const std::string &name) = 0;
|
||||
virtual void produce_datablock(std::string_view name) = 0;
|
||||
virtual void produce_category(std::string_view name) = 0;
|
||||
virtual void produce_row() = 0;
|
||||
virtual void produce_item(const std::string &category, const std::string &item, const std::string &value) = 0;
|
||||
virtual void produce_item(std::string_view category, std::string_view item, std::string_view value) = 0;
|
||||
|
||||
protected:
|
||||
enum State
|
||||
|
||||
enum class State
|
||||
{
|
||||
Start,
|
||||
White,
|
||||
@@ -245,23 +207,21 @@ class sac_parser
|
||||
UnquotedString,
|
||||
Tag,
|
||||
TextField,
|
||||
Float = 100,
|
||||
Int = 110,
|
||||
Value = 300,
|
||||
DATA,
|
||||
SAVE
|
||||
TextFieldNL,
|
||||
Reserved,
|
||||
Value
|
||||
};
|
||||
|
||||
std::streambuf &m_source;
|
||||
|
||||
// Parser state
|
||||
bool m_validate;
|
||||
uint32_t m_line_nr;
|
||||
bool m_bol;
|
||||
CIFToken m_lookahead;
|
||||
std::string m_token_value;
|
||||
CIFValue mTokenType;
|
||||
std::vector<int> m_buffer; // retract buffer, used to be a stack<char>
|
||||
|
||||
// token buffer
|
||||
std::vector<char> m_token_buffer;
|
||||
std::string_view m_token_value;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -275,13 +235,13 @@ class parser : public sac_parser
|
||||
{
|
||||
}
|
||||
|
||||
void produce_datablock(const std::string &name) override;
|
||||
void produce_datablock(std::string_view name) override;
|
||||
|
||||
void produce_category(const std::string &name) override;
|
||||
void produce_category(std::string_view name) override;
|
||||
|
||||
void produce_row() override;
|
||||
|
||||
void produce_item(const std::string &category, const std::string &item, const std::string &value) override;
|
||||
void produce_item(std::string_view category, std::string_view item, std::string_view value) override;
|
||||
|
||||
protected:
|
||||
file &m_file;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include "cif++/datablock.hpp"
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include "cif++/datablock.hpp"
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include "cif++/file.hpp"
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++/pdb/pdb2cif.hpp>
|
||||
#include "pdb2cif.hpp"
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -26,19 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/datablock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
extern const int
|
||||
kResidueNrWildcard,
|
||||
kNoSeqNum;
|
||||
|
||||
struct tls_selection;
|
||||
struct tls_residue;
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <functional>
|
||||
@@ -54,7 +57,7 @@ class quaternion_type
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
constexpr explicit quaternion_type(value_type const &value_a = value_type(), value_type const &value_b = value_type(), value_type const &value_c = value_type(), value_type const &value_d = value_type())
|
||||
constexpr explicit quaternion_type(value_type const &value_a = {}, value_type const &value_b = {}, value_type const &value_c = {}, value_type const &value_d = {})
|
||||
: a(value_a)
|
||||
, b(value_b)
|
||||
, c(value_c)
|
||||
@@ -305,6 +308,21 @@ class quaternion_type
|
||||
constexpr value_type get_c() const { return c; }
|
||||
constexpr value_type get_d() const { return d; }
|
||||
|
||||
constexpr bool operator==(const quaternion_type &rhs) const
|
||||
{
|
||||
return a == rhs.a and b == rhs.b and c == rhs.c and d == rhs.d;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const quaternion_type &rhs) const
|
||||
{
|
||||
return a != rhs.a or b != rhs.b or c != rhs.c or d != rhs.d;
|
||||
}
|
||||
|
||||
constexpr operator bool() const
|
||||
{
|
||||
return a != 0 or b != 0 or c != 0 or d != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type a, b, c, d;
|
||||
};
|
||||
@@ -483,6 +501,13 @@ struct point_type
|
||||
m_z = p.get_d();
|
||||
}
|
||||
|
||||
constexpr void rotate(const quaternion &q, point_type pivot)
|
||||
{
|
||||
operator-=(pivot);
|
||||
rotate(q);
|
||||
operator+=(pivot);
|
||||
}
|
||||
|
||||
#if HAVE_LIBCLIPPER
|
||||
operator clipper::Coord_orth() const
|
||||
{
|
||||
@@ -665,6 +690,12 @@ point nudge(point p, float offset);
|
||||
quaternion construct_from_angle_axis(float angle, point axis);
|
||||
std::tuple<double, point> quaternion_to_angle_axis(quaternion q);
|
||||
|
||||
/// @brief Given four points and an angle, return the quaternion required to rotate
|
||||
/// point p4 along the p2-p3 axis and around point p3 to obtain the required within
|
||||
/// an accuracy of esd
|
||||
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
|
||||
float angle, float esd);
|
||||
|
||||
point centroid(const std::vector<point> &Points);
|
||||
point center_points(std::vector<point> &Points);
|
||||
|
||||
@@ -687,7 +718,6 @@ template <int N>
|
||||
class spherical_dots
|
||||
{
|
||||
public:
|
||||
|
||||
constexpr static int P = 2 * N * 1;
|
||||
|
||||
using array_type = typename std::array<point, P>;
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cif++/item.hpp>
|
||||
#include "cif++/item.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -110,12 +112,12 @@ class row : public std::vector<item_value>
|
||||
|
||||
item_value* get(uint16_t ix)
|
||||
{
|
||||
return ix < size() ? &at(ix) : nullptr;
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
const item_value* get(uint16_t ix) const
|
||||
{
|
||||
return ix < size() ? &at(ix) : nullptr;
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -208,14 +210,14 @@ class row_handle
|
||||
return detail::get_row_result<C...>(*this, { get_column_ix(columns)... });
|
||||
}
|
||||
|
||||
template <typename... Ts, typename... C, std::enable_if_t<sizeof...(Ts) == sizeof...(C), int> = 0>
|
||||
template <typename... Ts, typename... C, std::enable_if_t<sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1, int> = 0>
|
||||
std::tuple<Ts...> get(C... columns) const
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_column_ix(columns)... });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get(const char *column)
|
||||
T get(const char *column) const
|
||||
{
|
||||
return operator[](get_column_ix(column)).template as<T>();
|
||||
}
|
||||
|
||||
@@ -26,15 +26,34 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/matrix.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
/// \file cif++/symmetry.hpp
|
||||
/// This file contains code to do symmetry operations based on the
|
||||
/// operations as specified in the International Tables.
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
inline point operator*(const matrix3x3<float> &m, const point &pt)
|
||||
{
|
||||
return {
|
||||
m(0, 0) * pt.m_x + m(0, 1) * pt.m_y + m(0, 2) * pt.m_z,
|
||||
m(1, 0) * pt.m_x + m(1, 1) * pt.m_y + m(1, 2) * pt.m_z,
|
||||
m(2, 0) * pt.m_x + m(2, 1) * pt.m_y + m(2, 2) * pt.m_z
|
||||
};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
enum class space_group_name
|
||||
{
|
||||
full,
|
||||
@@ -50,29 +69,29 @@ struct space_group
|
||||
int nr;
|
||||
};
|
||||
|
||||
extern const space_group kSpaceGroups[];
|
||||
extern const std::size_t kNrOfSpaceGroups;
|
||||
extern CIFPP_EXPORT const space_group kSpaceGroups[];
|
||||
extern CIFPP_EXPORT const std::size_t kNrOfSpaceGroups;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
struct symop_data
|
||||
{
|
||||
constexpr symop_data(const std::array<int, 15> &data)
|
||||
: m_packed((data[0] & 0x03ULL) << 34 bitor
|
||||
(data[1] & 0x03ULL) << 32 bitor
|
||||
(data[2] & 0x03ULL) << 30 bitor
|
||||
(data[3] & 0x03ULL) << 28 bitor
|
||||
(data[4] & 0x03ULL) << 26 bitor
|
||||
(data[5] & 0x03ULL) << 24 bitor
|
||||
(data[6] & 0x03ULL) << 22 bitor
|
||||
(data[7] & 0x03ULL) << 20 bitor
|
||||
(data[8] & 0x03ULL) << 18 bitor
|
||||
(data[9] & 0x07ULL) << 15 bitor
|
||||
(data[10] & 0x07ULL) << 12 bitor
|
||||
(data[11] & 0x07ULL) << 9 bitor
|
||||
(data[12] & 0x07ULL) << 6 bitor
|
||||
(data[13] & 0x07ULL) << 3 bitor
|
||||
(data[14] & 0x07ULL) << 0)
|
||||
: m_packed((data[0] bitand 0x03ULL) << 34 bitor
|
||||
(data[1] bitand 0x03ULL) << 32 bitor
|
||||
(data[2] bitand 0x03ULL) << 30 bitor
|
||||
(data[3] bitand 0x03ULL) << 28 bitor
|
||||
(data[4] bitand 0x03ULL) << 26 bitor
|
||||
(data[5] bitand 0x03ULL) << 24 bitor
|
||||
(data[6] bitand 0x03ULL) << 22 bitor
|
||||
(data[7] bitand 0x03ULL) << 20 bitor
|
||||
(data[8] bitand 0x03ULL) << 18 bitor
|
||||
(data[9] bitand 0x07ULL) << 15 bitor
|
||||
(data[10] bitand 0x07ULL) << 12 bitor
|
||||
(data[11] bitand 0x07ULL) << 9 bitor
|
||||
(data[12] bitand 0x07ULL) << 6 bitor
|
||||
(data[13] bitand 0x07ULL) << 3 bitor
|
||||
(data[14] bitand 0x07ULL) << 0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,24 +105,35 @@ struct symop_data
|
||||
return m_packed < rhs.m_packed;
|
||||
}
|
||||
|
||||
std::array<int, 15> data() const
|
||||
inline constexpr int unpack3(int offset) const
|
||||
{
|
||||
int result = (m_packed >> offset) bitand 0x03;
|
||||
return result == 3 ? -1 : result;
|
||||
}
|
||||
|
||||
inline constexpr int unpack7(int offset) const
|
||||
{
|
||||
return (m_packed >> offset) bitand 0x07;
|
||||
}
|
||||
|
||||
constexpr std::array<int, 15> data() const
|
||||
{
|
||||
return {
|
||||
static_cast<int>(m_packed >> 34) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 32) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 30) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 28) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 26) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 24) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 22) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 20) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 18) bitand 0x03,
|
||||
static_cast<int>(m_packed >> 15) bitand 0x07,
|
||||
static_cast<int>(m_packed >> 12) bitand 0x07,
|
||||
static_cast<int>(m_packed >> 9) bitand 0x07,
|
||||
static_cast<int>(m_packed >> 6) bitand 0x07,
|
||||
static_cast<int>(m_packed >> 3) bitand 0x07,
|
||||
static_cast<int>(m_packed >> 0) bitand 0x07,
|
||||
unpack3(34),
|
||||
unpack3(32),
|
||||
unpack3(30),
|
||||
unpack3(28),
|
||||
unpack3(26),
|
||||
unpack3(24),
|
||||
unpack3(22),
|
||||
unpack3(20),
|
||||
unpack3(18),
|
||||
unpack7(15),
|
||||
unpack7(12),
|
||||
unpack7(9),
|
||||
unpack7(6),
|
||||
unpack7(3),
|
||||
unpack7(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,8 +153,8 @@ struct symop_data
|
||||
struct symop_datablock
|
||||
{
|
||||
constexpr symop_datablock(int spacegroup, int rotational_number, const std::array<int, 15> &rt_data)
|
||||
: m_v((spacegroup & 0xffffULL) << 48 bitor
|
||||
(rotational_number & 0xffULL) << 40 bitor
|
||||
: m_v((spacegroup bitand 0xffffULL) << 48 bitor
|
||||
(rotational_number bitand 0xffULL) << 40 bitor
|
||||
symop_data(rt_data).m_packed)
|
||||
{
|
||||
}
|
||||
@@ -139,12 +169,250 @@ struct symop_datablock
|
||||
|
||||
static_assert(sizeof(symop_datablock) == sizeof(uint64_t), "Size of symop_data is wrong");
|
||||
|
||||
extern const symop_datablock kSymopNrTable[];
|
||||
extern const std::size_t kSymopNrTableSize;
|
||||
extern CIFPP_EXPORT const symop_datablock kSymopNrTable[];
|
||||
extern CIFPP_EXPORT const std::size_t kSymopNrTableSize;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Some more symmetry related stuff here.
|
||||
|
||||
class datablock;
|
||||
|
||||
class cell;
|
||||
class spacegroup;
|
||||
class rtop;
|
||||
class sym_op;
|
||||
|
||||
|
||||
/// @brief A class that encapsulates the symmetry operations as used in PDB files, i.e. a rotational number and a translation vector
|
||||
/// The syntax in string format follows the syntax as used in mmCIF files, i.e. rotational number followed by underscore and the
|
||||
/// three translations where 5 is no movement.
|
||||
struct sym_op
|
||||
{
|
||||
public:
|
||||
sym_op(uint8_t nr = 1, uint8_t ta = 5, uint8_t tb = 5, uint8_t tc = 5)
|
||||
: m_nr(nr)
|
||||
, m_ta(ta)
|
||||
, m_tb(tb)
|
||||
, m_tc(tc)
|
||||
{
|
||||
}
|
||||
|
||||
explicit sym_op(std::string_view s);
|
||||
|
||||
sym_op(const sym_op &) = default;
|
||||
sym_op(sym_op &&) = default;
|
||||
sym_op &operator=(const sym_op &) = default;
|
||||
sym_op &operator=(sym_op &&) = default;
|
||||
|
||||
constexpr bool is_identity() const
|
||||
{
|
||||
return m_nr == 1 and m_ta == 5 and m_tb == 5 and m_tc == 5;
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const
|
||||
{
|
||||
return not is_identity();
|
||||
}
|
||||
|
||||
std::string string() const;
|
||||
|
||||
#if defined(__cpp_impl_three_way_comparison)
|
||||
constexpr auto operator<=>(const sym_op &rhs) const = default;
|
||||
#else
|
||||
constexpr bool operator==(const sym_op &rhs) const
|
||||
{
|
||||
return m_nr == rhs.m_nr and m_ta == rhs.m_ta and m_tb == rhs.m_tb and m_tc == rhs.m_tc;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const sym_op &rhs) const
|
||||
{
|
||||
return not operator==(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t m_nr;
|
||||
uint8_t m_ta, m_tb, m_tc;
|
||||
};
|
||||
|
||||
static_assert(sizeof(sym_op) == 4, "Sym_op should be four bytes");
|
||||
|
||||
namespace literals
|
||||
{
|
||||
inline sym_op operator""_symop(const char *text, size_t length)
|
||||
{
|
||||
return sym_op({ text, length });
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// The transformation class
|
||||
|
||||
class transformation
|
||||
{
|
||||
public:
|
||||
transformation(const symop_data &data);
|
||||
transformation(const matrix3x3<float> &r, const cif::point &t);
|
||||
|
||||
transformation(const transformation &) = default;
|
||||
transformation(transformation &&) = default;
|
||||
transformation &operator=(const transformation &) = default;
|
||||
transformation &operator=(transformation &&) = default;
|
||||
|
||||
point operator()(point pt) const
|
||||
{
|
||||
if (m_q)
|
||||
pt.rotate(m_q);
|
||||
else
|
||||
pt = m_rotation * pt;
|
||||
|
||||
return pt + m_translation;
|
||||
}
|
||||
|
||||
friend transformation operator*(const transformation &lhs, const transformation &rhs);
|
||||
friend transformation inverse(const transformation &t);
|
||||
|
||||
transformation operator-() const
|
||||
{
|
||||
return inverse(*this);
|
||||
}
|
||||
|
||||
friend class spacegroup;
|
||||
|
||||
private:
|
||||
|
||||
// Most rotation matrices provided by the International Tables
|
||||
// are really rotation matrices, in those cases we can construct
|
||||
// a quaternion. Unfortunately, that doesn't work for all of them
|
||||
|
||||
void try_create_quaternion();
|
||||
|
||||
matrix3x3<float> m_rotation;
|
||||
quaternion m_q;
|
||||
point m_translation;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// class cell
|
||||
|
||||
class cell
|
||||
{
|
||||
public:
|
||||
cell(float a, float b, float c, float alpha = 90.f, float beta = 90.f, float gamma = 90.f);
|
||||
cell(const datablock &db);
|
||||
|
||||
float get_a() const { return m_a; }
|
||||
float get_b() const { return m_b; }
|
||||
float get_c() const { return m_c; }
|
||||
|
||||
float get_alpha() const { return m_alpha; }
|
||||
float get_beta() const { return m_beta; }
|
||||
float get_gamma() const { return m_gamma; }
|
||||
|
||||
matrix3x3<float> get_orthogonal_matrix() const { return m_orthogonal; }
|
||||
matrix3x3<float> get_fractional_matrix() const { return m_fractional; }
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
float m_a, m_b, m_c, m_alpha, m_beta, m_gamma;
|
||||
matrix3x3<float> m_orthogonal, m_fractional;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int get_space_group_number(std::string spacegroup); // alternative for clipper's parsing code, using space_group_name::full
|
||||
int get_space_group_number(std::string spacegroup, space_group_name type); // alternative for clipper's parsing code
|
||||
int get_space_group_number(const datablock &db);
|
||||
int get_space_group_number(std::string_view spacegroup);
|
||||
int get_space_group_number(std::string_view spacegroup, space_group_name type);
|
||||
|
||||
class spacegroup : public std::vector<transformation>
|
||||
{
|
||||
public:
|
||||
spacegroup(const datablock &db)
|
||||
: spacegroup(get_space_group_number(db))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
spacegroup(std::string_view name)
|
||||
: spacegroup(get_space_group_number(name))
|
||||
{
|
||||
}
|
||||
|
||||
spacegroup(std::string_view name, space_group_name type)
|
||||
: spacegroup(get_space_group_number(name, type))
|
||||
{
|
||||
}
|
||||
|
||||
spacegroup(int nr);
|
||||
|
||||
int get_nr() const { return m_nr; }
|
||||
std::string get_name() const;
|
||||
|
||||
point operator()(const point &pt, const cell &c, sym_op symop) const;
|
||||
|
||||
point inverse(const point &pt, const cell &c, sym_op symop) const;
|
||||
|
||||
private:
|
||||
int m_nr;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// A crystal combines a cell and a spacegroup.
|
||||
|
||||
class crystal
|
||||
{
|
||||
public:
|
||||
crystal(const datablock &db)
|
||||
: m_cell(db)
|
||||
, m_spacegroup(db)
|
||||
{
|
||||
}
|
||||
|
||||
crystal(const cell &c, const spacegroup &sg)
|
||||
: m_cell(c)
|
||||
, m_spacegroup(sg)
|
||||
{
|
||||
}
|
||||
|
||||
crystal(const crystal &) = default;
|
||||
crystal(crystal &&) = default;
|
||||
crystal &operator=(const crystal &) = default;
|
||||
crystal &operator=(crystal &&) = default;
|
||||
|
||||
const cell &get_cell() const { return m_cell; }
|
||||
const spacegroup &get_spacegroup() const { return m_spacegroup; }
|
||||
|
||||
point symmetry_copy(const point &pt, sym_op symop) const
|
||||
{
|
||||
return m_spacegroup(pt, m_cell, symop);
|
||||
}
|
||||
|
||||
point inverse_symmetry_copy(const point &pt, sym_op symop) const
|
||||
{
|
||||
return m_spacegroup.inverse(pt, m_cell, symop);
|
||||
}
|
||||
|
||||
std::tuple<float,point,sym_op> closest_symmetry_copy(point a, point b) const;
|
||||
|
||||
private:
|
||||
cell m_cell;
|
||||
spacegroup m_spacegroup;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Symmetry operations on points
|
||||
|
||||
inline point orthogonal(const point &pt, const cell &c)
|
||||
{
|
||||
return c.get_orthogonal_matrix() * pt;
|
||||
}
|
||||
|
||||
inline point fractional(const point &pt, const cell &c)
|
||||
{
|
||||
return c.get_fractional_matrix() * pt;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,78 +26,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#if __has_include(<experimental/type_traits>)
|
||||
#include <experimental/type_traits>
|
||||
#else
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
#if (not defined(__cpp_lib_experimental_detect) or (__cpp_lib_experimental_detect < 201505)) and (not defined(_LIBCPP_VERSION) or _LIBCPP_VERSION < 5000)
|
||||
// This code is copied from:
|
||||
// https://ld2015.scusa.lsu.edu/cppreference/en/cpp/experimental/is_detected.html
|
||||
|
||||
namespace std
|
||||
{
|
||||
template< class... >
|
||||
using void_t = void;
|
||||
|
||||
namespace experimental
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class Default, class AlwaysVoid,
|
||||
template<class...> class Op, class... Args>
|
||||
struct detector
|
||||
{
|
||||
using value_t = false_type;
|
||||
using type = Default;
|
||||
};
|
||||
|
||||
template <class Default, template<class...> class Op, class... Args>
|
||||
struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
|
||||
// Note that std::void_t is a c++17 feature
|
||||
using value_t = true_type;
|
||||
using type = Op<Args...>;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
struct nonesuch
|
||||
{
|
||||
nonesuch() = delete;
|
||||
~nonesuch() = delete;
|
||||
nonesuch(nonesuch const&) = delete;
|
||||
void operator=(nonesuch const&) = delete;
|
||||
};
|
||||
|
||||
template <template<class...> class Op, class... Args>
|
||||
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
|
||||
|
||||
template <template<class...> class Op, class... Args>
|
||||
constexpr inline bool is_detected_v = is_detected<Op,Args...>::value;
|
||||
|
||||
template <template<class...> class Op, class... Args>
|
||||
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
|
||||
|
||||
template <class Default, template<class...> class Op, class... Args>
|
||||
using detected_or = detail::detector<Default, void, Op, Args...>;
|
||||
|
||||
template <class Expected, template <class...> class Op, class... Args>
|
||||
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
||||
|
||||
template <class Expected, template<class...> class Op, class... Args>
|
||||
constexpr inline bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value;
|
||||
}
|
||||
}
|
||||
|
||||
// sub optimal, but replicating the same code is worse
|
||||
#include <zeep/type-traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace cif
|
||||
@@ -249,7 +193,7 @@ typedef std::set<std::string, iless> iset;
|
||||
// --------------------------------------------------------------------
|
||||
// This really makes a difference, having our own tolower routines
|
||||
|
||||
extern const uint8_t kCharToLowerMap[256];
|
||||
extern CIFPP_EXPORT const uint8_t kCharToLowerMap[256];
|
||||
|
||||
inline char tolower(int ch)
|
||||
{
|
||||
@@ -448,8 +392,8 @@ std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_f
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt, int precision)
|
||||
{
|
||||
int size = last - first;
|
||||
int r;
|
||||
int size = static_cast<int>(last - first);
|
||||
int r = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
@@ -50,7 +52,7 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
extern int VERBOSE;
|
||||
extern CIFPP_EXPORT int VERBOSE;
|
||||
|
||||
// the git 'build' number
|
||||
std::string get_version_nr();
|
||||
@@ -155,11 +157,11 @@ inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fo
|
||||
// --------------------------------------------------------------------
|
||||
// A progress bar
|
||||
|
||||
class Progress
|
||||
class progress_bar
|
||||
{
|
||||
public:
|
||||
Progress(int64_t inMax, const std::string &inAction);
|
||||
virtual ~Progress();
|
||||
progress_bar(int64_t inMax, const std::string &inAction);
|
||||
~progress_bar();
|
||||
|
||||
void consumed(int64_t inConsumed); // consumed is relative
|
||||
void progress(int64_t inProgress); // progress is absolute
|
||||
@@ -167,10 +169,10 @@ class Progress
|
||||
void message(const std::string &inMessage);
|
||||
|
||||
private:
|
||||
Progress(const Progress &) = delete;
|
||||
Progress &operator=(const Progress &) = delete;
|
||||
progress_bar(const progress_bar &) = delete;
|
||||
progress_bar &operator=(const progress_bar &) = delete;
|
||||
|
||||
struct ProgressImpl *m_impl;
|
||||
struct progress_bar_impl *m_impl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#include <cif++/text.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -228,8 +228,9 @@ class validator_factory
|
||||
|
||||
const validator &operator[](std::string_view dictionary_name);
|
||||
|
||||
const validator &construct_validator(std::string_view name, std::istream &is);
|
||||
|
||||
private:
|
||||
void construct_validator(std::string_view name, std::istream &is);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@ Name: libcifpp
|
||||
Description: C++ library for the manipulation of mmCIF files.
|
||||
Version: @PACKAGE_VERSION@
|
||||
|
||||
Requires.private: zlib, liblzma
|
||||
Requires: zlib
|
||||
Libs: -L${libdir} -lcifpp
|
||||
Cflags: -I${includedir} -pthread
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include <cif++/atom_type.hpp>
|
||||
#include "cif++.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -182,24 +181,24 @@ const struct ionic_radii
|
||||
{ F, { kNA, kNA, 119, kNA, kNA, kNA, kNA, kNA, kNA, 22, kNA } }, // Fluorine
|
||||
{ Na, { kNA, kNA, kNA, 116, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Sodium
|
||||
{ Mg, { kNA, kNA, kNA, kNA, 86, kNA, kNA, kNA, kNA, kNA, kNA } }, // Magnesium
|
||||
{ Al, { kNA, kNA, kNA, kNA, kNA, 67.5, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
|
||||
{ Al, { kNA, kNA, kNA, kNA, kNA, 67.5f, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
|
||||
{ Si, { kNA, kNA, kNA, kNA, kNA, kNA, 54, kNA, kNA, kNA, kNA } }, // Silicon
|
||||
{ P, { kNA, kNA, kNA, kNA, kNA, 58, kNA, 52, kNA, kNA, kNA } }, // Phosphorus
|
||||
{ S, { kNA, 170, kNA, kNA, kNA, kNA, 51, kNA, 43, kNA, kNA } }, // Sulfur
|
||||
{ Cl, { kNA, kNA, 181, kNA, kNA, kNA, kNA, 26, kNA, 41, kNA } }, // Chlorine
|
||||
{ K, { kNA, kNA, kNA, 152, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Potassium
|
||||
{ Ca, { kNA, kNA, kNA, kNA, 114, kNA, kNA, kNA, kNA, kNA, kNA } }, // Calcium
|
||||
{ Sc, { kNA, kNA, kNA, kNA, kNA, 88.5, kNA, kNA, kNA, kNA, kNA } }, // Scandium
|
||||
{ Ti, { kNA, kNA, kNA, kNA, 100, 81, 74.5, kNA, kNA, kNA, kNA } }, // Titanium
|
||||
{ Sc, { kNA, kNA, kNA, kNA, kNA, 88.5f, kNA, kNA, kNA, kNA, kNA } }, // Scandium
|
||||
{ Ti, { kNA, kNA, kNA, kNA, 100, 81, 74.5f, kNA, kNA, kNA, kNA } }, // Titanium
|
||||
{ V, { kNA, kNA, kNA, kNA, 93, 78, 72, 68, kNA, kNA, kNA } }, // Vanadium
|
||||
{ Cr, { kNA, kNA, kNA, kNA, 87, 75.5, 69, 63, 58, kNA, kNA } }, // Chromium ls
|
||||
{ Cr, { kNA, kNA, kNA, kNA, 87, 75.5f, 69, 63, 58, kNA, kNA } }, // Chromium ls
|
||||
// { Cr,{ kNA, kNA, kNA, kNA, 94, kNA, kNA, kNA, kNA, kNA, kNA } }, // Chromium hs
|
||||
{ Mn, { kNA, kNA, kNA, kNA, 81, 72, 67, 47, 39.5, 60, kNA } }, // Manganese ls
|
||||
// { Mn,{ kNA, kNA, kNA, kNA, 97, 78.5, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
|
||||
{ Fe, { kNA, kNA, kNA, kNA, 75, 69, 72.5, kNA, 39, kNA, kNA } }, // Iron ls
|
||||
// { Fe,{ kNA, kNA, kNA, kNA, 92, 78.5, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
|
||||
{ Co, { kNA, kNA, kNA, kNA, 79, 68.5, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
|
||||
// { Co,{ kNA, kNA, kNA, kNA, 88.5, 75, 67, kNA, kNA, kNA, kNA } }, // Cobalt hs
|
||||
{ Mn, { kNA, kNA, kNA, kNA, 81, 72, 67, 47, 39.5f, 60, kNA } }, // Manganese ls
|
||||
// { Mn,{ kNA, kNA, kNA, kNA, 97, 78.5f, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
|
||||
{ Fe, { kNA, kNA, kNA, kNA, 75, 69, 72.5f, kNA, 39, kNA, kNA } }, // Iron ls
|
||||
// { Fe,{ kNA, kNA, kNA, kNA, 92, 78.5f, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
|
||||
{ Co, { kNA, kNA, kNA, kNA, 79, 68.5f, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
|
||||
// { Co,{ kNA, kNA, kNA, kNA, 88.5f, 75, 67, kNA, kNA, kNA, kNA } }, // Cobalt hs
|
||||
{ Ni, { kNA, kNA, kNA, kNA, 83, 70, 62, kNA, kNA, kNA, kNA } }, // Nickel ls
|
||||
// { Ni,{ kNA, kNA, kNA, kNA, kNA, 74, kNA, kNA, kNA, kNA, kNA } }, // Nickel hs
|
||||
{ Cu, { kNA, kNA, kNA, 91, 87, 68, kNA, kNA, kNA, kNA, kNA } }, // Copper
|
||||
@@ -215,10 +214,10 @@ const struct ionic_radii
|
||||
{ Zr, { kNA, kNA, kNA, kNA, kNA, kNA, 86, kNA, kNA, kNA, kNA } }, // Zirconium
|
||||
{ Nb, { kNA, kNA, kNA, kNA, kNA, 86, 82, 78, kNA, kNA, kNA } }, // Niobium
|
||||
{ Mo, { kNA, kNA, kNA, kNA, kNA, 83, 79, 75, 73, kNA, kNA } }, // Molybdenum
|
||||
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 78.5, 74, kNA, 70, kNA } }, // Technetium
|
||||
{ Ru, { kNA, kNA, kNA, kNA, kNA, 82, 76, 70.5, kNA, 52, 150 } }, // Ruthenium
|
||||
{ Rh, { kNA, kNA, kNA, kNA, kNA, 80.5, 74, 69, kNA, kNA, kNA } }, // Rhodium
|
||||
{ Pd, { kNA, kNA, kNA, 73, 100, 90, 75.5, kNA, kNA, kNA, kNA } }, // Palladium
|
||||
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 78.5f, 74, kNA, 70, kNA } }, // Technetium
|
||||
{ Ru, { kNA, kNA, kNA, kNA, kNA, 82, 76, 70.5f, kNA, 52, 150 } }, // Ruthenium
|
||||
{ Rh, { kNA, kNA, kNA, kNA, kNA, 80.5f, 74, 69, kNA, kNA, kNA } }, // Rhodium
|
||||
{ Pd, { kNA, kNA, kNA, 73, 100, 90, 75.5f, kNA, kNA, kNA, kNA } }, // Palladium
|
||||
{ Ag, { kNA, kNA, kNA, 129, 108, 89, kNA, kNA, kNA, kNA, kNA } }, // Silver
|
||||
{ Cd, { kNA, kNA, kNA, kNA, 109, kNA, kNA, kNA, kNA, kNA, kNA } }, // Cadmium
|
||||
{ In, { kNA, kNA, kNA, kNA, kNA, 94, kNA, kNA, kNA, kNA, kNA } }, // Indium
|
||||
@@ -229,32 +228,32 @@ const struct ionic_radii
|
||||
{ Xe, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 62 } }, // Xenon
|
||||
{ Cs, { kNA, kNA, kNA, 167, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Caesium
|
||||
{ Ba, { kNA, kNA, kNA, kNA, 149, kNA, kNA, kNA, kNA, kNA, kNA } }, // Barium
|
||||
{ La, { kNA, kNA, kNA, kNA, kNA, 117.2, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
|
||||
{ La, { kNA, kNA, kNA, kNA, kNA, 117.2f, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
|
||||
{ Ce, { kNA, kNA, kNA, kNA, kNA, 115, 101, kNA, kNA, kNA, kNA } }, // Cerium
|
||||
{ Pr, { kNA, kNA, kNA, kNA, kNA, 113, 99, kNA, kNA, kNA, kNA } }, // Praseodymium
|
||||
{ Nd, { kNA, kNA, kNA, kNA, 143, 112.3, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
|
||||
{ Nd, { kNA, kNA, kNA, kNA, 143, 112.3f, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
|
||||
{ Pm, { kNA, kNA, kNA, kNA, kNA, 111, kNA, kNA, kNA, kNA, kNA } }, // Promethium
|
||||
{ Sm, { kNA, kNA, kNA, kNA, 136, 109.8, kNA, kNA, kNA, kNA, kNA } }, // Samarium
|
||||
{ Eu, { kNA, kNA, kNA, kNA, 131, 108.7, kNA, kNA, kNA, kNA, kNA } }, // Europium
|
||||
{ Gd, { kNA, kNA, kNA, kNA, kNA, 107.8, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
|
||||
{ Tb, { kNA, kNA, kNA, kNA, kNA, 106.3, 90, kNA, kNA, kNA, kNA } }, // Terbium
|
||||
{ Dy, { kNA, kNA, kNA, kNA, 121, 105.2, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
|
||||
{ Ho, { kNA, kNA, kNA, kNA, kNA, 104.1, kNA, kNA, kNA, kNA, kNA } }, // Holmium
|
||||
{ Sm, { kNA, kNA, kNA, kNA, 136, 109.8f, kNA, kNA, kNA, kNA, kNA } }, // Samarium
|
||||
{ Eu, { kNA, kNA, kNA, kNA, 131, 108.7f, kNA, kNA, kNA, kNA, kNA } }, // Europium
|
||||
{ Gd, { kNA, kNA, kNA, kNA, kNA, 107.8f, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
|
||||
{ Tb, { kNA, kNA, kNA, kNA, kNA, 106.3f, 90, kNA, kNA, kNA, kNA } }, // Terbium
|
||||
{ Dy, { kNA, kNA, kNA, kNA, 121, 105.2f, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
|
||||
{ Ho, { kNA, kNA, kNA, kNA, kNA, 104.1f, kNA, kNA, kNA, kNA, kNA } }, // Holmium
|
||||
{ Er, { kNA, kNA, kNA, kNA, kNA, 103, kNA, kNA, kNA, kNA, kNA } }, // Erbium
|
||||
{ Tm, { kNA, kNA, kNA, kNA, 117, 102, kNA, kNA, kNA, kNA, kNA } }, // Thulium
|
||||
{ Yb, { kNA, kNA, kNA, kNA, 116, 100.8, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
|
||||
{ Lu, { kNA, kNA, kNA, kNA, kNA, 100.1, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
|
||||
{ Yb, { kNA, kNA, kNA, kNA, 116, 100.8f, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
|
||||
{ Lu, { kNA, kNA, kNA, kNA, kNA, 100.1f, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
|
||||
{ Hf, { kNA, kNA, kNA, kNA, kNA, kNA, 85, kNA, kNA, kNA, kNA } }, // Hafnium
|
||||
{ Ta, { kNA, kNA, kNA, kNA, kNA, 86, 82, 78, kNA, kNA, kNA } }, // Tantalum
|
||||
{ W, { kNA, kNA, kNA, kNA, kNA, kNA, 80, 76, 74, kNA, kNA } }, // Tungsten
|
||||
{ Re, { kNA, kNA, kNA, kNA, kNA, kNA, 77, 72, 69, 67, kNA } }, // Rhenium
|
||||
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 77, 71.5, 68.5, 66.5, 53 } }, // Osmium
|
||||
{ Ir, { kNA, kNA, kNA, kNA, kNA, 82, 76.5, 71, kNA, kNA, kNA } }, // Iridium
|
||||
{ Pt, { kNA, kNA, kNA, kNA, 94, kNA, 76.5, 71, kNA, kNA, kNA } }, // Platinum
|
||||
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 77, 71.5f, 68.5f, 66.5f, 53 } }, // Osmium
|
||||
{ Ir, { kNA, kNA, kNA, kNA, kNA, 82, 76.5f, 71, kNA, kNA, kNA } }, // Iridium
|
||||
{ Pt, { kNA, kNA, kNA, kNA, 94, kNA, 76.5f, 71, kNA, kNA, kNA } }, // Platinum
|
||||
{ Au, { kNA, kNA, kNA, 151, kNA, 99, kNA, 71, kNA, kNA, kNA } }, // Gold
|
||||
{ Hg, { kNA, kNA, kNA, 133, 116, kNA, kNA, kNA, kNA, kNA, kNA } }, // Mercury
|
||||
{ Tl, { kNA, kNA, kNA, 164, kNA, 102.5, kNA, kNA, kNA, kNA, kNA } }, // Thallium
|
||||
{ Pb, { kNA, kNA, kNA, kNA, 133, kNA, 91.5, kNA, kNA, kNA, kNA } }, // Lead
|
||||
{ Tl, { kNA, kNA, kNA, 164, kNA, 102.5f, kNA, kNA, kNA, kNA, kNA } }, // Thallium
|
||||
{ Pb, { kNA, kNA, kNA, kNA, 133, kNA, 91.5f, kNA, kNA, kNA, kNA } }, // Lead
|
||||
{ Bi, { kNA, kNA, kNA, kNA, kNA, 117, kNA, 90, kNA, kNA, kNA } }, // Bismuth
|
||||
{ Po, { kNA, kNA, kNA, kNA, kNA, kNA, 108, kNA, 81, kNA, kNA } }, // Polonium
|
||||
{ At, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 76, kNA } }, // Astatine
|
||||
@@ -263,16 +262,16 @@ const struct ionic_radii
|
||||
{ Ac, { kNA, kNA, kNA, kNA, kNA, 126, kNA, kNA, kNA, kNA, kNA } }, // Actinium
|
||||
{ Th, { kNA, kNA, kNA, kNA, kNA, kNA, 108, kNA, kNA, kNA, kNA } }, // Thorium
|
||||
{ Pa, { kNA, kNA, kNA, kNA, kNA, 116, 104, 92, kNA, kNA, kNA } }, // Protactinium
|
||||
{ U, { kNA, kNA, kNA, kNA, kNA, 116.5, 103, 90, 87, kNA, kNA } }, // Uranium
|
||||
{ U, { kNA, kNA, kNA, kNA, kNA, 116.5f, 103, 90, 87, kNA, kNA } }, // Uranium
|
||||
{ Np, { kNA, kNA, kNA, kNA, 124, 115, 101, 89, 86, 85, kNA } }, // Neptunium
|
||||
{ Pu, { kNA, kNA, kNA, kNA, kNA, 114, 100, 88, 85, kNA, kNA } }, // Plutonium
|
||||
{ Am, { kNA, kNA, kNA, kNA, 140, 111.5, 99, kNA, kNA, kNA, kNA } }, // Americium
|
||||
{ Am, { kNA, kNA, kNA, kNA, 140, 111.5f, 99, kNA, kNA, kNA, kNA } }, // Americium
|
||||
{ Cm, { kNA, kNA, kNA, kNA, kNA, 111, 99, kNA, kNA, kNA, kNA } }, // Curium
|
||||
{ Bk, { kNA, kNA, kNA, kNA, kNA, 110, 97, kNA, kNA, kNA, kNA } }, // Berkelium
|
||||
{ Cf, { kNA, kNA, kNA, kNA, kNA, 109, 96.1, kNA, kNA, kNA, kNA } }, // Californium
|
||||
{ Es, { kNA, kNA, kNA, kNA, kNA, 92.8, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
|
||||
{ Cf, { kNA, kNA, kNA, kNA, kNA, 109, 96.1f, kNA, kNA, kNA, kNA } }, // Californium
|
||||
{ Es, { kNA, kNA, kNA, kNA, kNA, 92.8f, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
|
||||
}, kEffectiveIonicRadii[] = {
|
||||
{ H, { kNA, kNA, 139.9, -18, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Hydrogen
|
||||
{ H, { kNA, kNA, 139.9f, -18, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Hydrogen
|
||||
{ Li, { kNA, kNA, kNA, 76, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Lithium
|
||||
{ Be, { kNA, kNA, kNA, kNA, 45, kNA, kNA, kNA, kNA, kNA, kNA } }, // Beryllium
|
||||
{ B, { kNA, kNA, kNA, kNA, kNA, 27, kNA, kNA, kNA, kNA, kNA } }, // Boron
|
||||
@@ -282,24 +281,24 @@ const struct ionic_radii
|
||||
{ F, { kNA, kNA, 133, kNA, kNA, kNA, kNA, kNA, kNA, 8, kNA } }, // Fluorine
|
||||
{ Na, { kNA, kNA, kNA, 102, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Sodium
|
||||
{ Mg, { kNA, kNA, kNA, kNA, 72, kNA, kNA, kNA, kNA, kNA, kNA } }, // Magnesium
|
||||
{ Al, { kNA, kNA, kNA, kNA, kNA, 53.5, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
|
||||
{ Al, { kNA, kNA, kNA, kNA, kNA, 53.5f, kNA, kNA, kNA, kNA, kNA } }, // Aluminium
|
||||
{ Si, { kNA, kNA, kNA, kNA, kNA, kNA, 40, kNA, kNA, kNA, kNA } }, // Silicon
|
||||
{ P, { 212, kNA, kNA, kNA, kNA, 44, kNA, 38, kNA, kNA, kNA } }, // Phosphorus
|
||||
{ S, { kNA, 184, kNA, kNA, kNA, kNA, 37, kNA, 29, kNA, kNA } }, // Sulfur
|
||||
{ Cl, { kNA, kNA, 181, kNA, kNA, kNA, kNA, 12, kNA, 27, kNA } }, // Chlorine
|
||||
{ K, { kNA, kNA, kNA, 138, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Potassium
|
||||
{ Ca, { kNA, kNA, kNA, kNA, 100, kNA, kNA, kNA, kNA, kNA, kNA } }, // Calcium
|
||||
{ Sc, { kNA, kNA, kNA, kNA, kNA, 74.5, kNA, kNA, kNA, kNA, kNA } }, // Scandium
|
||||
{ Ti, { kNA, kNA, kNA, kNA, 86, 67, 60.5, kNA, kNA, kNA, kNA } }, // Titanium
|
||||
{ Sc, { kNA, kNA, kNA, kNA, kNA, 74.5f, kNA, kNA, kNA, kNA, kNA } }, // Scandium
|
||||
{ Ti, { kNA, kNA, kNA, kNA, 86, 67, 60.5f, kNA, kNA, kNA, kNA } }, // Titanium
|
||||
{ V, { kNA, kNA, kNA, kNA, 79, 64, 58, 54, kNA, kNA, kNA } }, // Vanadium
|
||||
{ Cr, { kNA, kNA, kNA, kNA, 73, 61.5, 55, 49, 44, kNA, kNA } }, // Chromium ls
|
||||
{ Cr, { kNA, kNA, kNA, kNA, 73, 61.5f, 55, 49, 44, kNA, kNA } }, // Chromium ls
|
||||
{ Cr, { kNA, kNA, kNA, kNA, 80, kNA, kNA, kNA, kNA, kNA, kNA } }, // Chromium hs
|
||||
{ Mn, { kNA, kNA, kNA, kNA, 67, 58, 53, 33, 25.5, 46, kNA } }, // Manganese ls
|
||||
{ Mn, { kNA, kNA, kNA, kNA, 83, 64.5, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
|
||||
{ Fe, { kNA, kNA, kNA, kNA, 61, 55, 58.5, kNA, 25, kNA, kNA } }, // Iron ls
|
||||
{ Fe, { kNA, kNA, kNA, kNA, 78, 64.5, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
|
||||
{ Co, { kNA, kNA, kNA, kNA, 65, 54.5, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
|
||||
{ Co, { kNA, kNA, kNA, kNA, 74.5, 61, 53, kNA, kNA, kNA, kNA } }, // Cobalt hs
|
||||
{ Mn, { kNA, kNA, kNA, kNA, 67, 58, 53, 33, 25.5f, 46, kNA } }, // Manganese ls
|
||||
{ Mn, { kNA, kNA, kNA, kNA, 83, 64.5f, kNA, kNA, kNA, kNA, kNA } }, // Manganese hs
|
||||
{ Fe, { kNA, kNA, kNA, kNA, 61, 55, 58.5f, kNA, 25, kNA, kNA } }, // Iron ls
|
||||
{ Fe, { kNA, kNA, kNA, kNA, 78, 64.5f, kNA, kNA, kNA, kNA, kNA } }, // Iron hs
|
||||
{ Co, { kNA, kNA, kNA, kNA, 65, 54.5f, kNA, kNA, kNA, kNA, kNA } }, // Cobalt ls
|
||||
{ Co, { kNA, kNA, kNA, kNA, 74.5f, 61, 53, kNA, kNA, kNA, kNA } }, // Cobalt hs
|
||||
{ Ni, { kNA, kNA, kNA, kNA, 69, 56, 48, kNA, kNA, kNA, kNA } }, // Nickel ls
|
||||
{ Ni, { kNA, kNA, kNA, kNA, kNA, 60, kNA, kNA, kNA, kNA, kNA } }, // Nickel hs
|
||||
{ Cu, { kNA, kNA, kNA, 77, 73, 54, kNA, kNA, kNA, kNA, kNA } }, // Copper
|
||||
@@ -315,10 +314,10 @@ const struct ionic_radii
|
||||
{ Zr, { kNA, kNA, kNA, kNA, kNA, kNA, 72, kNA, kNA, kNA, kNA } }, // Zirconium
|
||||
{ Nb, { kNA, kNA, kNA, kNA, kNA, 72, 68, 64, kNA, kNA, kNA } }, // Niobium
|
||||
{ Mo, { kNA, kNA, kNA, kNA, kNA, 69, 65, 61, 59, kNA, kNA } }, // Molybdenum
|
||||
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 64.5, 60, kNA, 56, kNA } }, // Technetium
|
||||
{ Ru, { kNA, kNA, kNA, kNA, kNA, 68, 62, 56.5, kNA, 38, 36 } }, // Ruthenium
|
||||
{ Rh, { kNA, kNA, kNA, kNA, kNA, 66.5, 60, 55, kNA, kNA, kNA } }, // Rhodium
|
||||
{ Pd, { kNA, kNA, kNA, 59, 86, 76, 61.5, kNA, kNA, kNA, kNA } }, // Palladium
|
||||
{ Tc, { kNA, kNA, kNA, kNA, kNA, kNA, 64.5f, 60, kNA, 56, kNA } }, // Technetium
|
||||
{ Ru, { kNA, kNA, kNA, kNA, kNA, 68, 62, 56.5f, kNA, 38, 36 } }, // Ruthenium
|
||||
{ Rh, { kNA, kNA, kNA, kNA, kNA, 66.5f, 60, 55, kNA, kNA, kNA } }, // Rhodium
|
||||
{ Pd, { kNA, kNA, kNA, 59, 86, 76, 61.5f, kNA, kNA, kNA, kNA } }, // Palladium
|
||||
{ Ag, { kNA, kNA, kNA, 115, 94, 75, kNA, kNA, kNA, kNA, kNA } }, // Silver
|
||||
{ Cd, { kNA, kNA, kNA, kNA, 95, kNA, kNA, kNA, kNA, kNA, kNA } }, // Cadmium
|
||||
{ In, { kNA, kNA, kNA, kNA, kNA, 80, kNA, kNA, kNA, kNA, kNA } }, // Indium
|
||||
@@ -329,48 +328,48 @@ const struct ionic_radii
|
||||
{ Xe, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 48 } }, // Xenon
|
||||
{ Cs, { kNA, kNA, kNA, 167, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Caesium
|
||||
{ Ba, { kNA, kNA, kNA, kNA, 135, kNA, kNA, kNA, kNA, kNA, kNA } }, // Barium
|
||||
{ La, { kNA, kNA, kNA, kNA, kNA, 103.2, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
|
||||
{ La, { kNA, kNA, kNA, kNA, kNA, 103.2f, kNA, kNA, kNA, kNA, kNA } }, // Lanthanum
|
||||
{ Ce, { kNA, kNA, kNA, kNA, kNA, 101, 87, kNA, kNA, kNA, kNA } }, // Cerium
|
||||
{ Pr, { kNA, kNA, kNA, kNA, kNA, 99, 85, kNA, kNA, kNA, kNA } }, // Praseodymium
|
||||
{ Nd, { kNA, kNA, kNA, kNA, 129, 98.3, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
|
||||
{ Nd, { kNA, kNA, kNA, kNA, 129, 98.3f, kNA, kNA, kNA, kNA, kNA } }, // Neodymium
|
||||
{ Pm, { kNA, kNA, kNA, kNA, kNA, 97, kNA, kNA, kNA, kNA, kNA } }, // Promethium
|
||||
{ Sm, { kNA, kNA, kNA, kNA, 122, 95.8, kNA, kNA, kNA, kNA, kNA } }, // Samarium
|
||||
{ Eu, { kNA, kNA, kNA, kNA, 117, 94.7, kNA, kNA, kNA, kNA, kNA } }, // Europium
|
||||
{ Gd, { kNA, kNA, kNA, kNA, kNA, 93.5, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
|
||||
{ Tb, { kNA, kNA, kNA, kNA, kNA, 92.3, 76, kNA, kNA, kNA, kNA } }, // Terbium
|
||||
{ Dy, { kNA, kNA, kNA, kNA, 107, 91.2, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
|
||||
{ Ho, { kNA, kNA, kNA, kNA, kNA, 90.1, kNA, kNA, kNA, kNA, kNA } }, // Holmium
|
||||
{ Sm, { kNA, kNA, kNA, kNA, 122, 95.8f, kNA, kNA, kNA, kNA, kNA } }, // Samarium
|
||||
{ Eu, { kNA, kNA, kNA, kNA, 117, 94.7f, kNA, kNA, kNA, kNA, kNA } }, // Europium
|
||||
{ Gd, { kNA, kNA, kNA, kNA, kNA, 93.5f, kNA, kNA, kNA, kNA, kNA } }, // Gadolinium
|
||||
{ Tb, { kNA, kNA, kNA, kNA, kNA, 92.3f, 76, kNA, kNA, kNA, kNA } }, // Terbium
|
||||
{ Dy, { kNA, kNA, kNA, kNA, 107, 91.2f, kNA, kNA, kNA, kNA, kNA } }, // Dysprosium
|
||||
{ Ho, { kNA, kNA, kNA, kNA, kNA, 90.1f, kNA, kNA, kNA, kNA, kNA } }, // Holmium
|
||||
{ Er, { kNA, kNA, kNA, kNA, kNA, 89, kNA, kNA, kNA, kNA, kNA } }, // Erbium
|
||||
{ Tm, { kNA, kNA, kNA, kNA, 103, 88, kNA, kNA, kNA, kNA, kNA } }, // Thulium
|
||||
{ Yb, { kNA, kNA, kNA, kNA, 102, 86.8, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
|
||||
{ Lu, { kNA, kNA, kNA, kNA, kNA, 86.1, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
|
||||
{ Yb, { kNA, kNA, kNA, kNA, 102, 86.8f, kNA, kNA, kNA, kNA, kNA } }, // Ytterbium
|
||||
{ Lu, { kNA, kNA, kNA, kNA, kNA, 86.1f, kNA, kNA, kNA, kNA, kNA } }, // Lutetium
|
||||
{ Hf, { kNA, kNA, kNA, kNA, kNA, kNA, 71, kNA, kNA, kNA, kNA } }, // Hafnium
|
||||
{ Ta, { kNA, kNA, kNA, kNA, kNA, 72, 68, 64, kNA, kNA, kNA } }, // Tantalum
|
||||
{ W, { kNA, kNA, kNA, kNA, kNA, kNA, 66, 62, 60, kNA, kNA } }, // Tungsten
|
||||
{ Re, { kNA, kNA, kNA, kNA, kNA, kNA, 63, 58, 55, 53, kNA } }, // Rhenium
|
||||
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 63, 57.5, 54.5, 52.5, 39 } }, // Osmium
|
||||
{ Ir, { kNA, kNA, kNA, kNA, kNA, 68, 62.5, 57, kNA, kNA, kNA } }, // Iridium
|
||||
{ Pt, { kNA, kNA, kNA, kNA, 80, kNA, 62.5, 57, kNA, kNA, kNA } }, // Platinum
|
||||
{ Os, { kNA, kNA, kNA, kNA, kNA, kNA, 63, 57.5f, 54.5f, 52.5f, 39 } }, // Osmium
|
||||
{ Ir, { kNA, kNA, kNA, kNA, kNA, 68, 62.5f, 57, kNA, kNA, kNA } }, // Iridium
|
||||
{ Pt, { kNA, kNA, kNA, kNA, 80, kNA, 62.5f, 57, kNA, kNA, kNA } }, // Platinum
|
||||
{ Au, { kNA, kNA, kNA, 137, kNA, 85, kNA, 57, kNA, kNA, kNA } }, // Gold
|
||||
{ Hg, { kNA, kNA, kNA, 119, 102, kNA, kNA, kNA, kNA, kNA, kNA } }, // Mercury
|
||||
{ Tl, { kNA, kNA, kNA, 150, kNA, 88.5, kNA, kNA, kNA, kNA, kNA } }, // Thallium
|
||||
{ Pb, { kNA, kNA, kNA, kNA, 119, kNA, 77.5, kNA, kNA, kNA, kNA } }, // Lead
|
||||
{ Tl, { kNA, kNA, kNA, 150, kNA, 88.5f, kNA, kNA, kNA, kNA, kNA } }, // Thallium
|
||||
{ Pb, { kNA, kNA, kNA, kNA, 119, kNA, 77.5f, kNA, kNA, kNA, kNA } }, // Lead
|
||||
{ Bi, { kNA, kNA, kNA, kNA, kNA, 103, kNA, 76, kNA, kNA, kNA } }, // Bismuth
|
||||
{ Po, { kNA, 223, kNA, kNA, kNA, kNA, 94, kNA, 67, kNA, kNA } }, // Polonium
|
||||
{ At, { kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, kNA, 62, kNA } }, // Astatine
|
||||
{ Fr, { kNA, kNA, kNA, 180, kNA, kNA, kNA, kNA, kNA, kNA, kNA } }, // Francium
|
||||
{ Ra, { kNA, kNA, kNA, kNA, 148, kNA, kNA, kNA, kNA, kNA, kNA } }, // Radium
|
||||
{ Ac, { kNA, kNA, kNA, kNA, kNA, 106.5, kNA, kNA, kNA, kNA, kNA } }, // Actinium
|
||||
{ Ac, { kNA, kNA, kNA, kNA, kNA, 106.5f, kNA, kNA, kNA, kNA, kNA } }, // Actinium
|
||||
{ Th, { kNA, kNA, kNA, kNA, kNA, kNA, 94, kNA, kNA, kNA, kNA } }, // Thorium
|
||||
{ Pa, { kNA, kNA, kNA, kNA, kNA, 104, 90, 78, kNA, kNA, kNA } }, // Protactinium
|
||||
{ U, { kNA, kNA, kNA, kNA, kNA, 102.5, 89, 76, 73, kNA, kNA } }, // Uranium
|
||||
{ U, { kNA, kNA, kNA, kNA, kNA, 102.5f, 89, 76, 73, kNA, kNA } }, // Uranium
|
||||
{ Np, { kNA, kNA, kNA, kNA, 110, 101, 87, 75, 72, 71, kNA } }, // Neptunium
|
||||
{ Pu, { kNA, kNA, kNA, kNA, kNA, 100, 86, 74, 71, kNA, kNA } }, // Plutonium
|
||||
{ Am, { kNA, kNA, kNA, kNA, 126, 97.5, 85, kNA, kNA, kNA, kNA } }, // Americium
|
||||
{ Am, { kNA, kNA, kNA, kNA, 126, 97.5f, 85, kNA, kNA, kNA, kNA } }, // Americium
|
||||
{ Cm, { kNA, kNA, kNA, kNA, kNA, 97, 85, kNA, kNA, kNA, kNA } }, // Curium
|
||||
{ Bk, { kNA, kNA, kNA, kNA, kNA, 96, 83, kNA, kNA, kNA, kNA } }, // Berkelium
|
||||
{ Cf, { kNA, kNA, kNA, kNA, kNA, 95, 82.1, kNA, kNA, kNA, kNA } }, // Californium
|
||||
{ Es, { kNA, kNA, kNA, kNA, kNA, 83.5, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
|
||||
{ Cf, { kNA, kNA, kNA, kNA, kNA, 95, 82.1f, kNA, kNA, kNA, kNA } }, // Californium
|
||||
{ Es, { kNA, kNA, kNA, kNA, kNA, 83.5f, kNA, kNA, kNA, kNA, kNA } }, // Einsteinium
|
||||
};
|
||||
|
||||
|
||||
@@ -1028,6 +1027,9 @@ atom_type_traits::atom_type_traits(const std::string& symbol)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol == "X")
|
||||
m_info = &data::kKnownAtoms[0];
|
||||
|
||||
if (m_info == nullptr)
|
||||
throw std::invalid_argument("Not a known element: " + symbol);
|
||||
@@ -1075,6 +1077,26 @@ bool atom_type_traits::is_metal(const std::string& symbol)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool atom_type_traits::has_sf(int charge) const
|
||||
{
|
||||
auto type = m_info->type;
|
||||
if (type == D)
|
||||
type = H;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (auto& sf: data::kWKSFData)
|
||||
{
|
||||
if (sf.symbol == type and sf.charge == charge)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto atom_type_traits::wksf(int charge) const -> const SFData&
|
||||
{
|
||||
auto type = m_info->type;
|
||||
|
||||
267
src/category.cpp
267
src/category.cpp
@@ -24,14 +24,14 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <numeric>
|
||||
#include <stack>
|
||||
|
||||
#include <cif++/category.hpp>
|
||||
#include <cif++/datablock.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include <cif++/utilities.hpp>
|
||||
|
||||
// TODO: Find out what the rules are exactly for linked items, the current implementation
|
||||
// is inconsistent. It all depends whether a link is satified if a field taking part in the
|
||||
// set of linked items is null at one side and not null in the other.
|
||||
@@ -51,7 +51,7 @@ class row_comparator
|
||||
{
|
||||
auto cv = cat.get_cat_validator();
|
||||
|
||||
for (auto k : cv->m_keys)
|
||||
for (auto &k : cv->m_keys)
|
||||
{
|
||||
uint16_t ix = cat.add_column(k);
|
||||
|
||||
@@ -78,13 +78,8 @@ class row_comparator
|
||||
row_handle rhb(m_category, *b);
|
||||
|
||||
int d = 0;
|
||||
for (auto &c : m_comparator)
|
||||
for (const auto &[k, f] : m_comparator)
|
||||
{
|
||||
uint16_t k;
|
||||
compareFunc f;
|
||||
|
||||
std::tie(k, f) = c;
|
||||
|
||||
std::string_view ka = rha[k].text();
|
||||
std::string_view kb = rhb[k].text();
|
||||
|
||||
@@ -103,29 +98,30 @@ class row_comparator
|
||||
|
||||
row_handle rhb(m_category, *b);
|
||||
|
||||
int d = 0, i = 0;
|
||||
for (auto &c : m_comparator)
|
||||
int d = 0;
|
||||
auto ai = a.begin();
|
||||
|
||||
for (const auto &[k, f] : m_comparator)
|
||||
{
|
||||
uint16_t k;
|
||||
compareFunc f;
|
||||
assert(ai != a.end());
|
||||
|
||||
std::tie(k, f) = c;
|
||||
|
||||
std::string_view ka = a[i++].value();
|
||||
std::string_view ka = ai->value();
|
||||
std::string_view kb = rhb[k].text();
|
||||
|
||||
d = f(ka, kb);
|
||||
|
||||
if (d != 0)
|
||||
break;
|
||||
|
||||
++ai;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::function<int(std::string_view, std::string_view)> compareFunc;
|
||||
typedef std::tuple<uint16_t, compareFunc> key_comparator;
|
||||
using compareFunc = std::function<int(std::string_view, std::string_view)>;
|
||||
using key_comparator = std::tuple<uint16_t, compareFunc>;
|
||||
|
||||
std::vector<key_comparator> m_comparator;
|
||||
category &m_category;
|
||||
@@ -139,13 +135,7 @@ class row_comparator
|
||||
class category_index
|
||||
{
|
||||
public:
|
||||
category_index(category *cat)
|
||||
: m_category(*cat)
|
||||
, m_row_comparator(m_category)
|
||||
, m_root(nullptr)
|
||||
{
|
||||
reconstruct();
|
||||
}
|
||||
category_index(category *cat);
|
||||
|
||||
~category_index()
|
||||
{
|
||||
@@ -158,9 +148,6 @@ class category_index
|
||||
void insert(row *r);
|
||||
void erase(row *r);
|
||||
|
||||
// batch create
|
||||
void reconstruct();
|
||||
|
||||
// reorder the row's and returns new head and tail
|
||||
std::tuple<row *, row *> reorder()
|
||||
{
|
||||
@@ -241,7 +228,7 @@ class category_index
|
||||
h->m_right->m_red = not h->m_right->m_red;
|
||||
}
|
||||
|
||||
bool is_red(entry *h) const
|
||||
constexpr bool is_red(entry *h) const
|
||||
{
|
||||
return h != nullptr and h->m_red;
|
||||
}
|
||||
@@ -342,6 +329,15 @@ class category_index
|
||||
entry *m_root;
|
||||
};
|
||||
|
||||
category_index::category_index(category *cat)
|
||||
: m_category(*cat)
|
||||
, m_row_comparator(m_category)
|
||||
, m_root(nullptr)
|
||||
{
|
||||
for (auto r : m_category)
|
||||
insert(r.get_row());
|
||||
}
|
||||
|
||||
row *category_index::find(row *k) const
|
||||
{
|
||||
const entry *r = m_root;
|
||||
@@ -482,83 +478,6 @@ category_index::entry *category_index::erase(entry *h, row *k)
|
||||
return fix_up(h);
|
||||
}
|
||||
|
||||
void category_index::reconstruct()
|
||||
{
|
||||
delete m_root;
|
||||
m_root = nullptr;
|
||||
|
||||
for (auto r : m_category)
|
||||
insert(r.get_row());
|
||||
|
||||
// maybe reconstruction can be done quicker by using the following commented code.
|
||||
// however, I've not had the time to think of a way to set the red/black flag correctly in that case.
|
||||
|
||||
// std::vector<row*> rows;
|
||||
// transform(mCat.begin(), mCat.end(), backInserter(rows),
|
||||
// [](Row r) -> row* { assert(r.mData); return r.mData; });
|
||||
//
|
||||
// assert(std::find(rows.begin(), rows.end(), nullptr) == rows.end());
|
||||
//
|
||||
// // don't use sort here, it will run out of the stack of something.
|
||||
// // quicksort is notorious for using excessive recursion.
|
||||
// // Besides, most of the time, the data is ordered already anyway.
|
||||
//
|
||||
// stable_sort(rows.begin(), rows.end(), [this](row* a, row* b) -> bool { return this->mComp(a, b) < 0; });
|
||||
//
|
||||
// for (size_t i = 0; i < rows.size() - 1; ++i)
|
||||
// assert(mComp(rows[i], rows[i + 1]) < 0);
|
||||
//
|
||||
// deque<entry*> e;
|
||||
// transform(rows.begin(), rows.end(), back_inserter(e),
|
||||
// [](row* r) -> entry* { return new entry(r); });
|
||||
//
|
||||
// while (e.size() > 1)
|
||||
// {
|
||||
// deque<entry*> ne;
|
||||
//
|
||||
// while (not e.empty())
|
||||
// {
|
||||
// entry* a = e.front();
|
||||
// e.pop_front();
|
||||
//
|
||||
// if (e.empty())
|
||||
// ne.push_back(a);
|
||||
// else
|
||||
// {
|
||||
// entry* b = e.front();
|
||||
// b->mLeft = a;
|
||||
//
|
||||
// assert(mComp(a->mRow, b->mRow) < 0);
|
||||
//
|
||||
// e.pop_front();
|
||||
//
|
||||
// if (not e.empty())
|
||||
// {
|
||||
// entry* c = e.front();
|
||||
// e.pop_front();
|
||||
//
|
||||
// assert(mComp(b->mRow, c->mRow) < 0);
|
||||
//
|
||||
// b->mRight = c;
|
||||
// }
|
||||
//
|
||||
// ne.push_back(b);
|
||||
//
|
||||
// if (not e.empty())
|
||||
// {
|
||||
// ne.push_back(e.front());
|
||||
// e.pop_front();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// swap (e, ne);
|
||||
// }
|
||||
//
|
||||
// assert(e.size() == 1);
|
||||
// mRoot = e.front();
|
||||
}
|
||||
|
||||
size_t category_index::size() const
|
||||
{
|
||||
std::stack<entry *> s;
|
||||
@@ -595,14 +514,12 @@ category::category(const category &rhs)
|
||||
, m_columns(rhs.m_columns)
|
||||
, m_validator(rhs.m_validator)
|
||||
, m_cat_validator(rhs.m_cat_validator)
|
||||
, m_parent_links(rhs.m_parent_links)
|
||||
, m_child_links(rhs.m_child_links)
|
||||
, m_cascade(rhs.m_cascade)
|
||||
{
|
||||
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
|
||||
insert_impl(end(), clone_row(*r));
|
||||
|
||||
if (m_cat_validator != nullptr)
|
||||
if (m_cat_validator != nullptr and m_index == nullptr)
|
||||
m_index = new category_index(this);
|
||||
}
|
||||
|
||||
@@ -645,10 +562,8 @@ category &category::operator=(const category &rhs)
|
||||
|
||||
m_validator = rhs.m_validator;
|
||||
m_cat_validator = rhs.m_cat_validator;
|
||||
m_parent_links = rhs.m_parent_links;
|
||||
m_child_links = rhs.m_child_links;
|
||||
|
||||
if (m_cat_validator != nullptr)
|
||||
if (m_cat_validator != nullptr and m_index == nullptr)
|
||||
m_index = new category_index(this);
|
||||
}
|
||||
|
||||
@@ -659,9 +574,6 @@ category &category::operator=(category &&rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
if (not empty())
|
||||
clear();
|
||||
|
||||
m_name = std::move(rhs.m_name);
|
||||
m_columns = std::move(rhs.m_columns);
|
||||
m_cascade = rhs.m_cascade;
|
||||
@@ -669,12 +581,10 @@ category &category::operator=(category &&rhs)
|
||||
m_cat_validator = rhs.m_cat_validator;
|
||||
m_parent_links = rhs.m_parent_links;
|
||||
m_child_links = rhs.m_child_links;
|
||||
m_index = rhs.m_index;
|
||||
m_head = rhs.m_head;
|
||||
m_tail = rhs.m_tail;
|
||||
|
||||
rhs.m_head = rhs.m_tail = nullptr;
|
||||
rhs.m_index = nullptr;
|
||||
std::swap(m_index, rhs.m_index);
|
||||
std::swap(m_head, rhs.m_head);
|
||||
std::swap(m_tail, rhs.m_tail);
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -983,11 +893,19 @@ bool category::validate_links() const
|
||||
|
||||
row_handle category::operator[](const key_type &key)
|
||||
{
|
||||
if (m_index == nullptr)
|
||||
throw std::logic_error("Category " + m_name + " does not have an index");
|
||||
row_handle result{};
|
||||
|
||||
auto row = m_index->find_by_value(key);
|
||||
return row != nullptr ? row_handle{ *this, *row } : row_handle{};
|
||||
if (not empty())
|
||||
{
|
||||
if (m_index == nullptr)
|
||||
throw std::logic_error("Category " + m_name + " does not have an index");
|
||||
|
||||
auto row = m_index->find_by_value(key);
|
||||
if (row != nullptr)
|
||||
result = { *this, *row };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -1142,10 +1060,6 @@ category::iterator category::erase(iterator pos)
|
||||
row *r = rh.get_row();
|
||||
iterator result = ++pos;
|
||||
|
||||
iset keys;
|
||||
if (m_cat_validator)
|
||||
keys = iset(m_cat_validator->m_keys.begin(), m_cat_validator->m_keys.end());
|
||||
|
||||
if (m_head == nullptr)
|
||||
throw std::runtime_error("erase");
|
||||
|
||||
@@ -1174,7 +1088,7 @@ category::iterator category::erase(iterator pos)
|
||||
// in mmcif_pdbx.dic dictionary.
|
||||
//
|
||||
// For each link group in _pdbx_item_linked_group_list
|
||||
// a std::set of keys from one category is mapped to another.
|
||||
// a set of keys from one category is mapped to another.
|
||||
// If all values in a child are the same as the specified parent ones
|
||||
// the child is removed as well, recursively of course.
|
||||
|
||||
@@ -1198,25 +1112,29 @@ category::iterator category::erase(iterator pos)
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t category::erase(condition &&cond)
|
||||
template<typename T>
|
||||
class save_value
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
cond.prepare(*this);
|
||||
|
||||
auto ri = begin();
|
||||
while (ri != end())
|
||||
public:
|
||||
save_value(T &v, const T nv = {})
|
||||
: m_v(v)
|
||||
, m_sv(std::exchange(m_v, nv))
|
||||
{
|
||||
if (cond(*ri))
|
||||
{
|
||||
ri = erase(ri);
|
||||
++result;
|
||||
}
|
||||
else
|
||||
++ri;
|
||||
}
|
||||
|
||||
return result;
|
||||
~save_value()
|
||||
{
|
||||
m_v = m_sv;
|
||||
}
|
||||
|
||||
private:
|
||||
T &m_v;
|
||||
const T m_sv;
|
||||
};
|
||||
|
||||
size_t category::erase(condition &&cond)
|
||||
{
|
||||
return erase(std::move(cond), {});
|
||||
}
|
||||
|
||||
size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit)
|
||||
@@ -1225,12 +1143,26 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
|
||||
|
||||
cond.prepare(*this);
|
||||
|
||||
std::map<category *, condition> potential_orphans;
|
||||
|
||||
auto ri = begin();
|
||||
while (ri != end())
|
||||
{
|
||||
if (cond(*ri))
|
||||
{
|
||||
visit(*ri);
|
||||
if (visit)
|
||||
visit(*ri);
|
||||
|
||||
for (auto &&[childCat, link] : m_child_links)
|
||||
{
|
||||
auto ccond = get_children_condition(*ri, *childCat);
|
||||
if (not ccond)
|
||||
continue;
|
||||
potential_orphans[childCat] = std::move(potential_orphans[childCat]) or std::move(ccond);
|
||||
}
|
||||
|
||||
save_value sv(m_validator);
|
||||
|
||||
ri = erase(ri);
|
||||
++result;
|
||||
}
|
||||
@@ -1238,6 +1170,9 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
|
||||
++ri;
|
||||
}
|
||||
|
||||
for (auto &&[childCat, condition] : potential_orphans)
|
||||
childCat->erase_orphans(std::move(condition), *this);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1292,23 +1227,37 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
std::string id_tag = "id";
|
||||
if (m_cat_validator != nullptr and m_cat_validator->m_keys.size() == 1)
|
||||
id_tag = m_cat_validator->m_keys.front();
|
||||
|
||||
// calling size() often is a waste of resources
|
||||
if (m_last_unique_num == 0)
|
||||
m_last_unique_num = static_cast<uint32_t>(size());
|
||||
|
||||
for (;;)
|
||||
std::string result = generator(static_cast<int>(m_last_unique_num++));
|
||||
|
||||
std::string id_tag = "id";
|
||||
if (m_cat_validator != nullptr and m_cat_validator->m_keys.size() == 1)
|
||||
{
|
||||
std::string result = generator(static_cast<int>(m_last_unique_num++));
|
||||
|
||||
if (exists(key(id_tag) == result))
|
||||
continue;
|
||||
|
||||
return result;
|
||||
if (m_index == nullptr and m_cat_validator != nullptr)
|
||||
m_index = new category_index(this);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_index->find_by_value({{ id_tag, result }}) == nullptr)
|
||||
break;
|
||||
result = generator(static_cast<int>(m_last_unique_num++));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (not exists(key(id_tag) == result))
|
||||
break;
|
||||
|
||||
result = generator(static_cast<int>(m_last_unique_num++));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void category::update_value(const std::vector<row_handle> &rows, std::string_view tag, std::string_view value)
|
||||
|
||||
@@ -24,16 +24,15 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <cif++/compound.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace cif
|
||||
@@ -223,6 +222,28 @@ bool compound::atoms_bonded(const std::string &atomId_1, const std::string &atom
|
||||
return i != m_bonds.end();
|
||||
}
|
||||
|
||||
float compound::bond_length(const std::string &atomId_1, const std::string &atomId_2) const
|
||||
{
|
||||
auto i = find_if(m_bonds.begin(), m_bonds.end(),
|
||||
[&](const compound_bond &b)
|
||||
{
|
||||
return (b.atom_id[0] == atomId_1 and b.atom_id[1] == atomId_2) or (b.atom_id[0] == atomId_2 and b.atom_id[1] == atomId_1);
|
||||
});
|
||||
|
||||
float result = std::numeric_limits<float>::max();
|
||||
|
||||
if (i != m_bonds.end())
|
||||
{
|
||||
auto a = get_atom_by_atom_id(atomId_1);
|
||||
auto b = get_atom_by_atom_id(atomId_2);
|
||||
|
||||
result = distance(point{a.x, a.y, a.z}, point{b.x, b.y, b.z});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// known amino acids and bases
|
||||
|
||||
@@ -655,13 +676,13 @@ compound_factory::compound_factory()
|
||||
{
|
||||
auto ccd = cif::load_resource("components.cif");
|
||||
if (ccd)
|
||||
m_impl.reset(new CCD_compound_factory_impl(m_impl));
|
||||
m_impl = std::make_shared<CCD_compound_factory_impl>(m_impl);
|
||||
else if (cif::VERBOSE > 0)
|
||||
std::cerr << "CCD components.cif file was not found" << std::endl;
|
||||
|
||||
const char *clibd_mon = getenv("CLIBD_MON");
|
||||
if (clibd_mon != nullptr and fs::is_directory(clibd_mon))
|
||||
m_impl.reset(new CCP4_compound_factory_impl(clibd_mon));
|
||||
m_impl = std::make_shared<CCP4_compound_factory_impl>(clibd_mon, m_impl);
|
||||
else if (cif::VERBOSE > 0)
|
||||
std::cerr << "CCP4 monomers library not found, CLIBD_MON is not defined" << std::endl;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/category.hpp>
|
||||
#include <cif++/condition.hpp>
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/condition.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -63,7 +63,7 @@ namespace detail
|
||||
|
||||
condition_impl *key_equals_condition_impl::prepare(const category &c)
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
m_item_ix = c.get_column_ix(m_item_tag);
|
||||
m_icase = is_column_type_uchar(c, m_item_tag);
|
||||
|
||||
if (c.get_cat_validator() != nullptr and
|
||||
@@ -76,53 +76,82 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
condition_impl *and_condition_impl::prepare(const category &c)
|
||||
bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
|
||||
{
|
||||
for (auto &sub : mSub)
|
||||
sub = sub->prepare(c);
|
||||
bool result = true;
|
||||
|
||||
for (;;)
|
||||
for (auto s = b; s != e; ++s)
|
||||
{
|
||||
auto si = find_if(mSub.begin(), mSub.end(), [](condition_impl *sub) { return dynamic_cast<and_condition_impl *>(sub) != nullptr; });
|
||||
if (si == mSub.end())
|
||||
auto &cs = (*s)->m_sub;
|
||||
|
||||
if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i) { return i->equals(c); }) == cs.end())
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
|
||||
and_condition_impl *sub_and = static_cast<and_condition_impl *>(*si);
|
||||
|
||||
mSub.erase(si);
|
||||
|
||||
mSub.insert(mSub.end(), sub_and->mSub.begin(), sub_and->mSub.end());
|
||||
sub_and->mSub.clear();
|
||||
delete sub_and;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
return result;
|
||||
}
|
||||
|
||||
condition_impl *and_condition_impl::combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc)
|
||||
{
|
||||
and_condition_impl *and_result = nullptr;
|
||||
|
||||
auto first = subs.front();
|
||||
auto &fc = first->m_sub;
|
||||
|
||||
for (auto c : fc)
|
||||
{
|
||||
if (not found_in_range(c, subs.begin() + 1, subs.end()))
|
||||
continue;
|
||||
|
||||
if (and_result == nullptr)
|
||||
and_result = new and_condition_impl();
|
||||
|
||||
and_result->m_sub.push_back(c);
|
||||
fc.erase(remove(fc.begin(), fc.end(), c), fc.end());
|
||||
|
||||
for (auto sub : subs)
|
||||
{
|
||||
auto &ssub = sub->m_sub;
|
||||
|
||||
for (auto sc : ssub)
|
||||
{
|
||||
if (not sc->equals(c))
|
||||
continue;
|
||||
|
||||
ssub.erase(remove(ssub.begin(), ssub.end(), sc), ssub.end());
|
||||
delete sc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (and_result != nullptr)
|
||||
{
|
||||
and_result->m_sub.push_back(oc);
|
||||
return and_result;
|
||||
}
|
||||
|
||||
return oc;
|
||||
}
|
||||
|
||||
condition_impl *or_condition_impl::prepare(const category &c)
|
||||
{
|
||||
condition_impl *result = this;
|
||||
std::vector<and_condition_impl *> and_conditions;
|
||||
|
||||
mA = mA->prepare(c);
|
||||
mB = mB->prepare(c);
|
||||
|
||||
key_equals_condition_impl *equals = dynamic_cast<key_equals_condition_impl*>(mA);
|
||||
key_is_empty_condition_impl *empty = dynamic_cast<key_is_empty_condition_impl*>(mB);
|
||||
|
||||
if (equals == nullptr and empty == nullptr)
|
||||
for (auto &sub : m_sub)
|
||||
{
|
||||
equals = dynamic_cast<key_equals_condition_impl*>(mB);
|
||||
empty = dynamic_cast<key_is_empty_condition_impl*>(mA);
|
||||
sub = sub->prepare(c);
|
||||
if (typeid(*sub) == typeid(and_condition_impl))
|
||||
and_conditions.push_back(static_cast<and_condition_impl *>(sub));
|
||||
}
|
||||
|
||||
if (equals != nullptr and empty != nullptr and equals->m_item_tag == empty->m_item_tag)
|
||||
{
|
||||
result = new detail::key_equals_or_empty_condition_impl(equals);
|
||||
result = result->prepare(c);
|
||||
delete this;
|
||||
}
|
||||
if (and_conditions.size() == m_sub.size())
|
||||
return and_condition_impl::combine_equal(and_conditions, this);
|
||||
|
||||
return result;
|
||||
return this;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -24,11 +24,35 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/datablock.hpp>
|
||||
#include "cif++/datablock.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
datablock::datablock(const datablock &db)
|
||||
: std::list<category>(db)
|
||||
, m_name(db.m_name)
|
||||
, m_validator(db.m_validator)
|
||||
{
|
||||
for (auto &cat : *this)
|
||||
cat.update_links(*this);
|
||||
}
|
||||
|
||||
datablock &datablock::operator=(const datablock &db)
|
||||
{
|
||||
if (this != &db)
|
||||
{
|
||||
std::list<category>::operator=(db);
|
||||
m_name = db.m_name;
|
||||
m_validator = db.m_validator;
|
||||
|
||||
for (auto &cat : *this)
|
||||
cat.update_links(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void datablock::set_validator(const validator *v)
|
||||
{
|
||||
m_validator = v;
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/condition.hpp>
|
||||
#include <cif++/dictionary_parser.hpp>
|
||||
#include <cif++/file.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -117,7 +117,7 @@ class dictionary_parser : public parser
|
||||
if (not m_collected_item_types)
|
||||
m_collected_item_types = collect_item_types();
|
||||
|
||||
std::string saveFrameName = m_token_value;
|
||||
std::string saveFrameName { m_token_value };
|
||||
|
||||
if (saveFrameName.empty())
|
||||
error("Invalid save frame, should contain more than just 'save_' here");
|
||||
@@ -127,7 +127,7 @@ class dictionary_parser : public parser
|
||||
datablock dict(m_token_value);
|
||||
datablock::iterator cat = dict.end();
|
||||
|
||||
match(CIFToken::SAVE);
|
||||
match(CIFToken::SAVE_NAME);
|
||||
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag)
|
||||
{
|
||||
if (m_lookahead == CIFToken::LOOP)
|
||||
@@ -183,7 +183,7 @@ class dictionary_parser : public parser
|
||||
}
|
||||
}
|
||||
|
||||
match(CIFToken::SAVE);
|
||||
match(CIFToken::SAVE_);
|
||||
|
||||
if (isCategorySaveFrame)
|
||||
{
|
||||
@@ -481,4 +481,11 @@ validator parse_dictionary(std::string_view name, std::istream &is)
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
void extend_dictionary(validator &v, std::istream &is)
|
||||
{
|
||||
file f;
|
||||
dictionary_parser p(v, is, f);
|
||||
p.load_dictionary();
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/file.hpp>
|
||||
#include <cif++/gzio.hpp>
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -125,7 +125,7 @@ void file::load_dictionary(std::string_view name)
|
||||
|
||||
bool file::contains(std::string_view name) const
|
||||
{
|
||||
return std::find_if(begin(), end(), [name](const datablock &db) { return db.name() == name; }) != end();
|
||||
return std::find_if(begin(), end(), [name](const datablock &db) { return iequals(db.name(), name); }) != end();
|
||||
}
|
||||
|
||||
datablock &file::operator[](std::string_view name)
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <cif++/row.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
790
src/model.cpp
790
src/model.cpp
File diff suppressed because it is too large
Load Diff
526
src/parser.cpp
526
src/parser.cpp
@@ -24,35 +24,167 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "cif++/forward_decl.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <stack>
|
||||
|
||||
#include <cif++/utilities.hpp>
|
||||
|
||||
#include <cif++/forward_decl.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include <cif++/file.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
extern int VERBOSE;
|
||||
}
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class reserved_words_automaton
|
||||
{
|
||||
public:
|
||||
reserved_words_automaton() {}
|
||||
|
||||
enum move_result
|
||||
{
|
||||
undefined,
|
||||
no_keyword,
|
||||
data,
|
||||
global,
|
||||
loop,
|
||||
save,
|
||||
save_plus,
|
||||
stop
|
||||
};
|
||||
|
||||
constexpr bool finished() const
|
||||
{
|
||||
return m_state <= 0;
|
||||
}
|
||||
|
||||
constexpr bool matched() const
|
||||
{
|
||||
return m_state < 0;
|
||||
}
|
||||
|
||||
constexpr move_result move(int ch)
|
||||
{
|
||||
move_result result = undefined;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case -1: // data_
|
||||
if (sac_parser::is_non_blank(ch))
|
||||
m_seen_trailing_chars = true;
|
||||
else if (m_seen_trailing_chars)
|
||||
result = data;
|
||||
else
|
||||
result = no_keyword;
|
||||
break;
|
||||
|
||||
case -2: // global_
|
||||
result = sac_parser::is_non_blank(ch) ? no_keyword : global;
|
||||
break;
|
||||
|
||||
case -3: // loop_
|
||||
result = sac_parser::is_non_blank(ch) ? no_keyword : loop;
|
||||
break;
|
||||
|
||||
case -4: // save_
|
||||
if (sac_parser::is_non_blank(ch))
|
||||
m_seen_trailing_chars = true;
|
||||
else if (m_seen_trailing_chars)
|
||||
result = save_plus;
|
||||
else
|
||||
result = save;
|
||||
break;
|
||||
|
||||
case -5: // stop_
|
||||
result = sac_parser::is_non_blank(ch) ? no_keyword : stop;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(m_state > 0 and m_state < NODE_COUNT);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (s_dag[m_state].ch == (ch & ~0x20))
|
||||
{
|
||||
m_state = s_dag[m_state].next_match;
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = s_dag[m_state].next_nomatch;
|
||||
|
||||
if (m_state == 0)
|
||||
{
|
||||
result = no_keyword;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != undefined)
|
||||
m_state = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr struct node
|
||||
{
|
||||
int16_t ch;
|
||||
int8_t next_match;
|
||||
int8_t next_nomatch;
|
||||
} s_dag[] = {
|
||||
{ 0 },
|
||||
{ 'D', 5, 2 },
|
||||
{ 'G', 9, 3 },
|
||||
{ 'L', 15, 4 },
|
||||
{ 'S', 19, 0 },
|
||||
{ 'A', 6, 0 },
|
||||
{ 'T', 7, 0 },
|
||||
{ 'A', 8, 0 },
|
||||
{ '_', -1, 0 },
|
||||
{ 'L', 10, 0 },
|
||||
{ 'O', 11, 0 },
|
||||
{ 'B', 12, 0 },
|
||||
{ 'A', 13, 0 },
|
||||
{ 'L', 14, 0 },
|
||||
{ '_', -2, 0 },
|
||||
{ 'O', 16, 0},
|
||||
{ 'O', 17, 0 },
|
||||
{ 'P', 18, 0 },
|
||||
{ '_', -3, 0 },
|
||||
{ 'A', 21, 20 },
|
||||
{ 'T', 24, 0 },
|
||||
{ 'V', 22, 0 },
|
||||
{ 'E', 23, 0 },
|
||||
{ '_', -4, 0 },
|
||||
{ 'O', 25, 0 },
|
||||
{ 'P', 26, 0 },
|
||||
{ '_', -5, 0 },
|
||||
};
|
||||
|
||||
static constexpr int NODE_COUNT = sizeof(s_dag) / sizeof(node);
|
||||
|
||||
int m_state = 1;
|
||||
bool m_seen_trailing_chars = false;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
sac_parser::sac_parser(std::istream &is, bool init)
|
||||
: m_source(*is.rdbuf())
|
||||
{
|
||||
m_token_buffer.reserve(8192);
|
||||
|
||||
if (is.rdbuf() == nullptr)
|
||||
throw std::runtime_error("Attempt to read from uninitialised stream");
|
||||
|
||||
m_validate = true;
|
||||
m_line_nr = 1;
|
||||
m_bol = true;
|
||||
|
||||
@@ -60,45 +192,54 @@ sac_parser::sac_parser(std::istream &is, bool init)
|
||||
m_lookahead = get_next_token();
|
||||
}
|
||||
|
||||
bool sac_parser::is_unquoted_string(std::string_view text)
|
||||
{
|
||||
bool result = text.empty() or is_ordinary(text.front());
|
||||
if (result)
|
||||
{
|
||||
reserved_words_automaton automaton;
|
||||
|
||||
for (char ch : text)
|
||||
{
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
automaton.move(ch);
|
||||
}
|
||||
|
||||
if (automaton.matched())
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// get_next_char takes a char from the buffer, or if it is empty
|
||||
// from the istream. This function also does carriage/linefeed
|
||||
// translation.
|
||||
int sac_parser::get_next_char()
|
||||
{
|
||||
int result = std::char_traits<char>::eof();
|
||||
|
||||
if (m_buffer.empty())
|
||||
result = m_source.sbumpc();
|
||||
else
|
||||
{
|
||||
result = m_buffer.back();
|
||||
m_buffer.pop_back();
|
||||
}
|
||||
|
||||
// very simple CR/LF translation into LF
|
||||
if (result == '\r')
|
||||
{
|
||||
int lookahead = m_source.sbumpc();
|
||||
if (lookahead != '\n')
|
||||
m_buffer.push_back(lookahead);
|
||||
result = '\n';
|
||||
}
|
||||
int result = m_source.sbumpc();
|
||||
|
||||
if (result == std::char_traits<char>::eof())
|
||||
m_token_value.push_back(0);
|
||||
m_token_buffer.push_back(0);
|
||||
else
|
||||
m_token_value.push_back(std::char_traits<char>::to_char_type(result));
|
||||
|
||||
if (result == '\n')
|
||||
++m_line_nr;
|
||||
|
||||
if (VERBOSE >= 6)
|
||||
{
|
||||
std::cerr << "get_next_char => ";
|
||||
if (iscntrl(result) or not isprint(result))
|
||||
std::cerr << int(result) << std::endl;
|
||||
else
|
||||
std::cerr << char(result) << std::endl;
|
||||
if (result == '\r')
|
||||
{
|
||||
if (m_source.sgetc() == '\n')
|
||||
m_source.sbumpc();
|
||||
|
||||
++m_line_nr;
|
||||
result = '\n';
|
||||
}
|
||||
else if (result == '\n')
|
||||
++m_line_nr;
|
||||
|
||||
m_token_buffer.push_back(std::char_traits<char>::to_char_type(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -106,44 +247,22 @@ int sac_parser::get_next_char()
|
||||
|
||||
void sac_parser::retract()
|
||||
{
|
||||
assert(not m_token_value.empty());
|
||||
assert(not m_token_buffer.empty());
|
||||
|
||||
char ch = m_token_value.back();
|
||||
char ch = m_token_buffer.back();
|
||||
if (ch == '\n')
|
||||
--m_line_nr;
|
||||
|
||||
m_buffer.push_back(ch == 0 ? std::char_traits<char>::eof() : std::char_traits<char>::to_int_type(ch));
|
||||
m_token_value.pop_back();
|
||||
}
|
||||
|
||||
int sac_parser::restart(int start)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while (not m_token_value.empty())
|
||||
retract();
|
||||
|
||||
switch (start)
|
||||
if (ch != 0)
|
||||
{
|
||||
case State::Start:
|
||||
result = State::Float;
|
||||
break;
|
||||
// since we always putback at most a single character,
|
||||
// the test below should never fail.
|
||||
|
||||
case State::Float:
|
||||
result = State::Int;
|
||||
break;
|
||||
|
||||
case State::Int:
|
||||
result = State::Value;
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Invalid state in SacParser");
|
||||
if (m_source.sputbackc(ch) == std::char_traits<char>::eof())
|
||||
throw std::runtime_error("putback failure");
|
||||
}
|
||||
|
||||
m_bol = false;
|
||||
|
||||
return result;
|
||||
m_token_buffer.pop_back();
|
||||
}
|
||||
|
||||
sac_parser::CIFToken sac_parser::get_next_token()
|
||||
@@ -152,11 +271,13 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
|
||||
CIFToken result = CIFToken::Unknown;
|
||||
int quoteChar = 0;
|
||||
int state = State::Start, start = State::Start;
|
||||
State state = State::Start;
|
||||
m_bol = false;
|
||||
|
||||
m_token_value.clear();
|
||||
mTokenType = CIFValue::Unknown;
|
||||
m_token_buffer.clear();
|
||||
m_token_value = {};
|
||||
|
||||
reserved_words_automaton dag;
|
||||
|
||||
while (result == CIFToken::Unknown)
|
||||
{
|
||||
@@ -180,23 +301,27 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
state = State::Tag;
|
||||
else if (ch == ';' and m_bol)
|
||||
state = State::TextField;
|
||||
else if (ch == '?')
|
||||
state = State::QuestionMark;
|
||||
else if (ch == '\'' or ch == '"')
|
||||
{
|
||||
quoteChar = ch;
|
||||
state = State::QuotedString;
|
||||
}
|
||||
else if (dag.move(ch) == reserved_words_automaton::undefined)
|
||||
state = State::Reserved;
|
||||
else
|
||||
state = start = restart(start);
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case State::White:
|
||||
if (ch == kEOF)
|
||||
result = CIFToken::Eof;
|
||||
else if (not isspace(ch))
|
||||
else if (not is_space(ch))
|
||||
{
|
||||
state = State::Start;
|
||||
retract();
|
||||
m_token_value.clear();
|
||||
m_token_buffer.clear();
|
||||
}
|
||||
else
|
||||
m_bol = (ch == '\n');
|
||||
@@ -207,38 +332,40 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
{
|
||||
state = State::Start;
|
||||
m_bol = true;
|
||||
m_token_value.clear();
|
||||
m_token_buffer.clear();
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
result = CIFToken::Eof;
|
||||
else if (not is_any_print(ch))
|
||||
error("invalid character in comment");
|
||||
break;
|
||||
|
||||
case State::QuestionMark:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
}
|
||||
else
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case State::TextField:
|
||||
if (ch == '\n')
|
||||
state = State::TextField + 1;
|
||||
state = State::TextFieldNL;
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
// else if (ch == '\\')
|
||||
// state = State::Esc;
|
||||
else if (not is_any_print(ch) and cif::VERBOSE > 2)
|
||||
warning("invalid character in text field '" + std::string({static_cast<char>(ch)}) + "' (" + std::to_string((int)ch) + ")");
|
||||
break;
|
||||
|
||||
// case State::Esc:
|
||||
// if (ch == '\n')
|
||||
|
||||
// break;
|
||||
|
||||
case State::TextField + 1:
|
||||
case State::TextFieldNL:
|
||||
if (is_text_lead(ch) or ch == ' ' or ch == '\t')
|
||||
state = State::TextField;
|
||||
else if (ch == ';')
|
||||
{
|
||||
assert(m_token_value.length() >= 2);
|
||||
m_token_value = m_token_value.substr(1, m_token_value.length() - 3);
|
||||
mTokenType = CIFValue::TextField;
|
||||
assert(m_token_buffer.size() >= 2);
|
||||
m_token_value = std::string_view(m_token_buffer.data() + 1, m_token_buffer.size() - 3);
|
||||
result = CIFToken::Value;
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
@@ -261,12 +388,10 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
mTokenType = CIFValue::String;
|
||||
|
||||
if (m_token_value.length() < 2)
|
||||
if (m_token_buffer.size() < 2)
|
||||
error("Invalid quoted string token");
|
||||
|
||||
m_token_value = m_token_value.substr(1, m_token_value.length() - 2);
|
||||
m_token_value = std::string_view(m_token_buffer.data() + 1, m_token_buffer.size() - 2);
|
||||
}
|
||||
else if (ch == quoteChar)
|
||||
;
|
||||
@@ -283,148 +408,68 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Tag;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Float:
|
||||
if (ch == '+' or ch == '-')
|
||||
case State::Reserved:
|
||||
switch (dag.move(ch))
|
||||
{
|
||||
state = State::Float + 1;
|
||||
case reserved_words_automaton::undefined:
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::no_keyword:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
else
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::data:
|
||||
retract();
|
||||
m_token_value = std::string_view(m_token_buffer.data() + 5, m_token_buffer.size() - 5);
|
||||
result = CIFToken::DATA;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::global:
|
||||
retract();
|
||||
result = CIFToken::GLOBAL;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::loop:
|
||||
retract();
|
||||
result = CIFToken::LOOP;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::save:
|
||||
retract();
|
||||
result = CIFToken::SAVE_;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::save_plus:
|
||||
retract();
|
||||
m_token_value = std::string_view(m_token_buffer.data() + 5, m_token_buffer.size() - 5);
|
||||
result = CIFToken::SAVE_NAME;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::stop:
|
||||
retract();
|
||||
result = CIFToken::STOP;
|
||||
break;
|
||||
}
|
||||
else if (isdigit(ch))
|
||||
state = State::Float + 1;
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
case State::Float + 1:
|
||||
// if (ch == '(') // numeric???
|
||||
// mState = State::NumericSuffix;
|
||||
// else
|
||||
if (ch == '.')
|
||||
state = State::Float + 2;
|
||||
else if (tolower(ch) == 'e')
|
||||
state = State::Float + 3;
|
||||
else if (is_white(ch) or ch == kEOF)
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
mTokenType = CIFValue::Int;
|
||||
}
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
// parsed '.'
|
||||
case State::Float + 2:
|
||||
if (tolower(ch) == 'e')
|
||||
state = State::Float + 3;
|
||||
else if (is_white(ch) or ch == kEOF)
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
mTokenType = CIFValue::Float;
|
||||
}
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
// parsed 'e'
|
||||
case State::Float + 3:
|
||||
if (ch == '-' or ch == '+')
|
||||
state = State::Float + 4;
|
||||
else if (isdigit(ch))
|
||||
state = State::Float + 5;
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
case State::Float + 4:
|
||||
if (isdigit(ch))
|
||||
state = State::Float + 5;
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
case State::Float + 5:
|
||||
if (is_white(ch) or ch == kEOF)
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
mTokenType = CIFValue::Float;
|
||||
}
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
case State::Int:
|
||||
if (isdigit(ch) or ch == '+' or ch == '-')
|
||||
state = State::Int + 1;
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
case State::Int + 1:
|
||||
if (is_white(ch) or ch == kEOF)
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
mTokenType = CIFValue::Int;
|
||||
}
|
||||
else
|
||||
state = start = restart(start);
|
||||
break;
|
||||
|
||||
case State::Value:
|
||||
if (ch == '_')
|
||||
{
|
||||
std::string s = to_lower_copy(m_token_value);
|
||||
|
||||
if (s == "global_")
|
||||
result = CIFToken::GLOBAL;
|
||||
else if (s == "stop_")
|
||||
result = CIFToken::STOP;
|
||||
else if (s == "loop_")
|
||||
result = CIFToken::LOOP;
|
||||
else if (s == "data_")
|
||||
{
|
||||
state = State::DATA;
|
||||
continue;
|
||||
}
|
||||
else if (s == "save_")
|
||||
{
|
||||
state = State::SAVE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == CIFToken::Unknown and not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::Value;
|
||||
|
||||
if (m_token_value == ".")
|
||||
mTokenType = CIFValue::Inapplicable;
|
||||
else if (m_token_value == "?")
|
||||
{
|
||||
mTokenType = CIFValue::Unknown;
|
||||
m_token_value.clear();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case State::DATA:
|
||||
case State::SAVE:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
|
||||
if (state == State::DATA)
|
||||
result = CIFToken::DATA;
|
||||
else
|
||||
result = CIFToken::SAVE;
|
||||
|
||||
m_token_value.erase(m_token_value.begin(), m_token_value.begin() + 5);
|
||||
result = CIFToken::Value;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -438,8 +483,6 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
if (VERBOSE >= 5)
|
||||
{
|
||||
std::cerr << get_token_name(result);
|
||||
if (mTokenType != CIFValue::Unknown)
|
||||
std::cerr << ' ' << get_value_name(mTokenType);
|
||||
if (result != CIFToken::Eof)
|
||||
std::cerr << " " << std::quoted(m_token_value);
|
||||
std::cerr << std::endl;
|
||||
@@ -511,7 +554,7 @@ bool sac_parser::parse_single_datablock(const std::string &datablock)
|
||||
break;
|
||||
|
||||
case string_quote:
|
||||
if (std::isspace(ch))
|
||||
if (is_space(ch))
|
||||
state = start;
|
||||
else
|
||||
state = string;
|
||||
@@ -523,7 +566,7 @@ bool sac_parser::parse_single_datablock(const std::string &datablock)
|
||||
break;
|
||||
|
||||
case data:
|
||||
if (isspace(ch) and dblk[si] == 0)
|
||||
if (is_space(ch) and dblk[si] == 0)
|
||||
found = true;
|
||||
else if (dblk[si++] != ch)
|
||||
state = start;
|
||||
@@ -601,7 +644,7 @@ sac_parser::datablock_index sac_parser::index_datablocks()
|
||||
break;
|
||||
|
||||
case string_quote:
|
||||
if (std::isspace(ch))
|
||||
if (is_space(ch))
|
||||
state = start;
|
||||
else
|
||||
state = string;
|
||||
@@ -625,7 +668,7 @@ sac_parser::datablock_index sac_parser::index_datablocks()
|
||||
case data_name:
|
||||
if (is_non_blank(ch))
|
||||
datablock.insert(datablock.end(), char(ch));
|
||||
else if (isspace(ch))
|
||||
else if (is_space(ch))
|
||||
{
|
||||
if (not datablock.empty())
|
||||
index[datablock] = m_source.pubseekoff(0, std::ios_base::cur, std::ios_base::in);
|
||||
@@ -701,7 +744,7 @@ void sac_parser::parse_datablock()
|
||||
static const std::string kUnitializedCategory("<invalid>");
|
||||
std::string cat = kUnitializedCategory; // intial value acts as a guard for empty category names
|
||||
|
||||
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE)
|
||||
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE_NAME)
|
||||
{
|
||||
switch (m_lookahead)
|
||||
{
|
||||
@@ -766,7 +809,7 @@ void sac_parser::parse_datablock()
|
||||
break;
|
||||
}
|
||||
|
||||
case CIFToken::SAVE:
|
||||
case CIFToken::SAVE_NAME:
|
||||
parse_save_frame();
|
||||
break;
|
||||
|
||||
@@ -784,13 +827,16 @@ void sac_parser::parse_save_frame()
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void parser::produce_datablock(const std::string &name)
|
||||
void parser::produce_datablock(std::string_view name)
|
||||
{
|
||||
if (VERBOSE >= 4)
|
||||
std::cerr << "producing data_" << name << std::endl;
|
||||
|
||||
const auto &[iter, ignore] = m_file.emplace(name);
|
||||
m_datablock = &(*iter);
|
||||
}
|
||||
|
||||
void parser::produce_category(const std::string &name)
|
||||
void parser::produce_category(std::string_view name)
|
||||
{
|
||||
if (VERBOSE >= 4)
|
||||
std::cerr << "producing category " << name << std::endl;
|
||||
@@ -801,7 +847,7 @@ void parser::produce_category(const std::string &name)
|
||||
|
||||
void parser::produce_row()
|
||||
{
|
||||
if (VERBOSE >= 4)
|
||||
if (VERBOSE >= 4 and m_category != nullptr)
|
||||
std::cerr << "producing row for category " << m_category->name() << std::endl;
|
||||
|
||||
if (m_category == nullptr)
|
||||
@@ -812,7 +858,7 @@ void parser::produce_row()
|
||||
// m_row.lineNr(m_line_nr);
|
||||
}
|
||||
|
||||
void parser::produce_item(const std::string &category, const std::string &item, const std::string &value)
|
||||
void parser::produce_item(std::string_view category, std::string_view item, std::string_view value)
|
||||
{
|
||||
if (VERBOSE >= 4)
|
||||
std::cerr << "producing _" << category << '.' << item << " -> " << value << std::endl;
|
||||
@@ -823,4 +869,4 @@ void parser::produce_item(const std::string &category, const std::string &item,
|
||||
m_row[item] = m_token_value;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++.hpp"
|
||||
#include "cif++/pdb/cif2pdb.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
@@ -31,9 +35,6 @@
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include <cif++/pdb/cif2pdb.hpp>
|
||||
#include <cif++/gzio.hpp>
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
@@ -121,9 +122,9 @@ std::string cifSoftware(const datablock &db, SoftwareType sw)
|
||||
{
|
||||
switch (sw)
|
||||
{
|
||||
case eRefinement: result = db["computing"].find1<std::string>(key("entry_id") == db.name(), "structure_refinement"); break;
|
||||
case eDataScaling: result = db["computing"].find1<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ds"); break;
|
||||
case eDataReduction: result = db["computing"].find1<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ii"); break;
|
||||
case eRefinement: result = db["computing"].find_first<std::string>(key("entry_id") == db.name(), "structure_refinement"); break;
|
||||
case eDataScaling: result = db["computing"].find_first<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ds"); break;
|
||||
case eDataReduction: result = db["computing"].find_first<std::string>(key("entry_id") == db.name(), "pdbx_data_reduction_ii"); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -135,11 +136,11 @@ std::string cifSoftware(const datablock &db, SoftwareType sw)
|
||||
|
||||
switch (sw)
|
||||
{
|
||||
case eRefinement: r = software.find1(key("classification") == "refinement"); break;
|
||||
case eDataScaling: r = software.find1(key("classification") == "data scaling"); break;
|
||||
case eDataExtraction: r = software.find1(key("classification") == "data extraction"); break;
|
||||
case eDataReduction: r = software.find1(key("classification") == "data reduction"); break;
|
||||
case ePhasing: r = software.find1(key("classification") == "phasing"); break;
|
||||
case eRefinement: r = software.find_first(key("classification") == "refinement"); break;
|
||||
case eDataScaling: r = software.find_first(key("classification") == "data scaling"); break;
|
||||
case eDataExtraction: r = software.find_first(key("classification") == "data extraction"); break;
|
||||
case eDataReduction: r = software.find_first(key("classification") == "data reduction"); break;
|
||||
case ePhasing: r = software.find_first(key("classification") == "phasing"); break;
|
||||
}
|
||||
|
||||
if (not r.empty())
|
||||
@@ -671,6 +672,7 @@ class Fi : public FBase
|
||||
virtual void out(std::ostream &os)
|
||||
{
|
||||
std::string s{ text() };
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
os << "NULL";
|
||||
@@ -678,7 +680,18 @@ class Fi : public FBase
|
||||
os << std::string(os.width() - 4, ' ');
|
||||
}
|
||||
else
|
||||
os << std::stol(s);
|
||||
{
|
||||
long l = 0;
|
||||
auto r = std::from_chars(s.data(), s.data() + s.length(), l);
|
||||
if (r.ec != std::errc())
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Failed to write '" << s << "' as a long from field " << mField << ", this indicates an error in the code for writing PDB files" << std::endl;
|
||||
os << s;
|
||||
}
|
||||
else
|
||||
os << l;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -711,7 +724,7 @@ class Ff : public FBase
|
||||
if (r.ec != std::errc())
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Failed to write '" << s << "' as a double, this indicates an error in the code for writing PDB files" << std::endl;
|
||||
std::cerr << "Failed to write '" << s << "' as a double from field " << mField << ", this indicates an error in the code for writing PDB files" << std::endl;
|
||||
os << s;
|
||||
}
|
||||
else
|
||||
@@ -957,7 +970,7 @@ void WriteRemark3BusterTNT(std::ostream &pdbFile, const datablock &db)
|
||||
for (auto t : tls)
|
||||
{
|
||||
std::string id = t["id"].as<std::string>();
|
||||
auto g = db["pdbx_refine_tls_group"].find1(key("refine_tls_id") == id);
|
||||
auto g = db["pdbx_refine_tls_group"].find_first(key("refine_tls_id") == id);
|
||||
|
||||
pdbFile << RM3("") << std::endl
|
||||
<< RM3(" TLS GROUP : ") << id << std::endl
|
||||
@@ -1383,7 +1396,7 @@ void WriteRemark3Refmac(std::ostream &pdbFile, const datablock &db)
|
||||
unit = " : ";
|
||||
|
||||
pdbFile << RM3(" ", 18) << type
|
||||
<< SEP("", -2) << Fi(l, "pdbx_ens_id")
|
||||
<< SEP("", -2) << Fs(l, "pdbx_ens_id")
|
||||
<< SEP(" ", 1) << Fs(l, "pdbx_auth_asym_id")
|
||||
<< SEP(unit.c_str(), -6) << Fi(l, "pdbx_number")
|
||||
<< SEP(" ;", -6, 3) << Ff(l, "rms_dev_position")
|
||||
@@ -1393,10 +1406,24 @@ void WriteRemark3Refmac(std::ostream &pdbFile, const datablock &db)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add twin information
|
||||
pdbFile << RM3("") << std::endl
|
||||
<< RM3(" TWIN DETAILS") << std::endl;
|
||||
|
||||
// { R"(TWIN DETAILS)", "", {} },
|
||||
// { R"(NUMBER OF TWIN DOMAINS)", "", {} },
|
||||
auto &twins = db["pdbx_reflns_twin"];
|
||||
if (twins.empty())
|
||||
pdbFile << RM3(" NUMBER OF TWIN DOMAINS : NULL") << std::endl;
|
||||
else
|
||||
{
|
||||
pdbFile << RM3(" NUMBER OF TWIN DOMAINS : ") << twins.size() << std::endl;
|
||||
|
||||
int nr = 1;
|
||||
for (auto twin : twins)
|
||||
{
|
||||
pdbFile << RM3(" TWIN DOMAIN : ") << nr++ << std::endl
|
||||
<< RM3(" TWIN OPERATOR : ") << Fs(twin, "operator") << std::endl
|
||||
<< RM3(" TWIN FRACTION : ") << SEP("", -6, 3) << Ff(twin, "fraction") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
auto &tls = db["pdbx_refine_tls"];
|
||||
|
||||
@@ -1655,7 +1682,7 @@ void WriteRemark3Phenix(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
std::string id = t["id"].as<std::string>();
|
||||
|
||||
auto pdbx_refine_tls_group = db["pdbx_refine_tls_group"].find1(key("refine_tls_id") == id);
|
||||
auto pdbx_refine_tls_group = db["pdbx_refine_tls_group"].find_first(key("refine_tls_id") == id);
|
||||
|
||||
pdbFile << RM3(" TLS GROUP : ") << id << std::endl
|
||||
<< RM3(" SELECTION: ") << Fs(pdbx_refine_tls_group, "selection_details") << std::endl
|
||||
@@ -2187,20 +2214,20 @@ void WriteRemark200(std::ostream &pdbFile, const datablock &db)
|
||||
std::string diffrn_id = diffrn["id"].as<std::string>();
|
||||
std::string crystal_id = diffrn["crystal_id"].as<std::string>();
|
||||
|
||||
auto diffrn_radiation = db["diffrn_radiation"].find1(key("diffrn_id") == diffrn_id);
|
||||
auto diffrn_radiation_wavelength = db["diffrn_radiation_wavelength"].find1(key("id") == diffrn_radiation["wavelength_id"].as<std::string>());
|
||||
auto diffrn_source = db["diffrn_source"].find1(key("diffrn_id") == diffrn_id);
|
||||
auto diffrn_detector = db["diffrn_detector"].find1(key("diffrn_id") == diffrn_id);
|
||||
auto exptl = db["exptl"].find1(key("entry_id") == db.name());
|
||||
auto exptl_crystal = db["exptl_crystal"].find1(key("id") == crystal_id);
|
||||
auto exptl_crystal_grow = db["exptl_crystal_grow"].find1(key("crystal_id") == crystal_id);
|
||||
auto computing = db["computing"].find1(key("entry_id") == db.name());
|
||||
auto reflns = db["reflns"].find1(key("entry_id") == db.name());
|
||||
auto diffrn_radiation = db["diffrn_radiation"].find_first(key("diffrn_id") == diffrn_id);
|
||||
auto diffrn_radiation_wavelength = db["diffrn_radiation_wavelength"].find_first(key("id") == diffrn_radiation["wavelength_id"].as<std::string>());
|
||||
auto diffrn_source = db["diffrn_source"].find_first(key("diffrn_id") == diffrn_id);
|
||||
auto diffrn_detector = db["diffrn_detector"].find_first(key("diffrn_id") == diffrn_id);
|
||||
auto exptl = db["exptl"].find_first(key("entry_id") == db.name());
|
||||
auto exptl_crystal = db["exptl_crystal"].find_first(key("id") == crystal_id);
|
||||
auto exptl_crystal_grow = db["exptl_crystal_grow"].find_first(key("crystal_id") == crystal_id);
|
||||
auto computing = db["computing"].find_first(key("entry_id") == db.name());
|
||||
auto reflns = db["reflns"].find_first(key("entry_id") == db.name());
|
||||
|
||||
std::string pdbx_diffrn_id = reflns["pdbx_diffrn_id"].as<std::string>();
|
||||
|
||||
auto reflns_shell = db["reflns_shell"].find1(key("pdbx_diffrn_id") == pdbx_diffrn_id);
|
||||
auto refine = db["refine"].find1(key("pdbx_diffrn_id") == pdbx_diffrn_id);
|
||||
auto reflns_shell = db["reflns_shell"].find_first(key("pdbx_diffrn_id") == pdbx_diffrn_id);
|
||||
auto refine = db["refine"].find_first(key("pdbx_diffrn_id") == pdbx_diffrn_id);
|
||||
|
||||
std::string date =
|
||||
diffrn_detector.empty() ? "NULL" : cif2pdbDate(diffrn_detector["pdbx_collection_date"].as<std::string>());
|
||||
@@ -2325,7 +2352,7 @@ void WriteRemark280(std::ostream &pdbFile, const datablock &db)
|
||||
for (auto exptl_crystal : db["exptl_crystal"])
|
||||
{
|
||||
std::string crystal_id = exptl_crystal["id"].as<std::string>();
|
||||
auto exptl_crystal_grow = db["exptl_crystal_grow"].find1(key("crystal_id") == crystal_id);
|
||||
auto exptl_crystal_grow = db["exptl_crystal_grow"].find_first(key("crystal_id") == crystal_id);
|
||||
|
||||
pdbFile
|
||||
<< RM("") << std::endl
|
||||
@@ -2457,7 +2484,7 @@ void WriteRemark350(std::ostream &pdbFile, const datablock &db)
|
||||
}
|
||||
}
|
||||
|
||||
auto gen = db["pdbx_struct_assembly_gen"].find1(key("assembly_id") == id);
|
||||
auto gen = db["pdbx_struct_assembly_gen"].find_first(key("assembly_id") == id);
|
||||
|
||||
if (gen)
|
||||
{
|
||||
@@ -2471,7 +2498,7 @@ void WriteRemark350(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
for (auto oper_id : split<std::string>(oper_id_list, ",", true))
|
||||
{
|
||||
auto r = db["pdbx_struct_oper_list"].find1(key("id") == oper_id);
|
||||
auto r = db["pdbx_struct_oper_list"].find_first(key("id") == oper_id);
|
||||
|
||||
pdbFile << RM(" BIOMT1 ", -3) << Fs(r, "id")
|
||||
<< SEP(" ", -9, 6) << Ff(r, "matrix[1][1]")
|
||||
@@ -2951,7 +2978,7 @@ int WriteHeterogen(std::ostream &pdbFile, const datablock &db)
|
||||
if (id == water_comp_id)
|
||||
continue;
|
||||
|
||||
std::string syn = db["chem_comp"].find1<std::string>(key("id") == id, "pdbx_synonyms");
|
||||
std::string syn = db["chem_comp"].find_first<std::string>(key("id") == id, "pdbx_synonyms");
|
||||
if (syn.empty())
|
||||
continue;
|
||||
|
||||
@@ -3104,7 +3131,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
|
||||
std::string initResName, initChainID, initICode, endResName, endChainID, endICode;
|
||||
int initSeqNum, endSeqNum;
|
||||
|
||||
auto r1 = db["struct_sheet_range"].find1(key("sheet_id") == sheetID and key("id") == rangeID1);
|
||||
auto r1 = db["struct_sheet_range"].find_first(key("sheet_id") == sheetID and key("id") == rangeID1);
|
||||
|
||||
cif::tie(initResName, initICode, endResName, endICode,
|
||||
initResName, initChainID, initSeqNum, endResName, endChainID, endSeqNum) = r1.get("beg_label_comp_id", "pdbx_beg_PDB_ins_code", "end_label_comp_id",
|
||||
@@ -3119,7 +3146,7 @@ std::tuple<int, int> WriteSecondaryStructure(std::ostream &pdbFile, const databl
|
||||
std::string initResName, initChainID, initICode, endResName, endChainID, endICode, curAtom, curResName, curChainID, curICode, prevAtom, prevResName, prevChainID, prevICode;
|
||||
int initSeqNum, endSeqNum, curResSeq, prevResSeq;
|
||||
|
||||
auto r2 = db["struct_sheet_range"].find1(key("sheet_id") == sheetID and key("id") == rangeID2);
|
||||
auto r2 = db["struct_sheet_range"].find_first(key("sheet_id") == sheetID and key("id") == rangeID2);
|
||||
|
||||
cif::tie(initResName, initICode, endResName, endICode,
|
||||
initResName, initChainID, initSeqNum, endResName, endChainID, endSeqNum) = r2.get("beg_label_comp_id", "pdbx_beg_PDB_ins_code", "end_label_comp_id",
|
||||
@@ -3288,10 +3315,10 @@ int WriteMiscellaneousFeatures(std::ostream &pdbFile, const datablock &db)
|
||||
|
||||
void WriteCrystallographic(std::ostream &pdbFile, const datablock &db)
|
||||
{
|
||||
auto r = db["symmetry"].find1(key("entry_id") == db.name());
|
||||
auto r = db["symmetry"].find_first(key("entry_id") == db.name());
|
||||
std::string symmetry = r["space_group_name_H-M"].as<std::string>();
|
||||
|
||||
r = db["cell"].find1(key("entry_id") == db.name());
|
||||
r = db["cell"].find_first(key("entry_id") == db.name());
|
||||
|
||||
pdbFile << cif::format("CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11.11s%4d", r["length_a"].as<double>(), r["length_b"].as<double>(), r["length_c"].as<double>(), r["angle_alpha"].as<double>(), r["angle_beta"].as<double>(), r["angle_gamma"].as<double>(), symmetry, r["Z_PDB"].as<int>()) << std::endl;
|
||||
}
|
||||
@@ -3338,10 +3365,16 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
const std::map<std::string, std::tuple<std::string, int, std::string>> &last_resseq_for_chain_map,
|
||||
std::set<std::string> &terminatedChains, int model_nr)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
int numCoord = 0, numTer = 0;
|
||||
|
||||
auto &atom_site = db["atom_site"];
|
||||
auto &atom_site_anisotrop = db["atom_site_anisotrop"];
|
||||
auto &entity = db["entity"];
|
||||
// auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"];
|
||||
// auto &pdbx_nonpoly_scheme = db["pdbx_nonpoly_scheme"];
|
||||
auto &pdbx_branch_scheme = db["pdbx_branch_scheme"];
|
||||
|
||||
int serial = 1;
|
||||
auto ri = atom_site.begin();
|
||||
@@ -3358,10 +3391,21 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
cif::tie(nextResName, nextChainID, nextICode, nextResSeq, modelNum) =
|
||||
(*ri).get("label_comp_id", "auth_asym_id", "pdbx_PDB_ins_code", "auth_seq_id", "pdbx_PDB_model_num");
|
||||
|
||||
if (modelNum.empty() == false and stol(modelNum) != model_nr)
|
||||
if (modelNum.empty() == false)
|
||||
{
|
||||
++ri;
|
||||
continue;
|
||||
int nr = 0;
|
||||
auto r = std::from_chars(modelNum.data(), modelNum.data() + modelNum.length(), nr);
|
||||
if (r.ec != std::errc())
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Model number '" << modelNum << "' is not a valid integer" << std::endl;
|
||||
}
|
||||
|
||||
if (nr != model_nr)
|
||||
{
|
||||
++ri;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (chainID.empty() == false and terminatedChains.count(chainID) == 0)
|
||||
@@ -3404,6 +3448,26 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
r.get("id", "group_PDB", "label_atom_id", "label_alt_id", "auth_comp_id", "auth_asym_id", "auth_seq_id",
|
||||
"pdbx_PDB_ins_code", "Cartn_x", "Cartn_y", "Cartn_z", "occupancy", "B_iso_or_equiv", "type_symbol", "pdbx_formal_charge");
|
||||
|
||||
if (resName != "HOH")
|
||||
{
|
||||
int entity_id = r.get<int>("label_entity_id");
|
||||
try
|
||||
{
|
||||
auto type = entity.find1<std::string>("id"_key == entity_id, "type");
|
||||
|
||||
if (type == "branched") // find the real auth_seq_num, since sugars have their auth_seq_num reused as sugar number... sigh.
|
||||
resSeq = pdbx_branch_scheme.find1<int>("asym_id"_key == r.get<std::string>("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num");
|
||||
// else if (type == "non-polymer") // same for non-polymers
|
||||
// resSeq = pdbx_nonpoly_scheme.find1<int>("asym_id"_key == r.get<std::string>("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num");
|
||||
// else if (type == "polymer")
|
||||
// resSeq = pdbx_poly_seq_scheme.find1<int>("asym_id"_key == r.get<std::string>("label_asym_id") and "pdb_seq_num"_key == resSeq, "auth_seq_num");
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
std::cerr << "Oops, there was not exactly one entity with id " << entity_id << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (chainID.length() > 1)
|
||||
throw std::runtime_error("Chain ID " + chainID + " won't fit into a PDB file");
|
||||
|
||||
@@ -3418,7 +3482,7 @@ std::tuple<int, int> WriteCoordinatesForModel(std::ostream &pdbFile, const datab
|
||||
|
||||
++numCoord;
|
||||
|
||||
auto ai = atom_site_anisotrop.find1(key("id") == id);
|
||||
auto ai = atom_site_anisotrop.find_first(key("id") == id);
|
||||
if (not ai.empty())
|
||||
//
|
||||
// auto ai = find_if(atom_site_anisotrop.begin(), atom_site_anisotrop.end(), [id](row_handle r) -> bool { return r["id"] == id; });
|
||||
|
||||
@@ -24,17 +24,16 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include <cif++/pdb/pdb2cif.hpp>
|
||||
#include <cif++/pdb/pdb2cif_remark_3.hpp>
|
||||
#include <cif++/gzio.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <cif++/pdb/pdb2cif.hpp>
|
||||
#include <cif++/pdb/pdb2cif_remark_3.hpp>
|
||||
#include <cif++/gzio.hpp>
|
||||
|
||||
using cif::category;
|
||||
using cif::datablock;
|
||||
using cif::iequals;
|
||||
@@ -1583,7 +1582,7 @@ void PDBFileParser::ParseTitle()
|
||||
|
||||
if (not iequals(key, "MOL_ID") and mCompounds.empty())
|
||||
{
|
||||
if (cif::VERBOSE >= 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Ignoring invalid COMPND record" << std::endl;
|
||||
break;
|
||||
}
|
||||
@@ -3820,41 +3819,48 @@ void PDBFileParser::ConstructEntities()
|
||||
|
||||
for (std::string monID : monIds)
|
||||
{
|
||||
std::string authMonID, authSeqNum, authInsCode;
|
||||
std::string authMonID, authSeqNum, authInsCode{'.'};
|
||||
|
||||
if (res.mSeen)
|
||||
{
|
||||
authMonID = monID;
|
||||
authSeqNum = std::to_string(res.mSeqNum);
|
||||
if (res.mIcode != ' ' and res.mIcode != 0)
|
||||
authInsCode = std::string{ res.mIcode };
|
||||
|
||||
cat->emplace({
|
||||
{ "asym_id", asymID },
|
||||
{ "entity_id", mMolID2EntityID[chain.mMolID] },
|
||||
{ "seq_id", seqID },
|
||||
{ "mon_id", monID },
|
||||
{ "ndb_seq_num", seqID },
|
||||
{ "pdb_seq_num", res.mSeqNum },
|
||||
{ "auth_seq_num", authSeqNum },
|
||||
{ "pdb_mon_id", authMonID },
|
||||
{ "auth_mon_id", authMonID },
|
||||
{ "pdb_strand_id", std::string{ chain.mDbref.chainID } },
|
||||
{ "pdb_ins_code", authInsCode },
|
||||
{ "hetero", res.mAlts.empty() ? "n" : "y" } });
|
||||
}
|
||||
else
|
||||
{
|
||||
authMonID = res.mMonID;
|
||||
authSeqNum = std::to_string(res.mSeqNum);
|
||||
|
||||
if (res.mIcode != ' ' and res.mIcode != 0)
|
||||
authInsCode = std::string{ res.mIcode } + "A";
|
||||
else
|
||||
authInsCode = "A";
|
||||
|
||||
cat->emplace({
|
||||
{ "asym_id", asymID },
|
||||
{ "entity_id", mMolID2EntityID[chain.mMolID] },
|
||||
{ "seq_id", seqID },
|
||||
{ "mon_id", monID },
|
||||
{ "ndb_seq_num", seqID },
|
||||
{ "pdb_seq_num", res.mSeqNum },
|
||||
{ "auth_seq_num", "." },
|
||||
{ "pdb_mon_id", "." },
|
||||
{ "auth_mon_id", "." },
|
||||
{ "pdb_strand_id", std::string{ chain.mDbref.chainID } },
|
||||
{ "pdb_ins_code", authInsCode },
|
||||
{ "hetero", res.mAlts.empty() ? "n" : "y" } });
|
||||
}
|
||||
|
||||
if (authInsCode.empty())
|
||||
authInsCode = ".";
|
||||
|
||||
cat->emplace({
|
||||
{ "asym_id", asymID },
|
||||
{ "entity_id", mMolID2EntityID[chain.mMolID] },
|
||||
{ "seq_id", seqID },
|
||||
{ "mon_id", monID },
|
||||
{ "ndb_seq_num", seqID },
|
||||
{ "pdb_seq_num", res.mSeqNum },
|
||||
{ "auth_seq_num", authSeqNum },
|
||||
{ "pdb_mon_id", authMonID },
|
||||
{ "auth_mon_id", authMonID },
|
||||
{ "pdb_strand_id", std::string{ chain.mDbref.chainID } },
|
||||
{ "pdb_ins_code", authInsCode },
|
||||
{ "hetero", res.mAlts.empty() ? "n" : "y" } });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4196,7 +4202,8 @@ void PDBFileParser::ConstructEntities()
|
||||
// done with the sugar, resume operation as before
|
||||
|
||||
std::map<char, std::string> waterChains;
|
||||
std::map<std::tuple<std::string, std::string>, int> ndbSeqNum; // for nonpoly scheme
|
||||
std::map<std::tuple<std::string, std::string>, int> ndbSeqNum; // for nonpoly scheme
|
||||
std::map<std::string,int> entityAuthSeqNum; // for nonpoly scheme too
|
||||
|
||||
for (size_t i = 0; i < mHets.size(); ++i)
|
||||
{
|
||||
@@ -4325,6 +4332,7 @@ void PDBFileParser::ConstructEntities()
|
||||
}
|
||||
|
||||
int seqNr = ++ndbSeqNum[std::make_tuple(hetID, asymID)];
|
||||
int authSeqNr = ++entityAuthSeqNum[hetID];
|
||||
|
||||
std::string iCode{ het.iCode };
|
||||
cif::trim(iCode);
|
||||
@@ -4333,13 +4341,13 @@ void PDBFileParser::ConstructEntities()
|
||||
|
||||
getCategory("pdbx_nonpoly_scheme")->emplace({
|
||||
{ "asym_id", asymID },
|
||||
{ "entity_id", mHet2EntityID[hetID] },
|
||||
{ "mon_id", hetID },
|
||||
{ "ndb_seq_num", seqNr },
|
||||
{ "pdb_seq_num", het.seqNum },
|
||||
// { "auth_seq_num", het.seqNum }, // ????
|
||||
{ "entity_id", mHet2EntityID[hetID] },
|
||||
{ "mon_id", hetID },
|
||||
{ "ndb_seq_num", seqNr },
|
||||
{ "pdb_seq_num", het.seqNum },
|
||||
{ "auth_seq_num", authSeqNr }, // Yes
|
||||
{ "pdb_mon_id", hetID },
|
||||
// { "auth_mon_id", hetID },
|
||||
{ "auth_mon_id", hetID },
|
||||
{ "pdb_strand_id", std::string{ het.chainID } },
|
||||
{ "pdb_ins_code", iCode } });
|
||||
|
||||
@@ -6102,13 +6110,6 @@ int PDBFileParser::PDBChain::AlignResToSeqRes()
|
||||
switch (tb(x, y))
|
||||
{
|
||||
case -1:
|
||||
// if (cif::VERBOSE > 0)
|
||||
// std::cerr << "A residue found in the ATOM records "
|
||||
// << "(" << ry[y].mMonID << " @ " << mDbref.chainID << ":" << ry[y].mSeqNum
|
||||
// << ((ry[y].mIcode == ' ' or ry[y].mIcode == 0) ? "" : std::string{ ry[y].mIcode }) << ")"
|
||||
// << " was not found in the SEQRES records" << std::endl;
|
||||
// --y;
|
||||
|
||||
throw std::runtime_error("A residue found in the ATOM records (" + ry[y].mMonID +
|
||||
" @ " + std::string{ mDbref.chainID } + ":" + std::to_string(ry[y].mSeqNum) +
|
||||
((ry[y].mIcode == ' ' or ry[y].mIcode == 0) ? "" : std::string{ ry[y].mIcode }) +
|
||||
@@ -6123,10 +6124,11 @@ int PDBFileParser::PDBChain::AlignResToSeqRes()
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (cif::VERBOSE > 3 and rx[x].mMonID != ry[y].mMonID)
|
||||
std::cerr << "Warning, unaligned residues at " << x << "/" << y << "(" << rx[x].mMonID << '/' << ry[y].mMonID << ')' << std::endl;
|
||||
else if (cif::VERBOSE > 4)
|
||||
std::cerr << rx[x].mMonID << " -> " << ry[y].mMonID << " (" << ry[y].mSeqNum << ')' << std::endl;
|
||||
if (rx[x].mMonID != ry[y].mMonID)
|
||||
{
|
||||
std::cerr << "Warning, unaligned residues at " << x << "/" << y << "(" << rx[x].mMonID << '/' << ry[y].mMonID << ") SEQRES does not agree with ATOM records" << std::endl;
|
||||
rx[x].mMonID = ry[y].mMonID;
|
||||
}
|
||||
|
||||
rx[x].mSeqNum = ry[y].mSeqNum;
|
||||
rx[x].mIcode = ry[y].mIcode;
|
||||
@@ -6211,7 +6213,16 @@ file read(std::istream &is)
|
||||
if (ch == 'h' or ch == 'H')
|
||||
ReadPDBFile(is, result);
|
||||
else
|
||||
result.load(is);
|
||||
{
|
||||
try
|
||||
{
|
||||
result.load(is);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
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."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must be a PDB like file, right?
|
||||
@@ -6237,4 +6248,4 @@ file read(const std::filesystem::path &file)
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdbx
|
||||
} // namespace pdbx
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include "cif++.hpp"
|
||||
#include "cif++/pdb/pdb2cif_remark_3.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <cif++/pdb/pdb2cif_remark_3.hpp>
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
@@ -1234,7 +1233,9 @@ void Remark3Parser::storeCapture(const char *category, std::initializer_list<con
|
||||
{
|
||||
cat.emplace({ // #warning("crystal id, diffrn id, what should be put here?")
|
||||
{ "crystal_id", 1 },
|
||||
{ "diffrn_id", 1 } });
|
||||
{ "diffrn_id", 1 },
|
||||
{ "operator", "" },
|
||||
{ "fraction", 0.f } });
|
||||
}
|
||||
else if (iequals(category, "reflns"))
|
||||
cat.emplace({ { "pdbx_ordinal", cat.size() + 1 },
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
// #include <sys/ioctl.h>
|
||||
// #include <termios.h>
|
||||
|
||||
#include "cif++.hpp"
|
||||
#include "cif++/pdb/tls.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++.hpp>
|
||||
#include <cif++/pdb/tls.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -320,7 +320,7 @@ struct tls_selection_not : public tls_selection
|
||||
for (auto &r : residues)
|
||||
r.selected = not r.selected;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "NOT" << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -339,7 +339,7 @@ struct tls_selection_all : public tls_selection
|
||||
for (auto &r : residues)
|
||||
r.selected = true;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "ALL" << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -361,7 +361,7 @@ struct tls_selection_chain : public tls_selection_all
|
||||
for (auto &r : residues)
|
||||
r.selected = allChains or r.chainID == m_chain;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "CHAIN " << m_chain << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -384,7 +384,7 @@ struct tls_selection_res_id : public tls_selection_all
|
||||
for (auto &r : residues)
|
||||
r.selected = r.seqNr == m_seq_nr and r.iCode == m_icode;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "ResID " << m_seq_nr << (m_icode ? std::string{ m_icode } : "") << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -411,7 +411,7 @@ struct tls_selection_range_seq : public tls_selection_all
|
||||
(r.seqNr <= m_last or m_last == kResidueNrWildcard));
|
||||
}
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "Range " << m_first << ':' << m_last << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -461,7 +461,7 @@ struct tls_selection_range_id : public tls_selection_all
|
||||
}
|
||||
}
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "Through " << m_first << ':' << m_last << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -502,7 +502,7 @@ struct tls_selection_union : public tls_selection
|
||||
for (auto ai = a.begin(), bi = b.begin(), ri = residues.begin(); ri != residues.end(); ++ai, ++bi, ++ri)
|
||||
ri->selected = ai->selected or bi->selected;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "Union" << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -543,7 +543,7 @@ struct tls_selection_intersection : public tls_selection
|
||||
for (auto ai = a.begin(), bi = b.begin(), ri = residues.begin(); ri != residues.end(); ++ai, ++bi, ++ri)
|
||||
ri->selected = ai->selected and bi->selected;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "Intersection" << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -567,7 +567,7 @@ struct tls_selection_by_name : public tls_selection_all
|
||||
for (auto &r : residues)
|
||||
r.selected = r.name == m_name;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "Name " << m_name << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -595,7 +595,7 @@ struct tls_selection_by_element : public tls_selection_all
|
||||
for (auto &r : residues)
|
||||
r.selected = iequals(r.name, m_element);
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
{
|
||||
std::cout << std::string(indentLevel * 2, ' ') << "Element " << m_element << std::endl;
|
||||
dump_selection(residues, indentLevel);
|
||||
@@ -1404,7 +1404,7 @@ std::tuple<std::string, int> TLSSelectionParserImplBuster::ParseAtom()
|
||||
match(':');
|
||||
std::string atom = m_value_s;
|
||||
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Warning: ignoring atom ID '" << atom << "' in TLS selection" << std::endl;
|
||||
|
||||
match(bt_IDENT);
|
||||
@@ -1958,14 +1958,14 @@ std::unique_ptr<tls_selection> parse_tls_selection_details(const std::string &pr
|
||||
|
||||
if (not result)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Falling back to old BUSTER" << std::endl;
|
||||
result = busterOld.Parse(selection);
|
||||
}
|
||||
|
||||
if (not result)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Falling back to PHENIX" << std::endl;
|
||||
result = phenix.Parse(selection);
|
||||
}
|
||||
@@ -1976,35 +1976,35 @@ std::unique_ptr<tls_selection> parse_tls_selection_details(const std::string &pr
|
||||
|
||||
if (not result)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Falling back to BUSTER" << std::endl;
|
||||
result = buster.Parse(selection);
|
||||
}
|
||||
|
||||
if (not result)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Falling back to old BUSTER" << std::endl;
|
||||
result = busterOld.Parse(selection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "No known program specified, trying PHENIX" << std::endl;
|
||||
|
||||
result = phenix.Parse(selection);
|
||||
|
||||
if (not result)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Falling back to BUSTER" << std::endl;
|
||||
result = buster.Parse(selection);
|
||||
}
|
||||
|
||||
if (not result)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Falling back to old BUSTER" << std::endl;
|
||||
result = busterOld.Parse(selection);
|
||||
}
|
||||
|
||||
298
src/point.cpp
298
src/point.cpp
@@ -24,253 +24,15 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/matrix.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <random>
|
||||
|
||||
#include <cif++/point.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// We're using expression templates here
|
||||
|
||||
template <typename M>
|
||||
class MatrixExpression
|
||||
{
|
||||
public:
|
||||
uint32_t dim_m() const { return static_cast<const M &>(*this).dim_m(); }
|
||||
uint32_t dim_n() const { return static_cast<const M &>(*this).dim_n(); }
|
||||
|
||||
double &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
return static_cast<M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return static_cast<const M &>(*this).operator()(i, j);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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
|
||||
|
||||
class Matrix : public MatrixExpression<Matrix>
|
||||
{
|
||||
public:
|
||||
template <typename M2>
|
||||
Matrix(const MatrixExpression<M2> &m)
|
||||
: m_m(m.dim_m())
|
||||
, m_n(m.dim_n())
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_m; ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < m_n; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
Matrix(size_t m, size_t n, double v = 0)
|
||||
: m_m(m)
|
||||
, m_n(n)
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
Matrix() = default;
|
||||
Matrix(Matrix &&m) = default;
|
||||
Matrix(const Matrix &m) = default;
|
||||
Matrix &operator=(Matrix &&m) = default;
|
||||
Matrix &operator=(const Matrix &m) = default;
|
||||
|
||||
uint32_t dim_m() const { return m_m; }
|
||||
uint32_t dim_n() const { return m_n; }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
double &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_m = 0, m_n = 0;
|
||||
std::vector<double> m_data;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class SymmetricMatrix : public MatrixExpression<SymmetricMatrix>
|
||||
{
|
||||
public:
|
||||
SymmetricMatrix(uint32_t n, double v = 0)
|
||||
: m_n(n)
|
||||
, m_data((m_n * (m_n + 1)) / 2)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
SymmetricMatrix() = default;
|
||||
SymmetricMatrix(SymmetricMatrix &&m) = default;
|
||||
SymmetricMatrix(const SymmetricMatrix &m) = default;
|
||||
SymmetricMatrix &operator=(SymmetricMatrix &&m) = default;
|
||||
SymmetricMatrix &operator=(const SymmetricMatrix &m) = default;
|
||||
|
||||
uint32_t dim_m() const { return m_n; }
|
||||
uint32_t dim_n() const { return m_n; }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
: m_data[(i * (i + 1)) / 2 + j];
|
||||
}
|
||||
|
||||
double &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
assert(j < m_n);
|
||||
return m_data[(j * (j + 1)) / 2 + i];
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
std::vector<double> m_data;
|
||||
};
|
||||
|
||||
class IdentityMatrix : public MatrixExpression<IdentityMatrix>
|
||||
{
|
||||
public:
|
||||
IdentityMatrix(uint32_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t dim_m() const { return m_n; }
|
||||
uint32_t dim_n() const { return m_n; }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i == j ? 1 : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// matrix functions, implemented as expression templates
|
||||
|
||||
template <typename M1, typename M2>
|
||||
class MatrixSubtraction : public MatrixExpression<MatrixSubtraction<M1, M2>>
|
||||
{
|
||||
public:
|
||||
MatrixSubtraction(const M1 &m1, const M2 &m2)
|
||||
: m_m1(m1)
|
||||
, m_m2(m2)
|
||||
{
|
||||
assert(m_m1.dim_m() == m_m2.dim_m());
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
uint32_t dim_m() const { return m_m1.dim_m(); }
|
||||
uint32_t dim_n() const { return m_m1.dim_n(); }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M1 &m_m1;
|
||||
const M2 &m_m2;
|
||||
};
|
||||
|
||||
template <typename M1, typename M2>
|
||||
MatrixSubtraction<M1, M2> operator-(const MatrixExpression<M1> &m1, const MatrixExpression<M2> &m2)
|
||||
{
|
||||
return MatrixSubtraction(*static_cast<const M1 *>(&m1), *static_cast<const M2 *>(&m2));
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
class MatrixMultiplication : public MatrixExpression<MatrixMultiplication<M>>
|
||||
{
|
||||
public:
|
||||
MatrixMultiplication(const M &m, double v)
|
||||
: m_m(m)
|
||||
, m_v(v)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t dim_m() const { return m_m.dim_m(); }
|
||||
uint32_t dim_n() const { return m_m.dim_n(); }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
double m_v;
|
||||
};
|
||||
|
||||
template <typename M>
|
||||
MatrixMultiplication<M> operator*(const MatrixExpression<M> &m, double v)
|
||||
{
|
||||
return MatrixMultiplication(*static_cast<const M *>(&m), v);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <class M1>
|
||||
Matrix Cofactors(const M1 &m)
|
||||
{
|
||||
Matrix cf(m.dim_m(), m.dim_m());
|
||||
|
||||
const size_t ixs[4][3] = {
|
||||
{ 1, 2, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 1, 2 }
|
||||
};
|
||||
|
||||
for (size_t x = 0; x < 4; ++x)
|
||||
{
|
||||
const size_t *ix = ixs[x];
|
||||
|
||||
for (size_t y = 0; y < 4; ++y)
|
||||
{
|
||||
const size_t *iy = ixs[y];
|
||||
|
||||
cf(x, y) =
|
||||
m(ix[0], iy[0]) * m(ix[1], iy[1]) * m(ix[2], iy[2]) +
|
||||
m(ix[0], iy[1]) * m(ix[1], iy[2]) * m(ix[2], iy[0]) +
|
||||
m(ix[0], iy[2]) * m(ix[1], iy[0]) * m(ix[2], iy[1]) -
|
||||
m(ix[0], iy[2]) * m(ix[1], iy[1]) * m(ix[2], iy[0]) -
|
||||
m(ix[0], iy[1]) * m(ix[1], iy[0]) * m(ix[2], iy[2]) -
|
||||
m(ix[0], iy[0]) * m(ix[1], iy[2]) * m(ix[2], iy[1]);
|
||||
|
||||
if ((x + y) % 2 == 1)
|
||||
cf(x, y) *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
@@ -299,13 +61,14 @@ quaternion_type<T> normalize(quaternion_type<T> q)
|
||||
|
||||
quaternion construct_from_angle_axis(float angle, point axis)
|
||||
{
|
||||
auto q = std::cos((angle * kPI / 180) / 2);
|
||||
auto s = std::sqrt(1 - q * q);
|
||||
angle = (angle * kPI / 180) / 2;
|
||||
auto s = std::sin(angle);
|
||||
auto c = std::cos(angle);
|
||||
|
||||
axis.normalize();
|
||||
|
||||
return normalize(quaternion{
|
||||
static_cast<float>(q),
|
||||
static_cast<float>(c),
|
||||
static_cast<float>(s * axis.m_x),
|
||||
static_cast<float>(s * axis.m_y),
|
||||
static_cast<float>(s * axis.m_z) });
|
||||
@@ -355,6 +118,21 @@ point center_points(std::vector<point> &Points)
|
||||
return t;
|
||||
}
|
||||
|
||||
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
|
||||
float angle, float esd)
|
||||
{
|
||||
p1 -= p3;
|
||||
p2 -= p3;
|
||||
p4 -= p3;
|
||||
p3 -= p3;
|
||||
|
||||
quaternion q;
|
||||
auto axis = -p2;
|
||||
|
||||
float dh = dihedral_angle(p1, p2, p3, p4);
|
||||
return construct_from_angle_axis(angle - dh, axis);
|
||||
}
|
||||
|
||||
point centroid(const std::vector<point> &pts)
|
||||
{
|
||||
point result;
|
||||
@@ -427,8 +205,8 @@ double LargestDepressedQuarticSolution(double a, double b, double c)
|
||||
|
||||
quaternion align_points(const std::vector<point> &pa, const std::vector<point> &pb)
|
||||
{
|
||||
// First calculate M, a 3x3 Matrix containing the sums of products of the coordinates of A and B
|
||||
Matrix M(3, 3, 0);
|
||||
// First calculate M, a 3x3 matrix containing the sums of products of the coordinates of A and B
|
||||
matrix3x3<double> M;
|
||||
|
||||
for (uint32_t i = 0; i < pa.size(); ++i)
|
||||
{
|
||||
@@ -446,8 +224,8 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
|
||||
M(2, 2) += a.m_z * b.m_z;
|
||||
}
|
||||
|
||||
// Now calculate N, a symmetric 4x4 Matrix
|
||||
SymmetricMatrix N(4);
|
||||
// Now calculate N, a symmetric 4x4 matrix
|
||||
symmetric_matrix4x4<double> N(4);
|
||||
|
||||
N(0, 0) = M(0, 0) + M(1, 1) + M(2, 2);
|
||||
N(0, 1) = M(1, 2) - M(2, 1);
|
||||
@@ -496,16 +274,22 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
|
||||
double lambda = LargestDepressedQuarticSolution(C, D, E);
|
||||
|
||||
// calculate t = (N - λI)
|
||||
Matrix t = N - IdentityMatrix(4) * lambda;
|
||||
matrix<double> t(N - identity_matrix(4) * lambda);
|
||||
|
||||
// calculate a Matrix of cofactors for t
|
||||
Matrix cf = Cofactors(t);
|
||||
// calculate a matrix of cofactors for t
|
||||
auto cf = matrix_cofactors(t);
|
||||
|
||||
int maxR = 0;
|
||||
double maxCF = std::abs(cf(0, 0));
|
||||
|
||||
for (int r = 1; r < 4; ++r)
|
||||
{
|
||||
if (std::abs(cf(r, 0)) > std::abs(cf(maxR, 0)))
|
||||
auto cfr = std::abs(cf(r, 0));
|
||||
if (maxCF < cfr)
|
||||
{
|
||||
maxCF = cfr;
|
||||
maxR = r;
|
||||
}
|
||||
}
|
||||
|
||||
quaternion q(
|
||||
@@ -522,15 +306,17 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
|
||||
|
||||
point nudge(point p, float offset)
|
||||
{
|
||||
static const float kPI_f = static_cast<float>(kPI);
|
||||
|
||||
static std::random_device rd;
|
||||
static std::mt19937_64 rng(rd());
|
||||
|
||||
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI);
|
||||
std::normal_distribution<> randomOffset(0, offset);
|
||||
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI_f);
|
||||
std::normal_distribution<float> randomOffset(0, offset);
|
||||
|
||||
float theta = randomAngle(rng);
|
||||
float phi1 = randomAngle(rng) - kPI;
|
||||
float phi2 = randomAngle(rng) - kPI;
|
||||
float phi1 = randomAngle(rng) - kPI_f;
|
||||
float phi2 = randomAngle(rng) - kPI_f;
|
||||
|
||||
quaternion q = spherical(1.0f, theta, phi1, phi2);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/category.hpp>
|
||||
#include "cif++/category.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
400
src/symmetry.cpp
400
src/symmetry.cpp
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -24,23 +24,301 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/symmetry.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++/symmetry.hpp>
|
||||
#include "symop_table_data.hpp"
|
||||
|
||||
#include "./symop_table_data.hpp"
|
||||
#include <Eigen/Eigenvalues>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Unfortunately, clipper has a different numbering scheme than PDB
|
||||
// for rotation numbers. So we created a table to map those.
|
||||
// Perhaps a bit over the top, but hey....
|
||||
|
||||
cell::cell(float a, float b, float c, float alpha, float beta, float gamma)
|
||||
: m_a(a)
|
||||
, m_b(b)
|
||||
, m_c(c)
|
||||
, m_alpha(alpha)
|
||||
, m_beta(beta)
|
||||
, m_gamma(gamma)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
cell::cell(const datablock &db)
|
||||
{
|
||||
auto &_cell = db["cell"];
|
||||
|
||||
tie(m_a, m_b, m_c, m_alpha, m_beta, m_gamma) =
|
||||
_cell.front().get("length_a", "length_b", "length_c", "angle_alpha", "angle_beta", "angle_gamma");
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
void cell::init()
|
||||
{
|
||||
auto alpha = (m_alpha * kPI) / 180;
|
||||
auto beta = (m_beta * kPI) / 180;
|
||||
auto gamma = (m_gamma * kPI) / 180;
|
||||
|
||||
auto alpha_star = std::acos((std::cos(gamma) * std::cos(beta) - std::cos(alpha)) / (std::sin(beta) * std::sin(gamma)));
|
||||
|
||||
m_orthogonal = identity_matrix(3);
|
||||
|
||||
m_orthogonal(0, 0) = m_a;
|
||||
m_orthogonal(0, 1) = m_b * std::cos(gamma);
|
||||
m_orthogonal(0, 2) = m_c * std::cos(beta);
|
||||
m_orthogonal(1, 1) = m_b * std::sin(gamma);
|
||||
m_orthogonal(1, 2) = -m_c * std::sin(beta) * std::cos(alpha_star);
|
||||
m_orthogonal(2, 2) = m_c * std::sin(beta) * std::sin(alpha_star);
|
||||
|
||||
m_fractional = inverse(m_orthogonal);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int get_space_group_number(std::string spacegroup)
|
||||
sym_op::sym_op(std::string_view s)
|
||||
{
|
||||
auto b = s.data();
|
||||
auto e = b + s.length();
|
||||
|
||||
int rnri = 256; // default to unexisting number
|
||||
auto r = std::from_chars(b, e, rnri);
|
||||
|
||||
m_nr = 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)
|
||||
throw std::invalid_argument("Could not convert string into sym_op");
|
||||
}
|
||||
|
||||
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)
|
||||
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) };
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
transformation::transformation(const symop_data &data)
|
||||
{
|
||||
const auto &d = data.data();
|
||||
|
||||
m_rotation(0, 0) = d[0];
|
||||
m_rotation(0, 1) = d[1];
|
||||
m_rotation(0, 2) = d[2];
|
||||
m_rotation(1, 0) = d[3];
|
||||
m_rotation(1, 1) = d[4];
|
||||
m_rotation(1, 2) = d[5];
|
||||
m_rotation(2, 0) = d[6];
|
||||
m_rotation(2, 1) = d[7];
|
||||
m_rotation(2, 2) = d[8];
|
||||
|
||||
try_create_quaternion();
|
||||
|
||||
m_translation.m_x = d[9] == 0 ? 0 : 1.0 * d[9] / d[10];
|
||||
m_translation.m_y = d[11] == 0 ? 0 : 1.0 * d[11] / d[12];
|
||||
m_translation.m_z = d[13] == 0 ? 0 : 1.0 * d[13] / d[14];
|
||||
}
|
||||
|
||||
transformation::transformation(const matrix3x3<float> &r, const cif::point &t)
|
||||
: m_rotation(r)
|
||||
, m_translation(t)
|
||||
{
|
||||
try_create_quaternion();
|
||||
}
|
||||
|
||||
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::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();
|
||||
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
transformation operator*(const transformation &lhs, const transformation &rhs)
|
||||
{
|
||||
auto r = lhs.m_rotation * rhs.m_rotation;
|
||||
auto t = lhs.m_rotation * rhs.m_translation;
|
||||
t = t + lhs.m_translation;
|
||||
|
||||
return transformation(r, t);
|
||||
}
|
||||
|
||||
transformation inverse(const transformation &t)
|
||||
{
|
||||
auto inv_matrix = inverse(t.m_rotation);
|
||||
return { inv_matrix, -(inv_matrix * t.m_translation) };
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
spacegroup::spacegroup(int nr)
|
||||
: m_nr(nr)
|
||||
{
|
||||
const size_t N = kSymopNrTableSize;
|
||||
int32_t L = 0, R = static_cast<int32_t>(N - 1);
|
||||
while (L <= R)
|
||||
{
|
||||
int32_t i = (L + R) / 2;
|
||||
if (kSymopNrTable[i].spacegroup() < m_nr)
|
||||
L = i + 1;
|
||||
else
|
||||
R = i - 1;
|
||||
}
|
||||
|
||||
m_index = L;
|
||||
|
||||
for (size_t i = L; i < N and kSymopNrTable[i].spacegroup() == m_nr; ++i)
|
||||
emplace_back(kSymopNrTable[i].symop().data());
|
||||
}
|
||||
|
||||
std::string spacegroup::get_name() const
|
||||
{
|
||||
for (auto &s : kSpaceGroups)
|
||||
{
|
||||
if (s.nr == m_nr)
|
||||
return s.name;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Spacegroup has an invalid number: " + std::to_string(m_nr));
|
||||
}
|
||||
|
||||
point offsetToOrigin(const cell &c, const point &p)
|
||||
{
|
||||
point d{};
|
||||
|
||||
while (p.m_x + d.m_x < -(c.get_a()))
|
||||
d.m_x += c.get_a();
|
||||
while (p.m_x + d.m_x > (c.get_a()))
|
||||
d.m_x -= c.get_a();
|
||||
|
||||
while (p.m_y + d.m_y < -(c.get_b()))
|
||||
d.m_y += c.get_b();
|
||||
while (p.m_y + d.m_y > (c.get_b()))
|
||||
d.m_y -= c.get_b();
|
||||
|
||||
while (p.m_z + d.m_z < -(c.get_c()))
|
||||
d.m_z += c.get_c();
|
||||
while (p.m_z + d.m_z > (c.get_c()))
|
||||
d.m_z -= c.get_c();
|
||||
|
||||
return d;
|
||||
};
|
||||
|
||||
point offsetToOriginFractional(const point &p)
|
||||
{
|
||||
point d{};
|
||||
|
||||
while (p.m_x + d.m_x < -0.5f)
|
||||
d.m_x += 1;
|
||||
while (p.m_x + d.m_x > 0.5f)
|
||||
d.m_x -= 1;
|
||||
|
||||
while (p.m_y + d.m_y < -0.5f)
|
||||
d.m_y += 1;
|
||||
while (p.m_y + d.m_y > 0.5f)
|
||||
d.m_y -= 1;
|
||||
|
||||
while (p.m_z + d.m_z < -0.5f)
|
||||
d.m_z += 1;
|
||||
while (p.m_z + d.m_z > 0.5f)
|
||||
d.m_z -= 1;
|
||||
|
||||
return d;
|
||||
};
|
||||
|
||||
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;
|
||||
t.m_translation.m_y += symop.m_tb - 5;
|
||||
t.m_translation.m_z += symop.m_tc - 5;
|
||||
|
||||
auto fpt = fractional(pt, c);
|
||||
auto o = offsetToOriginFractional(fpt);
|
||||
|
||||
auto spt = t(fpt + o) - o;
|
||||
|
||||
return orthogonal(spt, c);
|
||||
}
|
||||
|
||||
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;
|
||||
t.m_translation.m_y += symop.m_tb - 5;
|
||||
t.m_translation.m_z += symop.m_tc - 5;
|
||||
|
||||
auto fpt = fractional(pt, c);
|
||||
auto o = offsetToOriginFractional(fpt);
|
||||
|
||||
auto it = cif::inverse(t);
|
||||
auto spt = it(fpt + o) - o;
|
||||
|
||||
return orthogonal(spt, c);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int get_space_group_number(std::string_view spacegroup)
|
||||
{
|
||||
if (spacegroup == "P 21 21 2 A")
|
||||
spacegroup = "P 21 21 2 (a)";
|
||||
@@ -73,7 +351,7 @@ int get_space_group_number(std::string spacegroup)
|
||||
{
|
||||
for (size_t i = 0; i < kNrOfSpaceGroups; ++i)
|
||||
{
|
||||
auto& sp = kSpaceGroups[i];
|
||||
auto &sp = kSpaceGroups[i];
|
||||
if (sp.xHM == spacegroup)
|
||||
{
|
||||
result = sp.nr;
|
||||
@@ -83,14 +361,14 @@ int get_space_group_number(std::string spacegroup)
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
throw std::runtime_error("Spacegroup name " + spacegroup + " was not found in table");
|
||||
|
||||
throw std::runtime_error("Spacegroup name " + std::string(spacegroup) + " was not found in table");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int get_space_group_number(std::string spacegroup, space_group_name type)
|
||||
int get_space_group_number(std::string_view spacegroup, space_group_name type)
|
||||
{
|
||||
if (spacegroup == "P 21 21 2 A")
|
||||
spacegroup = "P 21 21 2 (a)";
|
||||
@@ -145,9 +423,99 @@ int get_space_group_number(std::string spacegroup, space_group_name type)
|
||||
|
||||
// not found, see if we can find a match based on xHM name
|
||||
if (result == 0)
|
||||
throw std::runtime_error("Spacegroup name " + spacegroup + " was not found in table");
|
||||
|
||||
throw std::runtime_error("Spacegroup name " + std::string(spacegroup) + " was not found in table");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int get_space_group_number(const datablock &db)
|
||||
{
|
||||
auto &_symmetry = db["symmetry"];
|
||||
|
||||
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
|
||||
{
|
||||
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");
|
||||
|
||||
point result_fsb;
|
||||
float result_d = std::numeric_limits<float>::max();
|
||||
sym_op result_s;
|
||||
|
||||
auto fa = fractional(a, m_cell);
|
||||
auto fb = fractional(b, m_cell);
|
||||
|
||||
auto o = offsetToOriginFractional(fa);
|
||||
|
||||
fa = fa + o;
|
||||
fb = fb + o;
|
||||
|
||||
a = orthogonal(fa, m_cell);
|
||||
|
||||
for (size_t i = 0; i < m_spacegroup.size(); ++i)
|
||||
{
|
||||
sym_op s(i + 1);
|
||||
auto &t = m_spacegroup[i];
|
||||
|
||||
auto fsb = t(fb);
|
||||
|
||||
while (fsb.m_x - 0.5f > fa.m_x)
|
||||
{
|
||||
fsb.m_x -= 1;
|
||||
s.m_ta -= 1;
|
||||
}
|
||||
|
||||
while (fsb.m_x + 0.5f < fa.m_x)
|
||||
{
|
||||
fsb.m_x += 1;
|
||||
s.m_ta += 1;
|
||||
}
|
||||
|
||||
while (fsb.m_y - 0.5f > fa.m_y)
|
||||
{
|
||||
fsb.m_y -= 1;
|
||||
s.m_tb -= 1;
|
||||
}
|
||||
|
||||
while (fsb.m_y + 0.5f < fa.m_y)
|
||||
{
|
||||
fsb.m_y += 1;
|
||||
s.m_tb += 1;
|
||||
}
|
||||
|
||||
while (fsb.m_z - 0.5f > fa.m_z)
|
||||
{
|
||||
fsb.m_z -= 1;
|
||||
s.m_tc -= 1;
|
||||
}
|
||||
|
||||
while (fsb.m_z + 0.5f < fa.m_z)
|
||||
{
|
||||
fsb.m_z += 1;
|
||||
s.m_tc += 1;
|
||||
}
|
||||
|
||||
auto p = orthogonal(fsb, m_cell);
|
||||
auto dsq = distance_squared(a, p);
|
||||
|
||||
if (result_d > dsq)
|
||||
{
|
||||
result_d = dsq;
|
||||
result_fsb = fsb;
|
||||
result_s = s;
|
||||
}
|
||||
}
|
||||
|
||||
auto p = orthogonal(result_fsb - o, m_cell);
|
||||
|
||||
return { std::sqrt(result_d), p, result_s };
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
@@ -169,7 +170,7 @@ class SymopParser
|
||||
}
|
||||
|
||||
Token m_lookahead;
|
||||
int m_nr;
|
||||
int m_nr = -1;
|
||||
|
||||
std::string m_s;
|
||||
std::string::const_iterator m_p, m_e;
|
||||
@@ -230,14 +231,15 @@ int main(int argc, char* const argv[])
|
||||
|
||||
try
|
||||
{
|
||||
if (argc != 3)
|
||||
if (argc != 4)
|
||||
{
|
||||
std::cerr << "Usage symop-map-generator <input-file> <output-file>" << std::endl;
|
||||
std::cerr << "Usage symop-map-generator <syminfo.lib-file> <symop.lib-file> < <output-file>" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fs::path input(argv[1]);
|
||||
fs::path output(argv[2]);
|
||||
fs::path syminfolib(argv[1]);
|
||||
fs::path symoplib(argv[2]);
|
||||
fs::path output(argv[3]);
|
||||
|
||||
tmpFile = output.parent_path() / (output.filename().string() + ".tmp");
|
||||
|
||||
@@ -261,22 +263,51 @@ int main(int argc, char* const argv[])
|
||||
};
|
||||
|
||||
std::map<int,SymInfoBlock> symInfo;
|
||||
int symopnr, mysymnr = 10000;
|
||||
|
||||
std::ifstream file(input);
|
||||
std::ifstream file(symoplib);
|
||||
if (not file.is_open())
|
||||
throw std::runtime_error("Could not open symop.lib file");
|
||||
|
||||
std::string line;
|
||||
int sgnr = 0;
|
||||
int rnr = 0;
|
||||
|
||||
while (getline(file, line))
|
||||
{
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
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())
|
||||
throw std::runtime_error("Error parsing symop.lib file");
|
||||
rnr = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (not std::isspace(line[0]) or sgnr == 0)
|
||||
throw std::runtime_error("Error parsing symop.lib file");
|
||||
|
||||
SymopParser p;
|
||||
data.emplace_back(sgnr, rnr, p.parse(line));
|
||||
++rnr;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
file.open(syminfolib);
|
||||
if (not file.is_open())
|
||||
throw std::runtime_error("Could not open syminfo.lib file");
|
||||
|
||||
enum class State { skip, spacegroup } state = State::skip;
|
||||
|
||||
std::string line;
|
||||
|
||||
const std::regex rx(R"(^symbol +(Hall|xHM|old) +'(.+?)'(?: +'(.+?)')?$)"),
|
||||
rx2(R"(symbol ccp4 (\d+))");;
|
||||
|
||||
SymInfoBlock cur = {};
|
||||
|
||||
std::vector<std::array<int,15>> symops, cenops;
|
||||
// std::vector<std::array<int,15>> symops, cenops;
|
||||
|
||||
while (getline(file, line))
|
||||
{
|
||||
@@ -286,9 +317,7 @@ int main(int argc, char* const argv[])
|
||||
if (line == "begin_spacegroup")
|
||||
{
|
||||
state = State::spacegroup;
|
||||
symopnr = 1;
|
||||
++mysymnr;
|
||||
cur = { mysymnr };
|
||||
cur = {};
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -314,34 +343,34 @@ int main(int argc, char* const argv[])
|
||||
if (nr != 0)
|
||||
cur.nr = nr;
|
||||
}
|
||||
else if (line.compare(0, 6, "symop ") == 0)
|
||||
{
|
||||
SymopParser p;
|
||||
symops.emplace_back(p.parse(line.substr(6)));
|
||||
}
|
||||
else if (line.compare(0, 6, "cenop ") == 0)
|
||||
{
|
||||
SymopParser p;
|
||||
cenops.emplace_back(p.parse(line.substr(6)));
|
||||
}
|
||||
// else if (line.compare(0, 6, "symop ") == 0)
|
||||
// {
|
||||
// SymopParser p;
|
||||
// symops.emplace_back(p.parse(line.substr(6)));
|
||||
// }
|
||||
// else if (line.compare(0, 6, "cenop ") == 0)
|
||||
// {
|
||||
// SymopParser p;
|
||||
// cenops.emplace_back(p.parse(line.substr(6)));
|
||||
// }
|
||||
else if (line == "end_spacegroup")
|
||||
{
|
||||
for (auto& cenop: cenops)
|
||||
{
|
||||
for (auto symop: symops)
|
||||
{
|
||||
symop = move_symop(symop, cenop);
|
||||
// for (auto& cenop: cenops)
|
||||
// {
|
||||
// for (auto symop: symops)
|
||||
// {
|
||||
// symop = move_symop(symop, cenop);
|
||||
|
||||
data.emplace_back(cur.nr, symopnr, symop);
|
||||
++symopnr;
|
||||
}
|
||||
}
|
||||
// data.emplace_back(cur.nr, symopnr, symop);
|
||||
// ++symopnr;
|
||||
// }
|
||||
// }
|
||||
|
||||
symInfo.emplace(cur.nr, cur);
|
||||
state = State::skip;
|
||||
|
||||
symops.clear();
|
||||
cenops.clear();
|
||||
// symops.clear();
|
||||
// cenops.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -358,7 +387,7 @@ int main(int argc, char* const argv[])
|
||||
// and $CLIBD/syminfo.lib using symop-map-generator,
|
||||
// part of the PDB-REDO suite of programs.
|
||||
|
||||
#include <cif++/symmetry.hpp>
|
||||
#include "cif++/symmetry.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -383,10 +412,10 @@ const space_group kSpaceGroups[] =
|
||||
old = '"' + old + '"' + std::string(20 - old.length(), ' ');
|
||||
xHM = '"' + xHM + '"' + std::string(30 - xHM.length(), ' ');
|
||||
|
||||
for (std::string::size_type p = Hall.length(); p > 0; --p)
|
||||
for (auto p = Hall.begin(); p != Hall.end(); ++p)
|
||||
{
|
||||
if (Hall[p - 1] == '"')
|
||||
Hall.insert(p - 1, "\\", 1);
|
||||
if (*p == '"')
|
||||
p = Hall.insert(p, '\\') + 1;
|
||||
}
|
||||
|
||||
Hall = '"' + Hall + '"' + std::string(40 - Hall.length(), ' ');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
29
src/text.cpp
29
src/text.cpp
@@ -24,11 +24,11 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include <cif++/text.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -236,28 +236,19 @@ std::string cif_id_for_number(int number)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (number >= 26 * 26 * 26)
|
||||
result = 'L' + std::to_string(number);
|
||||
else
|
||||
do
|
||||
{
|
||||
if (number >= 26 * 26)
|
||||
{
|
||||
int v = number / (26 * 26);
|
||||
result += char('A' - 1 + v);
|
||||
number %= (26 * 26);
|
||||
}
|
||||
int r = number % 26;
|
||||
result += 'A' + r;
|
||||
|
||||
if (number >= 26)
|
||||
{
|
||||
int v = number / 26;
|
||||
result += char('A' - 1 + v);
|
||||
number %= 26;
|
||||
}
|
||||
|
||||
result += char('A' + number);
|
||||
number = (number - r) / 26 - 1;
|
||||
}
|
||||
while (number >= 0);
|
||||
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
assert(not result.empty());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,14 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include "revision.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
@@ -35,7 +40,6 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
@@ -44,10 +48,6 @@
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#include <cif++/utilities.hpp>
|
||||
|
||||
#include "revision.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -124,7 +124,8 @@ std::string get_executable_path()
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
char path[PATH_MAX] = "";
|
||||
// This used to be PATH_MAX, but lets simply assume 1024 is enough...
|
||||
char path[1024] = "";
|
||||
if (readlink("/proc/self/exe", path, sizeof(path)) == -1)
|
||||
throw std::runtime_error("could not get exe path "s + strerror(errno));
|
||||
return {path};
|
||||
@@ -134,62 +135,81 @@ std::string get_executable_path()
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
struct ProgressImpl
|
||||
struct progress_bar_impl
|
||||
{
|
||||
ProgressImpl(int64_t inMax, const std::string &inAction)
|
||||
: mMax(inMax)
|
||||
, mConsumed(0)
|
||||
, mAction(inAction)
|
||||
, mMessage(inAction)
|
||||
, mThread(std::bind(&ProgressImpl::Run, this))
|
||||
progress_bar_impl(int64_t inMax, const std::string &inAction)
|
||||
: m_max_value(inMax)
|
||||
, m_consumed(0)
|
||||
, m_action(inAction)
|
||||
, m_message(inAction)
|
||||
, m_thread(std::bind(&progress_bar_impl::run, this))
|
||||
{
|
||||
}
|
||||
|
||||
void Run();
|
||||
void Stop()
|
||||
{
|
||||
mStop = true;
|
||||
if (mThread.joinable())
|
||||
mThread.join();
|
||||
}
|
||||
progress_bar_impl(const progress_bar_impl&) = delete;
|
||||
progress_bar_impl &operator=(const progress_bar_impl &) = delete;
|
||||
|
||||
void PrintProgress();
|
||||
void PrintDone();
|
||||
~progress_bar_impl();
|
||||
|
||||
int64_t mMax;
|
||||
std::atomic<int64_t> mConsumed;
|
||||
int64_t mLastConsumed = 0;
|
||||
int mSpinnerIndex = 0;
|
||||
std::string mAction, mMessage;
|
||||
std::mutex mMutex;
|
||||
std::thread mThread;
|
||||
std::chrono::time_point<std::chrono::system_clock>
|
||||
mStart = std::chrono::system_clock::now();
|
||||
bool mStop = false;
|
||||
void run();
|
||||
|
||||
void consumed(int64_t n);
|
||||
void progress(int64_t p);
|
||||
void message(const std::string &msg);
|
||||
|
||||
void print_progress();
|
||||
void print_done();
|
||||
|
||||
using time_point = std::chrono::time_point<std::chrono::system_clock>;
|
||||
|
||||
int64_t m_max_value;
|
||||
std::atomic<int64_t> m_consumed;
|
||||
int64_t m_last_consumed = 0;
|
||||
int m_spinner_index = 0;
|
||||
std::string m_action, m_message;
|
||||
std::mutex m_mutex;
|
||||
std::thread m_thread;
|
||||
time_point m_start = std::chrono::system_clock::now();
|
||||
time_point m_last = std::chrono::system_clock::now();
|
||||
bool m_stop = false;
|
||||
};
|
||||
|
||||
void ProgressImpl::Run()
|
||||
progress_bar_impl::~progress_bar_impl()
|
||||
{
|
||||
using namespace std::literals;
|
||||
assert(m_thread.joinable());
|
||||
|
||||
m_stop = true;
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void progress_bar_impl::run()
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
bool printedAny = false;
|
||||
|
||||
try
|
||||
{
|
||||
for (;;)
|
||||
while (not m_stop)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
std::unique_lock lock(mMutex);
|
||||
|
||||
if (mStop or mConsumed == mMax)
|
||||
break;
|
||||
|
||||
auto elapsed = std::chrono::system_clock::now() - mStart;
|
||||
|
||||
if (elapsed < std::chrono::seconds(5))
|
||||
if (now - m_start < 2s or now - m_last < 100ms)
|
||||
{
|
||||
std::this_thread::sleep_for(10ms);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (not printedAny and isatty(STDOUT_FILENO))
|
||||
std::cout << "\e[?25l";
|
||||
|
||||
print_progress();
|
||||
|
||||
PrintProgress();
|
||||
printedAny = true;
|
||||
m_last = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -197,93 +217,93 @@ void ProgressImpl::Run()
|
||||
}
|
||||
|
||||
if (printedAny)
|
||||
PrintDone();
|
||||
{
|
||||
print_done();
|
||||
if (isatty(STDOUT_FILENO))
|
||||
std::cout << "\e[?25h";
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressImpl::PrintProgress()
|
||||
void progress_bar_impl::consumed(int64_t n)
|
||||
{
|
||||
// const char* kBlocks[] = {
|
||||
// " ", // 0
|
||||
// u8"\u258F", // 1
|
||||
// u8"\u258E", // 2
|
||||
// u8"\u258D", // 3
|
||||
// u8"\u258C", // 4
|
||||
// u8"\u258B", // 5
|
||||
// u8"\u258A", // 6
|
||||
// u8"\u2589", // 7
|
||||
// u8"\u2588", // 8
|
||||
// };
|
||||
m_consumed += n;
|
||||
}
|
||||
|
||||
void progress_bar_impl::progress(int64_t p)
|
||||
{
|
||||
m_consumed = p;
|
||||
}
|
||||
|
||||
void progress_bar_impl::message(const std::string &msg)
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
m_message = msg;
|
||||
}
|
||||
|
||||
const char* kSpinner[] = {
|
||||
// "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"
|
||||
".", "o", "O", "0", "O", "o", ".", " "
|
||||
};
|
||||
const size_t kSpinnerCount = sizeof(kSpinner) / sizeof(char*);
|
||||
const uint32_t kMinBarWidth = 40, kMinMsgWidth = 12;
|
||||
|
||||
void progress_bar_impl::print_progress()
|
||||
{
|
||||
const char *kBlocks[] = {
|
||||
" ", // 0
|
||||
" ", // 1
|
||||
" ", // 2
|
||||
"-", // 3
|
||||
"-", // 4
|
||||
"-", // 5
|
||||
"=", // 6
|
||||
"=", // 7
|
||||
"=", // 8
|
||||
// "▯", // 0
|
||||
// "▮", // 1
|
||||
"=",
|
||||
"-"
|
||||
};
|
||||
|
||||
uint32_t width = get_terminal_width();
|
||||
|
||||
std::string msg;
|
||||
msg.reserve(width + 1);
|
||||
if (mMessage.length() <= 20)
|
||||
{
|
||||
msg = mMessage;
|
||||
if (msg.length() < 20)
|
||||
msg.append(20 - msg.length(), ' ');
|
||||
}
|
||||
float progress = static_cast<float>(m_consumed) / m_max_value;
|
||||
|
||||
if (width < kMinBarWidth)
|
||||
std::cout << (100 * progress) << '%' << std::endl;
|
||||
else
|
||||
msg = mMessage.substr(0, 17) + "...";
|
||||
|
||||
msg += " |";
|
||||
|
||||
int64_t consumed = mConsumed;
|
||||
float progress = static_cast<float>(consumed) / mMax;
|
||||
int pi = static_cast<int>(std::ceil(progress * 33 * 8));
|
||||
// int tw = width - 28;
|
||||
// int twd = static_cast<int>(tw * progress + 0.5f);
|
||||
// msg.append(twd, '=');
|
||||
// msg.append(tw - twd, ' ');
|
||||
|
||||
for (int i = 0; i < 33; ++i)
|
||||
{
|
||||
if (pi <= 0)
|
||||
msg += kBlocks[0];
|
||||
else if (pi >= 8)
|
||||
msg += kBlocks[8];
|
||||
uint32_t bar_width = 7 * width / 10;
|
||||
uint32_t pct_width = 7;
|
||||
uint32_t msg_width = width - bar_width - pct_width - 1;
|
||||
|
||||
if (msg_width < kMinMsgWidth)
|
||||
{
|
||||
bar_width += kMinMsgWidth - msg_width;
|
||||
msg_width = kMinMsgWidth;
|
||||
}
|
||||
|
||||
std::ostringstream msg;
|
||||
|
||||
if (m_message.length() <= msg_width)
|
||||
{
|
||||
msg << m_message;
|
||||
if (m_message.length() < msg_width)
|
||||
msg << std::string(msg_width - m_message.length(), ' ');
|
||||
}
|
||||
else
|
||||
msg += kBlocks[pi];
|
||||
pi -= 8;
|
||||
msg << m_message.substr(0, msg_width - 3) << "...";
|
||||
|
||||
msg << ' ';
|
||||
|
||||
uint32_t pi = static_cast<uint32_t>(std::ceil(progress * bar_width));
|
||||
|
||||
for (uint32_t i = 0; i < bar_width; ++i)
|
||||
msg << kBlocks[i > pi ? 1 : 0];
|
||||
|
||||
msg << ' ';
|
||||
|
||||
msg << std::setw(3) << static_cast<int>(std::ceil(progress * 100)) << "% ";
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
m_spinner_index = (std::chrono::duration_cast<std::chrono::milliseconds>(now - m_start).count() / 200) % kSpinnerCount;
|
||||
|
||||
msg << kSpinner[m_spinner_index];
|
||||
|
||||
std::cout << '\r' << msg.str();
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
msg.append("| ");
|
||||
|
||||
const char kSpinner[] = {' ', '.', 'o', 'O', '0', 'O', 'o', '.'};
|
||||
const size_t kSpinnerCount = sizeof(kSpinner);
|
||||
|
||||
if (mLastConsumed < consumed)
|
||||
{
|
||||
mLastConsumed = consumed;
|
||||
mSpinnerIndex = (mSpinnerIndex + 1) % kSpinnerCount;
|
||||
}
|
||||
|
||||
const char spinner[2] = {kSpinner[mSpinnerIndex], 0};
|
||||
msg.append(spinner);
|
||||
|
||||
// int perc = static_cast<int>(100 * progress);
|
||||
// if (perc < 100)
|
||||
// msg += ' ';
|
||||
// if (perc < 10)
|
||||
// msg += ' ';
|
||||
// msg += to_string(perc);
|
||||
// msg += '%';
|
||||
|
||||
std::cout << '\r' << msg;
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -322,12 +342,12 @@ namespace
|
||||
|
||||
} // namespace
|
||||
|
||||
void ProgressImpl::PrintDone()
|
||||
void progress_bar_impl::print_done()
|
||||
{
|
||||
std::chrono::duration<double> elapsed = std::chrono::system_clock::now() - mStart;
|
||||
std::chrono::duration<double> elapsed = std::chrono::system_clock::now() - m_start;
|
||||
|
||||
std::ostringstream msgstr;
|
||||
msgstr << mAction << " done in " << elapsed << " seconds";
|
||||
msgstr << m_action << " done in " << elapsed << " seconds";
|
||||
auto msg = msgstr.str();
|
||||
|
||||
uint32_t width = get_terminal_width();
|
||||
@@ -338,46 +358,34 @@ void ProgressImpl::PrintDone()
|
||||
std::cout << '\r' << msg << std::endl;
|
||||
}
|
||||
|
||||
Progress::Progress(int64_t inMax, const std::string &inAction)
|
||||
progress_bar::progress_bar(int64_t inMax, const std::string &inAction)
|
||||
: m_impl(nullptr)
|
||||
{
|
||||
if (isatty(STDOUT_FILENO) and VERBOSE >= 0)
|
||||
m_impl = new ProgressImpl(inMax, inAction);
|
||||
m_impl = new progress_bar_impl(inMax, inAction);
|
||||
}
|
||||
|
||||
Progress::~Progress()
|
||||
progress_bar::~progress_bar()
|
||||
{
|
||||
if (m_impl != nullptr)
|
||||
m_impl->Stop();
|
||||
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
void Progress::consumed(int64_t inConsumed)
|
||||
{
|
||||
if (m_impl != nullptr and
|
||||
(m_impl->mConsumed += inConsumed) >= m_impl->mMax)
|
||||
{
|
||||
m_impl->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void Progress::progress(int64_t inProgress)
|
||||
{
|
||||
if (m_impl != nullptr and
|
||||
(m_impl->mConsumed = inProgress) >= m_impl->mMax)
|
||||
{
|
||||
m_impl->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void Progress::message(const std::string &inMessage)
|
||||
void progress_bar::consumed(int64_t inConsumed)
|
||||
{
|
||||
if (m_impl != nullptr)
|
||||
{
|
||||
std::unique_lock lock(m_impl->mMutex);
|
||||
m_impl->mMessage = inMessage;
|
||||
}
|
||||
m_impl->consumed(inConsumed);
|
||||
}
|
||||
|
||||
void progress_bar::progress(int64_t inProgress)
|
||||
{
|
||||
if (m_impl != nullptr)
|
||||
m_impl->progress(inProgress);
|
||||
}
|
||||
|
||||
void progress_bar::message(const std::string &inMessage)
|
||||
{
|
||||
if (m_impl != nullptr)
|
||||
m_impl->message(inMessage);
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
@@ -405,9 +413,9 @@ struct rsrc_imp
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
extern "C" const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
|
||||
extern "C" const char *gResourceDataDefault[1] = {};
|
||||
extern "C" const char *gResourceNameDefault[1] = {};
|
||||
extern "C" CIFPP_EXPORT const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
|
||||
extern "C" CIFPP_EXPORT const char *gResourceDataDefault[1] = {};
|
||||
extern "C" CIFPP_EXPORT const char *gResourceNameDefault[1] = {};
|
||||
|
||||
extern "C" const mrsrc::rsrc_imp gResourceIndex[];
|
||||
extern "C" const char gResourceData[];
|
||||
@@ -819,12 +827,12 @@ namespace cif
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class ResourcePool
|
||||
class resource_pool
|
||||
{
|
||||
public:
|
||||
static ResourcePool &instance()
|
||||
static resource_pool &instance()
|
||||
{
|
||||
static std::unique_ptr<ResourcePool> s_instance(new ResourcePool);
|
||||
static std::unique_ptr<resource_pool> s_instance(new resource_pool);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
@@ -854,7 +862,7 @@ class ResourcePool
|
||||
std::unique_ptr<std::istream> load(fs::path name);
|
||||
|
||||
private:
|
||||
ResourcePool();
|
||||
resource_pool();
|
||||
|
||||
std::unique_ptr<std::ifstream> open(fs::path &p)
|
||||
{
|
||||
@@ -880,7 +888,7 @@ class ResourcePool
|
||||
std::deque<fs::path> mDirs;
|
||||
};
|
||||
|
||||
ResourcePool::ResourcePool()
|
||||
resource_pool::resource_pool()
|
||||
{
|
||||
#if defined(DATA_DIR)
|
||||
pushDir(DATA_DIR);
|
||||
@@ -897,7 +905,7 @@ ResourcePool::ResourcePool()
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<std::istream> ResourcePool::load(fs::path name)
|
||||
std::unique_ptr<std::istream> resource_pool::load(fs::path name)
|
||||
{
|
||||
std::unique_ptr<std::istream> result;
|
||||
std::error_code ec;
|
||||
@@ -907,6 +915,9 @@ std::unique_ptr<std::istream> ResourcePool::load(fs::path name)
|
||||
if (mLocalResources.count(name.string()))
|
||||
result = open(mLocalResources[name.string()]);
|
||||
|
||||
if (fs::exists(p, ec) and not ec)
|
||||
result = open(p);
|
||||
|
||||
for (auto di = mDirs.begin(); not result and di != mDirs.end(); ++di)
|
||||
{
|
||||
auto p2 = *di / p;
|
||||
@@ -929,17 +940,17 @@ std::unique_ptr<std::istream> ResourcePool::load(fs::path name)
|
||||
|
||||
void add_data_directory(std::filesystem::path dataDir)
|
||||
{
|
||||
ResourcePool::instance().pushDir(dataDir);
|
||||
resource_pool::instance().pushDir(dataDir);
|
||||
}
|
||||
|
||||
void add_file_resource(const std::string &name, std::filesystem::path dataFile)
|
||||
{
|
||||
ResourcePool::instance().pushAlias(name, dataFile);
|
||||
resource_pool::instance().pushAlias(name, dataFile);
|
||||
}
|
||||
|
||||
std::unique_ptr<std::istream> load_resource(std::filesystem::path name)
|
||||
{
|
||||
return ResourcePool::instance().load(name);
|
||||
return resource_pool::instance().load(name);
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
146
src/validate.cpp
146
src/validate.cpp
@@ -24,6 +24,11 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/validate.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -41,12 +46,6 @@ using boost::regex;
|
||||
using std::regex;
|
||||
#endif
|
||||
|
||||
#include <cif++/dictionary_parser.hpp>
|
||||
#include <cif++/validate.hpp>
|
||||
|
||||
#include <cif++/utilities.hpp>
|
||||
#include <cif++/gzio.hpp>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
@@ -402,92 +401,99 @@ void validator::report_error(const std::string &msg, bool fatal) const
|
||||
|
||||
const validator &validator_factory::operator[](std::string_view dictionary_name)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
try
|
||||
{
|
||||
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";
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
{
|
||||
if (iequals(validator.name(), dict_name))
|
||||
if (iequals(validator.name(), dictionary_name))
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
||||
// not found, add it
|
||||
// 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());
|
||||
|
||||
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)
|
||||
if (dictionary.extension() != ".dic")
|
||||
{
|
||||
for (const char *dir : {
|
||||
#if defined(CACHE_DIR)
|
||||
CACHE_DIR,
|
||||
#endif
|
||||
#if defined(DATA_DIR)
|
||||
DATA_DIR
|
||||
#endif
|
||||
})
|
||||
auto dict_name = dictionary.filename().string() + ".dic";
|
||||
|
||||
for (auto &validator : m_validators)
|
||||
{
|
||||
auto p2 = std::filesystem::path(dir) / p;
|
||||
if (std::filesystem::exists(p2, ec) and not ec)
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
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 (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() + ")");
|
||||
if (not in.is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
construct_validator(dictionary_name, in);
|
||||
construct_validator(dictionary_name, in);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
|
||||
}
|
||||
|
||||
return m_validators.back();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void validator_factory::construct_validator(std::string_view name, std::istream &is)
|
||||
const validator &validator_factory::construct_validator(std::string_view name, std::istream &is)
|
||||
{
|
||||
m_validators.emplace_back(parse_dictionary(name, is));
|
||||
return m_validators.emplace_back(parse_dictionary(name, is));
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
BIN
test/2bi3.cif.gz
Normal file
BIN
test/2bi3.cif.gz
Normal file
Binary file not shown.
BIN
test/3bwh.cif.gz
Normal file
BIN
test/3bwh.cif.gz
Normal file
Binary file not shown.
BIN
test/4wvp.cif.gz
Normal file
BIN
test/4wvp.cif.gz
Normal file
Binary file not shown.
39
test/io-test.cpp
Normal file
39
test/io-test.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <cif++.hpp>
|
||||
|
||||
class dummy_parser : public cif::sac_parser
|
||||
{
|
||||
public:
|
||||
dummy_parser(std::istream &is)
|
||||
: sac_parser(is)
|
||||
{
|
||||
}
|
||||
|
||||
void produce_datablock(std::string_view name) override
|
||||
{
|
||||
}
|
||||
|
||||
void produce_category(std::string_view name) override
|
||||
{
|
||||
}
|
||||
|
||||
void produce_row() override
|
||||
{
|
||||
}
|
||||
|
||||
void produce_item(std::string_view category, std::string_view item, std::string_view value) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
cif::gzio::ifstream in("/srv/data/pdb/mmCIF/gl/8glv.cif.gz");
|
||||
|
||||
dummy_parser parser(in);
|
||||
parser.parse_file();
|
||||
|
||||
// cif::file f("/srv/data/pdb/mmCIF/gl/8glv.cif.gz");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -58,6 +58,12 @@ bool init_unit_test()
|
||||
// not a test, just initialize test dir
|
||||
if (boost::unit_test::framework::master_test_suite().argc == 2)
|
||||
gTestDir = boost::unit_test::framework::master_test_suite().argv[1];
|
||||
else
|
||||
{
|
||||
while (not gTestDir.empty() and not std::filesystem::exists(gTestDir / "test"))
|
||||
gTestDir = gTestDir.parent_path();
|
||||
gTestDir /= "test";
|
||||
}
|
||||
|
||||
// do this now, avoids the need for installing
|
||||
cif::add_file_resource("mmcif_pdbx.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx.dic");
|
||||
@@ -194,6 +200,123 @@ _atom_type.symbol C
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_nonpoly_2)
|
||||
{
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
cif::file file;
|
||||
file.load_dictionary("mmcif_pdbx.dic");
|
||||
file.emplace("TEST"); // create a datablock
|
||||
|
||||
cif::mm::structure structure(file);
|
||||
|
||||
cif::file lig(gTestDir / "HEM.cif");
|
||||
auto &chem_comp_atom = lig["HEM"]["chem_comp_atom"];
|
||||
|
||||
std::vector<cif::row_initializer> atoms;
|
||||
|
||||
for (const auto &[type_symbol, label_atom_id, Cartn_x, Cartn_y, Cartn_z] :
|
||||
chem_comp_atom.rows<std::string,std::string,float,float,float>(
|
||||
"type_symbol", "atom_id", "model_Cartn_x", "model_Cartn_y", "model_Cartn_z"))
|
||||
{
|
||||
atoms.emplace_back(cif::row_initializer{
|
||||
{ "type_symbol", type_symbol },
|
||||
{ "label_atom_id", label_atom_id },
|
||||
{ "auth_atom_id", label_atom_id },
|
||||
{ "Cartn_x", Cartn_x },
|
||||
{ "Cartn_y", Cartn_y },
|
||||
{ "Cartn_z", Cartn_z }
|
||||
});
|
||||
|
||||
if (atoms.size() == 4)
|
||||
break;
|
||||
}
|
||||
|
||||
std::string entity_id = structure.create_non_poly_entity("HEM");
|
||||
structure.create_non_poly(entity_id, atoms);
|
||||
|
||||
auto expected = 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.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 CHA HEM 1 . C HETATM ? 2.748 -19.531 39.896 1.00 ? 1 HEM CHA 1
|
||||
2 A ? A CHB HEM 1 . C HETATM ? 3.258 -17.744 35.477 1.00 ? 1 HEM CHB 1
|
||||
3 A ? A CHC HEM 1 . C HETATM ? 1.703 -21.9 33.637 1.00 ? 1 HEM CHC 1
|
||||
4 A ? A CHD HEM 1 . C HETATM ? 1.149 -23.677 38.059 1.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 ?
|
||||
#
|
||||
_atom_type.symbol C
|
||||
)"_cf;
|
||||
|
||||
expected.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
if (not (expected.front() == structure.get_datablock()))
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
std::cout << expected.front() << std::endl
|
||||
<< std::endl
|
||||
<< structure.get_datablock() << std::endl;
|
||||
|
||||
|
||||
expected.save("/tmp/a");
|
||||
file.save("/tmp/b");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_atom_id)
|
||||
|
||||
@@ -39,6 +39,12 @@ int main(int argc, char* argv[])
|
||||
|
||||
if (argc == 3)
|
||||
testdir = argv[2];
|
||||
else
|
||||
{
|
||||
while (not testdir.empty() and not std::filesystem::exists(testdir / "test"))
|
||||
testdir = testdir.parent_path();
|
||||
testdir /= "test";
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(testdir / ".." / "data" / "ccd-subset.cif"))
|
||||
cif::add_file_resource("components.cif", testdir / ".." / "data" / "ccd-subset.cif");
|
||||
|
||||
49
test/spinner-test.cpp
Normal file
49
test/spinner-test.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <cif++/utilities.hpp>
|
||||
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
void test_one()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> distrib(100, 1000);
|
||||
|
||||
cif::progress_bar pb(10, "test");
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(distrib(gen)));
|
||||
|
||||
pb.message("step " + std::to_string(i));
|
||||
pb.consumed(1);
|
||||
}
|
||||
}
|
||||
|
||||
void test_two()
|
||||
{
|
||||
cif::progress_bar pb(10, "test");
|
||||
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
pb.consumed(1);
|
||||
}
|
||||
|
||||
void test_three()
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
cif::progress_bar pb(10, "test");
|
||||
pb.consumed(10);
|
||||
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_one();
|
||||
test_two();
|
||||
test_three();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -96,87 +96,87 @@ BOOST_AUTO_TEST_CASE(sugar_name_1)
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// // --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_sugar_1)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
// BOOST_AUTO_TEST_CASE(create_sugar_1)
|
||||
// {
|
||||
// using namespace cif::literals;
|
||||
|
||||
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
|
||||
cif::file file(example.string());
|
||||
cif::mm::structure s(file);
|
||||
// const std::filesystem::path example(gTestDir / "1juh.cif.gz");
|
||||
// cif::file file(example.string());
|
||||
// cif::mm::structure s(file);
|
||||
|
||||
// collect atoms from asym L first
|
||||
auto &NAG = s.get_residue("L");
|
||||
auto nagAtoms = NAG.atoms();
|
||||
// // collect atoms from asym L first
|
||||
// auto &NAG = s.get_residue("L");
|
||||
// auto nagAtoms = NAG.atoms();
|
||||
|
||||
std::vector<cif::row_initializer> ai;
|
||||
// std::vector<cif::row_initializer> ai;
|
||||
|
||||
auto &db = s.get_datablock();
|
||||
auto &as = db["atom_site"];
|
||||
// auto &db = s.get_datablock();
|
||||
// auto &as = db["atom_site"];
|
||||
|
||||
// NOTE, row_initializer does not actually hold the data, so copy it first
|
||||
// before it gets destroyed by remove_residue
|
||||
// // NOTE, row_initializer does not actually hold the data, so copy it first
|
||||
// // before it gets destroyed by remove_residue
|
||||
|
||||
for (auto r : as.find("label_asym_id"_key == "L"))
|
||||
/*auto &ri = */ai.emplace_back(r);
|
||||
// for (auto r : as.find("label_asym_id"_key == "L"))
|
||||
// /*auto &ri = */ai.emplace_back(r);
|
||||
|
||||
s.remove_residue(NAG);
|
||||
// s.remove_residue(NAG);
|
||||
|
||||
auto &branch = s.create_branch(ai);
|
||||
// auto &branch = s.create_branch(ai);
|
||||
|
||||
BOOST_CHECK_EQUAL(branch.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose");
|
||||
BOOST_CHECK_EQUAL(branch.size(), 1);
|
||||
// BOOST_CHECK_EQUAL(branch.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose");
|
||||
// BOOST_CHECK_EQUAL(branch.size(), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(branch[0].atoms().size(), nagAtoms.size());
|
||||
// BOOST_CHECK_EQUAL(branch[0].atoms().size(), nagAtoms.size());
|
||||
|
||||
BOOST_CHECK(file.is_valid());
|
||||
// BOOST_CHECK(file.is_valid());
|
||||
|
||||
file.save(gTestDir / "test-create_sugar_1.cif");
|
||||
}
|
||||
// file.save(gTestDir / "test-create_sugar_1.cif");
|
||||
// }
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// // --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_sugar_2)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
// BOOST_AUTO_TEST_CASE(create_sugar_2)
|
||||
// {
|
||||
// using namespace cif::literals;
|
||||
|
||||
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
|
||||
cif::file file(example.string());
|
||||
cif::mm::structure s(file);
|
||||
// const std::filesystem::path example(gTestDir / "1juh.cif.gz");
|
||||
// cif::file file(example.string());
|
||||
// cif::mm::structure s(file);
|
||||
|
||||
// Get branch for H
|
||||
auto &bH = s.get_branch_by_asym_id("H");
|
||||
// // Get branch for H
|
||||
// auto &bH = s.get_branch_by_asym_id("H");
|
||||
|
||||
BOOST_CHECK_EQUAL(bH.size(), 2);
|
||||
// BOOST_CHECK_EQUAL(bH.size(), 2);
|
||||
|
||||
std::vector<cif::row_initializer> ai[2];
|
||||
// std::vector<cif::row_initializer> ai[2];
|
||||
|
||||
auto &db = s.get_datablock();
|
||||
auto &as = db["atom_site"];
|
||||
// auto &db = s.get_datablock();
|
||||
// auto &as = db["atom_site"];
|
||||
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
for (auto r : as.find("label_asym_id"_key == "H" and "auth_seq_id"_key == i + 1))
|
||||
/*auto &ri = */ai[i].emplace_back(r);
|
||||
}
|
||||
// for (size_t i = 0; i < 2; ++i)
|
||||
// {
|
||||
// for (auto r : as.find("label_asym_id"_key == "H" and "auth_seq_id"_key == i + 1))
|
||||
// /*auto &ri = */ai[i].emplace_back(r);
|
||||
// }
|
||||
|
||||
s.remove_branch(bH);
|
||||
// s.remove_branch(bH);
|
||||
|
||||
BOOST_CHECK(file.is_valid());
|
||||
// BOOST_CHECK(file.is_valid());
|
||||
|
||||
auto &bN = s.create_branch(ai[0]);
|
||||
s.extend_branch(bN.get_asym_id(), ai[1], 1, "O4");
|
||||
// auto &bN = s.create_branch(ai[0]);
|
||||
// s.extend_branch(bN.get_asym_id(), ai[1], 1, "O4");
|
||||
|
||||
BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose-(1-4)-2-acetamido-2-deoxy-beta-D-glucopyranose");
|
||||
BOOST_CHECK_EQUAL(bN.size(), 2);
|
||||
// BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose-(1-4)-2-acetamido-2-deoxy-beta-D-glucopyranose");
|
||||
// BOOST_CHECK_EQUAL(bN.size(), 2);
|
||||
|
||||
BOOST_CHECK(file.is_valid());
|
||||
// BOOST_CHECK(file.is_valid());
|
||||
|
||||
file.save(gTestDir / "test-create_sugar_2.cif");
|
||||
// file.save(gTestDir / "test-create_sugar_2.cif");
|
||||
|
||||
BOOST_CHECK_NO_THROW(cif::mm::structure s2(file));
|
||||
}
|
||||
// BOOST_CHECK_NO_THROW(cif::mm::structure s2(file));
|
||||
// }
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <cif++/dictionary_parser.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include <Eigen/Eigenvalues>
|
||||
|
||||
namespace tt = boost::test_tools;
|
||||
namespace utf = boost::unit_test;
|
||||
|
||||
std::filesystem::path gTestDir = std::filesystem::current_path(); // filled in first test
|
||||
|
||||
@@ -87,19 +87,20 @@ BOOST_AUTO_TEST_CASE(t1)
|
||||
// q = Normalize(q);
|
||||
|
||||
// Quaternion q{ 0.1, 0.2, 0.3, 0.4 };
|
||||
cif::quaternion q{0.5, 0.5, 0.5, 0.5};
|
||||
cif::quaternion q{ 0.5, 0.5, 0.5, 0.5 };
|
||||
q = normalize(q);
|
||||
|
||||
const auto &&[angle0, axis0] = cif::quaternion_to_angle_axis(q);
|
||||
|
||||
std::vector<cif::point> p1{
|
||||
{16.979, 13.301, 44.555},
|
||||
{18.150, 13.525, 43.680},
|
||||
{18.656, 14.966, 43.784},
|
||||
{17.890, 15.889, 44.078},
|
||||
{17.678, 13.270, 42.255},
|
||||
{16.248, 13.734, 42.347},
|
||||
{15.762, 13.216, 43.724}};
|
||||
{ 16.979f, 13.301f, 44.555f },
|
||||
{ 18.150f, 13.525f, 43.680f },
|
||||
{ 18.656f, 14.966f, 43.784f },
|
||||
{ 17.890f, 15.889f, 44.078f },
|
||||
{ 17.678f, 13.270f, 42.255f },
|
||||
{ 16.248f, 13.734f, 42.347f },
|
||||
{ 15.762f, 13.216f, 43.724f }
|
||||
};
|
||||
|
||||
auto p2 = p1;
|
||||
|
||||
@@ -119,7 +120,7 @@ BOOST_AUTO_TEST_CASE(t1)
|
||||
for (auto &p : p1)
|
||||
p.rotate(q2);
|
||||
|
||||
float rmsd = cif::RMSd(p1, p2);
|
||||
auto rmsd = cif::RMSd(p1, p2);
|
||||
|
||||
BOOST_TEST(rmsd < 1e-5);
|
||||
|
||||
@@ -136,7 +137,7 @@ BOOST_AUTO_TEST_CASE(t2)
|
||||
|
||||
cif::point xp = cif::cross_product(p[1] - p[0], p[2] - p[0]);
|
||||
|
||||
auto q = cif::construct_from_angle_axis(45, xp); //mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
|
||||
auto q = cif::construct_from_angle_axis(45, xp); // mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
|
||||
|
||||
auto &&[angle, axis] = cif::quaternion_to_angle_axis(q);
|
||||
|
||||
@@ -153,7 +154,7 @@ BOOST_AUTO_TEST_CASE(t3)
|
||||
|
||||
cif::point xp = cif::cross_product(p[1] - p[0], p[2] - p[0]);
|
||||
|
||||
auto q = cif::construct_from_angle_axis(45, xp); //mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
|
||||
auto q = cif::construct_from_angle_axis(45, xp); // mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
|
||||
|
||||
auto v = p[1];
|
||||
v -= p[0];
|
||||
@@ -166,3 +167,376 @@ BOOST_AUTO_TEST_CASE(t3)
|
||||
|
||||
BOOST_TEST(a == 45, tt::tolerance(0.01));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dh_q_0)
|
||||
{
|
||||
cif::point axis(1, 0, 0);
|
||||
|
||||
cif::point p(1, 1, 0);
|
||||
|
||||
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);
|
||||
BOOST_TEST(a == 0, tt::tolerance(0.01f));
|
||||
|
||||
auto q = cif::construct_from_angle_axis(90, axis);
|
||||
|
||||
p.rotate(q);
|
||||
|
||||
BOOST_TEST(p.m_x == 1, tt::tolerance(0.01f));
|
||||
BOOST_TEST(p.m_y == 0, tt::tolerance(0.01f));
|
||||
BOOST_TEST(p.m_z == 1, tt::tolerance(0.01f));
|
||||
|
||||
a = cif::dihedral_angle(t[0], t[1], t[2], p);
|
||||
BOOST_TEST(a == 90, tt::tolerance(0.01f));
|
||||
|
||||
q = cif::construct_from_angle_axis(-90, axis);
|
||||
|
||||
p.rotate(q);
|
||||
|
||||
BOOST_TEST(p.m_x == 1, tt::tolerance(0.01f));
|
||||
BOOST_TEST(p.m_y == 1, tt::tolerance(0.01f));
|
||||
BOOST_TEST(p.m_z == 0, tt::tolerance(0.01f));
|
||||
|
||||
a = cif::dihedral_angle(t[0], t[1], t[2], p);
|
||||
BOOST_TEST(a == 0, tt::tolerance(0.01f));
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dh_q_1)
|
||||
{
|
||||
struct
|
||||
{
|
||||
float angle;
|
||||
cif::point pts[4];
|
||||
} tests[] = {
|
||||
{ -97.5f,
|
||||
{ { 68.8649979f, -7.34800005f, 54.3769989f },
|
||||
{ 68.1350021f, -8.18700027f, 53.6489983f },
|
||||
{ 68.7760239f, -9.07335377f, 52.7140236f },
|
||||
{ 68.9000015f, -10.3944235f, 53.2217026f } } },
|
||||
{ 80.3f,
|
||||
{ { 0.304512024f, 0.531184196f, 2.25860214f },
|
||||
{ 0.956512451f, 0.0321846008f, 1.07460022f },
|
||||
{ 0, 0, 0 },
|
||||
{ 0.21336633f, -1.09552193f, -0.878999829f } } },
|
||||
{ -97.5f,
|
||||
{ { 0.088973999f, 1.72535372f, 1.66297531f },
|
||||
{ -0.641021729f, 0.886353493f, 0.93497467f },
|
||||
{ 0, 0, 0 },
|
||||
{ 1.29433727f, -0.395142615f, 0.432300746f } } },
|
||||
{ -97.5f,
|
||||
{
|
||||
{ 0.088973999f, 1.72535372f, 1.66297531f },
|
||||
{ -0.641021729f, 0.886353493f, 0.93497467f },
|
||||
{ 0, 0, 0 },
|
||||
{ 1.33983064f, 0.384027064f, -0.275154471f },
|
||||
|
||||
} }
|
||||
};
|
||||
|
||||
for (auto &&[angle, pts] : tests)
|
||||
{
|
||||
auto q = cif::construct_for_dihedral_angle(pts[0], pts[1], pts[2], pts[3], angle, 1);
|
||||
|
||||
pts[3].rotate(q, pts[2]);
|
||||
|
||||
auto dh = cif::dihedral_angle(pts[0], pts[1], pts[2], pts[3]);
|
||||
BOOST_TEST(dh == angle, tt::tolerance(0.1f));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(m2q_0, *utf::tolerance(0.001f))
|
||||
{
|
||||
for (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();
|
||||
|
||||
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;
|
||||
|
||||
BOOST_TEST(p2.m_x == p3.m_x);
|
||||
BOOST_TEST(p2.m_y == p3.m_y);
|
||||
BOOST_TEST(p2.m_z == p3.m_z);
|
||||
}
|
||||
}
|
||||
|
||||
// BOOST_AUTO_TEST_CASE(m2q_1, *utf::tolerance(0.001f))
|
||||
// {
|
||||
// for (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];
|
||||
|
||||
// cif::matrix4x4<float> m({
|
||||
// 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
|
||||
// });
|
||||
|
||||
// auto &&[ev, em] = cif::eigen(m * (1/3.0f), false);
|
||||
|
||||
// size_t bestJ = 0;
|
||||
// float bestEV = -1;
|
||||
|
||||
// for (size_t j = 0; j < 4; ++j)
|
||||
// {
|
||||
// if (bestEV < ev[j])
|
||||
// {
|
||||
// bestEV = ev[j];
|
||||
// bestJ = j;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (std::abs(bestEV - 1) > 0.01)
|
||||
// continue; // not a rotation matrix
|
||||
|
||||
// auto q = normalize(cif::quaternion{
|
||||
// static_cast<float>(em(bestJ, 3)),
|
||||
// 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);
|
||||
|
||||
// cif::point p3 = rot * p1;
|
||||
|
||||
// BOOST_TEST(p2.m_x == p3.m_x);
|
||||
// BOOST_TEST(p2.m_y == p3.m_y);
|
||||
// BOOST_TEST(p2.m_z == p3.m_z);
|
||||
// }
|
||||
// }
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_1)
|
||||
{
|
||||
cif::cell c(10, 10, 10);
|
||||
|
||||
cif::point p{ 1, 1, 1 };
|
||||
|
||||
cif::point f = fractional(p, c);
|
||||
|
||||
BOOST_TEST(f.m_x == 0.1f, tt::tolerance(0.01));
|
||||
BOOST_TEST(f.m_y == 0.1f, tt::tolerance(0.01));
|
||||
BOOST_TEST(f.m_z == 0.1f, tt::tolerance(0.01));
|
||||
|
||||
cif::point o = orthogonal(f, c);
|
||||
|
||||
BOOST_TEST(o.m_x == 1.f, tt::tolerance(0.01));
|
||||
BOOST_TEST(o.m_y == 1.f, tt::tolerance(0.01));
|
||||
BOOST_TEST(o.m_z == 1.f, tt::tolerance(0.01));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_2)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
auto symop = "1_555"_symop;
|
||||
|
||||
BOOST_TEST(symop.is_identity() == true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_3)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
cif::spacegroup sg(18);
|
||||
|
||||
BOOST_TEST(sg.size() == 4);
|
||||
BOOST_TEST(sg.get_name() == "P 21 21 2");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_4, *utf::tolerance(0.1f))
|
||||
{
|
||||
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
|
||||
|
||||
BOOST_TEST(distance(a, sg(a, c, "1_455"_symop)) == static_cast<float>(c.get_a()));
|
||||
BOOST_TEST(distance(a, sg(a, c, "1_545"_symop)) == static_cast<float>(c.get_b()));
|
||||
BOOST_TEST(distance(a, sg(a, c, "1_554"_symop)) == static_cast<float>(c.get_c()));
|
||||
|
||||
auto sb2 = sg(b, c, "4_565"_symop);
|
||||
BOOST_TEST(sb.m_x == sb2.m_x);
|
||||
BOOST_TEST(sb.m_y == sb2.m_y);
|
||||
BOOST_TEST(sb.m_z == sb2.m_z);
|
||||
|
||||
BOOST_TEST(distance(a, sb2) == 7.42f);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_4wvp_1, *utf::tolerance(0.1f))
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
cif::file f(gTestDir / "4wvp.cif.gz");
|
||||
|
||||
auto &db = f.front();
|
||||
cif::mm::structure s(db);
|
||||
|
||||
cif::crystal c(db);
|
||||
|
||||
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);
|
||||
BOOST_TEST(sp1.m_x == p.m_x);
|
||||
BOOST_TEST(sp1.m_y == p.m_y);
|
||||
BOOST_TEST(sp1.m_z == p.m_z);
|
||||
|
||||
const auto &[d, sp2, so] = c.closest_symmetry_copy(p, a.get_location());
|
||||
|
||||
BOOST_TEST(d < 1);
|
||||
|
||||
BOOST_TEST(sp2.m_x == p.m_x);
|
||||
BOOST_TEST(sp2.m_y == p.m_y);
|
||||
BOOST_TEST(sp2.m_z == p.m_z);
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_2bi3_1, *utf::tolerance(0.1f))
|
||||
{
|
||||
cif::file f(gTestDir / "2bi3.cif.gz");
|
||||
|
||||
auto &db = f.front();
|
||||
cif::mm::structure s(db);
|
||||
|
||||
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"
|
||||
))
|
||||
{
|
||||
auto &r1 = s.get_residue(asym1, seqid1, authseqid1);
|
||||
auto &r2 = s.get_residue(asym2, seqid2, authseqid2);
|
||||
|
||||
auto a1 = r1.get_atom_by_atom_id(atomid1);
|
||||
auto a2 = r2.get_atom_by_atom_id(atomid2);
|
||||
|
||||
auto sa1 = c.symmetry_copy(a1.get_location(), cif::sym_op(symm1));
|
||||
auto sa2 = c.symmetry_copy(a2.get_location(), cif::sym_op(symm2));
|
||||
|
||||
BOOST_TEST(cif::distance(sa1, sa2) == dist);
|
||||
|
||||
auto pa1 = a1.get_location();
|
||||
|
||||
const auto &[d, p, so] = c.closest_symmetry_copy(pa1, a2.get_location());
|
||||
|
||||
BOOST_TEST(p.m_x == sa2.m_x);
|
||||
BOOST_TEST(p.m_y == sa2.m_y);
|
||||
BOOST_TEST(p.m_z == sa2.m_z);
|
||||
|
||||
BOOST_TEST(d == dist);
|
||||
BOOST_TEST(so.string() == symm2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_3bwh_1, *utf::tolerance(0.1f))
|
||||
{
|
||||
cif::file f(gTestDir / "3bwh.cif.gz");
|
||||
|
||||
auto &db = f.front();
|
||||
|
||||
cif::crystal c(db);
|
||||
cif::mm::structure s(db);
|
||||
|
||||
for (auto a1 : s.atoms())
|
||||
{
|
||||
for (auto a2 : s.atoms())
|
||||
{
|
||||
if (a1 == a2)
|
||||
continue;
|
||||
|
||||
const auto&[ d, p, so ] = c.closest_symmetry_copy(a1.get_location(), a2.get_location());
|
||||
|
||||
BOOST_TEST(d == distance(a1.get_location(), p));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <cif++/dictionary_parser.hpp>
|
||||
#include <cif++/parser.hpp>
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
|
||||
|
||||
namespace tt = boost::test_tools;
|
||||
|
||||
@@ -75,26 +75,50 @@ bool init_unit_test()
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(id_1)
|
||||
{
|
||||
BOOST_TEST(cif::cif_id_for_number(0) == "A");
|
||||
BOOST_TEST(cif::cif_id_for_number(25) == "Z");
|
||||
BOOST_TEST(cif::cif_id_for_number(26) == "AA");
|
||||
BOOST_TEST(cif::cif_id_for_number(26 + 1) == "AB");
|
||||
|
||||
BOOST_TEST(cif::cif_id_for_number(26 + 26 * 26 - 1) == "ZZ");
|
||||
BOOST_TEST(cif::cif_id_for_number(26 + 26 * 26) == "AAA");
|
||||
BOOST_TEST(cif::cif_id_for_number(26 + 26 * 26 + 1) == "AAB");
|
||||
|
||||
std::set<std::string> testset;
|
||||
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
{
|
||||
std::string id = cif::cif_id_for_number(i);
|
||||
BOOST_TEST(testset.count(id) == 0);
|
||||
testset.insert(id);
|
||||
}
|
||||
BOOST_TEST(testset.size() == 100000);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cc_1)
|
||||
{
|
||||
std::tuple<std::string_view, float, char> tests[] = {
|
||||
{ "1.0", 1.0, 0 },
|
||||
{ "1.0e10", 1.0e10, 0 },
|
||||
{ "-1.1e10", -1.1e10, 0 },
|
||||
{ "-.2e11", -.2e11, 0 },
|
||||
{ "1.3e-10", 1.3e-10, 0 },
|
||||
{ "1.0", 1.0f, 0 },
|
||||
{ "1.0e10", 1.0e10f, 0 },
|
||||
{ "-1.1e10", -1.1e10f, 0 },
|
||||
{ "-.2e11", -.2e11f, 0 },
|
||||
{ "1.3e-10", 1.3e-10f, 0 },
|
||||
|
||||
{ "1.0 ", 1.0, ' ' },
|
||||
{ "1.0e10 ", 1.0e10, ' ' },
|
||||
{ "-1.1e10 ", -1.1e10, ' ' },
|
||||
{ "-.2e11 ", -.2e11, ' ' },
|
||||
{ "1.3e-10 ", 1.3e-10, ' ' },
|
||||
{ "1.0 ", 1.0f, ' ' },
|
||||
{ "1.0e10 ", 1.0e10f, ' ' },
|
||||
{ "-1.1e10 ", -1.1e10f, ' ' },
|
||||
{ "-.2e11 ", -.2e11f, ' ' },
|
||||
{ "1.3e-10 ", 1.3e-10f, ' ' },
|
||||
|
||||
{ "3.0", 3.0, 0 },
|
||||
{ "3.0 ", 3.0, ' ' },
|
||||
{ "3.0", 3.0f, 0 },
|
||||
{ "3.0 ", 3.0f, ' ' },
|
||||
|
||||
{ "3.000000", 3.0, 0 },
|
||||
{ "3.000000 ", 3.0, ' ' },
|
||||
{ "3.000000", 3.0f, 0 },
|
||||
{ "3.000000 ", 3.0f, ' ' },
|
||||
};
|
||||
|
||||
for (const auto &[txt, val, ch] : tests)
|
||||
@@ -112,7 +136,7 @@ BOOST_AUTO_TEST_CASE(cc_1)
|
||||
BOOST_AUTO_TEST_CASE(cc_2)
|
||||
{
|
||||
std::tuple<float, int, std::string_view> tests[] = {
|
||||
{ 1.1, 1, "1.1" }
|
||||
{ 1.1f, 1, "1.1" }
|
||||
};
|
||||
|
||||
for (const auto &[val, prec, test] : tests)
|
||||
@@ -131,7 +155,7 @@ BOOST_AUTO_TEST_CASE(item_1)
|
||||
using namespace cif;
|
||||
|
||||
item i1("1", "1");
|
||||
item i2("2", 2.0);
|
||||
item i2("2", 2.0f);
|
||||
item i3("3", '3');
|
||||
|
||||
item ci1(i1);
|
||||
@@ -163,23 +187,23 @@ BOOST_AUTO_TEST_CASE(r_1)
|
||||
c.emplace({
|
||||
{ "f-1", 1 },
|
||||
{ "f-2", "two" },
|
||||
{ "f-3", 3.0, 3 },
|
||||
{ "f-3", 3.0f, 3 },
|
||||
});
|
||||
|
||||
auto row = c.front();
|
||||
BOOST_CHECK_EQUAL(row["f-1"].compare(1), 0);
|
||||
BOOST_CHECK_EQUAL(row["f-2"].compare("two"), 0);
|
||||
BOOST_CHECK_EQUAL(row["f-3"].compare(3.0), 0); // This fails when running in valgrind... sigh
|
||||
BOOST_CHECK_EQUAL(row["f-3"].compare(3.0f), 0); // This fails when running in valgrind... sigh
|
||||
|
||||
const auto &[f1, f2, f3] = row.get<int, std::string, float>("f-1", "f-2", "f-3");
|
||||
|
||||
BOOST_CHECK_EQUAL(f1, 1);
|
||||
BOOST_CHECK_EQUAL(f2, "two");
|
||||
BOOST_CHECK_EQUAL(f3, 3.0); // This fails when running in valgrind... sigh
|
||||
BOOST_CHECK_EQUAL(f3, 3.0f); // This fails when running in valgrind... sigh
|
||||
|
||||
BOOST_CHECK_EQUAL(row.get<int>("f-1"), 1);
|
||||
BOOST_CHECK_EQUAL(row.get<std::string>("f-2"), "two");
|
||||
BOOST_CHECK_EQUAL(row.get<float>("f-3"), 3.0);
|
||||
BOOST_CHECK_EQUAL(row.get<float>("f-3"), 3.0f);
|
||||
|
||||
int f_1;
|
||||
std::string f_2;
|
||||
@@ -189,7 +213,7 @@ BOOST_AUTO_TEST_CASE(r_1)
|
||||
|
||||
BOOST_CHECK_EQUAL(f_1, 1);
|
||||
BOOST_CHECK_EQUAL(f_2, "two");
|
||||
BOOST_CHECK_EQUAL(f_3, 3.0); // This fails when running in valgrind... sigh
|
||||
BOOST_CHECK_EQUAL(f_3, 3.0f); // This fails when running in valgrind... sigh
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(r_2)
|
||||
@@ -486,14 +510,14 @@ _test.value
|
||||
BOOST_CHECK_EQUAL(++n, 1);
|
||||
BOOST_CHECK_EQUAL(r["id"].as<int>(), 1);
|
||||
BOOST_CHECK_EQUAL(r["name"].as<std::string>(), "aap");
|
||||
BOOST_CHECK_EQUAL(r["value"].as<float>(), 1.0);
|
||||
BOOST_CHECK_EQUAL(r["value"].as<float>(), 1.0f);
|
||||
}
|
||||
|
||||
auto t = test.find(cif::key("id") == 1);
|
||||
BOOST_CHECK(not t.empty());
|
||||
BOOST_CHECK_EQUAL(t.front()["name"].as<std::string>(), "aap");
|
||||
|
||||
auto t2 = test.find(cif::key("value") == 1.2);
|
||||
auto t2 = test.find(cif::key("value") == 1.2f);
|
||||
BOOST_CHECK(not t2.empty());
|
||||
BOOST_CHECK_EQUAL(t2.front()["name"].as<std::string>(), "mies");
|
||||
}
|
||||
@@ -1774,8 +1798,6 @@ _test.name
|
||||
|
||||
BOOST_AUTO_TEST_CASE(c3)
|
||||
{
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
auto f = R"(data_TEST
|
||||
#
|
||||
loop_
|
||||
@@ -1811,6 +1833,43 @@ _test.name
|
||||
BOOST_CHECK_EQUAL(name, "aap");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(c4)
|
||||
{
|
||||
auto f = R"(data_TEST
|
||||
#
|
||||
loop_
|
||||
_test.id
|
||||
_test.name
|
||||
1 aap
|
||||
2 noot
|
||||
3 mies
|
||||
4 .
|
||||
5 ?
|
||||
)"_cf;
|
||||
|
||||
auto &db = f.front();
|
||||
|
||||
// query tests
|
||||
BOOST_TEST(db["test"].find_max<int>("id") == 5);
|
||||
BOOST_TEST(db["test"].find_max<int>("id", cif::key("name") != cif::null) == 3);
|
||||
|
||||
BOOST_TEST(db["test"].find_min<int>("id") == 1);
|
||||
BOOST_TEST(db["test"].find_min<int>("id", cif::key("name") == cif::null) == 4);
|
||||
|
||||
// count tests
|
||||
BOOST_TEST(db["test"].count(cif::all()) == 5);
|
||||
BOOST_TEST(db["test"].count(cif::key("name") != cif::null) == 3);
|
||||
BOOST_TEST(db["test"].count(cif::key("name") == cif::null) == 2);
|
||||
|
||||
// find_first tests
|
||||
BOOST_TEST(db["test"].find_first<int>(cif::key("id") == 1, "id") == 1);
|
||||
BOOST_TEST(db["test"].find_first<int>(cif::all(), "id") == 1);
|
||||
|
||||
// find1 tests
|
||||
BOOST_TEST(db["test"].find1<int>(cif::key("id") == 1, "id") == 1);
|
||||
BOOST_CHECK_THROW(db["test"].find1<int>(cif::all(), "id"), cif::multiple_results_error);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// rename test
|
||||
|
||||
@@ -2326,11 +2385,16 @@ BOOST_AUTO_TEST_CASE(output_test_1)
|
||||
data_Q
|
||||
loop_
|
||||
_test.text
|
||||
"stop_the_crap"
|
||||
stop_the_crap
|
||||
'and stop_ this too'
|
||||
'data_dinges'
|
||||
'blablaglobal_bla'
|
||||
blablaglobal_bla
|
||||
boo.data_.whatever
|
||||
'data_.whatever'
|
||||
'stop_'
|
||||
'loop_'
|
||||
'global_'
|
||||
'_with.leading_underscore'
|
||||
)"_cf;
|
||||
|
||||
auto &db1 = data1.front();
|
||||
@@ -2341,11 +2405,16 @@ boo.data_.whatever
|
||||
const char *s;
|
||||
bool q;
|
||||
} kS[] = {
|
||||
{ "stop_the_crap", false },
|
||||
{ "stop_the_crap", true },
|
||||
{ "and stop_ this too", false },
|
||||
{ "data_dinges", false },
|
||||
{ "blablaglobal_bla", false },
|
||||
{ "boo.data_.whatever", true }
|
||||
{ "blablaglobal_bla", true },
|
||||
{ "boo.data_.whatever", true },
|
||||
{ "data_.whatever", false },
|
||||
{ "stop_", false },
|
||||
{ "loop_", false },
|
||||
{ "global_", false },
|
||||
{ "_with.leading_underscore", false }
|
||||
};
|
||||
|
||||
BOOST_CHECK_EQUAL(test1.size(), sizeof(kS) / sizeof(T));
|
||||
@@ -2816,7 +2885,7 @@ save__cat_1.name
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
auto validator = cif::parse_dictionary("test_dict.dic", is_dict);
|
||||
auto &validator = cif::validator_factory::instance().construct_validator("test_dict.dic", is_dict);
|
||||
|
||||
cif::file f;
|
||||
f.set_validator(&validator);
|
||||
@@ -2854,8 +2923,6 @@ _cat_1.name
|
||||
ss << f;
|
||||
|
||||
cif::file f2(ss);
|
||||
|
||||
f2.set_validator(&validator);
|
||||
BOOST_ASSERT(f2.is_valid());
|
||||
|
||||
auto &audit_conform = f2.front()["audit_conform"];
|
||||
@@ -3058,3 +3125,29 @@ _date today
|
||||
BOOST_TEST(db == db2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(find1_opt_1)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
using namespace std::literals;
|
||||
|
||||
auto f = R"(data_TEST
|
||||
#
|
||||
loop_
|
||||
_test.id
|
||||
_test.name
|
||||
_test.value
|
||||
1 aap 1.0
|
||||
2 noot 1.1
|
||||
3 mies 1.2
|
||||
)"_cf;
|
||||
|
||||
auto &db = f.front();
|
||||
auto &test = db["test"];
|
||||
|
||||
auto v = test.find1<std::optional<float>>("id"_key == 1, "value");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_TEST(*v == 1.0f);
|
||||
|
||||
v = test.find1<std::optional<float>>("id"_key == 4, "value");
|
||||
BOOST_CHECK(v.has_value() == false);
|
||||
}
|
||||
@@ -1,55 +1,71 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# Code updated based on a bug report in Ubuntu:
|
||||
# Bug #1999259 reported by Kyler Laird on 2022-12-09
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "Please run as root"
|
||||
# Get the effective UID, but do so in a compatible way (we may be running dash)
|
||||
euid=${EUID:-$(id -u)}
|
||||
|
||||
if [ "${euid}" -ne 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -f /etc/libcifpp.conf ] ; then
|
||||
. /etc/libcifpp.conf
|
||||
if [ -f "@CIFPP_ETC_DIR@/libcifpp.conf" ]; then
|
||||
. "@CIFPP_ETC_DIR@/libcifpp.conf"
|
||||
fi
|
||||
|
||||
# check to see if we're supposed to run at all
|
||||
if [ "$update" != "true" ] ; then
|
||||
if [ "$update" != "true" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# if cache directory doesn't exist, exit.
|
||||
if ! [ -d @CIFPP_CACHE_DIR@ ]; then
|
||||
# if cache directory doesn't exist, exit.
|
||||
if ! [ -d "@CIFPP_CACHE_DIR@" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
fetch_dictionary () {
|
||||
# Create a temp file in the right directory and
|
||||
# make sure it is cleaned up when this script exits
|
||||
|
||||
tmpfile=$(mktemp)
|
||||
trap "rm -f \"${tmpfile}\"" EXIT
|
||||
|
||||
update_dictionary() {
|
||||
dict=$1
|
||||
source=$2
|
||||
|
||||
wget -O${dict}.gz ${source}
|
||||
# Using curl with
|
||||
# --location (follow redirects)
|
||||
# --silent (no diagnostic output at all)
|
||||
# --time-cond (only fetch if source is newer)
|
||||
#
|
||||
# Output is extracted and written to $tmpfile and when successful
|
||||
# the tmpfile is placed at the desired location and updated is set
|
||||
# to true
|
||||
|
||||
# be careful not to nuke an existing dictionary file
|
||||
# extract to a temporary file first
|
||||
|
||||
gunzip -c ${dict}.gz > ${dict}-tmp
|
||||
|
||||
# then move the extracted file to the final location
|
||||
|
||||
mv ${dict}-tmp ${dict}
|
||||
|
||||
# and clean up afterwards
|
||||
|
||||
rm ${dict}.gz
|
||||
curl --silent --location --compressed --time-cond "${dict}" "${source}" | (
|
||||
# uncompress the file on the fly, if it is compressed
|
||||
if [ "${source%.gz}" != "${source}" ]; then
|
||||
gunzip -c > "${tmpfile}" 2>/dev/null
|
||||
else
|
||||
cat > "${tmpfile}"
|
||||
fi
|
||||
) && (
|
||||
mv "${tmpfile}" "${dict}" && chmod a+r "${dict}"
|
||||
) || true
|
||||
}
|
||||
|
||||
# fetch the dictionaries
|
||||
# Update the dictionaries
|
||||
|
||||
fetch_dictionary "@CIFPP_CACHE_DIR@/mmcif_pdbx.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
|
||||
fetch_dictionary "@CIFPP_CACHE_DIR@/components.cif" "ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
|
||||
update_dictionary "@CIFPP_CACHE_DIR@/components.cif" "https://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
|
||||
update_dictionary "@CIFPP_CACHE_DIR@/mmcif_pdbx.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
|
||||
update_dictionary "@CIFPP_CACHE_DIR@/mmcif_ma.dic" "https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic"
|
||||
|
||||
# notify subscribers
|
||||
# notify subscribers, will fail on FreeBSD
|
||||
|
||||
if [ -d /etc/libcifpp/cache-update.d ] && [ -x /bin/run-parts ]; then
|
||||
run-parts --arg "@CIFPP_CACHE_DIR@" -- /etc/libcifpp/cache-update.d
|
||||
if [ -d "@CIFPP_ETC_DIR@/libcifpp/cache-update.d" ] && [ -x /bin/run-parts ]; then
|
||||
run-parts --arg "@CIFPP_CACHE_DIR@" -- "@CIFPP_ETC_DIR@/libcifpp/cache-update.d"
|
||||
fi
|
||||
|
||||
wget -O/var/cache/libcifpp/mmcif_ma.dic "https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic"
|
||||
|
||||
Reference in New Issue
Block a user