Compare commits

...

61 Commits

Author SHA1 Message Date
Maarten L. Hekkelman
18088457d3 last updates in develop 2021-09-29 14:21:41 +02:00
Maarten L. Hekkelman
056697d901 imported libname for stdc++fs 2021-09-29 13:24:16 +02:00
Maarten L. Hekkelman
2681cfad50 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-29 13:21:45 +02:00
Maarten L. Hekkelman
8aaa7925a3 fix lib name 2021-09-29 13:21:37 +02:00
Maarten L. Hekkelman
d4f73e471b No need to search zlib/bzip2 in Windows 2021-09-29 11:08:05 +02:00
Maarten L. Hekkelman
750be0c4a4 for 18.04 2021-09-28 15:26:15 +02:00
Maarten L. Hekkelman
0f4a2a26fc dependencies
check compiler version
2021-09-28 14:15:17 +02:00
Maarten L. Hekkelman
6adb56341d remove boost::date_time dependency 2021-09-28 12:48:15 +02:00
Maarten L. Hekkelman
4524357cd3 zlib, again (use the zlib from boost in Windows) 2021-09-28 11:20:02 +02:00
Maarten L. Hekkelman
0b05b6f6e3 run tests in build dir 2021-09-28 10:40:40 +02:00
Maarten L. Hekkelman
6382170157 zlib 2021-09-28 09:39:15 +02:00
Maarten L. Hekkelman
c2eeb69dcc optional static libs boost 2021-09-28 09:38:35 +02:00
Maarten L. Hekkelman
f32261fc59 revert zlib in boost 2021-09-28 09:37:42 +02:00
Maarten L. Hekkelman
90c967c8c6 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-28 09:30:56 +02:00
Maarten L. Hekkelman
4ac90128db zlib in boost 2021-09-28 09:30:43 +02:00
Maarten L. Hekkelman
3d71db1bb7 less stringent test for compiler version 2021-09-28 09:30:22 +02:00
Maarten L. Hekkelman
5e35ea5168 warnings and compiler detection 2021-09-28 09:17:28 +02:00
Maarten L. Hekkelman
2fc88d52eb Updating cmake file to install correct update mechanism 2021-09-28 08:50:28 +02:00
Maarten L. Hekkelman
567b0f3b57 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-28 07:57:05 +02:00
Maarten L. Hekkelman
8f29386998 fix file read test 2021-09-26 14:52:34 +02:00
Maarten L. Hekkelman
d2427d57d9 unit test for reading files 2021-09-27 11:36:24 +02:00
Maarten L. Hekkelman
14a9499962 fix cmake files, pkg-config file 2021-09-27 09:36:33 +02:00
Maarten L. Hekkelman
0fafb80d44 Remove bzip2 support 2021-09-27 08:40:05 +02:00
Maarten L. Hekkelman
b5454f0943 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-26 13:41:21 +02:00
Maarten L. Hekkelman
b698260d73 Merge branch 'trunk' of github.com:PDB-REDO/libcifpp into develop 2021-09-26 13:40:39 +02:00
Maarten L. Hekkelman
ccdd1b74a0 required 2021-09-26 13:39:49 +02:00
Maarten L. Hekkelman
298fe20a1b improve cmake files? 2021-09-25 12:05:42 +02:00
Maarten L. Hekkelman
12a7c45452 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-24 16:02:22 +02:00
Maarten L. Hekkelman
02a28c2fd6 clean up makefile 2021-09-24 16:01:48 +02:00
Maarten L. Hekkelman
68e182b0bd Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-24 15:31:31 +02:00
Maarten L. Hekkelman
b0ec88f469 link compression libs 2021-09-24 15:30:34 +02:00
Maarten L. Hekkelman
4feee6ac22 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-24 15:27:48 +02:00
Maarten L. Hekkelman
ee8a85ec2f static boost libs 2021-09-24 15:27:13 +02:00
Maarten L. Hekkelman
0245d4a881 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-24 15:24:42 +02:00
Maarten L. Hekkelman
e8f0058956 add link of stdc++fs 2021-09-24 15:24:30 +02:00
Maarten L. Hekkelman
9c75dbaae0 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-24 15:22:15 +02:00
Maarten L. Hekkelman
5bd39b598e Add filesystem check, with libstdc++fs test 2021-09-24 15:21:12 +02:00
Maarten L. Hekkelman
25a43abffd update version number, fix revision file 2021-09-24 14:06:47 +02:00
Maarten L. Hekkelman
9a7ca022e2 check for existence of run-parts to be more compatible 2021-09-21 08:56:22 +02:00
Maarten L. Hekkelman
46fe0d7caf fixed cmake file
reduced verbosity for missing atoms
update script, more cross platform
2021-09-21 08:52:48 +02:00
Maarten L. Hekkelman
0371cec415 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2021-09-21 08:40:25 +02:00
Maarten L. Hekkelman
2b1020cbb9 Merge branch 'trunk' into develop 2021-09-21 08:16:57 +02:00
Andrius Merkys
8c3ce2a87d Update OpenStructure compounds.chemlib if OpenStructure is found (#8)
* Update OpenStructure compounds.chemlib if OpenStructure is found.

* Replacing the code to update OpenStructure compounds.chemlib with a call to its internal script.

* Implementing more flexible approach allowing notifying all dependent software.
2021-09-20 12:39:15 +02:00
Maarten L. Hekkelman
d633622e27 Creating new nonpoly compounds 2021-09-20 11:34:07 +02:00
Maarten L. Hekkelman
19b652f615 Merge commit '37f7dd0' into develop 2021-09-15 16:06:43 +02:00
Maarten L. Hekkelman
37f7dd0631 load compound if needed 2021-09-15 16:04:49 +02:00
Maarten L. Hekkelman
4c99710fb3 Refactored iterators (Category, Row)
const versions of find
2021-09-15 11:38:12 +02:00
Maarten L. Hekkelman
59865cdb44 Rotate and Translate of structure data
update unit-test for create_nonpoly
2021-09-14 16:09:08 +02:00
Maarten L. Hekkelman
c3434507da new find1 2021-09-14 11:25:59 +02:00
Maarten L. Hekkelman
79ecf20b85 Sometimes extracting archives does not work in cmake 2021-09-10 09:24:06 +02:00
Maarten L. Hekkelman
1de9681bb7 revert mrc test
extended nonpoly unit-test
2021-09-10 09:22:37 +02:00
Maarten L. Hekkelman
345c4778e6 start structure-test unit test
added compare functions for Datablock and Category
2021-09-08 16:58:50 +02:00
Maarten L. Hekkelman
0ccb2f88ca Added more 3d code (alignpoints) 2021-09-08 11:44:27 +02:00
Maarten L. Hekkelman
f7bef8b0e9 update dictionary
do not throw from Category::isValid()
2021-09-07 14:50:06 +02:00
Maarten L. Hekkelman
9da8608f8f Merge branch 'cmake' into trunk
install update script (optionally, unix only)
2021-09-07 10:12:46 +02:00
Maarten L. Hekkelman
496cb0b909 last minute changes for building inside CCP4 2021-09-07 10:10:38 +02:00
Maarten L. Hekkelman
583cafa91e Merge branch 'cmake' of github.com:PDB-REDO/libcifpp into cmake 2021-09-07 09:23:02 +02:00
Maarten L. Hekkelman
01da665243 test nieuwe CCP4 regels 2021-09-07 09:15:47 +02:00
Maarten L. Hekkelman
e900cd1e3d Windows 2021-09-06 14:58:47 +02:00
Maarten L. Hekkelman
a8a838b33e extract using gzip for cmake < 3.19 (?) 2021-09-02 08:43:12 +02:00
Maarten L. Hekkelman
072be25335 install update script 2021-09-01 16:53:05 +02:00
26 changed files with 6469 additions and 2193 deletions

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@ test/rename-compound-test
tools/update-dictionary-script
data/
CMakeSettings.json
msvc/
Testing/

View File

@@ -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()

View File

@@ -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@")

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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
View 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);

View File

@@ -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);
// --------------------------------------------------------------------

View File

@@ -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();

View File

@@ -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

View File

@@ -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"

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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())

View File

@@ -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))
{

View File

@@ -29,7 +29,6 @@
#include <map>
#include <set>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

View File

@@ -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);

View File

@@ -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

View File

@@ -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@
)";

View File

@@ -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
View 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;
}
}

View File

@@ -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);
}

View File

@@ -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