mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 22:14:24 +08:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18088457d3 | ||
|
|
056697d901 | ||
|
|
2681cfad50 | ||
|
|
8aaa7925a3 | ||
|
|
d4f73e471b | ||
|
|
750be0c4a4 | ||
|
|
0f4a2a26fc | ||
|
|
6adb56341d | ||
|
|
4524357cd3 | ||
|
|
0b05b6f6e3 | ||
|
|
6382170157 | ||
|
|
c2eeb69dcc | ||
|
|
f32261fc59 | ||
|
|
90c967c8c6 | ||
|
|
4ac90128db | ||
|
|
3d71db1bb7 | ||
|
|
5e35ea5168 | ||
|
|
2fc88d52eb | ||
|
|
567b0f3b57 | ||
|
|
8f29386998 | ||
|
|
d2427d57d9 | ||
|
|
14a9499962 | ||
|
|
0fafb80d44 | ||
|
|
b5454f0943 | ||
|
|
b698260d73 | ||
|
|
ccdd1b74a0 | ||
|
|
298fe20a1b | ||
|
|
12a7c45452 | ||
|
|
02a28c2fd6 | ||
|
|
68e182b0bd | ||
|
|
b0ec88f469 | ||
|
|
4feee6ac22 | ||
|
|
ee8a85ec2f | ||
|
|
0245d4a881 | ||
|
|
e8f0058956 | ||
|
|
9c75dbaae0 | ||
|
|
5bd39b598e | ||
|
|
25a43abffd | ||
|
|
9a7ca022e2 | ||
|
|
46fe0d7caf | ||
|
|
0371cec415 | ||
|
|
2b1020cbb9 | ||
|
|
8c3ce2a87d | ||
|
|
d633622e27 | ||
|
|
19b652f615 | ||
|
|
37f7dd0631 | ||
|
|
4c99710fb3 | ||
|
|
59865cdb44 | ||
|
|
c3434507da | ||
|
|
79ecf20b85 | ||
|
|
1de9681bb7 | ||
|
|
345c4778e6 | ||
|
|
0ccb2f88ca | ||
|
|
f7bef8b0e9 | ||
|
|
9da8608f8f | ||
|
|
496cb0b909 | ||
|
|
583cafa91e | ||
|
|
01da665243 | ||
|
|
e900cd1e3d | ||
|
|
a8a838b33e | ||
|
|
072be25335 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,3 +9,6 @@ test/rename-compound-test
|
||||
tools/update-dictionary-script
|
||||
data/
|
||||
CMakeSettings.json
|
||||
msvc/
|
||||
Testing/
|
||||
|
||||
|
||||
248
CMakeLists.txt
248
CMakeLists.txt
@@ -1,9 +1,33 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
# Copyright (c) 2021 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# set the project name
|
||||
project(cifpp VERSION 1.1.1 LANGUAGES CXX)
|
||||
project(cifpp VERSION 2.0.0 LANGUAGES CXX)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
enable_testing()
|
||||
|
||||
@@ -13,43 +37,68 @@ include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(Dart)
|
||||
include(FindFilesystem)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
set(CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
||||
endif()
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
find_package(Filesystem REQUIRED)
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# https://stackoverflow.com/questions/63902528/program-crashes-when-filesystempath-is-destroyed
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
||||
elseif(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
|
||||
# Build shared libraries by default (not my cup of tea, but hey)
|
||||
# Building shared libraries?
|
||||
option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF)
|
||||
|
||||
# We do not want to write an export file for all our symbols...
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
# Only try to recreate SymOpTable_data.hpp if CCP4 is known
|
||||
option(CCP4 "The location where ccp4 is installed" "")
|
||||
if(DEFINED CCP4 AND EXISTS ${CCP4})
|
||||
set(CLIBD ${CCP4}/lib/data)
|
||||
elseif(EXISTS "$ENV{CCP4}")
|
||||
# Optionally build a version to be installed inside CCP4
|
||||
option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4" OFF)
|
||||
if(BUILD_FOR_CCP4)
|
||||
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced")
|
||||
else()
|
||||
list(APPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
|
||||
|
||||
# This is the only option:
|
||||
if(WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
endif("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
endif()
|
||||
|
||||
# Check if CCP4 is available
|
||||
if(EXISTS "$ENV{CCP4}")
|
||||
set(CCP4 $ENV{CCP4})
|
||||
set(CLIBD ${CCP4}/lib/data)
|
||||
endif()
|
||||
if(CCP4 AND NOT CLIBD)
|
||||
set(CLIBD ${CCP4}/lib/data)
|
||||
endif()
|
||||
|
||||
# When CCP4 is sourced in the environment, we can recreate the symmetry operations table
|
||||
if(EXISTS "${CCP4}")
|
||||
option(RECREATE_SYMOP_DATA "Recreate SymOp data table in case it is out of date" ON)
|
||||
|
||||
if(RECREATE_SYMOP_DATA AND NOT EXISTS "${CLIBD}/syminfo.lib")
|
||||
message(FATAL_ERROR "Symop data table recreation requested, but file syminfo.lib was not found in ${CLIBD}")
|
||||
message(WARNING "Symop data table recreation requested, but file syminfo.lib was not found in ${CLIBD}")
|
||||
set(RECREATE_SYMOP_DATA OFF)
|
||||
else()
|
||||
option(RECREATE_SYMOP_DATA "Recreate SymOp data table in case it is out of date" ON)
|
||||
endif()
|
||||
else()
|
||||
set(RECREATE_SYMOP_DATA OFF)
|
||||
message("Not trying to recreate SymOpTable_data.hpp since CCP4 is not defined")
|
||||
endif()
|
||||
|
||||
# set(CMAKE_DEBUG_POSTFIX d)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
|
||||
if(MSVC)
|
||||
# make msvc standards compliant...
|
||||
@@ -69,8 +118,8 @@ if(MSVC)
|
||||
add_definitions(-D_WIN32_WINNT=${ver})
|
||||
|
||||
# On Windows, do not install in the system location
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
message(WARNING "The library and auxiliary files will be installed in $ENV{LOCALAPPDATA}/${PROJECT_NAME}")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND NOT BUILD_FOR_CCP4)
|
||||
message(STATUS "The library and auxiliary files will be installed in $ENV{LOCALAPPDATA}/${PROJECT_NAME}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{LOCALAPPDATA}/${PROJECT_NAME}" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
|
||||
@@ -86,30 +135,36 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
set(COFF_SPEC "--coff=${COFF_TYPE}")
|
||||
|
||||
# for mrc, just in case
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{LOCALAPPDATA}/mrc")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(UNIX AND NOT APPLE AND NOT BUILD_FOR_CCP4 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
# On Linux, install in the $HOME/.local folder by default
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
message(WARNING "The library and auxiliary files will be installed in $ENV{HOME}/.local")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
message(STATUS "The library and auxiliary files will be installed in $ENV{HOME}/.local")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
|
||||
# Optionally use mrc to create resources
|
||||
find_program(MRC mrc HINTS "$ENV{LOCALAPPDATA}/mrc" "$ENV{HOME}/.local/bin" "${CMAKE_INSTALL_PREFIX}/../mrc" "/usr/local/bin")
|
||||
|
||||
if(MRC)
|
||||
option(USE_RSRC "Use mrc to create resources" ON)
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
message("Not using resources when building shared libraries for Windows")
|
||||
else()
|
||||
message(WARNING "Not using resources since mrc was not found")
|
||||
endif()
|
||||
find_program(MRC mrc)
|
||||
|
||||
if(USE_RSRC STREQUAL "ON")
|
||||
set(USE_RSRC 1)
|
||||
if(MRC)
|
||||
option(USE_RSRC "Use mrc to create resources" ON)
|
||||
else()
|
||||
message("Using resources not possible since mrc was not found")
|
||||
endif()
|
||||
|
||||
message("Using resources compiled with ${MRC}")
|
||||
add_compile_definitions(USE_RSRC)
|
||||
if(USE_RSRC STREQUAL "ON")
|
||||
set(USE_RSRC 1)
|
||||
|
||||
message("Using resources compiled with ${MRC}")
|
||||
add_compile_definitions(USE_RSRC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Libraries
|
||||
@@ -118,14 +173,16 @@ set(CMAKE_THREAD_PREFER_PTHREAD)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG)
|
||||
find_package(Threads)
|
||||
|
||||
set (Boost_DETAILED_FAILURE_MSG ON)
|
||||
find_package(Boost 1.71.0 REQUIRED COMPONENTS system iostreams regex date_time program_options)
|
||||
set(Boost_DETAILED_FAILURE_MSG ON)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
find_package(Boost 1.70.0 REQUIRED COMPONENTS system iostreams regex program_options)
|
||||
|
||||
find_package(ZLIB)
|
||||
find_package(BZip2)
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIR})
|
||||
link_libraries(${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(NOT MSVC AND Boost_USE_STATIC_LIBS)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(BZip2 REQUIRED)
|
||||
endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
|
||||
@@ -139,11 +196,10 @@ if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
else()
|
||||
message(WARNING "Git not found, cannot set version info")
|
||||
|
||||
SET(BUILD_VERSION_STRING "unknown")
|
||||
SET(BUILD_VERSION_STRING ${PROJECT_VERSION})
|
||||
endif()
|
||||
|
||||
# generate version.h
|
||||
include_directories(${CMAKE_BINARY_DIR} PRIVATE)
|
||||
string(TIMESTAMP BUILD_DATE_TIME "%Y-%m-%dT%H:%M:%SZ" UTC)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/src/revision.hpp.in" "${CMAKE_BINARY_DIR}/revision.hpp" @ONLY)
|
||||
|
||||
@@ -153,7 +209,10 @@ if(RECREATE_SYMOP_DATA)
|
||||
|
||||
add_executable(symop-map-generator "${CMAKE_SOURCE_DIR}/tools/symop-map-generator.cpp")
|
||||
|
||||
target_link_libraries(symop-map-generator Threads::Threads ${Boost_LIBRARIES})
|
||||
target_link_libraries(symop-map-generator Threads::Threads ${Boost_LIBRARIES} std::filesystem ${ZLIB_LIBRARIES} ${BZip2_LIBRARIES})
|
||||
if(Boost_INCLUDE_DIR)
|
||||
target_include_directories(symop-map-generator PUBLIC ${Boost_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set($ENV{CLIBD} ${CLIBD})
|
||||
|
||||
@@ -197,6 +256,7 @@ set(project_headers
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/CifUtils.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/CifValidator.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/Compound.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/Matrix.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/PDB2Cif.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/PDB2CifRemark3.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/Point.hpp
|
||||
@@ -206,15 +266,23 @@ set(project_headers
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/TlsParser.hpp
|
||||
)
|
||||
|
||||
add_library(cifpp ${project_sources} ${project_headers} ${PROJECT_SOURCE_DIR}/src/SymOpTable_data.hpp)
|
||||
add_library(cifpp ${project_sources} ${project_headers} ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp)
|
||||
set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(cifpp
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
${Boost_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(cifpp
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(cifpp Threads::Threads ${Boost_LIBRARIES} std::filesystem ${ZLIB_LIBRARIES} ${BZip2_LIBRARIES})
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
endif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
@@ -228,7 +296,7 @@ if (NOT EXISTS ${COMPONENTS_CIF})
|
||||
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.18.0")
|
||||
# if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
|
||||
find_program(GUNZIP gunzip)
|
||||
|
||||
if(GUNZIP)
|
||||
@@ -241,31 +309,35 @@ if (NOT EXISTS ${COMPONENTS_CIF})
|
||||
file(DOWNLOAD ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif ${COMPONENTS_CIF}
|
||||
SHOW_PROGRESS)
|
||||
endif()
|
||||
else()
|
||||
file(DOWNLOAD ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz ${COMPONENTS_CIF}.gz
|
||||
SHOW_PROGRESS)
|
||||
file(ARCHIVE_EXTRACT INPUT ${COMPONENTS_CIF}.gz
|
||||
DESTINATION ${CMAKE_SOURCE_DIR}/data/
|
||||
VERBOSE)
|
||||
endif()
|
||||
# else()
|
||||
# file(DOWNLOAD ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz ${COMPONENTS_CIF}.gz
|
||||
# SHOW_PROGRESS)
|
||||
# file(ARCHIVE_EXTRACT INPUT ${COMPONENTS_CIF}.gz
|
||||
# DESTINATION ${CMAKE_SOURCE_DIR}/data/
|
||||
# VERBOSE)
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
link_libraries(${Boost_LIBRARIES})
|
||||
if(UNIX)
|
||||
option(INSTALL_UPDATE_SCRIPT "Install the script to update CCD and dictionary files" OFF)
|
||||
if(INSTALL_UPDATE_SCRIPT)
|
||||
set(CIFPP_CACHE_DIR "/var/cache/libcifpp")
|
||||
if(NOT "${CIFPP_CACHE_DIR}" STREQUAL "OFF")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
generate_export_header(cifpp
|
||||
EXPORT_FILE_NAME cif++/Cif++Export.hpp)
|
||||
|
||||
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} )
|
||||
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} )
|
||||
set(SHARE_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
# Fix cache dir
|
||||
add_compile_definitions(
|
||||
# CACHE_DIR="${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}"
|
||||
DATA_DIR="${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" )
|
||||
|
||||
generate_export_header(cifpp
|
||||
EXPORT_FILE_NAME cif++/Cif++Export.hpp)
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}")
|
||||
|
||||
# Install rules
|
||||
|
||||
@@ -314,11 +386,11 @@ install(FILES
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
set(cifpp_MAJOR_VERSION 1)
|
||||
set(cifpp_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR})
|
||||
set_target_properties(cifpp PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION 1
|
||||
INTERFACE_cifpp_MAJOR_VERSION 1)
|
||||
SOVERSION ${cifpp_MAJOR_VERSION}
|
||||
INTERFACE_cifpp_MAJOR_VERSION ${cifpp_MAJOR_VERSION})
|
||||
|
||||
set_property(TARGET cifpp APPEND PROPERTY
|
||||
COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION
|
||||
@@ -359,6 +431,7 @@ if(CIFPP_BUILD_TESTS)
|
||||
list(APPEND CIFPP_tests
|
||||
# pdb2cif
|
||||
rename-compound
|
||||
structure
|
||||
unit)
|
||||
|
||||
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
|
||||
@@ -372,15 +445,7 @@ if(CIFPP_BUILD_TESTS)
|
||||
${CMAKE_CURRENT_BINARY_DIR} # for config.h
|
||||
)
|
||||
|
||||
target_link_libraries(${CIFPP_TEST} Threads::Threads ${Boost_LIBRARIES} cifpp)
|
||||
|
||||
if(${ZLIB_FOUND})
|
||||
target_link_libraries(${CIFPP_TEST} ZLIB::ZLIB)
|
||||
endif()
|
||||
|
||||
if(${BZip2_FOUND})
|
||||
target_link_libraries(${CIFPP_TEST} BZip2::BZip2)
|
||||
endif()
|
||||
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp ${Boost_LIBRARIES} std::filesystem ${ZLIB_LIBRARIES} ${BZip2_LIBRARIES})
|
||||
|
||||
if(MSVC)
|
||||
# Specify unwind semantics so that MSVC knowns how to handle exceptions
|
||||
@@ -391,12 +456,39 @@ if(CIFPP_BUILD_TESTS)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}>
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test)
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${PROJECT_SOURCE_DIR}/test)
|
||||
|
||||
add_test(NAME ${CIFPP_TEST}
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}>
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test)
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${PROJECT_SOURCE_DIR}/test)
|
||||
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message("Will install in ${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
# Optionally install the update scripts for CCD and dictionary files
|
||||
|
||||
if(INSTALL_UPDATE_SCRIPT)
|
||||
set(CIFPP_CRON_DIR "$ENV{DESTDIR}/etc/cron.weekly")
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/tools/update-dictionary-script.in update-dictionary-script @ONLY)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-dictionary-script
|
||||
DESTINATION ${CIFPP_CRON_DIR}
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CIFPP_CACHE_DIR})
|
||||
install(DIRECTORY DESTINATION "$ENV{DESTDIR}/etc/libcifpp/cache-update.d")
|
||||
|
||||
# a config to, to make it complete
|
||||
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")
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
|
||||
install(CODE "message(\"A configuration file has been written to $ENV{DESTDIR}/etc/libcifpp.conf, please edit this file to enable automatic updates\")")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Boost 1.70.0 REQUIRED COMPONENTS system iostreams regex program_options)
|
||||
if(NOT WIN32)
|
||||
find_dependency(ZLIB)
|
||||
find_dependency(BZip2)
|
||||
endif()
|
||||
|
||||
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
|
||||
|
||||
set_and_check(CIFPP_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
Version 2.0.0
|
||||
- New API interface for accessing query results
|
||||
- Removed bzip2 support
|
||||
- improved makefiles
|
||||
|
||||
Version 1.1.1
|
||||
- Now with full support for MS Windows
|
||||
|
||||
@@ -10,4 +15,4 @@ Version 1.0.1
|
||||
then /var/cache and finally compiled in resources (with mrc).
|
||||
|
||||
Version 1.0.0
|
||||
- First public release
|
||||
- First public release
|
||||
|
||||
74
cmake/FindFilesystem.cmake
Normal file
74
cmake/FindFilesystem.cmake
Normal file
@@ -0,0 +1,74 @@
|
||||
# Simplistic reimplementation of https://github.com/vector-of-bool/CMakeCM/blob/master/modules/FindFilesystem.cmake
|
||||
|
||||
if(TARGET std::filesystem)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
cmake_push_check_state()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
|
||||
set(code [[
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
|
||||
int main() {
|
||||
auto cwd = std::filesystem::current_path();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
]])
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 8.4.0)
|
||||
# >> https://stackoverflow.com/questions/63902528/program-crashes-when-filesystempath-is-destroyed
|
||||
set(CXX_FILESYSTEM_NO_LINK_NEEDED 0)
|
||||
else()
|
||||
# Check a simple filesystem program without any linker flags
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
endif()
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
set(_found 1)
|
||||
else()
|
||||
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# Add the libstdc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set(_found ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
|
||||
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
# Try the libc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set(_found ${CXX_FILESYSTEM_CPPFS_NEEDED})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_found)
|
||||
add_library(std::filesystem INTERFACE IMPORTED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
# Nothing to add...
|
||||
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set_target_properties(std::filesystem PROPERTIES IMPORTED_LIBNAME stdc++fs)
|
||||
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set_target_properties(std::filesystem PROPERTIES IMPORTED_LIBNAME c++fs)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||
|
||||
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
|
||||
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,13 +26,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
@@ -48,11 +48,11 @@
|
||||
#include "cif++/Cif++Export.hpp"
|
||||
|
||||
#if _MSC_VER
|
||||
# pragma warning (disable : 4996) // unsafe function or variable (strcpy e.g.)
|
||||
# pragma warning (disable : 4068) // unknown pragma
|
||||
# pragma warning (disable : 4100) // unreferenced formal parameter
|
||||
# pragma warning (disable : 4101) // unreferenced local variable
|
||||
# define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1
|
||||
#pragma warning(disable : 4996) // unsafe function or variable (strcpy e.g.)
|
||||
#pragma warning(disable : 4068) // unknown pragma
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
#pragma warning(disable : 4101) // unreferenced local variable
|
||||
#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1
|
||||
#endif
|
||||
|
||||
namespace cif
|
||||
@@ -67,26 +67,26 @@ std::string get_version_nr();
|
||||
// some basic utilities: Since we're using ASCII input only, we define for optimisation
|
||||
// our own case conversion routines.
|
||||
|
||||
bool iequals(const std::string& a, const std::string& b);
|
||||
int icompare(const std::string& a, const std::string& b);
|
||||
bool iequals(const std::string &a, const std::string &b);
|
||||
int icompare(const std::string &a, const std::string &b);
|
||||
|
||||
bool iequals(const char* a, const char* b);
|
||||
int icompare(const char* a, const char* b);
|
||||
bool iequals(const char *a, const char *b);
|
||||
int icompare(const char *a, const char *b);
|
||||
|
||||
void toLower(std::string& s);
|
||||
std::string toLowerCopy(const std::string& s);
|
||||
void toLower(std::string &s);
|
||||
std::string toLowerCopy(const std::string &s);
|
||||
|
||||
// To make life easier, we also define iless and iset using iequals
|
||||
|
||||
struct iless
|
||||
{
|
||||
bool operator()(const std::string& a, const std::string& b) const
|
||||
bool operator()(const std::string &a, const std::string &b) const
|
||||
{
|
||||
return icompare(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set<std::string, iless> iset;
|
||||
typedef std::set<std::string, iless> iset;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// This really makes a difference, having our own tolower routines
|
||||
@@ -100,7 +100,7 @@ inline char tolower(int ch)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<std::string,std::string> splitTagName(const std::string& tag);
|
||||
std::tuple<std::string, std::string> splitTagName(const std::string &tag);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// generate a cif name, mainly used to generate asym_id's
|
||||
@@ -110,7 +110,7 @@ std::string cifIdForNumber(int number);
|
||||
// --------------------------------------------------------------------
|
||||
// custom wordwrapping routine
|
||||
|
||||
std::vector<std::string> wordWrap(const std::string& text, size_t width);
|
||||
std::vector<std::string> wordWrap(const std::string &text, size_t width);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Code helping with terminal i/o
|
||||
@@ -125,26 +125,41 @@ std::string get_executable_path();
|
||||
// --------------------------------------------------------------------
|
||||
// some manipulators to write coloured text to terminals
|
||||
|
||||
enum StringColour {
|
||||
scBLACK = 0, scRED, scGREEN, scYELLOW, scBLUE, scMAGENTA, scCYAN, scWHITE, scNONE = 9 };
|
||||
enum StringColour
|
||||
{
|
||||
scBLACK = 0,
|
||||
scRED,
|
||||
scGREEN,
|
||||
scYELLOW,
|
||||
scBLUE,
|
||||
scMAGENTA,
|
||||
scCYAN,
|
||||
scWHITE,
|
||||
scNONE = 9
|
||||
};
|
||||
|
||||
template<typename String, typename CharT>
|
||||
template <typename String, typename CharT>
|
||||
struct ColouredString
|
||||
{
|
||||
static_assert(std::is_reference<String>::value or std::is_pointer<String>::value, "String type must be pointer or reference");
|
||||
|
||||
|
||||
ColouredString(String s, StringColour fore, StringColour back, bool bold = true)
|
||||
: m_s(s), m_fore(fore), m_back(back), m_bold(bold) {}
|
||||
|
||||
ColouredString& operator=(const ColouredString&) = delete;
|
||||
|
||||
: m_s(s)
|
||||
, m_fore(fore)
|
||||
, m_back(back)
|
||||
, m_bold(bold)
|
||||
{
|
||||
}
|
||||
|
||||
ColouredString &operator=(const ColouredString &) = delete;
|
||||
|
||||
String m_s;
|
||||
StringColour m_fore, m_back;
|
||||
bool m_bold;
|
||||
};
|
||||
|
||||
template<typename CharT, typename Traits>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const ColouredString<const CharT*,CharT>& s)
|
||||
template <typename CharT, typename Traits>
|
||||
std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os, const ColouredString<const CharT *, CharT> &s)
|
||||
{
|
||||
if (isatty(STDOUT_FILENO))
|
||||
{
|
||||
@@ -152,15 +167,15 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
|
||||
ostr << "\033[" << (30 + s.m_fore) << ';' << (s.m_bold ? "1" : "22") << ';' << (40 + s.m_back) << 'm'
|
||||
<< s.m_s
|
||||
<< "\033[0m";
|
||||
|
||||
|
||||
return os << ostr.str();
|
||||
}
|
||||
else
|
||||
return os << s.m_s;
|
||||
}
|
||||
|
||||
template<typename CharT, typename Traits, typename String>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const ColouredString<String,CharT>& s)
|
||||
template <typename CharT, typename Traits, typename String>
|
||||
std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os, const ColouredString<String, CharT> &s)
|
||||
{
|
||||
if (isatty(STDOUT_FILENO))
|
||||
{
|
||||
@@ -168,27 +183,27 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
|
||||
ostr << "\033[" << (30 + s.m_fore) << ';' << (s.m_bold ? "1" : "22") << ';' << (40 + s.m_back) << 'm'
|
||||
<< s.m_s
|
||||
<< "\033[0m";
|
||||
|
||||
|
||||
return os << ostr.str();
|
||||
}
|
||||
else
|
||||
return os << s.m_s;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
inline auto coloured(const CharT* s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
template <typename CharT>
|
||||
inline auto coloured(const CharT *s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
{
|
||||
return ColouredString<const CharT*, CharT>(s, fore, back, bold);
|
||||
return ColouredString<const CharT *, CharT>(s, fore, back, bold);
|
||||
}
|
||||
|
||||
template<typename CharT, typename Traits, typename Alloc>
|
||||
inline auto coloured(const std::basic_string<CharT, Traits, Alloc>& s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
template <typename CharT, typename Traits, typename Alloc>
|
||||
inline auto coloured(const std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
{
|
||||
return ColouredString<const std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold);
|
||||
}
|
||||
|
||||
template<typename CharT, typename Traits, typename Alloc>
|
||||
inline auto coloured(std::basic_string<CharT, Traits, Alloc>& s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
template <typename CharT, typename Traits, typename Alloc>
|
||||
inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
{
|
||||
return ColouredString<std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold);
|
||||
}
|
||||
@@ -199,19 +214,19 @@ inline auto coloured(std::basic_string<CharT, Traits, Alloc>& s, StringColour fo
|
||||
class Progress
|
||||
{
|
||||
public:
|
||||
Progress(int64_t inMax, const std::string& inAction);
|
||||
virtual ~Progress();
|
||||
|
||||
void consumed(int64_t inConsumed); // consumed is relative
|
||||
void progress(int64_t inProgress); // progress is absolute
|
||||
Progress(int64_t inMax, const std::string &inAction);
|
||||
virtual ~Progress();
|
||||
|
||||
void message(const std::string& inMessage);
|
||||
void consumed(int64_t inConsumed); // consumed is relative
|
||||
void progress(int64_t inProgress); // progress is absolute
|
||||
|
||||
void message(const std::string &inMessage);
|
||||
|
||||
private:
|
||||
Progress(const Progress&) = delete;
|
||||
Progress& operator=(const Progress&) = delete;
|
||||
Progress(const Progress &) = delete;
|
||||
Progress &operator=(const Progress &) = delete;
|
||||
|
||||
struct ProgressImpl* mImpl;
|
||||
struct ProgressImpl *mImpl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -221,4 +236,4 @@ std::unique_ptr<std::istream> loadResource(std::filesystem::path name);
|
||||
void addFileResource(const std::string &name, std::filesystem::path dataFile);
|
||||
void addDataDirectory(std::filesystem::path dataDir);
|
||||
|
||||
}
|
||||
} // namespace cif
|
||||
|
||||
@@ -162,8 +162,8 @@ class CompoundFactory
|
||||
static CompoundFactory &instance();
|
||||
static void clear();
|
||||
|
||||
void setDefaultDictionary(const std::string &inDictFile);
|
||||
void pushDictionary(const std::string &inDictFile);
|
||||
void setDefaultDictionary(const std::filesystem::path &inDictFile);
|
||||
void pushDictionary(const std::filesystem::path &inDictFile);
|
||||
void popDictionary();
|
||||
|
||||
bool isKnownPeptide(const std::string &res_name) const;
|
||||
|
||||
391
include/cif++/Matrix.hpp
Normal file
391
include/cif++/Matrix.hpp
Normal file
@@ -0,0 +1,391 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright Maarten L. Hekkelman, Radboud University 2008-2011.
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// uBlas compatible matrix types
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// 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 T>
|
||||
class MatrixBase
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
virtual ~MatrixBase() {}
|
||||
|
||||
virtual uint32_t dim_m() const = 0;
|
||||
virtual uint32_t dim_n() const = 0;
|
||||
|
||||
virtual value_type &operator()(uint32_t i, uint32_t j) { throw std::runtime_error("unimplemented method"); }
|
||||
virtual value_type operator()(uint32_t i, uint32_t j) const = 0;
|
||||
|
||||
MatrixBase &operator*=(const value_type &rhs);
|
||||
|
||||
MatrixBase &operator-=(const value_type &rhs);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
MatrixBase<T> &MatrixBase<T>::operator*=(const T &rhs)
|
||||
{
|
||||
for (uint32_t i = 0; i < dim_m(); ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < dim_n(); ++j)
|
||||
{
|
||||
operator()(i, j) *= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MatrixBase<T> &MatrixBase<T>::operator-=(const T &rhs)
|
||||
{
|
||||
for (uint32_t i = 0; i < dim_m(); ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < dim_n(); ++j)
|
||||
{
|
||||
operator()(i, j) -= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &lhs, const MatrixBase<T> &rhs)
|
||||
{
|
||||
lhs << '[' << rhs.dim_m() << ',' << rhs.dim_n() << ']' << '(';
|
||||
for (uint32_t i = 0; i < rhs.dim_m(); ++i)
|
||||
{
|
||||
lhs << '(';
|
||||
for (uint32_t j = 0; j < rhs.dim_n(); ++j)
|
||||
{
|
||||
if (j > 0)
|
||||
lhs << ',';
|
||||
lhs << rhs(i, j);
|
||||
}
|
||||
lhs << ')';
|
||||
}
|
||||
lhs << ')';
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Matrix : public MatrixBase<T>
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
template <typename T2>
|
||||
Matrix(const MatrixBase<T2> &m)
|
||||
: m_m(m.dim_m())
|
||||
, m_n(m.dim_n())
|
||||
{
|
||||
m_data = new value_type[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()
|
||||
: m_data(nullptr)
|
||||
, m_m(0)
|
||||
, m_n(0)
|
||||
{
|
||||
}
|
||||
|
||||
Matrix(const Matrix &m)
|
||||
: m_m(m.m_m)
|
||||
, m_n(m.m_n)
|
||||
{
|
||||
m_data = new value_type[m_m * m_n];
|
||||
std::copy(m.m_data, m.m_data + (m_m * m_n), m_data);
|
||||
}
|
||||
|
||||
Matrix &operator=(const Matrix &m)
|
||||
{
|
||||
value_type *t = new value_type[m.m_m * m.m_n];
|
||||
std::copy(m.m_data, m.m_data + (m.m_m * m.m_n), t);
|
||||
|
||||
delete[] m_data;
|
||||
m_data = t;
|
||||
m_m = m.m_m;
|
||||
m_n = m.m_n;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix(uint32_t m, uint32_t n, T v = T())
|
||||
: m_m(m)
|
||||
, m_n(n)
|
||||
{
|
||||
m_data = new value_type[m_m * m_n];
|
||||
std::fill(m_data, m_data + (m_m * m_n), v);
|
||||
}
|
||||
|
||||
virtual ~Matrix()
|
||||
{
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
virtual uint32_t dim_m() const { return m_m; }
|
||||
virtual uint32_t dim_n() const { return m_n; }
|
||||
|
||||
virtual value_type operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
virtual value_type &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void each(Func f)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_m * m_n; ++i)
|
||||
f(m_data[i]);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
Matrix &operator/=(U v)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_m * m_n; ++i)
|
||||
m_data[i] /= v;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type *m_data;
|
||||
uint32_t m_m, m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class SymmetricMatrix : public MatrixBase<T>
|
||||
{
|
||||
public:
|
||||
typedef typename MatrixBase<T>::value_type value_type;
|
||||
|
||||
SymmetricMatrix(uint32_t n, T v = T())
|
||||
: m_owner(true)
|
||||
, m_n(n)
|
||||
{
|
||||
uint32_t N = (m_n * (m_n + 1)) / 2;
|
||||
m_data = new value_type[N];
|
||||
std::fill(m_data, m_data + N, v);
|
||||
}
|
||||
|
||||
SymmetricMatrix(const T *data, uint32_t n)
|
||||
: m_owner(false)
|
||||
, m_data(const_cast<T *>(data))
|
||||
, m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~SymmetricMatrix()
|
||||
{
|
||||
if (m_owner)
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
virtual uint32_t dim_m() const { return m_n; }
|
||||
virtual uint32_t dim_n() const { return m_n; }
|
||||
|
||||
T operator()(uint32_t i, uint32_t j) const;
|
||||
virtual T &operator()(uint32_t i, uint32_t j);
|
||||
|
||||
// erase two rows, add one at the end (for neighbour joining)
|
||||
void erase_2(uint32_t i, uint32_t j);
|
||||
|
||||
template <typename Func>
|
||||
void each(Func f)
|
||||
{
|
||||
uint32_t N = (m_n * (m_n + 1)) / 2;
|
||||
|
||||
for (uint32_t i = 0; i < N; ++i)
|
||||
f(m_data[i]);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
SymmetricMatrix &operator/=(U v)
|
||||
{
|
||||
uint32_t N = (m_n * (m_n + 1)) / 2;
|
||||
|
||||
for (uint32_t i = 0; i < N; ++i)
|
||||
m_data[i] /= v;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_owner;
|
||||
value_type *m_data;
|
||||
uint32_t m_n;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T SymmetricMatrix<T>::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];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T &SymmetricMatrix<T>::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];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SymmetricMatrix<T>::erase_2(uint32_t di, uint32_t dj)
|
||||
{
|
||||
uint32_t s = 0, d = 0;
|
||||
for (uint32_t i = 0; i < m_n; ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < i; ++j)
|
||||
{
|
||||
if (i != di and j != dj and i != dj and j != di)
|
||||
{
|
||||
if (s != d)
|
||||
m_data[d] = m_data[s];
|
||||
++d;
|
||||
}
|
||||
|
||||
++s;
|
||||
}
|
||||
}
|
||||
|
||||
--m_n;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class IdentityMatrix : public MatrixBase<T>
|
||||
{
|
||||
public:
|
||||
typedef typename MatrixBase<T>::value_type value_type;
|
||||
|
||||
IdentityMatrix(uint32_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint32_t dim_m() const { return m_n; }
|
||||
virtual uint32_t dim_n() const { return m_n; }
|
||||
|
||||
virtual value_type operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
value_type result = 0;
|
||||
if (i == j)
|
||||
result = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// matrix functions
|
||||
|
||||
template <typename T>
|
||||
Matrix<T> operator*(const MatrixBase<T> &lhs, const MatrixBase<T> &rhs)
|
||||
{
|
||||
Matrix<T> result(std::min(lhs.dim_m(), rhs.dim_m()), std::min(lhs.dim_n(), rhs.dim_n()));
|
||||
|
||||
for (uint32_t i = 0; i < result.dim_m(); ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < result.dim_n(); ++j)
|
||||
{
|
||||
for (uint32_t li = 0, rj = 0; li < lhs.dim_m() and rj < rhs.dim_n(); ++li, ++rj)
|
||||
result(i, j) += lhs(li, j) * rhs(i, rj);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Matrix<T> operator*(const MatrixBase<T> &lhs, T rhs)
|
||||
{
|
||||
Matrix<T> result(lhs);
|
||||
result *= rhs;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Matrix<T> operator-(const MatrixBase<T> &lhs, const MatrixBase<T> &rhs)
|
||||
{
|
||||
Matrix<T> result(std::min(lhs.dim_m(), rhs.dim_m()), std::min(lhs.dim_n(), rhs.dim_n()));
|
||||
|
||||
for (uint32_t i = 0; i < result.dim_m(); ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < result.dim_n(); ++j)
|
||||
{
|
||||
result(i, j) = lhs(i, j) - rhs(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Matrix<T> operator-(const MatrixBase<T> &lhs, T rhs)
|
||||
{
|
||||
Matrix<T> result(lhs.dim_m(), lhs.dim_n());
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
// template <typename T>
|
||||
// symmetric_matrix<T> hammingDistance(const MatrixBase<T> &lhs, T rhs);
|
||||
|
||||
// template <typename T>
|
||||
// std::vector<T> sum(const MatrixBase<T> &m);
|
||||
@@ -37,7 +37,7 @@
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
typedef boost::math::quaternion<float> quaternion;
|
||||
typedef boost::math::quaternion<float> Quaternion;
|
||||
|
||||
const double
|
||||
kPI = 3.141592653589793238462643383279502884;
|
||||
@@ -361,12 +361,12 @@ PointF<F> Nudge(PointF<F> p, F offset);
|
||||
// --------------------------------------------------------------------
|
||||
// We use quaternions to do rotations in 3d space
|
||||
|
||||
quaternion Normalize(quaternion q);
|
||||
Quaternion Normalize(Quaternion q);
|
||||
|
||||
//std::tuple<double,Point> QuaternionToAngleAxis(quaternion q);
|
||||
std::tuple<double,Point> QuaternionToAngleAxis(Quaternion q);
|
||||
Point Centroid(std::vector<Point>& Points);
|
||||
Point CenterPoints(std::vector<Point>& Points);
|
||||
quaternion AlignPoints(const std::vector<Point>& a, const std::vector<Point>& b);
|
||||
Quaternion AlignPoints(const std::vector<Point>& a, const std::vector<Point>& b);
|
||||
double RMSd(const std::vector<Point>& a, const std::vector<Point>& b);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -61,11 +61,12 @@ class File;
|
||||
class Atom
|
||||
{
|
||||
public:
|
||||
// Atom(const structure& s, const std::string& id);
|
||||
Atom();
|
||||
Atom(struct AtomImpl *impl);
|
||||
Atom(const Atom &rhs);
|
||||
|
||||
Atom(cif::Datablock &db, cif::Row &row);
|
||||
|
||||
// a special constructor to create symmetry copies
|
||||
Atom(const Atom &rhs, const Point &symmmetry_location, const std::string &symmetry_operation);
|
||||
|
||||
@@ -84,6 +85,12 @@ class Atom
|
||||
Point location() const;
|
||||
void location(Point p);
|
||||
|
||||
/// \brief Translate the position of this atom by \a t
|
||||
void translate(Point t);
|
||||
|
||||
/// \brief Rotate the position of this atom by \a q
|
||||
void rotate(Quaternion q);
|
||||
|
||||
// for direct access to underlying data, be careful!
|
||||
const cif::Row getRow() const;
|
||||
const cif::Row getRowAniso() const;
|
||||
@@ -199,15 +206,15 @@ class Residue
|
||||
|
||||
// constructor for waters
|
||||
Residue(const Structure &structure, const std::string &compoundID,
|
||||
const std::string &asymID, const std::string &authSeqID);
|
||||
const std::string &asymID, const std::string &authSeqID);
|
||||
|
||||
// constructor for a residue without a sequence number
|
||||
Residue(const Structure &structure, const std::string &compoundID,
|
||||
const std::string &asymID);
|
||||
const std::string &asymID);
|
||||
|
||||
// constructor for a residue with a sequence number
|
||||
Residue(const Structure &structure, const std::string &compoundID,
|
||||
const std::string &asymID, int seqID, const std::string &authSeqID);
|
||||
const std::string &asymID, int seqID, const std::string &authSeqID);
|
||||
|
||||
Residue(const Residue &rhs) = delete;
|
||||
Residue &operator=(const Residue &rhs) = delete;
|
||||
@@ -297,7 +304,7 @@ class Monomer : public Residue
|
||||
Monomer &operator=(Monomer &&rhs);
|
||||
|
||||
Monomer(const Polymer &polymer, size_t index, int seqID, const std::string &authSeqID,
|
||||
const std::string &compoundID);
|
||||
const std::string &compoundID);
|
||||
|
||||
bool is_first_in_chain() const;
|
||||
bool is_last_in_chain() const;
|
||||
@@ -390,15 +397,17 @@ class File : public std::enable_shared_from_this<File>
|
||||
{
|
||||
public:
|
||||
File();
|
||||
File(const std::string &path);
|
||||
File(const std::filesystem::path &path);
|
||||
File(const char *data, size_t length); // good luck trying to find out what it is...
|
||||
~File();
|
||||
|
||||
File(const File &) = delete;
|
||||
File &operator=(const File &) = delete;
|
||||
|
||||
void load(const std::string &path);
|
||||
void save(const std::string &path);
|
||||
cif::Datablock& createDatablock(const std::string &name);
|
||||
|
||||
void load(const std::filesystem::path &path);
|
||||
void save(const std::filesystem::path &path);
|
||||
|
||||
Structure *model(size_t nr = 1);
|
||||
|
||||
@@ -450,7 +459,7 @@ class Structure
|
||||
// Atom getAtomByLocation(Point pt, float maxDistance) const;
|
||||
|
||||
Atom getAtomByLabel(const std::string &atomID, const std::string &asymID,
|
||||
const std::string &compID, int seqID, const std::string &altID = "");
|
||||
const std::string &compID, int seqID, const std::string &altID = "");
|
||||
|
||||
/// \brief Get a residue, if \a seqID is zero, the non-polymers are searched
|
||||
const Residue &getResidue(const std::string &asymID, const std::string &compID, int seqID = 0) const;
|
||||
@@ -458,7 +467,7 @@ class Structure
|
||||
// map between auth and label locations
|
||||
|
||||
std::tuple<std::string, int, std::string> MapAuthToLabel(const std::string &asymID,
|
||||
const std::string &seqID, const std::string &compID, const std::string &insCode = "");
|
||||
const std::string &seqID, const std::string &compID, const std::string &insCode = "");
|
||||
|
||||
std::tuple<std::string, std::string, std::string, std::string> MapLabelToAuth(
|
||||
const std::string &asymID, int seqID, const std::string &compID);
|
||||
@@ -480,12 +489,31 @@ class Structure
|
||||
void swapAtoms(Atom &a1, Atom &a2); // swap the labels for these atoms
|
||||
void moveAtom(Atom &a, Point p); // move atom to a new location
|
||||
void changeResidue(const Residue &res, const std::string &newCompound,
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms);
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms);
|
||||
|
||||
/// To sort the atoms in order of model > asym-id > res-id > atom-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
|
||||
/// \return The ID of the created entity
|
||||
std::string createNonPolyEntity(const std::string &mon_id);
|
||||
|
||||
/// \brief Create a new NonPolymer struct_asym with atoms constructed from \a atoms, returns asym_id.
|
||||
/// This method assumes you are copying data from one cif file to another.
|
||||
///
|
||||
/// \param entity_id The entity ID of the new nonpoly
|
||||
/// \param atoms The array of atom_site rows containing the data.
|
||||
/// \return The newly create asym ID
|
||||
std::string createNonpoly(const std::string &entity_id, const std::vector<mmcif::Atom> &atoms);
|
||||
|
||||
/// \brief To sort the atoms in order of model > asym-id > res-id > atom-id
|
||||
/// Will asssign new atom_id's to all atoms. Be carefull
|
||||
void sortAtoms();
|
||||
|
||||
/// \brief Translate the coordinates of all atoms in the structure by \a t
|
||||
void translate(Point t);
|
||||
|
||||
/// \brief Rotate the coordinates of all atoms in the structure by \a q
|
||||
void rotate(Quaternion t);
|
||||
|
||||
const std::vector<Residue> &getNonPolymers() const { return mNonPolymers; }
|
||||
const std::vector<Residue> &getBranchResidues() const { return mBranchResidues; }
|
||||
|
||||
@@ -500,7 +528,7 @@ class Structure
|
||||
cif::Category &category(const char *name) const;
|
||||
cif::Datablock &datablock() const;
|
||||
|
||||
void insertCompound(const std::string &compoundID, bool isEntity);
|
||||
std::string insertCompound(const std::string &compoundID, bool isEntity);
|
||||
|
||||
void loadData();
|
||||
void updateAtomIndex();
|
||||
|
||||
@@ -8,5 +8,5 @@ Name: libcifpp
|
||||
Description: C++ library for the manipulation of mmCIF files.
|
||||
Version: @PACKAGE_VERSION@
|
||||
|
||||
Libs: -L${libdir} -lcifpp
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lcifpp @PRIVATE_LIBS@
|
||||
Cflags: -I${includedir} @PRIVATE_INC_DIRS@
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,10 +28,6 @@
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
#include <boost/iostreams/copy.hpp>
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/Compound.hpp"
|
||||
#include "cif++/CifUtils.hpp"
|
||||
|
||||
1863
src/Cif++.cpp
1863
src/Cif++.cpp
File diff suppressed because it is too large
Load Diff
@@ -27,8 +27,9 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <regex>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
@@ -3638,12 +3639,12 @@ std::tuple<int,int> WriteCoordinatesForModel(std::ostream& pdbFile, Datablock& d
|
||||
% chainID
|
||||
% resSeq
|
||||
% iCode
|
||||
% lrintf(u11 * 10000)
|
||||
% lrintf(u22 * 10000)
|
||||
% lrintf(u33 * 10000)
|
||||
% lrintf(u12 * 10000)
|
||||
% lrintf(u13 * 10000)
|
||||
% lrintf(u23 * 10000)
|
||||
% std::lrintf(u11 * 10000)
|
||||
% std::lrintf(u22 * 10000)
|
||||
% std::lrintf(u33 * 10000)
|
||||
% std::lrintf(u12 * 10000)
|
||||
% std::lrintf(u13 * 10000)
|
||||
% std::lrintf(u23 * 10000)
|
||||
% element
|
||||
% sCharge) << std::endl;
|
||||
}
|
||||
|
||||
@@ -268,9 +268,13 @@ class CompoundFactoryImpl : public std::enable_shared_from_this<CompoundFactoryI
|
||||
public:
|
||||
CompoundFactoryImpl(std::shared_ptr<CompoundFactoryImpl> next);
|
||||
|
||||
CompoundFactoryImpl(const std::string &file, std::shared_ptr<CompoundFactoryImpl> next);
|
||||
CompoundFactoryImpl(const std::filesystem::path &file, std::shared_ptr<CompoundFactoryImpl> next);
|
||||
|
||||
virtual ~CompoundFactoryImpl() = default;
|
||||
virtual ~CompoundFactoryImpl()
|
||||
{
|
||||
for (auto c: mCompounds)
|
||||
delete c;
|
||||
}
|
||||
|
||||
Compound *get(std::string id)
|
||||
{
|
||||
@@ -358,7 +362,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(std::shared_ptr<CompoundFactoryImpl> ne
|
||||
mKnownBases.insert(key);
|
||||
}
|
||||
|
||||
CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, std::shared_ptr<CompoundFactoryImpl> next)
|
||||
CompoundFactoryImpl::CompoundFactoryImpl(const std::filesystem::path &file, std::shared_ptr<CompoundFactoryImpl> next)
|
||||
: mNext(next)
|
||||
{
|
||||
cif::File cifFile(file);
|
||||
@@ -368,7 +372,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, std::shared_pt
|
||||
{
|
||||
auto &chemComp = (*compList)["chem_comp"];
|
||||
|
||||
for (const auto &[id, name, group] : chemComp.rows<std::string, std::string, std::string>({"id", "name", "group"}))
|
||||
for (const auto &[id, name, group] : chemComp.rows<std::string, std::string, std::string>("id", "name", "group"))
|
||||
{
|
||||
std::string type;
|
||||
|
||||
@@ -673,10 +677,10 @@ void CompoundFactory::clear()
|
||||
sInstance.reset();
|
||||
}
|
||||
|
||||
void CompoundFactory::setDefaultDictionary(const std::string &inDictFile)
|
||||
void CompoundFactory::setDefaultDictionary(const std::filesystem::path &inDictFile)
|
||||
{
|
||||
if (not fs::exists(inDictFile))
|
||||
throw std::runtime_error("file not found: " + inDictFile);
|
||||
throw std::runtime_error("file not found: " + inDictFile.string());
|
||||
|
||||
try
|
||||
{
|
||||
@@ -689,10 +693,10 @@ void CompoundFactory::setDefaultDictionary(const std::string &inDictFile)
|
||||
}
|
||||
}
|
||||
|
||||
void CompoundFactory::pushDictionary(const std::string &inDictFile)
|
||||
void CompoundFactory::pushDictionary(const std::filesystem::path &inDictFile)
|
||||
{
|
||||
if (not fs::exists(inDictFile))
|
||||
throw std::runtime_error("file not found: " + inDictFile);
|
||||
throw std::runtime_error("file not found: " + inDictFile.string());
|
||||
|
||||
// ifstream file(inDictFile);
|
||||
// if (not file.is_open())
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <system_error>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/numeric/ublas/matrix.hpp>
|
||||
|
||||
@@ -896,8 +896,6 @@ class PDBFileParser
|
||||
{
|
||||
if (regex_match(s, m, rx1))
|
||||
{
|
||||
using namespace boost::gregorian;
|
||||
|
||||
int day = stoi(m[1].str());
|
||||
auto mi = kMonths.find(m[2].str());
|
||||
if (mi == kMonths.end())
|
||||
@@ -907,9 +905,12 @@ class PDBFileParser
|
||||
if (year < 1950)
|
||||
year += 100;
|
||||
|
||||
date dateOriginal(static_cast<uint16_t>(year), static_cast<uint16_t>(month), static_cast<uint16_t>(day));
|
||||
std::stringstream ss;
|
||||
ss << std::setw(4) << std::setfill('0') << year << '-'
|
||||
<< std::setw(2) << std::setfill('0') << month << '-'
|
||||
<< std::setw(2) << std::setfill('0') << day;
|
||||
|
||||
s = to_iso_extended_string(dateOriginal);
|
||||
s = ss.str();
|
||||
}
|
||||
else if (regex_match(s, m, rx2))
|
||||
{
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
|
||||
225
src/Point.cpp
225
src/Point.cpp
@@ -28,13 +28,14 @@
|
||||
#include <valarray>
|
||||
|
||||
#include "cif++/Point.hpp"
|
||||
#include "cif++/Matrix.hpp"
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
quaternion Normalize(quaternion q)
|
||||
Quaternion Normalize(Quaternion q)
|
||||
{
|
||||
std::valarray<double> t(4);
|
||||
|
||||
@@ -48,16 +49,16 @@ quaternion Normalize(quaternion q)
|
||||
double length = std::sqrt(t.sum());
|
||||
|
||||
if (length > 0.001)
|
||||
q /= static_cast<quaternion::value_type>(length);
|
||||
q /= static_cast<Quaternion::value_type>(length);
|
||||
else
|
||||
q = quaternion(1, 0, 0, 0);
|
||||
q = Quaternion(1, 0, 0, 0);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<double,Point> QuaternionToAngleAxis(quaternion q)
|
||||
std::tuple<double,Point> QuaternionToAngleAxis(Quaternion q)
|
||||
{
|
||||
if (q.R_component_1() > 1)
|
||||
q = Normalize(q);
|
||||
@@ -171,113 +172,113 @@ double LargestDepressedQuarticSolution(double a, double b, double c)
|
||||
return t.max();
|
||||
}
|
||||
|
||||
//quaternion AlignPoints(const vector<Point>& pa, const vector<Point>& pb)
|
||||
//{
|
||||
// // First calculate M, a 3x3 matrix containing the sums of products of the coordinates of A and B
|
||||
// matrix<double> M(3, 3, 0);
|
||||
//
|
||||
// for (uint32_t i = 0; i < pa.size(); ++i)
|
||||
// {
|
||||
// const Point& a = pa[i];
|
||||
// const Point& b = pb[i];
|
||||
//
|
||||
// M(0, 0) += a.mX * b.mX; M(0, 1) += a.mX * b.mY; M(0, 2) += a.mX * b.mZ;
|
||||
// M(1, 0) += a.mY * b.mX; M(1, 1) += a.mY * b.mY; M(1, 2) += a.mY * b.mZ;
|
||||
// M(2, 0) += a.mZ * b.mX; M(2, 1) += a.mZ * b.mY; M(2, 2) += a.mZ * b.mZ;
|
||||
// }
|
||||
//
|
||||
// // Now calculate N, a symmetric 4x4 matrix
|
||||
// symmetric_matrix<double> N(4);
|
||||
//
|
||||
// N(0, 0) = M(0, 0) + M(1, 1) + M(2, 2);
|
||||
// N(0, 1) = M(1, 2) - M(2, 1);
|
||||
// N(0, 2) = M(2, 0) - M(0, 2);
|
||||
// N(0, 3) = M(0, 1) - M(1, 0);
|
||||
//
|
||||
// N(1, 1) = M(0, 0) - M(1, 1) - M(2, 2);
|
||||
// N(1, 2) = M(0, 1) + M(1, 0);
|
||||
// N(1, 3) = M(0, 2) + M(2, 0);
|
||||
//
|
||||
// N(2, 2) = -M(0, 0) + M(1, 1) - M(2, 2);
|
||||
// N(2, 3) = M(1, 2) + M(2, 1);
|
||||
//
|
||||
// N(3, 3) = -M(0, 0) - M(1, 1) + M(2, 2);
|
||||
//
|
||||
// // det(N - λI) = 0
|
||||
// // find the largest λ (λm)
|
||||
// //
|
||||
// // Aλ4 + Bλ3 + Cλ2 + Dλ + E = 0
|
||||
// // A = 1
|
||||
// // B = 0
|
||||
// // and so this is a so-called depressed quartic
|
||||
// // solve it using Ferrari's algorithm
|
||||
//
|
||||
// double C = -2 * (
|
||||
// M(0, 0) * M(0, 0) + M(0, 1) * M(0, 1) + M(0, 2) * M(0, 2) +
|
||||
// M(1, 0) * M(1, 0) + M(1, 1) * M(1, 1) + M(1, 2) * M(1, 2) +
|
||||
// M(2, 0) * M(2, 0) + M(2, 1) * M(2, 1) + M(2, 2) * M(2, 2));
|
||||
//
|
||||
// double D = 8 * (M(0, 0) * M(1, 2) * M(2, 1) +
|
||||
// M(1, 1) * M(2, 0) * M(0, 2) +
|
||||
// M(2, 2) * M(0, 1) * M(1, 0)) -
|
||||
// 8 * (M(0, 0) * M(1, 1) * M(2, 2) +
|
||||
// M(1, 2) * M(2, 0) * M(0, 1) +
|
||||
// M(2, 1) * M(1, 0) * M(0, 2));
|
||||
//
|
||||
// double E =
|
||||
// (N(0,0) * N(1,1) - N(0,1) * N(0,1)) * (N(2,2) * N(3,3) - N(2,3) * N(2,3)) +
|
||||
// (N(0,1) * N(0,2) - N(0,0) * N(2,1)) * (N(2,1) * N(3,3) - N(2,3) * N(1,3)) +
|
||||
// (N(0,0) * N(1,3) - N(0,1) * N(0,3)) * (N(2,1) * N(2,3) - N(2,2) * N(1,3)) +
|
||||
// (N(0,1) * N(2,1) - N(1,1) * N(0,2)) * (N(0,2) * N(3,3) - N(2,3) * N(0,3)) +
|
||||
// (N(1,1) * N(0,3) - N(0,1) * N(1,3)) * (N(0,2) * N(2,3) - N(2,2) * N(0,3)) +
|
||||
// (N(0,2) * N(1,3) - N(2,1) * N(0,3)) * (N(0,2) * N(1,3) - N(2,1) * N(0,3));
|
||||
//
|
||||
// // solve quartic
|
||||
// double lm = LargestDepressedQuarticSolution(C, D, E);
|
||||
//
|
||||
// // calculate t = (N - λI)
|
||||
// matrix<double> li = identity_matrix<double>(4) * lm;
|
||||
// matrix<double> t = N - li;
|
||||
//
|
||||
// // calculate a matrix of cofactors for t
|
||||
// matrix<double> cf(4, 4);
|
||||
//
|
||||
// const uint32_t ixs[4][3] =
|
||||
// {
|
||||
// { 1, 2, 3 },
|
||||
// { 0, 2, 3 },
|
||||
// { 0, 1, 3 },
|
||||
// { 0, 1, 2 }
|
||||
// };
|
||||
//
|
||||
// uint32_t maxR = 0;
|
||||
// for (uint32_t r = 0; r < 4; ++r)
|
||||
// {
|
||||
// const uint32_t* ir = ixs[r];
|
||||
//
|
||||
// for (uint32_t c = 0; c < 4; ++c)
|
||||
// {
|
||||
// const uint32_t* ic = ixs[c];
|
||||
//
|
||||
// cf(r, c) =
|
||||
// t(ir[0], ic[0]) * t(ir[1], ic[1]) * t(ir[2], ic[2]) +
|
||||
// t(ir[0], ic[1]) * t(ir[1], ic[2]) * t(ir[2], ic[0]) +
|
||||
// t(ir[0], ic[2]) * t(ir[1], ic[0]) * t(ir[2], ic[1]) -
|
||||
// t(ir[0], ic[2]) * t(ir[1], ic[1]) * t(ir[2], ic[0]) -
|
||||
// t(ir[0], ic[1]) * t(ir[1], ic[0]) * t(ir[2], ic[2]) -
|
||||
// t(ir[0], ic[0]) * t(ir[1], ic[2]) * t(ir[2], ic[1]);
|
||||
// }
|
||||
//
|
||||
// if (r > maxR and cf(r, 0) > cf(maxR, 0))
|
||||
// maxR = r;
|
||||
// }
|
||||
//
|
||||
// // NOTE the negation of the y here, why? Maybe I swapped r/c above?
|
||||
// quaternion q(cf(maxR, 0), cf(maxR, 1), -cf(maxR, 2), cf(maxR, 3));
|
||||
// q = Normalize(q);
|
||||
//
|
||||
// return q;
|
||||
//}
|
||||
Quaternion AlignPoints(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<double> M(3, 3, 0);
|
||||
|
||||
for (uint32_t i = 0; i < pa.size(); ++i)
|
||||
{
|
||||
const Point& a = pa[i];
|
||||
const Point& b = pb[i];
|
||||
|
||||
M(0, 0) += a.mX * b.mX; M(0, 1) += a.mX * b.mY; M(0, 2) += a.mX * b.mZ;
|
||||
M(1, 0) += a.mY * b.mX; M(1, 1) += a.mY * b.mY; M(1, 2) += a.mY * b.mZ;
|
||||
M(2, 0) += a.mZ * b.mX; M(2, 1) += a.mZ * b.mY; M(2, 2) += a.mZ * b.mZ;
|
||||
}
|
||||
|
||||
// Now calculate N, a symmetric 4x4 Matrix
|
||||
SymmetricMatrix<double> N(4);
|
||||
|
||||
N(0, 0) = M(0, 0) + M(1, 1) + M(2, 2);
|
||||
N(0, 1) = M(1, 2) - M(2, 1);
|
||||
N(0, 2) = M(2, 0) - M(0, 2);
|
||||
N(0, 3) = M(0, 1) - M(1, 0);
|
||||
|
||||
N(1, 1) = M(0, 0) - M(1, 1) - M(2, 2);
|
||||
N(1, 2) = M(0, 1) + M(1, 0);
|
||||
N(1, 3) = M(0, 2) + M(2, 0);
|
||||
|
||||
N(2, 2) = -M(0, 0) + M(1, 1) - M(2, 2);
|
||||
N(2, 3) = M(1, 2) + M(2, 1);
|
||||
|
||||
N(3, 3) = -M(0, 0) - M(1, 1) + M(2, 2);
|
||||
|
||||
// det(N - λI) = 0
|
||||
// find the largest λ (λm)
|
||||
//
|
||||
// Aλ4 + Bλ3 + Cλ2 + Dλ + E = 0
|
||||
// A = 1
|
||||
// B = 0
|
||||
// and so this is a so-called depressed quartic
|
||||
// solve it using Ferrari's algorithm
|
||||
|
||||
double C = -2 * (
|
||||
M(0, 0) * M(0, 0) + M(0, 1) * M(0, 1) + M(0, 2) * M(0, 2) +
|
||||
M(1, 0) * M(1, 0) + M(1, 1) * M(1, 1) + M(1, 2) * M(1, 2) +
|
||||
M(2, 0) * M(2, 0) + M(2, 1) * M(2, 1) + M(2, 2) * M(2, 2));
|
||||
|
||||
double D = 8 * (M(0, 0) * M(1, 2) * M(2, 1) +
|
||||
M(1, 1) * M(2, 0) * M(0, 2) +
|
||||
M(2, 2) * M(0, 1) * M(1, 0)) -
|
||||
8 * (M(0, 0) * M(1, 1) * M(2, 2) +
|
||||
M(1, 2) * M(2, 0) * M(0, 1) +
|
||||
M(2, 1) * M(1, 0) * M(0, 2));
|
||||
|
||||
double E =
|
||||
(N(0,0) * N(1,1) - N(0,1) * N(0,1)) * (N(2,2) * N(3,3) - N(2,3) * N(2,3)) +
|
||||
(N(0,1) * N(0,2) - N(0,0) * N(2,1)) * (N(2,1) * N(3,3) - N(2,3) * N(1,3)) +
|
||||
(N(0,0) * N(1,3) - N(0,1) * N(0,3)) * (N(2,1) * N(2,3) - N(2,2) * N(1,3)) +
|
||||
(N(0,1) * N(2,1) - N(1,1) * N(0,2)) * (N(0,2) * N(3,3) - N(2,3) * N(0,3)) +
|
||||
(N(1,1) * N(0,3) - N(0,1) * N(1,3)) * (N(0,2) * N(2,3) - N(2,2) * N(0,3)) +
|
||||
(N(0,2) * N(1,3) - N(2,1) * N(0,3)) * (N(0,2) * N(1,3) - N(2,1) * N(0,3));
|
||||
|
||||
// solve quartic
|
||||
double lm = LargestDepressedQuarticSolution(C, D, E);
|
||||
|
||||
// calculate t = (N - λI)
|
||||
Matrix<double> li = IdentityMatrix<double>(4) * lm;
|
||||
Matrix<double> t = N - li;
|
||||
|
||||
// calculate a Matrix of cofactors for t
|
||||
Matrix<double> cf(4, 4);
|
||||
|
||||
const uint32_t ixs[4][3] =
|
||||
{
|
||||
{ 1, 2, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 1, 2 }
|
||||
};
|
||||
|
||||
uint32_t maxR = 0;
|
||||
for (uint32_t r = 0; r < 4; ++r)
|
||||
{
|
||||
const uint32_t* ir = ixs[r];
|
||||
|
||||
for (uint32_t c = 0; c < 4; ++c)
|
||||
{
|
||||
const uint32_t* ic = ixs[c];
|
||||
|
||||
cf(r, c) =
|
||||
t(ir[0], ic[0]) * t(ir[1], ic[1]) * t(ir[2], ic[2]) +
|
||||
t(ir[0], ic[1]) * t(ir[1], ic[2]) * t(ir[2], ic[0]) +
|
||||
t(ir[0], ic[2]) * t(ir[1], ic[0]) * t(ir[2], ic[1]) -
|
||||
t(ir[0], ic[2]) * t(ir[1], ic[1]) * t(ir[2], ic[0]) -
|
||||
t(ir[0], ic[1]) * t(ir[1], ic[0]) * t(ir[2], ic[2]) -
|
||||
t(ir[0], ic[0]) * t(ir[1], ic[2]) * t(ir[2], ic[1]);
|
||||
}
|
||||
|
||||
if (r > maxR and cf(r, 0) > cf(maxR, 0))
|
||||
maxR = r;
|
||||
}
|
||||
|
||||
// NOTE the negation of the y here, why? Maybe I swapped r/c above?
|
||||
Quaternion q(cf(maxR, 0), cf(maxR, 1), -cf(maxR, 2), cf(maxR, 3));
|
||||
q = Normalize(q);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -293,7 +294,7 @@ Point Nudge(Point p, float offset)
|
||||
float phi1 = static_cast<float>(randomAngle(rng) - kPI);
|
||||
float phi2 = static_cast<float>(randomAngle(rng) - kPI);
|
||||
|
||||
quaternion q = boost::math::spherical(1.0f, theta, phi1, phi2);
|
||||
Quaternion q = boost::math::spherical(1.0f, theta, phi1, phi2);
|
||||
|
||||
Point r{ 0, 0, 1 };
|
||||
r.rotate(q);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/iostreams/filter/bzip2.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
|
||||
@@ -60,14 +59,13 @@ struct FileImpl
|
||||
|
||||
void load_data(const char *data, size_t length);
|
||||
|
||||
void load(const std::string &p);
|
||||
void save(const std::string &p);
|
||||
void load(const std::filesystem::path &path);
|
||||
void save(const std::filesystem::path &path);
|
||||
};
|
||||
|
||||
void FileImpl::load_data(const char *data, size_t length)
|
||||
{
|
||||
bool gzipped = length > 2 and data[0] == static_cast<char>(0x1f) and data[1] == static_cast<char>(0x8b);
|
||||
bool bzip2ed = length > 3 and data[0] == static_cast<char>(0x42) and data[1] == static_cast<char>(0x5A) and data[2] == static_cast<char>(0x68);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -82,8 +80,6 @@ void FileImpl::load_data(const char *data, size_t length)
|
||||
io::filtering_stream<io::input> in;
|
||||
if (gzipped)
|
||||
in.push(io::gzip_decompressor());
|
||||
else if (bzip2ed)
|
||||
in.push(io::bzip2_decompressor());
|
||||
in.push(is);
|
||||
|
||||
mData.load(in);
|
||||
@@ -101,8 +97,6 @@ void FileImpl::load_data(const char *data, size_t length)
|
||||
io::filtering_stream<io::input> in;
|
||||
if (gzipped)
|
||||
in.push(io::gzip_decompressor());
|
||||
else if (bzip2ed)
|
||||
in.push(io::bzip2_decompressor());
|
||||
in.push(is);
|
||||
|
||||
ReadPDBFile(in, mData);
|
||||
@@ -118,10 +112,8 @@ void FileImpl::load_data(const char *data, size_t length)
|
||||
std::cerr << "Invalid mmCIF file" << (cif::VERBOSE ? "." : " use --verbose option to see errors") << std::endl;
|
||||
}
|
||||
|
||||
void FileImpl::load(const std::string &p)
|
||||
void FileImpl::load(const std::filesystem::path &path)
|
||||
{
|
||||
fs::path path(p);
|
||||
|
||||
std::ifstream inFile(path, std::ios_base::in | std::ios_base::binary);
|
||||
if (not inFile.is_open())
|
||||
throw std::runtime_error("No such file: " + path.string());
|
||||
@@ -129,12 +121,7 @@ void FileImpl::load(const std::string &p)
|
||||
io::filtering_stream<io::input> in;
|
||||
std::string ext = path.extension().string();
|
||||
|
||||
if (path.extension() == ".bz2")
|
||||
{
|
||||
in.push(io::bzip2_decompressor());
|
||||
ext = path.stem().extension().string();
|
||||
}
|
||||
else if (path.extension() == ".gz")
|
||||
if (path.extension() == ".gz")
|
||||
{
|
||||
in.push(io::gzip_decompressor());
|
||||
ext = path.stem().extension().string();
|
||||
@@ -171,9 +158,7 @@ void FileImpl::load(const std::string &p)
|
||||
else
|
||||
inFile.open(path, std::ios_base::in | std::ios::binary);
|
||||
|
||||
if (path.extension() == ".bz2")
|
||||
in.push(io::bzip2_decompressor());
|
||||
else if (path.extension() == ".gz")
|
||||
if (path.extension() == ".gz")
|
||||
in.push(io::gzip_decompressor());
|
||||
|
||||
in.push(inFile);
|
||||
@@ -198,23 +183,13 @@ void FileImpl::load(const std::string &p)
|
||||
std::cerr << "Invalid mmCIF file" << (cif::VERBOSE ? "." : " use --verbose option to see errors") << std::endl;
|
||||
}
|
||||
|
||||
void FileImpl::save(const std::string &p)
|
||||
void FileImpl::save(const std::filesystem::path &path)
|
||||
{
|
||||
fs::path path(p);
|
||||
|
||||
std::ofstream outFile(p, std::ios_base::out | std::ios_base::binary);
|
||||
std::ofstream outFile(path, std::ios_base::out | std::ios_base::binary);
|
||||
io::filtering_stream<io::output> out;
|
||||
|
||||
if (path.extension() == ".gz")
|
||||
{
|
||||
out.push(io::gzip_compressor());
|
||||
path = path.stem();
|
||||
}
|
||||
else if (path.extension() == ".bz2")
|
||||
{
|
||||
out.push(io::bzip2_compressor());
|
||||
path = path.stem();
|
||||
}
|
||||
|
||||
out.push(outFile);
|
||||
|
||||
@@ -230,7 +205,7 @@ void FileImpl::save(const std::string &p)
|
||||
struct AtomImpl
|
||||
{
|
||||
AtomImpl(const AtomImpl &i)
|
||||
: mFile(i.mFile)
|
||||
: mDb(i.mDb)
|
||||
, mID(i.mID)
|
||||
, mType(i.mType)
|
||||
, mAtomID(i.mAtomID)
|
||||
@@ -250,13 +225,12 @@ struct AtomImpl
|
||||
{
|
||||
}
|
||||
|
||||
AtomImpl(const File &f, const std::string &id)
|
||||
: mFile(f)
|
||||
AtomImpl(cif::Datablock &db, const std::string &id)
|
||||
: mDb(db)
|
||||
, mID(id)
|
||||
, mRefcount(1)
|
||||
, mCompound(nullptr)
|
||||
{
|
||||
auto &db = *mFile.impl().mDb;
|
||||
auto &cat = db["atom_site"];
|
||||
|
||||
mRow = cat[cif::Key("id") == mID];
|
||||
@@ -264,8 +238,18 @@ struct AtomImpl
|
||||
prefetch();
|
||||
}
|
||||
|
||||
AtomImpl(const File &f, const std::string &id, cif::Row row)
|
||||
: mFile(f)
|
||||
AtomImpl(cif::Datablock &db, cif::Row &row)
|
||||
: mDb(db)
|
||||
, mID(row["id"].as<std::string>())
|
||||
, mRefcount(1)
|
||||
, mRow(row)
|
||||
, mCompound(nullptr)
|
||||
{
|
||||
prefetch();
|
||||
}
|
||||
|
||||
AtomImpl(cif::Datablock &db, const std::string &id, cif::Row row)
|
||||
: mDb(db)
|
||||
, mID(id)
|
||||
, mRefcount(1)
|
||||
, mRow(row)
|
||||
@@ -274,21 +258,8 @@ struct AtomImpl
|
||||
prefetch();
|
||||
}
|
||||
|
||||
// AtomImpl(const AtomImpl& impl, const Point& d, const clipper::RTop_orth& rt)
|
||||
// : mFile(impl.mFile), mID(impl.mID), mType(impl.mType), mAtomID(impl.mAtomID)
|
||||
// , mCompID(impl.mCompID), mAsymID(impl.mAsymID), mSeqID(impl.mSeqID)
|
||||
// , mAltID(impl.mAltID), mLocation(impl.mLocation), mRefcount(1)
|
||||
// , mRow(impl.mRow), mCompound(impl.mCompound), mRadius(impl.mRadius)
|
||||
// , mCachedProperties(impl.mCachedProperties)
|
||||
// , mSymmetryCopy(true), mRTop(rt), mD(d)
|
||||
// {
|
||||
// mLocation += d;
|
||||
// mLocation = ((clipper::Coord_orth)mLocation).transform(rt);
|
||||
// mLocation -= d;
|
||||
// }
|
||||
|
||||
AtomImpl(const AtomImpl &impl, const Point &loc, const std::string &sym_op)
|
||||
: mFile(impl.mFile)
|
||||
: mDb(impl.mDb)
|
||||
, mID(impl.mID)
|
||||
, mType(impl.mType)
|
||||
, mAtomID(impl.mAtomID)
|
||||
@@ -341,16 +312,19 @@ struct AtomImpl
|
||||
|
||||
bool getAnisoU(float anisou[6]) const
|
||||
{
|
||||
auto &db = *mFile.impl().mDb;
|
||||
auto &cat = db["atom_site_anisotrop"];
|
||||
auto r = cat[cif::Key("id") == mID];
|
||||
bool result = false;
|
||||
|
||||
if (not r.empty())
|
||||
auto cat = mDb.get("atom_site_anisotrop");
|
||||
if (cat)
|
||||
{
|
||||
result = true;
|
||||
cif::tie(anisou[0], anisou[1], anisou[2], anisou[3], anisou[4], anisou[5]) =
|
||||
r.get("U[1][1]", "U[1][2]", "U[1][3]", "U[2][2]", "U[2][3]", "U[3][3]");
|
||||
auto r = cat->find1(cif::Key("id") == mID);
|
||||
|
||||
if (not r.empty())
|
||||
{
|
||||
result = true;
|
||||
cif::tie(anisou[0], anisou[1], anisou[2], anisou[3], anisou[4], anisou[5]) =
|
||||
r.get("U[1][1]", "U[1][2]", "U[1][3]", "U[2][2]", "U[2][3]", "U[3][3]");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -445,7 +419,7 @@ struct AtomImpl
|
||||
std::swap(mAtomID, b.mAtomID);
|
||||
}
|
||||
|
||||
const File &mFile;
|
||||
const cif::Datablock &mDb;
|
||||
std::string mID;
|
||||
AtomType mType;
|
||||
|
||||
@@ -487,6 +461,11 @@ Atom::Atom(AtomImpl *impl)
|
||||
{
|
||||
}
|
||||
|
||||
Atom::Atom(cif::Datablock &db, cif::Row &row)
|
||||
: mImpl_(new AtomImpl(db, row))
|
||||
{
|
||||
}
|
||||
|
||||
AtomImpl *Atom::impl()
|
||||
{
|
||||
if (mImpl_ == nullptr)
|
||||
@@ -545,9 +524,12 @@ const cif::Row Atom::getRow() const
|
||||
|
||||
const cif::Row Atom::getRowAniso() const
|
||||
{
|
||||
auto &db = *mImpl_->mFile.impl().mDb;
|
||||
auto &cat = db["atom_site_anisotrop"];
|
||||
return cat[cif::Key("id") == mImpl_->mID];
|
||||
auto &db = mImpl_->mDb;
|
||||
auto cat = db.get("atom_site_anisotrop");
|
||||
if (not cat)
|
||||
return {};
|
||||
else
|
||||
return cat->find1(cif::Key("id") == mImpl_->mID);
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -701,6 +683,20 @@ void Atom::location(Point p)
|
||||
impl()->moveTo(p);
|
||||
}
|
||||
|
||||
void Atom::translate(Point t)
|
||||
{
|
||||
auto loc = location();
|
||||
loc += t;
|
||||
location(loc);
|
||||
}
|
||||
|
||||
void Atom::rotate(Quaternion q)
|
||||
{
|
||||
auto loc = location();
|
||||
loc.rotate(q);
|
||||
location(loc);
|
||||
}
|
||||
|
||||
// Atom Atom::symmetryCopy(const Point& d, const clipper::RTop_orth& rt)
|
||||
// {
|
||||
// return Atom(new AtomImpl(*impl(), d, rt));
|
||||
@@ -744,7 +740,7 @@ bool Atom::isWater() const
|
||||
bool Atom::operator==(const Atom &rhs) const
|
||||
{
|
||||
return impl() == rhs.impl() or
|
||||
(&impl()->mFile == &rhs.impl()->mFile and impl()->mID == rhs.impl()->mID);
|
||||
(&impl()->mDb == &rhs.impl()->mDb and impl()->mID == rhs.impl()->mID);
|
||||
}
|
||||
|
||||
// clipper::Atom Atom::toClipper() const
|
||||
@@ -795,7 +791,7 @@ std::ostream &operator<<(std::ostream &os, const Atom &atom)
|
||||
// First constructor used to be for waters only, but now accepts sugars as well.
|
||||
|
||||
Residue::Residue(const Structure &structure, const std::string &compoundID,
|
||||
const std::string &asymID, const std::string &authSeqID)
|
||||
const std::string &asymID, const std::string &authSeqID)
|
||||
: mStructure(&structure)
|
||||
, mCompoundID(compoundID)
|
||||
, mAsymID(asymID)
|
||||
@@ -804,7 +800,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID,
|
||||
for (auto &a : mStructure->atoms())
|
||||
{
|
||||
if (a.labelAsymID() != mAsymID or
|
||||
a.labelCompID() != mCompoundID)
|
||||
a.labelCompID() != mCompoundID)
|
||||
continue;
|
||||
|
||||
if (compoundID == "HOH")
|
||||
@@ -830,7 +826,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID, cons
|
||||
}
|
||||
|
||||
Residue::Residue(const Structure &structure, const std::string &compoundID,
|
||||
const std::string &asymID, int seqID, const std::string &authSeqID)
|
||||
const std::string &asymID, int seqID, const std::string &authSeqID)
|
||||
: mStructure(&structure)
|
||||
, mCompoundID(compoundID)
|
||||
, mAsymID(asymID)
|
||||
@@ -845,7 +841,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID,
|
||||
continue;
|
||||
|
||||
if (a.labelAsymID() != mAsymID or
|
||||
a.labelCompID() != mCompoundID)
|
||||
a.labelCompID() != mCompoundID)
|
||||
continue;
|
||||
|
||||
mAtoms.push_back(a);
|
||||
@@ -968,7 +964,7 @@ std::string Residue::unique_alt_id() const
|
||||
throw std::runtime_error("Invalid Residue object");
|
||||
|
||||
auto firstAlt = std::find_if(mAtoms.begin(), mAtoms.end(), [](auto &a)
|
||||
{ return not a.labelAltID().empty(); });
|
||||
{ return not a.labelAltID().empty(); });
|
||||
|
||||
return firstAlt != mAtoms.end() ? firstAlt->labelAltID() : "";
|
||||
}
|
||||
@@ -1032,7 +1028,7 @@ Atom Residue::atomByID(const std::string &atomID) const
|
||||
}
|
||||
}
|
||||
|
||||
if (not result and cif::VERBOSE)
|
||||
if (not result and cif::VERBOSE > 1)
|
||||
std::cerr << "Atom with atom_id " << atomID << " not found in residue " << mAsymID << ':' << mSeqID << std::endl;
|
||||
|
||||
return result;
|
||||
@@ -1104,7 +1100,7 @@ std::tuple<Point, float> Residue::centerAndRadius() const
|
||||
bool Residue::hasAlternateAtoms() const
|
||||
{
|
||||
return std::find_if(mAtoms.begin(), mAtoms.end(), [](const Atom &atom)
|
||||
{ return atom.isAlternate(); }) != mAtoms.end();
|
||||
{ return atom.isAlternate(); }) != mAtoms.end();
|
||||
}
|
||||
|
||||
std::set<std::string> Residue::getAtomIDs() const
|
||||
@@ -1476,7 +1472,7 @@ float Monomer::chiralVolume() const
|
||||
auto atom3 = atomByID("CD2");
|
||||
|
||||
result = DotProduct(atom1.location() - centre.location(),
|
||||
CrossProduct(atom2.location() - centre.location(), atom3.location() - centre.location()));
|
||||
CrossProduct(atom2.location() - centre.location(), atom3.location() - centre.location()));
|
||||
}
|
||||
else if (mCompoundID == "VAL")
|
||||
{
|
||||
@@ -1486,7 +1482,7 @@ float Monomer::chiralVolume() const
|
||||
auto atom3 = atomByID("CG2");
|
||||
|
||||
result = DotProduct(atom1.location() - centre.location(),
|
||||
CrossProduct(atom2.location() - centre.location(), atom3.location() - centre.location()));
|
||||
CrossProduct(atom2.location() - centre.location(), atom3.location() - centre.location()));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1729,7 +1725,7 @@ File::File(const char *data, size_t length)
|
||||
mImpl->load_data(data, length);
|
||||
}
|
||||
|
||||
File::File(const std::string &File)
|
||||
File::File(const std::filesystem::path &File)
|
||||
: mImpl(new FileImpl)
|
||||
{
|
||||
load(File);
|
||||
@@ -1740,12 +1736,22 @@ File::~File()
|
||||
delete mImpl;
|
||||
}
|
||||
|
||||
void File::load(const std::string &p)
|
||||
cif::Datablock& File::createDatablock(const std::string &name)
|
||||
{
|
||||
auto db = new cif::Datablock(name);
|
||||
|
||||
mImpl->mData.append(db);
|
||||
mImpl->mDb = db;
|
||||
|
||||
return *mImpl->mDb;
|
||||
}
|
||||
|
||||
void File::load(const std::filesystem::path &p)
|
||||
{
|
||||
mImpl->load(p);
|
||||
}
|
||||
|
||||
void File::save(const std::string &file)
|
||||
void File::save(const std::filesystem::path &file)
|
||||
{
|
||||
mImpl->save(file);
|
||||
}
|
||||
@@ -1778,8 +1784,11 @@ Structure::Structure(File &f, size_t modelNr, StructureOpenOptions options)
|
||||
: mFile(f)
|
||||
, mModelNr(modelNr)
|
||||
{
|
||||
auto &db = *mFile.impl().mDb;
|
||||
auto &atomCat = db["atom_site"];
|
||||
auto db = mFile.impl().mDb;
|
||||
if (db == nullptr)
|
||||
throw std::logic_error("Empty file!");
|
||||
|
||||
auto &atomCat = (*db)["atom_site"];
|
||||
|
||||
for (auto &a : atomCat)
|
||||
{
|
||||
@@ -1794,7 +1803,7 @@ Structure::Structure(File &f, size_t modelNr, StructureOpenOptions options)
|
||||
if ((options bitand StructureOpenOptions::SkipHydrogen) and type_symbol == "H")
|
||||
continue;
|
||||
|
||||
mAtoms.emplace_back(new AtomImpl(f, id, a));
|
||||
mAtoms.emplace_back(new AtomImpl(*db, id, a));
|
||||
}
|
||||
|
||||
loadData();
|
||||
@@ -1864,13 +1873,13 @@ void Structure::updateAtomIndex()
|
||||
iota(mAtomIndex.begin(), mAtomIndex.end(), 0);
|
||||
|
||||
sort(mAtomIndex.begin(), mAtomIndex.end(), [this](size_t a, size_t b)
|
||||
{ return mAtoms[a].id() < mAtoms[b].id(); });
|
||||
{ return mAtoms[a].id() < mAtoms[b].id(); });
|
||||
}
|
||||
|
||||
void Structure::sortAtoms()
|
||||
{
|
||||
sort(mAtoms.begin(), mAtoms.end(), [](auto &a, auto &b)
|
||||
{ return a.compare(b) < 0; });
|
||||
{ return a.compare(b) < 0; });
|
||||
|
||||
int id = 1;
|
||||
for (auto &atom : mAtoms)
|
||||
@@ -1914,8 +1923,8 @@ AtomView Structure::waters() const
|
||||
Atom Structure::getAtomByID(std::string id) const
|
||||
{
|
||||
auto i = std::lower_bound(mAtomIndex.begin(), mAtomIndex.end(),
|
||||
id, [this](auto &a, auto &b)
|
||||
{ return mAtoms[a].id() < b; });
|
||||
id, [this](auto &a, auto &b)
|
||||
{ return mAtoms[a].id() < b; });
|
||||
|
||||
// auto i = find_if(mAtoms.begin(), mAtoms.end(),
|
||||
// [&id](auto& a) { return a.id() == id; });
|
||||
@@ -1931,10 +1940,10 @@ Atom Structure::getAtomByLabel(const std::string &atomID, const std::string &asy
|
||||
for (auto &a : mAtoms)
|
||||
{
|
||||
if (a.labelAtomID() == atomID and
|
||||
a.labelAsymID() == asymID and
|
||||
a.labelCompID() == compID and
|
||||
a.labelSeqID() == seqID and
|
||||
a.labelAltID() == altID)
|
||||
a.labelAsymID() == asymID and
|
||||
a.labelCompID() == compID and
|
||||
a.labelSeqID() == seqID and
|
||||
a.labelAltID() == altID)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
@@ -2013,12 +2022,12 @@ std::tuple<char, int, char> Structure::MapLabelToAuth(
|
||||
try
|
||||
{
|
||||
result = std::make_tuple(auth_asym_id.front(), std::stoi(auth_seq_num),
|
||||
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
|
||||
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
result = std::make_tuple(auth_asym_id.front(), 0,
|
||||
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
|
||||
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
|
||||
}
|
||||
|
||||
found = true;
|
||||
@@ -2037,7 +2046,7 @@ std::tuple<char, int, char> Structure::MapLabelToAuth(
|
||||
r.front().get("pdb_strand_id", "pdb_seq_num", "pdb_ins_code");
|
||||
|
||||
result = std::make_tuple(pdb_strand_id.front(), pdb_seq_num,
|
||||
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
|
||||
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
|
||||
|
||||
found = true;
|
||||
}
|
||||
@@ -2089,7 +2098,7 @@ std::tuple<std::string, int, std::string, std::string> Structure::MapLabelToPDB(
|
||||
}
|
||||
|
||||
std::tuple<std::string, int, std::string> Structure::MapPDBToLabel(const std::string &asymID, int seqID,
|
||||
const std::string &compID, const std::string &iCode) const
|
||||
const std::string &compID, const std::string &iCode) const
|
||||
{
|
||||
auto &db = datablock();
|
||||
|
||||
@@ -2148,8 +2157,10 @@ cif::Datablock &Structure::datablock() const
|
||||
return *mFile.impl().mDb;
|
||||
}
|
||||
|
||||
void Structure::insertCompound(const std::string &compoundID, bool isEntity)
|
||||
std::string Structure::insertCompound(const std::string &compoundID, bool isEntity)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
auto compound = CompoundFactory::instance().create(compoundID);
|
||||
if (compound == nullptr)
|
||||
throw std::runtime_error("Trying to insert unknown compound " + compoundID + " (not found in CCD)");
|
||||
@@ -2160,31 +2171,42 @@ void Structure::insertCompound(const std::string &compoundID, bool isEntity)
|
||||
auto r = chemComp.find(cif::Key("id") == compoundID);
|
||||
if (r.empty())
|
||||
{
|
||||
chemComp.emplace({{"id", compoundID},
|
||||
{"name", compound->name()},
|
||||
{"formula", compound->formula()},
|
||||
{"formula_weight", compound->formulaWeight()},
|
||||
{"type", compound->type()}});
|
||||
chemComp.emplace({
|
||||
{"id", compoundID},
|
||||
{"name", compound->name()},
|
||||
{"formula", compound->formula()},
|
||||
{"formula_weight", compound->formulaWeight()},
|
||||
{"type", compound->type()}});
|
||||
}
|
||||
|
||||
std::string entity_id;
|
||||
|
||||
if (isEntity)
|
||||
{
|
||||
auto &pdbxEntityNonpoly = db["pdbx_entity_nonpoly"];
|
||||
if (not pdbxEntityNonpoly.exists(cif::Key("comp_id") == compoundID))
|
||||
try
|
||||
{
|
||||
entity_id = pdbxEntityNonpoly.find1<std::string>("comp_id"_key == compoundID, "entity_id");
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
auto &entity = db["entity"];
|
||||
std::string entityID = std::to_string(entity.size() + 1);
|
||||
entity_id = entity.getUniqueID("");
|
||||
|
||||
entity.emplace({{"id", entityID},
|
||||
{"type", "non-polymer"},
|
||||
{"pdbx_description", compound->name()},
|
||||
{"formula_weight", compound->formulaWeight()}});
|
||||
entity.emplace({
|
||||
{"id", entity_id},
|
||||
{"type", "non-polymer"},
|
||||
{"pdbx_description", compound->name()},
|
||||
{"formula_weight", compound->formulaWeight()}});
|
||||
|
||||
pdbxEntityNonpoly.emplace({{"entity_id", entityID},
|
||||
{"name", compound->name()},
|
||||
{"comp_id", compoundID}});
|
||||
pdbxEntityNonpoly.emplace({
|
||||
{"entity_id", entity_id},
|
||||
{"name", compound->name()},
|
||||
{"comp_id", compoundID}});
|
||||
}
|
||||
}
|
||||
|
||||
return entity_id;
|
||||
}
|
||||
|
||||
// // --------------------------------------------------------------------
|
||||
@@ -2305,7 +2327,7 @@ void Structure::moveAtom(Atom &a, Point p)
|
||||
}
|
||||
|
||||
void Structure::changeResidue(const Residue &res, const std::string &newCompound,
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms)
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
@@ -2327,21 +2349,21 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
|
||||
|
||||
try
|
||||
{
|
||||
std::tie(entityID) = entity.find1<std::string>("type"_key == "non-polymer" and "pdbx_description"_key == compound->name(), {"id"});
|
||||
entityID = entity.find1<std::string>("type"_key == "non-polymer" and "pdbx_description"_key == compound->name(), "id");
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
entityID = entity.getUniqueID("");
|
||||
entity.emplace({{"id", entityID},
|
||||
{"type", "non-polymer"},
|
||||
{"pdbx_description", compound->name()},
|
||||
{"formula_weight", compound->formulaWeight()}});
|
||||
{"type", "non-polymer"},
|
||||
{"pdbx_description", compound->name()},
|
||||
{"formula_weight", compound->formulaWeight()}});
|
||||
}
|
||||
|
||||
auto &pdbxEntityNonpoly = db["pdbx_entity_nonpoly"];
|
||||
pdbxEntityNonpoly.emplace({{"entity_id", entityID},
|
||||
{"name", compound->name()},
|
||||
{"comp_id", newCompound}});
|
||||
{"name", compound->name()},
|
||||
{"comp_id", newCompound}});
|
||||
|
||||
auto &pdbxNonPolyScheme = db["pdbx_nonpoly_scheme"];
|
||||
for (auto &nps : pdbxNonPolyScheme.find("asym_id"_key == asymID))
|
||||
@@ -2356,10 +2378,10 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
|
||||
if (not chemComp.exists(cif::Key("id") == newCompound))
|
||||
{
|
||||
chemComp.emplace({{"id", newCompound},
|
||||
{"name", compound->name()},
|
||||
{"formula", compound->formula()},
|
||||
{"formula_weight", compound->formulaWeight()},
|
||||
{"type", compound->type()}});
|
||||
{"name", compound->name()},
|
||||
{"formula", compound->formula()},
|
||||
{"formula_weight", compound->formulaWeight()},
|
||||
{"type", compound->type()}});
|
||||
}
|
||||
|
||||
// update the struct_asym for the new entity
|
||||
@@ -2377,7 +2399,7 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
|
||||
tie(a1, a2) = a;
|
||||
|
||||
auto i = find_if(atoms.begin(), atoms.end(), [&](const Atom &a)
|
||||
{ return a.labelAtomID() == a1; });
|
||||
{ return a.labelAtomID() == a1; });
|
||||
if (i == atoms.end())
|
||||
{
|
||||
std::cerr << "Missing atom for atom ID " << a1 << std::endl;
|
||||
@@ -2400,6 +2422,67 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
|
||||
}
|
||||
}
|
||||
|
||||
std::string Structure::createNonPolyEntity(const std::string &comp_id)
|
||||
{
|
||||
return insertCompound(comp_id, true);
|
||||
}
|
||||
|
||||
std::string Structure::createNonpoly(const std::string &entity_id, const std::vector<mmcif::Atom> &atoms)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
cif::Datablock &db = *mFile.impl().mDb;
|
||||
auto &struct_asym = db["struct_asym"];
|
||||
std::string asym_id = struct_asym.getUniqueID();
|
||||
|
||||
struct_asym.emplace({
|
||||
{ "id", asym_id },
|
||||
{ "pdbx_blank_PDB_chainid_flag", "N" },
|
||||
{ "pdbx_modified", "N" },
|
||||
{ "entity_id", entity_id },
|
||||
{ "details", "?" }
|
||||
});
|
||||
|
||||
std::string comp_id = db["pdbx_entity_nonpoly"].find1<std::string>("entity_id"_key == entity_id, "comp_id");
|
||||
|
||||
auto &atom_site = db["atom_site"];
|
||||
|
||||
for (auto& atom: atoms)
|
||||
{
|
||||
auto atom_id = atom_site.getUniqueID("");
|
||||
|
||||
auto &&[row, inserted ] = atom_site.emplace({
|
||||
{ "group_PDB", atom.property<std::string>("group_PDB") },
|
||||
{ "id", atom_id },
|
||||
{ "type_symbol", atom.property<std::string>("type_symbol") },
|
||||
{ "label_atom_id", atom.property<std::string>("label_atom_id") },
|
||||
{ "label_alt_id", atom.property<std::string>("label_alt_id") },
|
||||
{ "label_comp_id", comp_id },
|
||||
{ "label_asym_id", asym_id },
|
||||
{ "label_entity_id", entity_id },
|
||||
{ "label_seq_id", "." },
|
||||
{ "pdbx_PDB_ins_code", "" },
|
||||
{ "Cartn_x", atom.property<std::string>("Cartn_x") },
|
||||
{ "Cartn_y", atom.property<std::string>("Cartn_y") },
|
||||
{ "Cartn_z", atom.property<std::string>("Cartn_z") },
|
||||
{ "occupancy", atom.property<std::string>("occupancy") },
|
||||
{ "B_iso_or_equiv", atom.property<std::string>("B_iso_or_equiv") },
|
||||
{ "pdbx_formal_charge", atom.property<std::string>("pdbx_formal_charge") },
|
||||
{ "auth_seq_id", "" },
|
||||
{ "auth_comp_id", comp_id },
|
||||
{ "auth_asym_id", asym_id },
|
||||
{ "auth_atom_id", atom.property<std::string>("label_atom_id") },
|
||||
{ "pdbx_PDB_model_num", 1 }
|
||||
});
|
||||
|
||||
mAtoms.emplace_back(new AtomImpl(db, atom_id, row));
|
||||
}
|
||||
|
||||
mNonPolymers.emplace_back(*this, comp_id, asym_id);
|
||||
|
||||
return asym_id;
|
||||
}
|
||||
|
||||
void Structure::cleanupEmptyCategories()
|
||||
{
|
||||
using namespace cif::literals;
|
||||
@@ -2473,7 +2556,7 @@ void Structure::cleanupEmptyCategories()
|
||||
{
|
||||
// is this correct?
|
||||
std::set<std::string> asym_ids;
|
||||
for (const auto &[asym_id] : db["pdbx_branch_scheme"].find<std::string>("entity_id"_key == id, {"asym_id"}))
|
||||
for (const auto &[ asym_id ] : db["pdbx_branch_scheme"].find<std::string>("entity_id"_key == id, "asym_id"))
|
||||
asym_ids.insert(asym_id);
|
||||
count = asym_ids.size();
|
||||
}
|
||||
@@ -2482,4 +2565,16 @@ void Structure::cleanupEmptyCategories()
|
||||
}
|
||||
}
|
||||
|
||||
void Structure::translate(Point t)
|
||||
{
|
||||
for (auto& a: mAtoms)
|
||||
a.translate(t);
|
||||
}
|
||||
|
||||
void Structure::rotate(Quaternion q)
|
||||
{
|
||||
for (auto& a: mAtoms)
|
||||
a.rotate(q);
|
||||
}
|
||||
|
||||
} // namespace mmcif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const char kRevision[] = R"(
|
||||
libzeep-version: @PROJECT_VERSION@
|
||||
lib@PROJECT_NAME@-version: @PROJECT_VERSION@
|
||||
@BUILD_VERSION_STRING@
|
||||
Date: @BUILD_DATE_TIME@
|
||||
)";
|
||||
|
||||
@@ -15,12 +15,17 @@ int main(int argc, char* argv[])
|
||||
|
||||
try
|
||||
{
|
||||
if (std::filesystem::exists("../data/components.cif"))
|
||||
cif::addFileResource("components.cif", "../data/components.cif");
|
||||
std::filesystem::path testdir = std::filesystem::current_path();
|
||||
|
||||
mmcif::CompoundFactory::instance().pushDictionary("RXA.cif");
|
||||
if (argc == 3)
|
||||
testdir = argv[2];
|
||||
|
||||
mmcif::File f("../examples/1cbs.cif.gz");
|
||||
if (std::filesystem::exists(testdir / ".."/"data"/"components.cif"))
|
||||
cif::addFileResource("components.cif", testdir / ".."/"data"/"components.cif");
|
||||
|
||||
mmcif::CompoundFactory::instance().pushDictionary(testdir / "RXA.cif");
|
||||
|
||||
mmcif::File f(testdir / ".."/"examples"/"1cbs.cif.gz");
|
||||
mmcif::Structure structure(f);
|
||||
|
||||
auto &res = structure.getResidue("B", "REA");
|
||||
|
||||
161
test/structure-test.cpp
Normal file
161
test/structure-test.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#define BOOST_TEST_MODULE Structure_Test
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/Structure.hpp"
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::File operator""_cf(const char* text, size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char* text, size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} buffer(const_cast<char*>(text), length);
|
||||
|
||||
std::istream is(&buffer);
|
||||
return cif::File(is);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_nonpoly_1)
|
||||
{
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
// do this now, avoids the need for installing
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", "../rsrc/mmcif_pdbx_v50.dic");
|
||||
|
||||
mmcif::File file;
|
||||
file.file().loadDictionary("mmcif_pdbx_v50.dic");
|
||||
file.createDatablock("TEST"); // create a datablock
|
||||
|
||||
mmcif::Structure structure(file);
|
||||
|
||||
std::string entity_id = structure.createNonPolyEntity("HEM");
|
||||
|
||||
auto atoms = R"(
|
||||
data_HEM
|
||||
loop_
|
||||
_atom_site.group_PDB
|
||||
_atom_site.type_symbol
|
||||
_atom_site.label_atom_id
|
||||
_atom_site.label_alt_id
|
||||
_atom_site.pdbx_PDB_ins_code
|
||||
_atom_site.Cartn_x
|
||||
_atom_site.Cartn_y
|
||||
_atom_site.Cartn_z
|
||||
_atom_site.occupancy
|
||||
_atom_site.B_iso_or_equiv
|
||||
_atom_site.pdbx_formal_charge
|
||||
HETATM C CHA . ? -5.248 39.769 -0.250 1.00 7.67 ?
|
||||
HETATM C CHB . ? -3.774 36.790 3.280 1.00 7.05 ?
|
||||
HETATM C CHC . ? -2.879 33.328 0.013 1.00 7.69 ?
|
||||
HETATM C CHD . ? -4.342 36.262 -3.536 1.00 8.00 ?
|
||||
# that's enough to test with
|
||||
)"_cf;
|
||||
|
||||
auto &hem_data = atoms["HEM"];
|
||||
auto &atom_site = hem_data["atom_site"];
|
||||
|
||||
auto hem_atoms = atom_site.rows();
|
||||
std::vector<mmcif::Atom> atom_data;
|
||||
for (auto &hem_atom: hem_atoms)
|
||||
atom_data.emplace_back(hem_data, hem_atom);
|
||||
|
||||
structure.createNonpoly(entity_id, atom_data);
|
||||
|
||||
auto expected = R"(
|
||||
data_TEST
|
||||
#
|
||||
loop_
|
||||
_atom_site.id
|
||||
_atom_site.auth_asym_id
|
||||
_atom_site.label_alt_id
|
||||
_atom_site.label_asym_id
|
||||
_atom_site.label_atom_id
|
||||
_atom_site.label_comp_id
|
||||
_atom_site.label_entity_id
|
||||
_atom_site.label_seq_id
|
||||
_atom_site.type_symbol
|
||||
_atom_site.group_PDB
|
||||
_atom_site.pdbx_PDB_ins_code
|
||||
_atom_site.Cartn_x
|
||||
_atom_site.Cartn_y
|
||||
_atom_site.Cartn_z
|
||||
_atom_site.occupancy
|
||||
_atom_site.B_iso_or_equiv
|
||||
_atom_site.pdbx_formal_charge
|
||||
_atom_site.auth_seq_id
|
||||
_atom_site.auth_comp_id
|
||||
_atom_site.auth_atom_id
|
||||
_atom_site.pdbx_PDB_model_num
|
||||
1 A ? A CHA HEM 1 . C HETATM ? -5.248 39.769 -0.250 1.00 7.67 ? ? HEM CHA 1
|
||||
2 A ? A CHB HEM 1 . C HETATM ? -3.774 36.790 3.280 1.00 7.05 ? ? HEM CHB 1
|
||||
3 A ? A CHC HEM 1 . C HETATM ? -2.879 33.328 0.013 1.00 7.69 ? ? HEM CHC 1
|
||||
4 A ? A CHD HEM 1 . C HETATM ? -4.342 36.262 -3.536 1.00 8.00 ? ? HEM CHD 1
|
||||
#
|
||||
_chem_comp.id HEM
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_chem_comp.formula 'C34 H32 Fe N4 O4'
|
||||
_chem_comp.formula_weight 616.487000
|
||||
#
|
||||
_pdbx_entity_nonpoly.entity_id 1
|
||||
_pdbx_entity_nonpoly.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_pdbx_entity_nonpoly.comp_id HEM
|
||||
#
|
||||
_entity.id 1
|
||||
_entity.type non-polymer
|
||||
_entity.pdbx_description 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_entity.formula_weight 616.487000
|
||||
#
|
||||
_struct_asym.id A
|
||||
_struct_asym.entity_id 1
|
||||
_struct_asym.pdbx_blank_PDB_chainid_flag N
|
||||
_struct_asym.pdbx_modified N
|
||||
_struct_asym.details ?
|
||||
#
|
||||
)"_cf;
|
||||
|
||||
expected.loadDictionary("mmcif_pdbx_v50.dic");
|
||||
|
||||
if (not (expected.firstDatablock() == structure.getFile().data()))
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
std::cout << expected.firstDatablock() << std::endl
|
||||
<< std::endl
|
||||
<< structure.getFile().data() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/BondMap.hpp"
|
||||
|
||||
std::filesystem::path gTestDir = std::filesystem::current_path(); // filled in first test
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::File operator""_cf(const char* text, size_t length)
|
||||
@@ -51,12 +53,22 @@ cif::File operator""_cf(const char* text, size_t length)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(init)
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ut1)
|
||||
{
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
// do this now, avoids the need for installing
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", "../rsrc/mmcif_pdbx_v50.dic");
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx_v50.dic");
|
||||
|
||||
// using namespace mmcif;
|
||||
|
||||
@@ -1158,7 +1170,7 @@ _test.name
|
||||
|
||||
// query tests
|
||||
|
||||
for (const auto& [id, name]: db["test"].rows<int, std::optional<std::string>>({ "id", "name" }))
|
||||
for (const auto& [id, name]: db["test"].rows<int, std::optional<std::string>>("id", "name"))
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
@@ -1193,7 +1205,7 @@ _test.name
|
||||
auto& db = f.firstDatablock();
|
||||
|
||||
// query tests
|
||||
for (const auto& [id, name]: db["test"].find<int, std::optional<std::string>>(cif::All(), { "id", "name" }))
|
||||
for (const auto& [id, name]: db["test"].find<int, std::optional<std::string>>(cif::All(), "id", "name"))
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
@@ -1207,7 +1219,7 @@ _test.name
|
||||
}
|
||||
}
|
||||
|
||||
const auto& [id, name] = db["test"].find1<int, std::string>(cif::Key("id") == 1, { "id", "name" });
|
||||
const auto& [id, name] = db["test"].find1<int, std::string>(cif::Key("id") == 1, "id", "name");
|
||||
|
||||
BOOST_CHECK(id == 1);
|
||||
BOOST_CHECK(name == "aap");
|
||||
@@ -1441,7 +1453,7 @@ _cat_3.num
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (const auto &[id, name, num, desc]: cat2.rows<int,std::string,int,std::string>({"id", "name", "num", "desc"}))
|
||||
for (const auto &[id, name, num, desc]: cat2.rows<int,std::string,int,std::string>("id", "name", "num", "desc"))
|
||||
{
|
||||
switch (++i)
|
||||
{
|
||||
@@ -1473,7 +1485,7 @@ _cat_3.num
|
||||
|
||||
BOOST_CHECK(cat1.size() == 4);
|
||||
i = 0;
|
||||
for (const auto &[id, name, desc]: cat1.rows<int,std::string,std::string>({"id", "name", "desc"}))
|
||||
for (const auto &[id, name, desc]: cat1.rows<int,std::string,std::string>("id", "name", "desc"))
|
||||
{
|
||||
switch (++i)
|
||||
{
|
||||
@@ -1515,7 +1527,7 @@ BOOST_AUTO_TEST_CASE(bondmap_1)
|
||||
{
|
||||
cif::VERBOSE = 2;
|
||||
|
||||
cif::addFileResource("components.cif", "../data/components.cif");
|
||||
cif::addFileResource("components.cif", gTestDir / ".." / "data" / "components.cif");
|
||||
|
||||
// sections taken from CCD compounds.cif
|
||||
auto components = R"(
|
||||
@@ -1604,7 +1616,7 @@ PRO CD HD3 SING N N 16
|
||||
PRO OXT HXT SING N N 17
|
||||
)"_cf;
|
||||
|
||||
const std::filesystem::path example("../examples/1cbs.cif.gz");
|
||||
const std::filesystem::path example(gTestDir / ".."/"examples"/"1cbs.cif.gz");
|
||||
mmcif::File file(example.string());
|
||||
mmcif::Structure structure(file);
|
||||
|
||||
@@ -1627,7 +1639,7 @@ PRO OXT HXT SING N N 17
|
||||
|
||||
std::set<std::tuple<std::string,std::string>> bonded;
|
||||
|
||||
for (const auto& [atom_id_1, atom_id_2]: cc->rows<std::string,std::string>({ "atom_id_1", "atom_id_2" }))
|
||||
for (const auto& [atom_id_1, atom_id_2]: cc->rows<std::string,std::string>("atom_id_1", "atom_id_2"))
|
||||
{
|
||||
if (atom_id_1 > atom_id_2)
|
||||
bonded.insert({ atom_id_2, atom_id_1 });
|
||||
@@ -1661,7 +1673,15 @@ BOOST_AUTO_TEST_CASE(bondmap_2)
|
||||
{
|
||||
BOOST_CHECK_THROW(mmcif::BondMap::atomIDsForCompound("UN_"), mmcif::BondMapException);
|
||||
|
||||
mmcif::CompoundFactory::instance().pushDictionary("./UN_.cif");
|
||||
mmcif::CompoundFactory::instance().pushDictionary(gTestDir / "UN_.cif");
|
||||
|
||||
BOOST_CHECK(mmcif::BondMap::atomIDsForCompound("UN_").empty() == false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reading_file_1)
|
||||
{
|
||||
std::istringstream is("Hello, world!");
|
||||
|
||||
cif::File file;
|
||||
BOOST_CHECK_THROW(file.load(is), std::runtime_error);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ if [ "$update" != "true" ] ; then
|
||||
fi
|
||||
|
||||
# if cache directory doesn't exist, exit.
|
||||
if ! [ -d @DATA_CACHE_DIR@ ]; then
|
||||
if ! [ -d @CIFPP_CACHE_DIR@ ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
@@ -43,5 +43,11 @@ fetch_dictionary () {
|
||||
|
||||
# fetch the dictionaries
|
||||
|
||||
fetch_dictionary "@DATA_CACHE_DIR@/mmcif_pdbx_v50.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
|
||||
fetch_dictionary "@DATA_CACHE_DIR@/components.cif" "ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
|
||||
fetch_dictionary "@CIFPP_CACHE_DIR@/mmcif_pdbx_v50.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"
|
||||
|
||||
# notify subscribers
|
||||
|
||||
if [ -d /etc/libcifpp/cache-update.d ] && [ -x /bin/run-parts ]; then
|
||||
run-parts --arg "@CIFPP_CACHE_DIR@" -- /etc/libcifpp/cache-update.d
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user