mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-07 07:44:22 +08:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ba9f688c7 | ||
|
|
883f0307a2 | ||
|
|
c9719f873f | ||
|
|
123d25f853 | ||
|
|
56da42db84 | ||
|
|
7f820449ca | ||
|
|
ecb2cf5f11 | ||
|
|
7f27da9b3b | ||
|
|
01eb499c69 | ||
|
|
1ff6f70682 | ||
|
|
ddde996e10 | ||
|
|
1c9212c7e0 | ||
|
|
a568143991 | ||
|
|
2b6f1bd9ee | ||
|
|
2527aa5ea6 | ||
|
|
4c28091ecd | ||
|
|
d49725423e | ||
|
|
fcb4dc61b5 | ||
|
|
b7330c074f | ||
|
|
e8f4123030 | ||
|
|
975057c4c4 | ||
|
|
a0e01668d1 | ||
|
|
2c77491416 | ||
|
|
be19e4a9cb | ||
|
|
61ce91a9d7 | ||
|
|
18f1d07e85 | ||
|
|
b596976194 | ||
|
|
1f6b86d516 | ||
|
|
31499b977d | ||
|
|
f83850e380 | ||
|
|
1a4ccd86fe | ||
|
|
5c3c6fec09 | ||
|
|
f97e742daa | ||
|
|
7f39d401e2 | ||
|
|
af412c284d | ||
|
|
874cd3bae5 | ||
|
|
ea28ebdd13 | ||
|
|
3ba468933f | ||
|
|
45f33e4bea | ||
|
|
021487ed16 | ||
|
|
cb3443ffb1 | ||
|
|
6b2c9dc3e3 | ||
|
|
7513cc1947 | ||
|
|
c98b8ae5c9 | ||
|
|
ab2dd4b75f | ||
|
|
be77316545 | ||
|
|
cdfb0d9497 | ||
|
|
71f7e7c741 | ||
|
|
cff099596e | ||
|
|
e182604455 | ||
|
|
45a7defb7e | ||
|
|
906f6ac1ea | ||
|
|
8d96e513bd | ||
|
|
cdefd063e2 | ||
|
|
8bbcba76cf |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -6,8 +6,8 @@ tools/symop-map-generator
|
||||
test/unit-test
|
||||
test/pdb2cif-test
|
||||
test/rename-compound-test
|
||||
tools/update-dictionary-script
|
||||
data/
|
||||
tools/update-libcifpp-data
|
||||
data/components.cif*
|
||||
CMakeSettings.json
|
||||
msvc/
|
||||
Testing/
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# set the project name
|
||||
project(cifpp VERSION 2.0.1 LANGUAGES CXX)
|
||||
project(cifpp VERSION 3.0.1 LANGUAGES CXX)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -87,14 +87,14 @@ endif()
|
||||
|
||||
# When CCP4 is sourced in the environment, we can recreate the symmetry operations table
|
||||
if(EXISTS "${CCP4}")
|
||||
if(RECREATE_SYMOP_DATA AND NOT EXISTS "${CLIBD}/syminfo.lib")
|
||||
if(CIFPP_RECREATE_SYMOP_DATA AND NOT EXISTS "${CLIBD}/syminfo.lib")
|
||||
message(WARNING "Symop data table recreation requested, but file syminfo.lib was not found in ${CLIBD}")
|
||||
set(RECREATE_SYMOP_DATA OFF)
|
||||
set(CIFPP_RECREATE_SYMOP_DATA OFF)
|
||||
else()
|
||||
option(RECREATE_SYMOP_DATA "Recreate SymOp data table in case it is out of date" ON)
|
||||
option(CIFPP_RECREATE_SYMOP_DATA "Recreate SymOp data table in case it is out of date" ON)
|
||||
endif()
|
||||
else()
|
||||
set(RECREATE_SYMOP_DATA OFF)
|
||||
set(CIFPP_RECREATE_SYMOP_DATA OFF)
|
||||
message("Not trying to recreate SymOpTable_data.hpp since CCP4 is not defined")
|
||||
endif()
|
||||
|
||||
@@ -154,16 +154,16 @@ else()
|
||||
find_program(MRC mrc)
|
||||
|
||||
if(MRC)
|
||||
option(USE_RSRC "Use mrc to create resources" ON)
|
||||
option(CIFPP_USE_RSRC "Use mrc to create resources" ON)
|
||||
else()
|
||||
message("Using resources not possible since mrc was not found")
|
||||
endif()
|
||||
|
||||
if(USE_RSRC STREQUAL "ON")
|
||||
set(USE_RSRC 1)
|
||||
if(CIFPP_USE_RSRC STREQUAL "ON")
|
||||
set(CIFPP_USE_RSRC 1)
|
||||
|
||||
message("Using resources compiled with ${MRC}")
|
||||
add_compile_definitions(USE_RSRC)
|
||||
add_compile_definitions(CIFPP_USE_RSRC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -173,10 +173,6 @@ set(CMAKE_THREAD_PREFER_PTHREAD)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG)
|
||||
find_package(Threads)
|
||||
|
||||
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)
|
||||
|
||||
if(NOT MSVC AND Boost_USE_STATIC_LIBS)
|
||||
@@ -186,16 +182,14 @@ endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
|
||||
find_package(Git)
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
include(GetGitRevisionDescription)
|
||||
include(GetGitRevisionDescription)
|
||||
option(GENERATE_CUSTOM_VERSION "Generate a custom version string" OFF)
|
||||
if(GIT-NOTFOUND OR HEAD-HASH-NOTFOUND OR NOT GENERATE_CUSTOM_VERSION)
|
||||
get_git_head_revision(REFSPEC COMMITHASH)
|
||||
|
||||
# Generate our own version string
|
||||
git_describe_working_tree(BUILD_VERSION_STRING --match=build --dirty)
|
||||
else()
|
||||
message(WARNING "Git not found, cannot set version info")
|
||||
|
||||
SET(BUILD_VERSION_STRING ${PROJECT_VERSION})
|
||||
endif()
|
||||
|
||||
@@ -204,7 +198,7 @@ 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)
|
||||
|
||||
# SymOp data table
|
||||
if(RECREATE_SYMOP_DATA)
|
||||
if(CIFPP_RECREATE_SYMOP_DATA)
|
||||
# The tool to create the table
|
||||
|
||||
add_executable(symop-map-generator "${CMAKE_SOURCE_DIR}/tools/symop-map-generator.cpp")
|
||||
@@ -256,7 +250,6 @@ 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
|
||||
@@ -287,16 +280,17 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
endif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${PROJECT_SOURCE_DIR}/data/components.cif)
|
||||
option(CIFPP_DOWNLOAD_CCD "Download the CCD file components.cif during installation" OFF)
|
||||
if(CIFPP_DOWNLOAD_CCD)
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${PROJECT_SOURCE_DIR}/data/components.cif)
|
||||
|
||||
if (NOT EXISTS ${COMPONENTS_CIF})
|
||||
if (NOT EXISTS ${COMPONENTS_CIF})
|
||||
|
||||
if (NOT EXISTS ${PROJECT_SOURCE_DIR}/data)
|
||||
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_SOURCE_DIR}/data)
|
||||
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
|
||||
endif()
|
||||
|
||||
# if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
|
||||
find_program(GUNZIP gunzip)
|
||||
|
||||
if(GUNZIP)
|
||||
@@ -309,25 +303,15 @@ 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()
|
||||
endif()
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
endif()
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
|
||||
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()
|
||||
option(CIFPP_INSTALL_UPDATE_SCRIPT "Install the script to update CCD and dictionary files" OFF)
|
||||
set(CIFPP_CACHE_DIR "/var/cache/libcifpp" CACHE STRING "The cache directory to use")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
endif()
|
||||
|
||||
generate_export_header(cifpp
|
||||
@@ -337,7 +321,9 @@ set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} )
|
||||
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} )
|
||||
set(SHARE_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}")
|
||||
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING "The directory containing the provided data files")
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
|
||||
# Install rules
|
||||
|
||||
@@ -369,7 +355,7 @@ install(
|
||||
install(FILES
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx_v50.dic
|
||||
${PROJECT_SOURCE_DIR}/data/components.cif
|
||||
${COMPONENTS_CIF}
|
||||
DESTINATION ${SHARE_INSTALL_DIR}
|
||||
)
|
||||
|
||||
@@ -421,7 +407,7 @@ option(CIFPP_BUILD_TESTS "Build test exectuables" OFF)
|
||||
|
||||
if(CIFPP_BUILD_TESTS)
|
||||
|
||||
if(USE_RSRC)
|
||||
if(CIFPP_USE_RSRC)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cifpp_test_rsrc.obj
|
||||
COMMAND ${MRC} -o ${CMAKE_CURRENT_BINARY_DIR}/cifpp_test_rsrc.obj ${CMAKE_SOURCE_DIR}/rsrc/mmcif_pdbx_v50.dic ${COFF_SPEC}
|
||||
)
|
||||
@@ -456,10 +442,10 @@ if(CIFPP_BUILD_TESTS)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${PROJECT_SOURCE_DIR}/test)
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_SOURCE_DIR}/test)
|
||||
|
||||
add_test(NAME ${CIFPP_TEST}
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${PROJECT_SOURCE_DIR}/test)
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_SOURCE_DIR}/test)
|
||||
|
||||
endforeach()
|
||||
endif()
|
||||
@@ -468,12 +454,12 @@ message("Will install in ${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
# Optionally install the update scripts for CCD and dictionary files
|
||||
|
||||
if(INSTALL_UPDATE_SCRIPT)
|
||||
if(CIFPP_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)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/tools/update-libcifpp-data.in update-libcifpp-data @ONLY)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-dictionary-script
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CIFPP_CRON_DIR}
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
|
||||
)
|
||||
@@ -482,13 +468,14 @@ if(INSTALL_UPDATE_SCRIPT)
|
||||
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
|
||||
if(NOT EXISTS "$ENV{DESTDIR}/etc/libcifpp.conf")
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf [[# Uncomment the next line to enable automatic updates
|
||||
# update=true
|
||||
]])
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf DESTINATION "$ENV{DESTDIR}/etc")
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf DESTINATION "$ENV{DESTDIR}/etc")
|
||||
install(CODE "message(\"A configuration file has been written to $ENV{DESTDIR}/etc/libcifpp.conf, please edit this file to enable automatic updates\")")
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
|
||||
20
changelog
20
changelog
@@ -1,3 +1,23 @@
|
||||
Version 3.0.0
|
||||
- Replaced many strings in the API with string_view for
|
||||
performance reasons.
|
||||
- Upgraded mmcif::Structure
|
||||
- various other small fixes
|
||||
|
||||
Version 2.0.4
|
||||
- Reverted a too strict test when reading cif files.
|
||||
|
||||
Version 2.0.3
|
||||
- Fixed reading mmCIF files where model numbers are used and
|
||||
model number 1 is missing.
|
||||
|
||||
Version 2.0.2
|
||||
- Added configuration flag to disable downloading CCD data during build
|
||||
Note that there are now two flags for CCD data:
|
||||
DOWNLOAD_CCD to enable downloading during build
|
||||
INSTALL_UPDATE_SCRIPT to install an update mechanism for this file
|
||||
- Updated unit tests to work even if no CCD data is available
|
||||
|
||||
Version 2.0.1
|
||||
- Fixed the generator for the symmetry operator table
|
||||
|
||||
|
||||
2396
data/ccd-subset.cif
Normal file
2396
data/ccd-subset.cif
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,9 +22,7 @@ int main()
|
||||
<< "residues with an OXT are:" << std::endl;
|
||||
|
||||
for (const auto& [asym, comp, seqnr]: db.find<std::string,std::string,int>(
|
||||
cif::Key("label_atom_id") == "OXT",
|
||||
{ "label_asym_id", "label_comp_id", "label_seq_id" }
|
||||
))
|
||||
cif::Key("label_atom_id") == "OXT", "label_asym_id", "label_comp_id", "label_seq_id"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
|
||||
}
|
||||
|
||||
1573
examples/pdb1cbs.ent
1573
examples/pdb1cbs.ent
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -29,150 +29,151 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
enum AtomType : uint8_t
|
||||
{
|
||||
Nn = 0, // Unknown
|
||||
|
||||
H = 1, // Hydrogen
|
||||
He = 2, // Helium
|
||||
Nn = 0, // Unknown
|
||||
|
||||
Li = 3, // Lithium
|
||||
Be = 4, // Beryllium
|
||||
B = 5, // Boron
|
||||
C = 6, // Carbon
|
||||
N = 7, // Nitrogen
|
||||
O = 8, // Oxygen
|
||||
F = 9, // Fluorine
|
||||
Ne = 10, // Neon
|
||||
H = 1, // Hydrogen
|
||||
He = 2, // Helium
|
||||
|
||||
Na = 11, // Sodium
|
||||
Mg = 12, // Magnesium
|
||||
Al = 13, // Aluminium
|
||||
Si = 14, // Silicon
|
||||
P = 15, // Phosphorus
|
||||
S = 16, // Sulfur
|
||||
Cl = 17, // Chlorine
|
||||
Ar = 18, // Argon
|
||||
Li = 3, // Lithium
|
||||
Be = 4, // Beryllium
|
||||
B = 5, // Boron
|
||||
C = 6, // Carbon
|
||||
N = 7, // Nitrogen
|
||||
O = 8, // Oxygen
|
||||
F = 9, // Fluorine
|
||||
Ne = 10, // Neon
|
||||
|
||||
K = 19, // Potassium
|
||||
Ca = 20, // Calcium
|
||||
Sc = 21, // Scandium
|
||||
Ti = 22, // Titanium
|
||||
V = 23, // Vanadium
|
||||
Cr = 24, // Chromium
|
||||
Mn = 25, // Manganese
|
||||
Fe = 26, // Iron
|
||||
Co = 27, // Cobalt
|
||||
Ni = 28, // Nickel
|
||||
Cu = 29, // Copper
|
||||
Zn = 30, // Zinc
|
||||
Ga = 31, // Gallium
|
||||
Ge = 32, // Germanium
|
||||
As = 33, // Arsenic
|
||||
Se = 34, // Selenium
|
||||
Br = 35, // Bromine
|
||||
Kr = 36, // Krypton
|
||||
Na = 11, // Sodium
|
||||
Mg = 12, // Magnesium
|
||||
Al = 13, // Aluminium
|
||||
Si = 14, // Silicon
|
||||
P = 15, // Phosphorus
|
||||
S = 16, // Sulfur
|
||||
Cl = 17, // Chlorine
|
||||
Ar = 18, // Argon
|
||||
|
||||
Rb = 37, // Rubidium
|
||||
Sr = 38, // Strontium
|
||||
Y = 39, // Yttrium
|
||||
Zr = 40, // Zirconium
|
||||
Nb = 41, // Niobium
|
||||
Mo = 42, // Molybdenum
|
||||
Tc = 43, // Technetium
|
||||
Ru = 44, // Ruthenium
|
||||
Rh = 45, // Rhodium
|
||||
Pd = 46, // Palladium
|
||||
Ag = 47, // Silver
|
||||
Cd = 48, // Cadmium
|
||||
In = 49, // Indium
|
||||
Sn = 50, // Tin
|
||||
Sb = 51, // Antimony
|
||||
Te = 52, // Tellurium
|
||||
I = 53, // Iodine
|
||||
Xe = 54, // Xenon
|
||||
Cs = 55, // Caesium
|
||||
Ba = 56, // Barium
|
||||
La = 57, // Lanthanum
|
||||
K = 19, // Potassium
|
||||
Ca = 20, // Calcium
|
||||
Sc = 21, // Scandium
|
||||
Ti = 22, // Titanium
|
||||
V = 23, // Vanadium
|
||||
Cr = 24, // Chromium
|
||||
Mn = 25, // Manganese
|
||||
Fe = 26, // Iron
|
||||
Co = 27, // Cobalt
|
||||
Ni = 28, // Nickel
|
||||
Cu = 29, // Copper
|
||||
Zn = 30, // Zinc
|
||||
Ga = 31, // Gallium
|
||||
Ge = 32, // Germanium
|
||||
As = 33, // Arsenic
|
||||
Se = 34, // Selenium
|
||||
Br = 35, // Bromine
|
||||
Kr = 36, // Krypton
|
||||
|
||||
Hf = 72, // Hafnium
|
||||
Ta = 73, // Tantalum
|
||||
W = 74, // Tungsten
|
||||
Re = 75, // Rhenium
|
||||
Os = 76, // Osmium
|
||||
Ir = 77, // Iridium
|
||||
Pt = 78, // Platinum
|
||||
Au = 79, // Gold
|
||||
Hg = 80, // Mercury
|
||||
Tl = 81, // Thallium
|
||||
Pb = 82, // Lead
|
||||
Bi = 83, // Bismuth
|
||||
Po = 84, // Polonium
|
||||
At = 85, // Astatine
|
||||
Rn = 86, // Radon
|
||||
Fr = 87, // Francium
|
||||
Ra = 88, // Radium
|
||||
Ac = 89, // Actinium
|
||||
Rb = 37, // Rubidium
|
||||
Sr = 38, // Strontium
|
||||
Y = 39, // Yttrium
|
||||
Zr = 40, // Zirconium
|
||||
Nb = 41, // Niobium
|
||||
Mo = 42, // Molybdenum
|
||||
Tc = 43, // Technetium
|
||||
Ru = 44, // Ruthenium
|
||||
Rh = 45, // Rhodium
|
||||
Pd = 46, // Palladium
|
||||
Ag = 47, // Silver
|
||||
Cd = 48, // Cadmium
|
||||
In = 49, // Indium
|
||||
Sn = 50, // Tin
|
||||
Sb = 51, // Antimony
|
||||
Te = 52, // Tellurium
|
||||
I = 53, // Iodine
|
||||
Xe = 54, // Xenon
|
||||
Cs = 55, // Caesium
|
||||
Ba = 56, // Barium
|
||||
La = 57, // Lanthanum
|
||||
|
||||
Rf = 104, // Rutherfordium
|
||||
Db = 105, // Dubnium
|
||||
Sg = 106, // Seaborgium
|
||||
Bh = 107, // Bohrium
|
||||
Hs = 108, // Hassium
|
||||
Mt = 109, // Meitnerium
|
||||
Ds = 110, // Darmstadtium
|
||||
Rg = 111, // Roentgenium
|
||||
Cn = 112, // Copernicium
|
||||
Nh = 113, // Nihonium
|
||||
Fl = 114, // Flerovium
|
||||
Mc = 115, // Moscovium
|
||||
Lv = 116, // Livermorium
|
||||
Ts = 117, // Tennessine
|
||||
Og = 118, // Oganesson
|
||||
Hf = 72, // Hafnium
|
||||
Ta = 73, // Tantalum
|
||||
W = 74, // Tungsten
|
||||
Re = 75, // Rhenium
|
||||
Os = 76, // Osmium
|
||||
Ir = 77, // Iridium
|
||||
Pt = 78, // Platinum
|
||||
Au = 79, // Gold
|
||||
Hg = 80, // Mercury
|
||||
Tl = 81, // Thallium
|
||||
Pb = 82, // Lead
|
||||
Bi = 83, // Bismuth
|
||||
Po = 84, // Polonium
|
||||
At = 85, // Astatine
|
||||
Rn = 86, // Radon
|
||||
Fr = 87, // Francium
|
||||
Ra = 88, // Radium
|
||||
Ac = 89, // Actinium
|
||||
|
||||
Ce = 58, // Cerium
|
||||
Pr = 59, // Praseodymium
|
||||
Nd = 60, // Neodymium
|
||||
Pm = 61, // Promethium
|
||||
Sm = 62, // Samarium
|
||||
Eu = 63, // Europium
|
||||
Gd = 64, // Gadolinium
|
||||
Tb = 65, // Terbium
|
||||
Dy = 66, // Dysprosium
|
||||
Ho = 67, // Holmium
|
||||
Er = 68, // Erbium
|
||||
Tm = 69, // Thulium
|
||||
Yb = 70, // Ytterbium
|
||||
Lu = 71, // Lutetium
|
||||
Rf = 104, // Rutherfordium
|
||||
Db = 105, // Dubnium
|
||||
Sg = 106, // Seaborgium
|
||||
Bh = 107, // Bohrium
|
||||
Hs = 108, // Hassium
|
||||
Mt = 109, // Meitnerium
|
||||
Ds = 110, // Darmstadtium
|
||||
Rg = 111, // Roentgenium
|
||||
Cn = 112, // Copernicium
|
||||
Nh = 113, // Nihonium
|
||||
Fl = 114, // Flerovium
|
||||
Mc = 115, // Moscovium
|
||||
Lv = 116, // Livermorium
|
||||
Ts = 117, // Tennessine
|
||||
Og = 118, // Oganesson
|
||||
|
||||
Th = 90, // Thorium
|
||||
Pa = 91, // Protactinium
|
||||
U = 92, // Uranium
|
||||
Np = 93, // Neptunium
|
||||
Pu = 94, // Plutonium
|
||||
Am = 95, // Americium
|
||||
Cm = 96, // Curium
|
||||
Bk = 97, // Berkelium
|
||||
Cf = 98, // Californium
|
||||
Es = 99, // Einsteinium
|
||||
Fm = 100, // Fermium
|
||||
Md = 101, // Mendelevium
|
||||
No = 102, // Nobelium
|
||||
Lr = 103, // Lawrencium
|
||||
Ce = 58, // Cerium
|
||||
Pr = 59, // Praseodymium
|
||||
Nd = 60, // Neodymium
|
||||
Pm = 61, // Promethium
|
||||
Sm = 62, // Samarium
|
||||
Eu = 63, // Europium
|
||||
Gd = 64, // Gadolinium
|
||||
Tb = 65, // Terbium
|
||||
Dy = 66, // Dysprosium
|
||||
Ho = 67, // Holmium
|
||||
Er = 68, // Erbium
|
||||
Tm = 69, // Thulium
|
||||
Yb = 70, // Ytterbium
|
||||
Lu = 71, // Lutetium
|
||||
|
||||
D = 129, // Deuterium
|
||||
Th = 90, // Thorium
|
||||
Pa = 91, // Protactinium
|
||||
U = 92, // Uranium
|
||||
Np = 93, // Neptunium
|
||||
Pu = 94, // Plutonium
|
||||
Am = 95, // Americium
|
||||
Cm = 96, // Curium
|
||||
Bk = 97, // Berkelium
|
||||
Cf = 98, // Californium
|
||||
Es = 99, // Einsteinium
|
||||
Fm = 100, // Fermium
|
||||
Md = 101, // Mendelevium
|
||||
No = 102, // Nobelium
|
||||
Lr = 103, // Lawrencium
|
||||
|
||||
D = 129, // Deuterium
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// AtomTypeInfo
|
||||
|
||||
enum RadiusType {
|
||||
enum RadiusType
|
||||
{
|
||||
eRadiusCalculated,
|
||||
eRadiusEmpirical,
|
||||
eRadiusCovalentEmpirical,
|
||||
@@ -188,12 +189,12 @@ enum RadiusType {
|
||||
|
||||
struct AtomTypeInfo
|
||||
{
|
||||
AtomType type;
|
||||
std::string name;
|
||||
std::string symbol;
|
||||
float weight;
|
||||
bool metal;
|
||||
float radii[eRadiusTypeCount];
|
||||
AtomType type;
|
||||
std::string name;
|
||||
std::string symbol;
|
||||
float weight;
|
||||
bool metal;
|
||||
float radii[eRadiusTypeCount];
|
||||
};
|
||||
|
||||
extern const AtomTypeInfo kKnownAtoms[];
|
||||
@@ -205,25 +206,25 @@ class AtomTypeTraits
|
||||
{
|
||||
public:
|
||||
AtomTypeTraits(AtomType a);
|
||||
AtomTypeTraits(const std::string& symbol);
|
||||
|
||||
AtomType type() const { return mInfo->type; }
|
||||
std::string name() const { return mInfo->name; }
|
||||
std::string symbol() const { return mInfo->symbol; }
|
||||
float weight() const { return mInfo->weight; }
|
||||
|
||||
bool isMetal() const { return mInfo->metal; }
|
||||
|
||||
static bool isElement(const std::string& symbol);
|
||||
static bool isMetal(const std::string& symbol);
|
||||
|
||||
AtomTypeTraits(const std::string &symbol);
|
||||
|
||||
AtomType type() const { return mInfo->type; }
|
||||
std::string name() const { return mInfo->name; }
|
||||
std::string symbol() const { return mInfo->symbol; }
|
||||
float weight() const { return mInfo->weight; }
|
||||
|
||||
bool isMetal() const { return mInfo->metal; }
|
||||
|
||||
static bool isElement(const std::string &symbol);
|
||||
static bool isMetal(const std::string &symbol);
|
||||
|
||||
float radius(RadiusType type = eRadiusSingleBond) const
|
||||
{
|
||||
if (type >= eRadiusTypeCount)
|
||||
throw std::invalid_argument("invalid radius requested");
|
||||
return mInfo->radii[type] / 100.f;
|
||||
}
|
||||
|
||||
|
||||
// data type encapsulating the Waasmaier & Kirfel scattering factors
|
||||
// in a simplified form (only a and b).
|
||||
// Added the electrion scattering factors as well
|
||||
@@ -231,15 +232,18 @@ class AtomTypeTraits
|
||||
{
|
||||
double a[6], b[6];
|
||||
};
|
||||
|
||||
|
||||
// to get the Cval and Siva values, use this constant as charge:
|
||||
enum { kWKSFVal = -99 };
|
||||
|
||||
const SFData& wksf(int charge = 0) const;
|
||||
const SFData& elsf() const;
|
||||
enum
|
||||
{
|
||||
kWKSFVal = -99
|
||||
};
|
||||
|
||||
const SFData &wksf(int charge = 0) const;
|
||||
const SFData &elsf() const;
|
||||
|
||||
private:
|
||||
const struct AtomTypeInfo* mInfo;
|
||||
const struct AtomTypeInfo *mInfo;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mmcif
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cif++/Structure.hpp"
|
||||
|
||||
@@ -38,39 +38,40 @@ namespace mmcif
|
||||
class BondMapException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
BondMapException(const std::string& msg)
|
||||
: runtime_error(msg) {}
|
||||
BondMapException(const std::string &msg)
|
||||
: runtime_error(msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class BondMap
|
||||
{
|
||||
public:
|
||||
BondMap(const Structure& p);
|
||||
|
||||
BondMap(const BondMap&) = delete;
|
||||
BondMap& operator=(const BondMap&) = delete;
|
||||
BondMap(const Structure &p);
|
||||
|
||||
bool operator()(const Atom& a, const Atom& b) const
|
||||
BondMap(const BondMap &) = delete;
|
||||
BondMap &operator=(const BondMap &) = delete;
|
||||
|
||||
bool operator()(const Atom &a, const Atom &b) const
|
||||
{
|
||||
return isBonded(index.at(a.id()), index.at(b.id()));
|
||||
}
|
||||
|
||||
bool is1_4(const Atom& a, const Atom& b) const
|
||||
bool is1_4(const Atom &a, const Atom &b) const
|
||||
{
|
||||
uint32_t ixa = index.at(a.id());
|
||||
uint32_t ixb = index.at(b.id());
|
||||
|
||||
|
||||
return bond_1_4.count(key(ixa, ixb));
|
||||
}
|
||||
|
||||
|
||||
// links coming from the struct_conn records:
|
||||
std::vector<std::string> linked(const Atom& a) const;
|
||||
std::vector<std::string> linked(const Atom &a) const;
|
||||
|
||||
// This list of atomID's is comming from either CCD or the CCP4 dictionaries loaded
|
||||
static std::vector<std::string> atomIDsForCompound(const std::string& compoundID);
|
||||
|
||||
private:
|
||||
static std::vector<std::string> atomIDsForCompound(const std::string &compoundID);
|
||||
|
||||
private:
|
||||
bool isBonded(uint32_t ai, uint32_t bi) const
|
||||
{
|
||||
return bond.count(key(ai, bi)) != 0;
|
||||
@@ -82,20 +83,19 @@ class BondMap
|
||||
std::swap(a, b);
|
||||
return static_cast<uint64_t>(a) | (static_cast<uint64_t>(b) << 32);
|
||||
}
|
||||
|
||||
std::tuple<uint32_t,uint32_t> dekey(uint64_t k) const
|
||||
|
||||
std::tuple<uint32_t, uint32_t> dekey(uint64_t k) const
|
||||
{
|
||||
return std::make_tuple(
|
||||
static_cast<uint32_t>(k >> 32),
|
||||
static_cast<uint32_t>(k)
|
||||
);
|
||||
static_cast<uint32_t>(k));
|
||||
}
|
||||
|
||||
|
||||
uint32_t dim;
|
||||
std::unordered_map<std::string,uint32_t> index;
|
||||
std::unordered_map<std::string, uint32_t> index;
|
||||
std::set<uint64_t> bond, bond_1_4;
|
||||
|
||||
std::map<std::string,std::set<std::string>> link;
|
||||
std::map<std::string, std::set<std::string>> link;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mmcif
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "cif++/CifUtils.hpp"
|
||||
|
||||
@@ -141,14 +145,27 @@ class Item
|
||||
public:
|
||||
Item() {}
|
||||
|
||||
Item(std::string_view name, char value)
|
||||
: mName(name)
|
||||
, mValue({ value })
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
Item(std::string_view name, const T& value, const char *fmt)
|
||||
: mName(name)
|
||||
, mValue((boost::format(fmt) % value).str())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
Item(const std::string &name, const T &value)
|
||||
Item(const std::string_view name, const T &value)
|
||||
: mName(name)
|
||||
, mValue(std::to_string(value))
|
||||
{
|
||||
}
|
||||
|
||||
Item(const std::string &name, const std::string &value)
|
||||
Item(const std::string_view name, const std::string_view value)
|
||||
: mName(name)
|
||||
, mValue(value)
|
||||
{
|
||||
@@ -221,7 +238,7 @@ class Datablock
|
||||
using iterator = CategoryList::iterator;
|
||||
using const_iterator = CategoryList::const_iterator;
|
||||
|
||||
Datablock(const std::string &name);
|
||||
Datablock(const std::string_view name);
|
||||
~Datablock();
|
||||
|
||||
Datablock(const Datablock &) = delete;
|
||||
@@ -230,33 +247,31 @@ class Datablock
|
||||
std::string getName() const { return mName; }
|
||||
void setName(const std::string &n) { mName = n; }
|
||||
|
||||
std::string firstItem(const std::string &tag) const;
|
||||
|
||||
iterator begin() { return mCategories.begin(); }
|
||||
iterator end() { return mCategories.end(); }
|
||||
|
||||
const_iterator begin() const { return mCategories.begin(); }
|
||||
const_iterator end() const { return mCategories.end(); }
|
||||
|
||||
Category &operator[](const std::string &name);
|
||||
Category &operator[](std::string_view name);
|
||||
|
||||
std::tuple<iterator, bool> emplace(const std::string &name);
|
||||
std::tuple<iterator, bool> emplace(std::string_view name);
|
||||
|
||||
bool isValid();
|
||||
void validateLinks() const;
|
||||
|
||||
void setValidator(Validator *v);
|
||||
void setValidator(const Validator *v);
|
||||
|
||||
// this one only looks up a Category, returns nullptr if it does not exist
|
||||
const Category *get(const std::string &name) const;
|
||||
Category *get(const std::string &name);
|
||||
const Category *get(std::string_view name) const;
|
||||
Category *get(std::string_view name);
|
||||
|
||||
void getTagOrder(std::vector<std::string> &tags) const;
|
||||
void write(std::ostream &os, const std::vector<std::string> &order);
|
||||
void write(std::ostream &os);
|
||||
|
||||
// convenience function, add a line to the software category
|
||||
void add_software(const std::string &name, const std::string &classification,
|
||||
void add_software(const std::string_view name, const std::string &classification,
|
||||
const std::string &versionNr, const std::string &versionDate);
|
||||
|
||||
friend bool operator==(const Datablock &lhs, const Datablock &rhs);
|
||||
@@ -264,9 +279,10 @@ class Datablock
|
||||
friend std::ostream& operator<<(std::ostream &os, const Datablock &data);
|
||||
|
||||
private:
|
||||
std::list<Category> mCategories;
|
||||
CategoryList mCategories; // LRU
|
||||
mutable std::shared_mutex mLock;
|
||||
std::string mName;
|
||||
Validator *mValidator;
|
||||
const Validator *mValidator;
|
||||
Datablock *mNext;
|
||||
};
|
||||
|
||||
@@ -350,14 +366,14 @@ namespace detail
|
||||
private:
|
||||
friend class ::cif::Row;
|
||||
|
||||
ItemReference(const char *name, size_t column, Row &row)
|
||||
ItemReference(std::string_view name, size_t column, Row &row)
|
||||
: mName(name)
|
||||
, mColumn(column)
|
||||
, mRow(row)
|
||||
{
|
||||
}
|
||||
|
||||
ItemReference(const char *name, size_t column, const Row &row)
|
||||
ItemReference(std::string_view name, size_t column, const Row &row)
|
||||
: mName(name)
|
||||
, mColumn(column)
|
||||
, mRow(const_cast<Row &>(row))
|
||||
@@ -365,7 +381,7 @@ namespace detail
|
||||
{
|
||||
}
|
||||
|
||||
const char *mName;
|
||||
std::string_view mName;
|
||||
size_t mColumn;
|
||||
Row &mRow;
|
||||
bool mConst = false;
|
||||
@@ -746,16 +762,16 @@ class Row
|
||||
return detail::ItemReference(itemTag, column, *this);
|
||||
}
|
||||
|
||||
const detail::ItemReference operator[](const std::string &itemTag) const
|
||||
const detail::ItemReference operator[](std::string_view itemTag) const
|
||||
{
|
||||
size_t column = ColumnForItemTag(itemTag.c_str());
|
||||
return detail::ItemReference(itemTag.c_str(), column, *this);
|
||||
size_t column = ColumnForItemTag(itemTag);
|
||||
return detail::ItemReference(itemTag, column, *this);
|
||||
}
|
||||
|
||||
detail::ItemReference operator[](const std::string &itemTag)
|
||||
detail::ItemReference operator[](std::string_view itemTag)
|
||||
{
|
||||
size_t column = ColumnForItemTag(itemTag.c_str());
|
||||
return detail::ItemReference(itemTag.c_str(), column, *this);
|
||||
size_t column = ColumnForItemTag(itemTag);
|
||||
return detail::ItemReference(itemTag, column, *this);
|
||||
}
|
||||
|
||||
template <typename... Ts, size_t N>
|
||||
@@ -776,7 +792,7 @@ class Row
|
||||
}
|
||||
|
||||
void assign(const std::vector<Item> &values);
|
||||
void assign(const std::string &name, const std::string &value, bool updateLinked);
|
||||
void assign(std::string_view name, const std::string &value, bool updateLinked);
|
||||
|
||||
bool operator==(const Row &rhs) const
|
||||
{
|
||||
@@ -803,7 +819,7 @@ class Row
|
||||
|
||||
static void swap(size_t column, ItemRow *a, ItemRow *b);
|
||||
|
||||
size_t ColumnForItemTag(const char *itemTag) const;
|
||||
size_t ColumnForItemTag(std::string_view itemTag) const;
|
||||
|
||||
mutable ItemRow *mData;
|
||||
uint32_t mLineNr = 0;
|
||||
@@ -1169,11 +1185,11 @@ struct Empty
|
||||
|
||||
struct Key
|
||||
{
|
||||
Key(const std::string &itemTag)
|
||||
explicit Key(const std::string &itemTag)
|
||||
: mItemTag(itemTag)
|
||||
{
|
||||
}
|
||||
Key(const char *itemTag)
|
||||
explicit Key(const char *itemTag)
|
||||
: mItemTag(itemTag)
|
||||
{
|
||||
}
|
||||
@@ -1816,12 +1832,12 @@ class Category
|
||||
friend class Row;
|
||||
friend class detail::ItemReference;
|
||||
|
||||
Category(Datablock &db, const std::string &name, Validator *Validator);
|
||||
Category(Datablock &db, const std::string_view name, const Validator *Validator);
|
||||
Category(const Category &) = delete;
|
||||
Category &operator=(const Category &) = delete;
|
||||
~Category();
|
||||
|
||||
const std::string name() const { return mName; }
|
||||
const std::string &name() const { return mName; }
|
||||
|
||||
using iterator = iterator_impl<Row>;
|
||||
using const_iterator = iterator_impl<const Row>;
|
||||
@@ -2064,7 +2080,7 @@ class Category
|
||||
|
||||
Datablock &db() { return mDb; }
|
||||
|
||||
void setValidator(Validator *v);
|
||||
void setValidator(const Validator *v);
|
||||
|
||||
iset fields() const;
|
||||
iset mandatoryFields() const;
|
||||
@@ -2077,8 +2093,8 @@ class Category
|
||||
void getTagOrder(std::vector<std::string> &tags) const;
|
||||
|
||||
// return index for known column, or the next available column index
|
||||
size_t getColumnIndex(const std::string &name) const;
|
||||
bool hasColumn(const std::string &name) const;
|
||||
size_t getColumnIndex(std::string_view name) const;
|
||||
bool hasColumn(std::string_view name) const;
|
||||
const std::string &getColumnName(size_t columnIndex) const;
|
||||
std::vector<std::string> getColumnNames() const;
|
||||
|
||||
@@ -2119,16 +2135,26 @@ class Category
|
||||
void write(std::ostream &os, const std::vector<std::string> &order);
|
||||
void write(std::ostream &os, const std::vector<size_t> &order, bool includeEmptyColumns);
|
||||
|
||||
size_t addColumn(const std::string &name);
|
||||
size_t addColumn(std::string_view name);
|
||||
|
||||
struct Linked
|
||||
{
|
||||
Category *linked;
|
||||
const ValidateLink *v;
|
||||
};
|
||||
|
||||
void updateLinks();
|
||||
|
||||
Datablock &mDb;
|
||||
std::string mName;
|
||||
Validator *mValidator;
|
||||
const Validator *mValidator;
|
||||
const ValidateCategory *mCatValidator = nullptr;
|
||||
std::vector<ItemColumn> mColumns;
|
||||
ItemRow *mHead;
|
||||
ItemRow *mTail;
|
||||
class CatIndex *mIndex;
|
||||
|
||||
std::vector<Linked> mParentLinks, mChildLinks;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -2162,7 +2188,8 @@ class File
|
||||
|
||||
void loadDictionary(); // load the default dictionary, that is mmcifDdl in this case
|
||||
void loadDictionary(const char *dict); // load one of the compiled in dictionaries
|
||||
void loadDictionary(std::istream &is); // load dictionary from input stream
|
||||
|
||||
void setValidator(const Validator *v);
|
||||
|
||||
bool isValid();
|
||||
void validateLinks() const;
|
||||
@@ -2183,8 +2210,8 @@ class File
|
||||
|
||||
void append(Datablock *e);
|
||||
|
||||
Datablock *get(const std::string &name) const;
|
||||
Datablock &operator[](const std::string &name);
|
||||
Datablock *get(std::string_view name) const;
|
||||
Datablock &operator[](std::string_view name);
|
||||
|
||||
struct iterator
|
||||
{
|
||||
@@ -2226,10 +2253,8 @@ class File
|
||||
void getTagOrder(std::vector<std::string> &tags) const;
|
||||
|
||||
private:
|
||||
void setValidator(Validator *v);
|
||||
|
||||
Datablock *mHead;
|
||||
Validator *mValidator;
|
||||
const Validator *mValidator;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace cif
|
||||
class CifParserError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
CifParserError(uint32_t lineNr, const std::string& message);
|
||||
CifParserError(uint32_t lineNr, const std::string &message);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -48,7 +48,8 @@ extern const uint32_t kMaxLineLength;
|
||||
|
||||
extern const uint8_t kCharTraitsTable[128];
|
||||
|
||||
enum CharTraitsMask: uint8_t {
|
||||
enum CharTraitsMask : uint8_t
|
||||
{
|
||||
kOrdinaryMask = 1 << 0,
|
||||
kNonBlankMask = 1 << 1,
|
||||
kTextLeadMask = 1 << 2,
|
||||
@@ -75,13 +76,13 @@ inline bool isTextLead(int ch)
|
||||
return ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kTextLeadMask) != 0;
|
||||
}
|
||||
|
||||
inline bool isAnyPrint(int ch)
|
||||
inline bool isAnyPrint(int ch)
|
||||
{
|
||||
return ch == '\t' or
|
||||
(ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kAnyPrintMask) != 0);
|
||||
return ch == '\t' or
|
||||
(ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kAnyPrintMask) != 0);
|
||||
}
|
||||
|
||||
inline bool isUnquotedString(const char* s)
|
||||
inline bool isUnquotedString(const char *s)
|
||||
{
|
||||
bool result = isOrdinary(*s++);
|
||||
while (result and *s != 0)
|
||||
@@ -94,11 +95,7 @@ inline bool isUnquotedString(const char* s)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<std::string,std::string> splitTagName(const std::string& tag);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
using DatablockIndex = std::map<std::string,std::size_t>;
|
||||
using DatablockIndex = std::map<std::string, std::size_t>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// sac Parser, analogous to SAX Parser (simple api for xml)
|
||||
@@ -106,15 +103,15 @@ using DatablockIndex = std::map<std::string,std::size_t>;
|
||||
class SacParser
|
||||
{
|
||||
public:
|
||||
SacParser(std::istream& is, bool init = true);
|
||||
SacParser(std::istream &is, bool init = true);
|
||||
virtual ~SacParser() {}
|
||||
|
||||
enum CIFToken
|
||||
{
|
||||
eCIFTokenUnknown,
|
||||
|
||||
|
||||
eCIFTokenEOF,
|
||||
|
||||
|
||||
eCIFTokenDATA,
|
||||
eCIFTokenLOOP,
|
||||
eCIFTokenGLOBAL,
|
||||
@@ -124,7 +121,7 @@ class SacParser
|
||||
eCIFTokenValue,
|
||||
};
|
||||
|
||||
static const char* kTokenName[];
|
||||
static const char *kTokenName[];
|
||||
|
||||
enum CIFValueType
|
||||
{
|
||||
@@ -137,40 +134,39 @@ class SacParser
|
||||
eCIFValueUnknown
|
||||
};
|
||||
|
||||
static const char* kValueName[];
|
||||
|
||||
static const char *kValueName[];
|
||||
|
||||
int getNextChar();
|
||||
|
||||
void retract();
|
||||
void restart();
|
||||
|
||||
|
||||
CIFToken getNextToken();
|
||||
void match(CIFToken token);
|
||||
|
||||
bool parseSingleDatablock(const std::string& datablock);
|
||||
bool parseSingleDatablock(const std::string &datablock);
|
||||
|
||||
DatablockIndex indexDatablocks();
|
||||
bool parseSingleDatablock(const std::string& datablock, const DatablockIndex &index);
|
||||
bool parseSingleDatablock(const std::string &datablock, const DatablockIndex &index);
|
||||
|
||||
void parseFile();
|
||||
void parseGlobal();
|
||||
void parseDataBlock();
|
||||
|
||||
virtual void parseSaveFrame();
|
||||
|
||||
|
||||
void parseDictionary();
|
||||
|
||||
void error(const std::string& msg);
|
||||
|
||||
|
||||
void error(const std::string &msg);
|
||||
|
||||
// production methods, these are pure virtual here
|
||||
|
||||
virtual void produceDatablock(const std::string& name) = 0;
|
||||
virtual void produceCategory(const std::string& name) = 0;
|
||||
|
||||
virtual void produceDatablock(const std::string &name) = 0;
|
||||
virtual void produceCategory(const std::string &name) = 0;
|
||||
virtual void produceRow() = 0;
|
||||
virtual void produceItem(const std::string& category, const std::string& item, const std::string& value) = 0;
|
||||
virtual void produceItem(const std::string &category, const std::string &item, const std::string &value) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
enum State
|
||||
{
|
||||
eStateStart,
|
||||
@@ -185,21 +181,21 @@ class SacParser
|
||||
eStateTextField,
|
||||
eStateFloat = 100,
|
||||
eStateInt = 110,
|
||||
// eStateNumericSuffix = 200,
|
||||
// eStateNumericSuffix = 200,
|
||||
eStateValue = 300
|
||||
};
|
||||
|
||||
std::istream& mData;
|
||||
std::istream &mData;
|
||||
|
||||
// Parser state
|
||||
bool mValidate;
|
||||
uint32_t mLineNr;
|
||||
bool mBol;
|
||||
int mState, mStart;
|
||||
CIFToken mLookahead;
|
||||
std::string mTokenValue;
|
||||
CIFValueType mTokenType;
|
||||
std::stack<int> mBuffer;
|
||||
bool mValidate;
|
||||
uint32_t mLineNr;
|
||||
bool mBol;
|
||||
int mState, mStart;
|
||||
CIFToken mLookahead;
|
||||
std::string mTokenValue;
|
||||
CIFValueType mTokenType;
|
||||
std::stack<int> mBuffer;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -207,18 +203,18 @@ class SacParser
|
||||
class Parser : public SacParser
|
||||
{
|
||||
public:
|
||||
Parser(std::istream& is, File& f, bool init = true);
|
||||
Parser(std::istream &is, File &f, bool init = true);
|
||||
|
||||
virtual void produceDatablock(const std::string& name);
|
||||
virtual void produceCategory(const std::string& name);
|
||||
virtual void produceDatablock(const std::string &name);
|
||||
virtual void produceCategory(const std::string &name);
|
||||
virtual void produceRow();
|
||||
virtual void produceItem(const std::string& category, const std::string& item, const std::string& value);
|
||||
virtual void produceItem(const std::string &category, const std::string &item, const std::string &value);
|
||||
|
||||
protected:
|
||||
File& mFile;
|
||||
Datablock* mDataBlock;
|
||||
Datablock::iterator mCat;
|
||||
Row mRow;
|
||||
File &mFile;
|
||||
Datablock *mDataBlock;
|
||||
Datablock::iterator mCat;
|
||||
Row mRow;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -226,23 +222,21 @@ class Parser : public SacParser
|
||||
class DictParser : public Parser
|
||||
{
|
||||
public:
|
||||
|
||||
DictParser(Validator& validator, std::istream& is);
|
||||
DictParser(Validator &validator, std::istream &is);
|
||||
~DictParser();
|
||||
|
||||
void loadDictionary();
|
||||
|
||||
private:
|
||||
|
||||
void loadDictionary();
|
||||
|
||||
private:
|
||||
virtual void parseSaveFrame();
|
||||
|
||||
|
||||
bool collectItemTypes();
|
||||
void linkItems();
|
||||
|
||||
Validator& mValidator;
|
||||
File mFile;
|
||||
struct DictParserDataImpl* mImpl;
|
||||
bool mCollectedItemTypes = false;
|
||||
Validator &mValidator;
|
||||
File mFile;
|
||||
struct DictParserDataImpl *mImpl;
|
||||
bool mCollectedItemTypes = false;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace cif
|
||||
|
||||
@@ -67,8 +67,8 @@ 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(std::string_view a, std::string_view b);
|
||||
int icompare(std::string_view a, std::string_view b);
|
||||
|
||||
bool iequals(const char *a, const char *b);
|
||||
int icompare(const char *a, const char *b);
|
||||
@@ -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(std::string_view tag);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// generate a cif name, mainly used to generate asym_id's
|
||||
|
||||
@@ -36,18 +36,19 @@
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
|
||||
struct ValidateCategory;
|
||||
class ValidatorFactory;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class ValidationError : public std::exception
|
||||
{
|
||||
public:
|
||||
ValidationError(const std::string& msg);
|
||||
ValidationError(const std::string& cat, const std::string& item,
|
||||
const std::string& msg);
|
||||
const char* what() const noexcept { return mMsg.c_str(); }
|
||||
ValidationError(const std::string &msg);
|
||||
ValidationError(const std::string &cat, const std::string &item,
|
||||
const std::string &msg);
|
||||
const char *what() const noexcept { return mMsg.c_str(); }
|
||||
std::string mMsg;
|
||||
};
|
||||
|
||||
@@ -55,58 +56,60 @@ class ValidationError : public std::exception
|
||||
|
||||
enum class DDL_PrimitiveType
|
||||
{
|
||||
Char, UChar, Numb
|
||||
Char,
|
||||
UChar,
|
||||
Numb
|
||||
};
|
||||
|
||||
DDL_PrimitiveType mapToPrimitiveType(const std::string& s);
|
||||
DDL_PrimitiveType mapToPrimitiveType(std::string_view s);
|
||||
|
||||
struct ValidateType
|
||||
{
|
||||
std::string mName;
|
||||
DDL_PrimitiveType mPrimitiveType;
|
||||
std::string mName;
|
||||
DDL_PrimitiveType mPrimitiveType;
|
||||
// std::regex mRx;
|
||||
boost::regex mRx;
|
||||
boost::regex mRx;
|
||||
|
||||
bool operator<(const ValidateType& rhs) const
|
||||
bool operator<(const ValidateType &rhs) const
|
||||
{
|
||||
return icompare(mName, rhs.mName) < 0;
|
||||
}
|
||||
|
||||
// compare values based on type
|
||||
// int compare(const std::string& a, const std::string& b) const
|
||||
// {
|
||||
// return compare(a.c_str(), b.c_str());
|
||||
// }
|
||||
|
||||
int compare(const char* a, const char* b) const;
|
||||
// compare values based on type
|
||||
// int compare(const std::string& a, const std::string& b) const
|
||||
// {
|
||||
// return compare(a.c_str(), b.c_str());
|
||||
// }
|
||||
|
||||
int compare(const char *a, const char *b) const;
|
||||
};
|
||||
|
||||
struct ValidateItem
|
||||
{
|
||||
std::string mTag;
|
||||
bool mMandatory;
|
||||
const ValidateType* mType;
|
||||
cif::iset mEnums;
|
||||
std::string mDefault;
|
||||
bool mDefaultIsNull;
|
||||
ValidateCategory* mCategory = nullptr;
|
||||
std::string mTag;
|
||||
bool mMandatory;
|
||||
const ValidateType *mType;
|
||||
cif::iset mEnums;
|
||||
std::string mDefault;
|
||||
bool mDefaultIsNull;
|
||||
ValidateCategory *mCategory = nullptr;
|
||||
|
||||
// ItemLinked is used for non-key links
|
||||
struct ItemLinked
|
||||
{
|
||||
ValidateItem* mParent;
|
||||
std::string mParentItem;
|
||||
std::string mChildItem;
|
||||
ValidateItem *mParent;
|
||||
std::string mParentItem;
|
||||
std::string mChildItem;
|
||||
};
|
||||
|
||||
std::vector<ItemLinked> mLinked;
|
||||
|
||||
bool operator<(const ValidateItem& rhs) const
|
||||
std::vector<ItemLinked> mLinked;
|
||||
|
||||
bool operator<(const ValidateItem &rhs) const
|
||||
{
|
||||
return icompare(mTag, rhs.mTag) < 0;
|
||||
}
|
||||
|
||||
bool operator==(const ValidateItem& rhs) const
|
||||
bool operator==(const ValidateItem &rhs) const
|
||||
{
|
||||
return iequals(mTag, rhs.mTag);
|
||||
}
|
||||
@@ -116,22 +119,22 @@ struct ValidateItem
|
||||
|
||||
struct ValidateCategory
|
||||
{
|
||||
std::string mName;
|
||||
std::vector<std::string> mKeys;
|
||||
cif::iset mGroups;
|
||||
cif::iset mMandatoryFields;
|
||||
std::set<ValidateItem> mItemValidators;
|
||||
std::string mName;
|
||||
std::vector<std::string> mKeys;
|
||||
cif::iset mGroups;
|
||||
cif::iset mMandatoryFields;
|
||||
std::set<ValidateItem> mItemValidators;
|
||||
|
||||
bool operator<(const ValidateCategory& rhs) const
|
||||
bool operator<(const ValidateCategory &rhs) const
|
||||
{
|
||||
return icompare(mName, rhs.mName) < 0;
|
||||
}
|
||||
|
||||
void addItemValidator(ValidateItem&& v);
|
||||
|
||||
const ValidateItem* getValidatorForItem(std::string tag) const;
|
||||
|
||||
const std::set<ValidateItem>& itemValidators() const
|
||||
void addItemValidator(ValidateItem &&v);
|
||||
|
||||
const ValidateItem *getValidatorForItem(std::string_view tag) const;
|
||||
|
||||
const std::set<ValidateItem> &itemValidators() const
|
||||
{
|
||||
return mItemValidators;
|
||||
}
|
||||
@@ -139,12 +142,12 @@ struct ValidateCategory
|
||||
|
||||
struct ValidateLink
|
||||
{
|
||||
int mLinkGroupID;
|
||||
std::string mParentCategory;
|
||||
std::vector<std::string> mParentKeys;
|
||||
std::string mChildCategory;
|
||||
std::vector<std::string> mChildKeys;
|
||||
std::string mLinkGroupLabel;
|
||||
int mLinkGroupID;
|
||||
std::string mParentCategory;
|
||||
std::vector<std::string> mParentKeys;
|
||||
std::string mChildCategory;
|
||||
std::vector<std::string> mChildKeys;
|
||||
std::string mLinkGroupLabel;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -152,47 +155,72 @@ struct ValidateLink
|
||||
class Validator
|
||||
{
|
||||
public:
|
||||
friend class DictParser;
|
||||
|
||||
Validator();
|
||||
Validator(std::string_view name, std::istream &is);
|
||||
~Validator();
|
||||
|
||||
Validator(const Validator& rhs) = delete;
|
||||
Validator& operator=(const Validator& rhs) = delete;
|
||||
|
||||
Validator(Validator&& rhs);
|
||||
Validator& operator=(Validator&& rhs);
|
||||
|
||||
void addTypeValidator(ValidateType&& v);
|
||||
const ValidateType* getValidatorForType(std::string typeCode) const;
|
||||
Validator(const Validator &rhs) = delete;
|
||||
Validator &operator=(const Validator &rhs) = delete;
|
||||
|
||||
void addCategoryValidator(ValidateCategory&& v);
|
||||
const ValidateCategory* getValidatorForCategory(std::string category) const;
|
||||
Validator(Validator &&rhs);
|
||||
Validator &operator=(Validator &&rhs);
|
||||
|
||||
void addLinkValidator(ValidateLink&& v);
|
||||
std::vector<const ValidateLink*> getLinksForParent(const std::string& category) const;
|
||||
std::vector<const ValidateLink*> getLinksForChild(const std::string& category) const;
|
||||
friend class DictParser;
|
||||
friend class ValidatorFactory;
|
||||
|
||||
void reportError(const std::string& msg, bool fatal);
|
||||
|
||||
std::string dictName() const { return mName; }
|
||||
void dictName(const std::string& name) { mName = name; }
|
||||
void addTypeValidator(ValidateType &&v);
|
||||
const ValidateType *getValidatorForType(std::string_view typeCode) const;
|
||||
|
||||
std::string dictVersion() const { return mVersion; }
|
||||
void dictVersion(const std::string& version) { mVersion = version; }
|
||||
void addCategoryValidator(ValidateCategory &&v);
|
||||
const ValidateCategory *getValidatorForCategory(std::string_view category) const;
|
||||
|
||||
void addLinkValidator(ValidateLink &&v);
|
||||
std::vector<const ValidateLink *> getLinksForParent(std::string_view category) const;
|
||||
std::vector<const ValidateLink *> getLinksForChild(std::string_view category) const;
|
||||
|
||||
void reportError(const std::string &msg, bool fatal) const;
|
||||
|
||||
std::string dictName() const { return mName; }
|
||||
void dictName(const std::string &name) { mName = name; }
|
||||
|
||||
std::string dictVersion() const { return mVersion; }
|
||||
void dictVersion(const std::string &version) { mVersion = version; }
|
||||
|
||||
private:
|
||||
|
||||
// name is fully qualified here:
|
||||
ValidateItem* getValidatorForItem(std::string name) const;
|
||||
ValidateItem *getValidatorForItem(std::string_view name) const;
|
||||
|
||||
std::string mName;
|
||||
std::string mVersion;
|
||||
bool mStrict = false;
|
||||
// std::set<uint32_t> mSubCategories;
|
||||
std::set<ValidateType> mTypeValidators;
|
||||
std::set<ValidateCategory> mCategoryValidators;
|
||||
std::vector<ValidateLink> mLinkValidators;
|
||||
std::string mName;
|
||||
std::string mVersion;
|
||||
bool mStrict = false;
|
||||
// std::set<uint32_t> mSubCategories;
|
||||
std::set<ValidateType> mTypeValidators;
|
||||
std::set<ValidateCategory> mCategoryValidators;
|
||||
std::vector<ValidateLink> mLinkValidators;
|
||||
};
|
||||
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class ValidatorFactory
|
||||
{
|
||||
public:
|
||||
|
||||
static ValidatorFactory &instance()
|
||||
{
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
const Validator &operator[](std::string_view dictionary);
|
||||
|
||||
private:
|
||||
|
||||
static ValidatorFactory sInstance;
|
||||
|
||||
ValidatorFactory();
|
||||
|
||||
std::mutex mMutex;
|
||||
std::list<Validator> mValidators;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -104,6 +104,7 @@ class Compound
|
||||
std::string id() const { return mID; }
|
||||
std::string name() const { return mName; }
|
||||
std::string type() const { return mType; }
|
||||
std::string group() const { return mGroup; }
|
||||
std::string formula() const { return mFormula; }
|
||||
float formulaWeight() const { return mFormulaWeight; }
|
||||
int formalCharge() const { return mFormalCharge; }
|
||||
@@ -130,11 +131,12 @@ class Compound
|
||||
friend class CCP4CompoundFactoryImpl;
|
||||
|
||||
Compound(cif::Datablock &db);
|
||||
Compound(cif::Datablock &db, const std::string &id, const std::string &name, const std::string &type);
|
||||
Compound(cif::Datablock &db, const std::string &id, const std::string &name, const std::string &type, const std::string &group);
|
||||
|
||||
std::string mID;
|
||||
std::string mName;
|
||||
std::string mType;
|
||||
std::string mGroup;
|
||||
std::string mFormula;
|
||||
float mFormulaWeight = 0;
|
||||
int mFormalCharge = 0;
|
||||
|
||||
@@ -1,391 +0,0 @@
|
||||
/*-
|
||||
* 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);
|
||||
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -37,7 +37,7 @@
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
typedef boost::math::quaternion<float> Quaternion;
|
||||
typedef boost::math::quaternion<float> Quaternion;
|
||||
|
||||
const double
|
||||
kPI = 3.141592653589793238462643383279502884;
|
||||
@@ -51,26 +51,43 @@ const double
|
||||
// float x, y, z;
|
||||
// tie(x, y, z) = atom.loc();
|
||||
|
||||
template<typename F>
|
||||
template <typename F>
|
||||
struct PointF
|
||||
{
|
||||
typedef F FType;
|
||||
|
||||
FType mX, mY, mZ;
|
||||
|
||||
PointF() : mX(0), mY(0), mZ(0) {}
|
||||
PointF(FType x, FType y, FType z) : mX(x), mY(y), mZ(z) {}
|
||||
|
||||
template<typename PF>
|
||||
PointF(const PointF<PF>& pt)
|
||||
PointF()
|
||||
: mX(0)
|
||||
, mY(0)
|
||||
, mZ(0)
|
||||
{
|
||||
}
|
||||
PointF(FType x, FType y, FType z)
|
||||
: mX(x)
|
||||
, mY(y)
|
||||
, mZ(z)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename PF>
|
||||
PointF(const PointF<PF> &pt)
|
||||
: mX(static_cast<F>(pt.mX))
|
||||
, mY(static_cast<F>(pt.mY))
|
||||
, mZ(static_cast<F>(pt.mZ)) {}
|
||||
, mZ(static_cast<F>(pt.mZ))
|
||||
{
|
||||
}
|
||||
|
||||
#if HAVE_LIBCLIPPER
|
||||
PointF(const clipper::Coord_orth& pt): mX(pt[0]), mY(pt[1]), mZ(pt[2]) {}
|
||||
#if HAVE_LIBCLIPPER
|
||||
PointF(const clipper::Coord_orth &pt)
|
||||
: mX(pt[0])
|
||||
, mY(pt[1])
|
||||
, mZ(pt[2])
|
||||
{
|
||||
}
|
||||
|
||||
PointF& operator=(const clipper::Coord_orth& rhs)
|
||||
PointF &operator=(const clipper::Coord_orth &rhs)
|
||||
{
|
||||
mX = rhs[0];
|
||||
mY = rhs[1];
|
||||
@@ -79,72 +96,72 @@ struct PointF
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename PF>
|
||||
PointF& operator=(const PointF<PF>& rhs)
|
||||
template <typename PF>
|
||||
PointF &operator=(const PointF<PF> &rhs)
|
||||
{
|
||||
mX = static_cast<F>(rhs.mX);
|
||||
mY = static_cast<F>(rhs.mY);
|
||||
mZ = static_cast<F>(rhs.mZ);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FType& getX() { return mX; }
|
||||
FType getX() const { return mX; }
|
||||
void setX(FType x) { mX = x; }
|
||||
|
||||
FType& getY() { return mY; }
|
||||
FType getY() const { return mY; }
|
||||
void setY(FType y) { mY = y; }
|
||||
FType &getX() { return mX; }
|
||||
FType getX() const { return mX; }
|
||||
void setX(FType x) { mX = x; }
|
||||
|
||||
FType& getZ() { return mZ; }
|
||||
FType getZ() const { return mZ; }
|
||||
void setZ(FType z) { mZ = z; }
|
||||
|
||||
PointF& operator+=(const PointF& rhs)
|
||||
FType &getY() { return mY; }
|
||||
FType getY() const { return mY; }
|
||||
void setY(FType y) { mY = y; }
|
||||
|
||||
FType &getZ() { return mZ; }
|
||||
FType getZ() const { return mZ; }
|
||||
void setZ(FType z) { mZ = z; }
|
||||
|
||||
PointF &operator+=(const PointF &rhs)
|
||||
{
|
||||
mX += rhs.mX;
|
||||
mY += rhs.mY;
|
||||
mZ += rhs.mZ;
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator+=(FType d)
|
||||
|
||||
PointF &operator+=(FType d)
|
||||
{
|
||||
mX += d;
|
||||
mY += d;
|
||||
mZ += d;
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator-=(const PointF& rhs)
|
||||
PointF &operator-=(const PointF &rhs)
|
||||
{
|
||||
mX -= rhs.mX;
|
||||
mY -= rhs.mY;
|
||||
mZ -= rhs.mZ;
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator-=(FType d)
|
||||
PointF &operator-=(FType d)
|
||||
{
|
||||
mX -= d;
|
||||
mY -= d;
|
||||
mZ -= d;
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator*=(FType rhs)
|
||||
PointF &operator*=(FType rhs)
|
||||
{
|
||||
mX *= rhs;
|
||||
mY *= rhs;
|
||||
mZ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator/=(FType rhs)
|
||||
|
||||
PointF &operator/=(FType rhs)
|
||||
{
|
||||
mX /= rhs;
|
||||
mY /= rhs;
|
||||
@@ -162,18 +179,18 @@ struct PointF
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void rotate(const boost::math::quaternion<FType>& q)
|
||||
|
||||
void rotate(const boost::math::quaternion<FType> &q)
|
||||
{
|
||||
boost::math::quaternion<FType> p(0, mX, mY, mZ);
|
||||
|
||||
|
||||
p = q * p * boost::math::conj(q);
|
||||
|
||||
|
||||
mX = p.R_component_2();
|
||||
mY = p.R_component_3();
|
||||
mZ = p.R_component_4();
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_LIBCLIPPER
|
||||
operator clipper::Coord_orth() const
|
||||
{
|
||||
@@ -181,21 +198,21 @@ struct PointF
|
||||
}
|
||||
#endif
|
||||
|
||||
operator std::tuple<const FType&, const FType&, const FType&>() const
|
||||
operator std::tuple<const FType &, const FType &, const FType &>() const
|
||||
{
|
||||
return std::make_tuple(std::ref(mX), std::ref(mY), std::ref(mZ));
|
||||
}
|
||||
|
||||
operator std::tuple<FType&,FType&,FType&>()
|
||||
operator std::tuple<FType &, FType &, FType &>()
|
||||
{
|
||||
return std::make_tuple(std::ref(mX), std::ref(mY), std::ref(mZ));
|
||||
}
|
||||
|
||||
bool operator==(const PointF& rhs) const
|
||||
|
||||
bool operator==(const PointF &rhs) const
|
||||
{
|
||||
return mX == rhs.mX and mY == rhs.mY and mZ == rhs.mZ;
|
||||
}
|
||||
|
||||
|
||||
// consider point as a vector... perhaps I should rename Point?
|
||||
FType lengthsq() const
|
||||
{
|
||||
@@ -211,45 +228,45 @@ struct PointF
|
||||
typedef PointF<float> Point;
|
||||
typedef PointF<double> DPoint;
|
||||
|
||||
template<typename F>
|
||||
inline std::ostream& operator<<(std::ostream& os, const PointF<F>& pt)
|
||||
template <typename F>
|
||||
inline std::ostream &operator<<(std::ostream &os, const PointF<F> &pt)
|
||||
{
|
||||
os << '(' << pt.mX << ',' << pt.mY << ',' << pt.mZ << ')';
|
||||
return os;
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator+(const PointF<F>& lhs, const PointF<F>& rhs)
|
||||
template <typename F>
|
||||
inline PointF<F> operator+(const PointF<F> &lhs, const PointF<F> &rhs)
|
||||
{
|
||||
return PointF<F>(lhs.mX + rhs.mX, lhs.mY + rhs.mY, lhs.mZ + rhs.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator-(const PointF<F>& lhs, const PointF<F>& rhs)
|
||||
template <typename F>
|
||||
inline PointF<F> operator-(const PointF<F> &lhs, const PointF<F> &rhs)
|
||||
{
|
||||
return PointF<F>(lhs.mX - rhs.mX, lhs.mY - rhs.mY, lhs.mZ - rhs.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator-(const PointF<F>& pt)
|
||||
template <typename F>
|
||||
inline PointF<F> operator-(const PointF<F> &pt)
|
||||
{
|
||||
return PointF<F>(-pt.mX, -pt.mY, -pt.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator*(const PointF<F>& pt, F f)
|
||||
template <typename F>
|
||||
inline PointF<F> operator*(const PointF<F> &pt, F f)
|
||||
{
|
||||
return PointF<F>(pt.mX * f, pt.mY * f, pt.mZ * f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator*(F f, const PointF<F>& pt)
|
||||
template <typename F>
|
||||
inline PointF<F> operator*(F f, const PointF<F> &pt)
|
||||
{
|
||||
return PointF<F>(pt.mX * f, pt.mY * f, pt.mZ * f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator/(const PointF<F>& pt, F f)
|
||||
template <typename F>
|
||||
inline PointF<F> operator/(const PointF<F> &pt, F f)
|
||||
{
|
||||
return PointF<F>(pt.mX / f, pt.mY / f, pt.mZ / f);
|
||||
}
|
||||
@@ -257,17 +274,16 @@ inline PointF<F> operator/(const PointF<F>& pt, F f)
|
||||
// --------------------------------------------------------------------
|
||||
// several standard 3d operations
|
||||
|
||||
template<typename F>
|
||||
inline double DistanceSquared(const PointF<F>& a, const PointF<F>& b)
|
||||
template <typename F>
|
||||
inline double DistanceSquared(const PointF<F> &a, const PointF<F> &b)
|
||||
{
|
||||
return
|
||||
(a.mX - b.mX) * (a.mX - b.mX) +
|
||||
(a.mY - b.mY) * (a.mY - b.mY) +
|
||||
(a.mZ - b.mZ) * (a.mZ - b.mZ);
|
||||
return (a.mX - b.mX) * (a.mX - b.mX) +
|
||||
(a.mY - b.mY) * (a.mY - b.mY) +
|
||||
(a.mZ - b.mZ) * (a.mZ - b.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline double Distance(const PointF<F>& a, const PointF<F>& b)
|
||||
template <typename F>
|
||||
inline double Distance(const PointF<F> &a, const PointF<F> &b)
|
||||
{
|
||||
return sqrt(
|
||||
(a.mX - b.mX) * (a.mX - b.mX) +
|
||||
@@ -275,44 +291,44 @@ inline double Distance(const PointF<F>& a, const PointF<F>& b)
|
||||
(a.mZ - b.mZ) * (a.mZ - b.mZ));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline F DotProduct(const PointF<F>& a, const PointF<F>& b)
|
||||
template <typename F>
|
||||
inline F DotProduct(const PointF<F> &a, const PointF<F> &b)
|
||||
{
|
||||
return a.mX * b.mX + a.mY * b.mY + a.mZ * b.mZ;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> CrossProduct(const PointF<F>& a, const PointF<F>& b)
|
||||
template <typename F>
|
||||
inline PointF<F> CrossProduct(const PointF<F> &a, const PointF<F> &b)
|
||||
{
|
||||
return PointF<F>(a.mY * b.mZ - b.mY * a.mZ,
|
||||
a.mZ * b.mX - b.mZ * a.mX,
|
||||
a.mX * b.mY - b.mX * a.mY);
|
||||
a.mZ * b.mX - b.mZ * a.mX,
|
||||
a.mX * b.mY - b.mX * a.mY);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double Angle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>& p3)
|
||||
template <typename F>
|
||||
double Angle(const PointF<F> &p1, const PointF<F> &p2, const PointF<F> &p3)
|
||||
{
|
||||
PointF<F> v1 = p1 - p2;
|
||||
PointF<F> v2 = p3 - p2;
|
||||
|
||||
|
||||
return std::acos(DotProduct(v1, v2) / (v1.length() * v2.length())) * 180 / kPI;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double DihedralAngle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>& p3, const PointF<F>& p4)
|
||||
template <typename F>
|
||||
double DihedralAngle(const PointF<F> &p1, const PointF<F> &p2, const PointF<F> &p3, const PointF<F> &p4)
|
||||
{
|
||||
PointF<F> v12 = p1 - p2; // vector from p2 to p1
|
||||
PointF<F> v43 = p4 - p3; // vector from p3 to p4
|
||||
|
||||
PointF<F> z = p2 - p3; // vector from p3 to p2
|
||||
|
||||
PointF<F> v12 = p1 - p2; // vector from p2 to p1
|
||||
PointF<F> v43 = p4 - p3; // vector from p3 to p4
|
||||
|
||||
PointF<F> z = p2 - p3; // vector from p3 to p2
|
||||
|
||||
PointF<F> p = CrossProduct(z, v12);
|
||||
PointF<F> x = CrossProduct(z, v43);
|
||||
PointF<F> y = CrossProduct(z, x);
|
||||
|
||||
|
||||
double u = DotProduct(x, x);
|
||||
double v = DotProduct(y, y);
|
||||
|
||||
|
||||
double result = 360;
|
||||
if (u > 0 and v > 0)
|
||||
{
|
||||
@@ -321,33 +337,33 @@ double DihedralAngle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>&
|
||||
if (u != 0 or v != 0)
|
||||
result = atan2(v, u) * 180 / kPI;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double CosinusAngle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>& p3, const PointF<F>& p4)
|
||||
template <typename F>
|
||||
double CosinusAngle(const PointF<F> &p1, const PointF<F> &p2, const PointF<F> &p3, const PointF<F> &p4)
|
||||
{
|
||||
PointF<F> v12 = p1 - p2;
|
||||
PointF<F> v34 = p3 - p4;
|
||||
|
||||
|
||||
double result = 0;
|
||||
|
||||
|
||||
double x = DotProduct(v12, v12) * DotProduct(v34, v34);
|
||||
if (x > 0)
|
||||
result = DotProduct(v12, v34) / sqrt(x);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
template <typename F>
|
||||
auto DistancePointToLine(const PointF<F> &l1, const PointF<F> &l2, const PointF<F> &p)
|
||||
{
|
||||
auto line = l2 - l1;
|
||||
auto p_to_l1 = p - l1;
|
||||
auto p_to_l2 = p - l2;
|
||||
auto cross = CrossProduct(p_to_l1, p_to_l2);
|
||||
return cross.length() / line.length();
|
||||
auto line = l2 - l1;
|
||||
auto p_to_l1 = p - l1;
|
||||
auto p_to_l2 = p - l2;
|
||||
auto cross = CrossProduct(p_to_l1, p_to_l2);
|
||||
return cross.length() / line.length();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -355,7 +371,7 @@ auto DistancePointToLine(const PointF<F> &l1, const PointF<F> &l2, const PointF<
|
||||
// a random direction with a distance randomly chosen from a normal
|
||||
// distribution with a stddev of offset.
|
||||
|
||||
template<typename F>
|
||||
template <typename F>
|
||||
PointF<F> Nudge(PointF<F> p, F offset);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -363,66 +379,77 @@ PointF<F> Nudge(PointF<F> p, F offset);
|
||||
|
||||
Quaternion Normalize(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);
|
||||
double RMSd(const std::vector<Point>& a, const std::vector<Point>& b);
|
||||
std::tuple<double, Point> QuaternionToAngleAxis(Quaternion q);
|
||||
Point Centroid(const std::vector<Point> &Points);
|
||||
Point CenterPoints(std::vector<Point> &Points);
|
||||
|
||||
/// \brief Returns how the two sets of points \a a and \b b can be aligned
|
||||
///
|
||||
/// \param a The first set of points
|
||||
/// \param b The second set of points
|
||||
/// \result The quaternion which should be applied to the points in \a a to
|
||||
/// obtain the best superposition.
|
||||
Quaternion AlignPoints(const std::vector<Point> &a, const std::vector<Point> &b);
|
||||
|
||||
/// \brief The RMSd for the points in \a a and \a b
|
||||
double RMSd(const std::vector<Point> &a, const std::vector<Point> &b);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Helper class to generate evenly divided Points on a sphere
|
||||
// we use a fibonacci sphere to calculate even distribution of the dots
|
||||
|
||||
template<int N>
|
||||
template <int N>
|
||||
class SphericalDots
|
||||
{
|
||||
public:
|
||||
enum { P = 2 * N + 1 };
|
||||
typedef typename std::array<Point,P> array_type;
|
||||
typedef typename array_type::const_iterator iterator;
|
||||
enum
|
||||
{
|
||||
P = 2 * N + 1
|
||||
};
|
||||
typedef typename std::array<Point, P> array_type;
|
||||
typedef typename array_type::const_iterator iterator;
|
||||
|
||||
static SphericalDots& instance()
|
||||
static SphericalDots &instance()
|
||||
{
|
||||
static SphericalDots sInstance;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
size_t size() const { return mPoints.size(); }
|
||||
const Point operator[](uint32_t inIx) const { return mPoints[inIx]; }
|
||||
iterator begin() const { return mPoints.begin(); }
|
||||
iterator end() const { return mPoints.end(); }
|
||||
|
||||
double weight() const { return mWeight; }
|
||||
size_t size() const { return mPoints.size(); }
|
||||
const Point operator[](uint32_t inIx) const { return mPoints[inIx]; }
|
||||
iterator begin() const { return mPoints.begin(); }
|
||||
iterator end() const { return mPoints.end(); }
|
||||
|
||||
double weight() const { return mWeight; }
|
||||
|
||||
SphericalDots()
|
||||
{
|
||||
|
||||
|
||||
const double
|
||||
kGoldenRatio = (1 + std::sqrt(5.0)) / 2;
|
||||
|
||||
|
||||
mWeight = (4 * kPI) / P;
|
||||
|
||||
|
||||
auto p = mPoints.begin();
|
||||
|
||||
|
||||
for (int32_t i = -N; i <= N; ++i)
|
||||
{
|
||||
double lat = std::asin((2.0 * i) / P);
|
||||
double lon = std::fmod(i, kGoldenRatio) * 2 * kPI / kGoldenRatio;
|
||||
|
||||
|
||||
p->mX = sin(lon) * cos(lat);
|
||||
p->mY = cos(lon) * cos(lat);
|
||||
p->mZ = sin(lat);
|
||||
p->mZ = sin(lat);
|
||||
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
array_type mPoints;
|
||||
double mWeight;
|
||||
array_type mPoints;
|
||||
double mWeight;
|
||||
};
|
||||
|
||||
typedef SphericalDots<50> SphericalDots_50;
|
||||
|
||||
}
|
||||
} // namespace mmcif
|
||||
|
||||
@@ -137,6 +137,22 @@ class DSSP
|
||||
public:
|
||||
friend class iterator;
|
||||
|
||||
ResidueInfo()
|
||||
: mImpl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ResidueInfo(const ResidueInfo &rhs)
|
||||
: mImpl(rhs.mImpl)
|
||||
{
|
||||
}
|
||||
|
||||
ResidueInfo& operator=(const ResidueInfo &rhs)
|
||||
{
|
||||
mImpl = rhs.mImpl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return not empty(); }
|
||||
bool empty() const { return mImpl == nullptr; }
|
||||
|
||||
|
||||
@@ -109,12 +109,12 @@ class Atom
|
||||
float occupancy() const;
|
||||
|
||||
template <typename T>
|
||||
T property(const std::string &name) const;
|
||||
T property(const std::string_view name) const;
|
||||
|
||||
void property(const std::string &name, const std::string &value);
|
||||
void property(const std::string_view name, const std::string &value);
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
void property(const std::string &name, const T &value)
|
||||
void property(const std::string_view name, const T &value)
|
||||
{
|
||||
property(name, std::to_string(value));
|
||||
}
|
||||
@@ -236,6 +236,8 @@ class Residue
|
||||
Atom atomByID(const std::string &atomID) const;
|
||||
|
||||
const std::string &compoundID() const { return mCompoundID; }
|
||||
void setCompoundID(const std::string &id) { mCompoundID = id; }
|
||||
|
||||
const std::string &asymID() const { return mAsymID; }
|
||||
int seqID() const { return mSeqID; }
|
||||
std::string entityID() const;
|
||||
@@ -404,7 +406,7 @@ class File : public std::enable_shared_from_this<File>
|
||||
File(const File &) = delete;
|
||||
File &operator=(const File &) = delete;
|
||||
|
||||
cif::Datablock& createDatablock(const std::string &name);
|
||||
cif::Datablock& createDatablock(const std::string_view name);
|
||||
|
||||
void load(const std::filesystem::path &path);
|
||||
void save(const std::filesystem::path &path);
|
||||
@@ -461,9 +463,24 @@ class Structure
|
||||
Atom getAtomByLabel(const std::string &atomID, const std::string &asymID,
|
||||
const std::string &compID, int seqID, const std::string &altID = "");
|
||||
|
||||
/// \brief Return the atom closest to point \a p
|
||||
Atom getAtomByPosition(Point p) const;
|
||||
|
||||
/// \brief Return the atom closest to point \a p with atom type \a type in a residue of type \a res_type
|
||||
Atom getAtomByPositionAndType(Point p, std::string_view type, std::string_view res_type) const;
|
||||
|
||||
/// \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;
|
||||
|
||||
/// \brief Get a residue, if \a seqID is zero, the non-polymers are searched
|
||||
Residue &getResidue(const std::string &asymID, const std::string &compID, int seqID = 0);
|
||||
|
||||
/// \brief Get a the single residue for an asym with id \a asymID
|
||||
const Residue &getResidue(const std::string &asymID) const;
|
||||
|
||||
/// \brief Get a the single residue for an asym with id \a asymID
|
||||
Residue &getResidue(const std::string &asymID);
|
||||
|
||||
// map between auth and label locations
|
||||
|
||||
std::tuple<std::string, int, std::string> MapAuthToLabel(const std::string &asymID,
|
||||
@@ -488,7 +505,7 @@ class Structure
|
||||
void removeAtom(Atom &a);
|
||||
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,
|
||||
void changeResidue(Residue &res, const std::string &newCompound,
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms);
|
||||
|
||||
/// \brief Create a new non-polymer entity, returns new ID
|
||||
@@ -519,20 +536,23 @@ class Structure
|
||||
|
||||
void cleanupEmptyCategories();
|
||||
|
||||
/// \brief Direct access to underlying data
|
||||
cif::Category &category(std::string_view name) const;
|
||||
cif::Datablock &datablock() const;
|
||||
|
||||
private:
|
||||
friend Polymer;
|
||||
friend Residue;
|
||||
// friend residue_view;
|
||||
// friend residue_iterator;
|
||||
|
||||
cif::Category &category(const char *name) const;
|
||||
cif::Datablock &datablock() const;
|
||||
|
||||
std::string insertCompound(const std::string &compoundID, bool isEntity);
|
||||
|
||||
void loadData();
|
||||
void updateAtomIndex();
|
||||
|
||||
void loadAtomsForModel(StructureOpenOptions options);
|
||||
|
||||
File &mFile;
|
||||
size_t mModelNr;
|
||||
AtomView mAtoms;
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace mmcif
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
enum class SpacegroupName
|
||||
{
|
||||
full, xHM, Hall
|
||||
};
|
||||
|
||||
struct Spacegroup
|
||||
{
|
||||
const char* name;
|
||||
@@ -133,6 +138,7 @@ CIFPP_EXPORT extern const std::size_t kSymopNrTableSize;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int GetSpacegroupNumber(std::string spacegroup); // alternative for clipper's parsing code
|
||||
int GetSpacegroupNumber(std::string spacegroup); // alternative for clipper's parsing code, using SpacegroupName::full
|
||||
int GetSpacegroupNumber(std::string spacegroup, SpacegroupName type); // alternative for clipper's parsing code
|
||||
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ Name: libcifpp
|
||||
Description: C++ library for the manipulation of mmCIF files.
|
||||
Version: @PACKAGE_VERSION@
|
||||
|
||||
Libs: -L${libdir} -lcifpp @PRIVATE_LIBS@
|
||||
Cflags: -I${includedir} @PRIVATE_INC_DIRS@
|
||||
Libs: -L${libdir} -lcifpp -lboost_regex -lboost_iostreams
|
||||
Cflags: -I${includedir} -pthread
|
||||
|
||||
1280
src/AtomType.cpp
1280
src/AtomType.cpp
File diff suppressed because it is too large
Load Diff
433
src/BondMap.cpp
433
src/BondMap.cpp
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -24,14 +24,14 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/Compound.hpp"
|
||||
#include "cif++/CifUtils.hpp"
|
||||
#include "cif++/BondMap.hpp"
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/CifUtils.hpp"
|
||||
#include "cif++/Compound.hpp"
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
@@ -39,223 +39,79 @@ namespace mmcif
|
||||
namespace
|
||||
{
|
||||
|
||||
union IDType
|
||||
{
|
||||
IDType() : id_n(0){}
|
||||
IDType(const IDType& rhs) : id_n(rhs.id_n) {}
|
||||
IDType(const std::string& s)
|
||||
: IDType()
|
||||
union IDType
|
||||
{
|
||||
assert(s.length() <= 4);
|
||||
if (s.length() > 4)
|
||||
throw BondMapException("Atom ID '" + s + "' is too long");
|
||||
std::copy(s.begin(), s.end(), id_s);
|
||||
}
|
||||
IDType()
|
||||
: id_n(0)
|
||||
{
|
||||
}
|
||||
IDType(const IDType &rhs)
|
||||
: id_n(rhs.id_n)
|
||||
{
|
||||
}
|
||||
IDType(const std::string &s)
|
||||
: IDType()
|
||||
{
|
||||
assert(s.length() <= 4);
|
||||
if (s.length() > 4)
|
||||
throw BondMapException("Atom ID '" + s + "' is too long");
|
||||
std::copy(s.begin(), s.end(), id_s);
|
||||
}
|
||||
|
||||
IDType& operator=(const IDType& rhs)
|
||||
{
|
||||
id_n = rhs.id_n;
|
||||
return *this;
|
||||
}
|
||||
IDType &operator=(const IDType &rhs)
|
||||
{
|
||||
id_n = rhs.id_n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IDType& operator=(const std::string& s)
|
||||
{
|
||||
id_n = 0;
|
||||
assert(s.length() <= 4);
|
||||
if (s.length() > 4)
|
||||
throw BondMapException("Atom ID '" + s + "' is too long");
|
||||
std::copy(s.begin(), s.end(), id_s);
|
||||
return *this;
|
||||
}
|
||||
IDType &operator=(const std::string &s)
|
||||
{
|
||||
id_n = 0;
|
||||
assert(s.length() <= 4);
|
||||
if (s.length() > 4)
|
||||
throw BondMapException("Atom ID '" + s + "' is too long");
|
||||
std::copy(s.begin(), s.end(), id_s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(const IDType& rhs) const
|
||||
{
|
||||
return id_n < rhs.id_n;
|
||||
}
|
||||
bool operator<(const IDType &rhs) const
|
||||
{
|
||||
return id_n < rhs.id_n;
|
||||
}
|
||||
|
||||
bool operator<=(const IDType& rhs) const
|
||||
{
|
||||
return id_n <= rhs.id_n;
|
||||
}
|
||||
bool operator<=(const IDType &rhs) const
|
||||
{
|
||||
return id_n <= rhs.id_n;
|
||||
}
|
||||
|
||||
bool operator==(const IDType& rhs) const
|
||||
{
|
||||
return id_n == rhs.id_n;
|
||||
}
|
||||
bool operator==(const IDType &rhs) const
|
||||
{
|
||||
return id_n == rhs.id_n;
|
||||
}
|
||||
|
||||
bool operator!=(const IDType& rhs) const
|
||||
{
|
||||
return id_n != rhs.id_n;
|
||||
}
|
||||
bool operator!=(const IDType &rhs) const
|
||||
{
|
||||
return id_n != rhs.id_n;
|
||||
}
|
||||
|
||||
char id_s[4];
|
||||
uint32_t id_n;
|
||||
};
|
||||
char id_s[4];
|
||||
uint32_t id_n;
|
||||
};
|
||||
|
||||
static_assert(sizeof(IDType) == 4, "atom_id_type should be 4 bytes");
|
||||
}
|
||||
|
||||
// // --------------------------------------------------------------------
|
||||
|
||||
// void createBondInfoFile(const fs::path& components, const fs::path& infofile)
|
||||
// {
|
||||
// std::ofstream outfile(infofile.string() + ".tmp", std::ios::binary);
|
||||
// if (not outfile.is_open())
|
||||
// throw BondMapException("Could not create bond info file " + infofile.string() + ".tmp");
|
||||
|
||||
// cif::File infile(components);
|
||||
|
||||
// std::set<atom_id_type> atomIDs;
|
||||
// std::vector<atom_id_type> compoundIDs;
|
||||
|
||||
// for (auto& db: infile)
|
||||
// {
|
||||
// auto chem_comp_bond = db.get("chem_comp_bond");
|
||||
// if (not chem_comp_bond)
|
||||
// {
|
||||
// if (cif::VERBOSE > 1)
|
||||
// std::cerr << "Missing chem_comp_bond category in data block " << db.getName() << std::endl;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// for (const auto& [atom_id_1, atom_id_2]: chem_comp_bond->rows<std::string,std::string>({"atom_id_1", "atom_id_2"}))
|
||||
// {
|
||||
// atomIDs.insert(atom_id_1);
|
||||
// atomIDs.insert(atom_id_2);
|
||||
// }
|
||||
|
||||
// compoundIDs.push_back({ db.getName() });
|
||||
// }
|
||||
|
||||
// if (cif::VERBOSE)
|
||||
// std::cout << "Number of unique atom names is " << atomIDs.size() << std::endl
|
||||
// << "Number of unique residue names is " << compoundIDs.size() << std::endl;
|
||||
|
||||
// CompoundBondInfoFileHeader header = {};
|
||||
// header.indexEntries = compoundIDs.size();
|
||||
// header.atomEntries = atomIDs.size();
|
||||
|
||||
// outfile << header;
|
||||
|
||||
// for (auto atomID: atomIDs)
|
||||
// outfile << atomID;
|
||||
|
||||
// auto dataOffset = outfile.tellp();
|
||||
|
||||
// std::vector<CompoundBondInfo> entries;
|
||||
// entries.reserve(compoundIDs.size());
|
||||
|
||||
// std::map<atom_id_type, uint16_t> atomIDMap;
|
||||
// for (auto& atomID: atomIDs)
|
||||
// atomIDMap[atomID] = atomIDMap.size();
|
||||
|
||||
// for (auto& db: infile)
|
||||
// {
|
||||
// auto chem_comp_bond = db.get("chem_comp_bond");
|
||||
// if (not chem_comp_bond)
|
||||
// continue;
|
||||
|
||||
// std::set<uint16_t> bondedAtoms;
|
||||
|
||||
// for (const auto& [atom_id_1, atom_id_2]: chem_comp_bond->rows<std::string,std::string>({"atom_id_1", "atom_id_2"}))
|
||||
// {
|
||||
// bondedAtoms.insert(atomIDMap[atom_id_1]);
|
||||
// bondedAtoms.insert(atomIDMap[atom_id_2]);
|
||||
// }
|
||||
|
||||
// std::map<uint16_t, int32_t> bondedAtomMap;
|
||||
// for (auto id: bondedAtoms)
|
||||
// bondedAtomMap[id] = static_cast<int32_t>(bondedAtomMap.size());
|
||||
|
||||
// CompoundBondInfo info = {
|
||||
// db.getName(),
|
||||
// static_cast<uint32_t>(bondedAtomMap.size()),
|
||||
// outfile.tellp() - dataOffset
|
||||
// };
|
||||
|
||||
// entries.push_back(info);
|
||||
|
||||
// // An now first write the array of atom ID's in this compound
|
||||
// for (uint16_t id: bondedAtoms)
|
||||
// write(outfile, id);
|
||||
|
||||
// // And then the symmetric matrix with bonds
|
||||
// size_t N = bondedAtoms.size();
|
||||
// size_t M = (N * (N - 1)) / 2;
|
||||
|
||||
// size_t K = M / 8;
|
||||
// if (M % 8)
|
||||
// K += 1;
|
||||
|
||||
// std::vector<uint8_t> m(K);
|
||||
|
||||
// for (const auto& [atom_id_1, atom_id_2]: chem_comp_bond->rows<std::string,std::string>({"atom_id_1", "atom_id_2"}))
|
||||
// {
|
||||
// auto a = bondedAtomMap[atomIDMap[atom_id_1]];
|
||||
// auto b = bondedAtomMap[atomIDMap[atom_id_2]];
|
||||
|
||||
// assert(a != b);
|
||||
// assert((int)b < (int)N);
|
||||
|
||||
// if (a > b)
|
||||
// std::swap(a, b);
|
||||
|
||||
// size_t ix = ((b - 1) * b) / 2 + a;
|
||||
// assert(ix < M);
|
||||
|
||||
// auto Bix = ix / 8;
|
||||
// auto bix = ix % 8;
|
||||
|
||||
// m[Bix] |= 1 << bix;
|
||||
// }
|
||||
|
||||
// outfile.write(reinterpret_cast<char*>(m.data()), m.size());
|
||||
// }
|
||||
|
||||
// header.dataSize = outfile.tellp() - dataOffset;
|
||||
|
||||
// std::sort(entries.begin(), entries.end(), [](CompoundBondInfo& a, CompoundBondInfo& b)
|
||||
// {
|
||||
// return a.id < b.id;
|
||||
// });
|
||||
|
||||
// for (auto& info: entries)
|
||||
// outfile << info;
|
||||
|
||||
// outfile.seekp(0);
|
||||
// outfile << header;
|
||||
|
||||
// // compress
|
||||
// outfile.close();
|
||||
|
||||
// std::ifstream in(infofile.string() + ".tmp", std::ios::binary);
|
||||
// std::ofstream out(infofile, std::ios::binary);
|
||||
|
||||
// {
|
||||
// io::filtering_stream<io::output> os;
|
||||
// os.push(io::gzip_compressor());
|
||||
// os.push(out);
|
||||
// io::copy(in, os);
|
||||
// }
|
||||
|
||||
// in.close();
|
||||
// out.close();
|
||||
|
||||
// fs::remove(infofile.string() + ".tmp");
|
||||
// }
|
||||
static_assert(sizeof(IDType) == 4, "atom_id_type should be 4 bytes");
|
||||
} // namespace
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
struct CompoundBondInfo
|
||||
{
|
||||
IDType mID;
|
||||
std::set<std::tuple<uint32_t,uint32_t>> mBonded;
|
||||
IDType mID;
|
||||
std::set<std::tuple<uint32_t, uint32_t>> mBonded;
|
||||
|
||||
bool bonded(uint32_t a1, uint32_t a2) const
|
||||
{
|
||||
return mBonded.count({ a1, a2 }) > 0;
|
||||
return mBonded.count({a1, a2}) > 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -263,20 +119,18 @@ struct CompoundBondInfo
|
||||
class CompoundBondMap
|
||||
{
|
||||
public:
|
||||
|
||||
static CompoundBondMap &instance()
|
||||
{
|
||||
static std::unique_ptr<CompoundBondMap> s_instance(new CompoundBondMap);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
bool bonded(const std::string& compoundID, const std::string& atomID1, const std::string& atomID2);
|
||||
bool bonded(const std::string &compoundID, const std::string &atomID1, const std::string &atomID2);
|
||||
|
||||
private:
|
||||
|
||||
CompoundBondMap() {}
|
||||
|
||||
uint32_t getAtomID(const std::string& atomID)
|
||||
uint32_t getAtomID(const std::string &atomID)
|
||||
{
|
||||
IDType id(atomID);
|
||||
|
||||
@@ -290,16 +144,16 @@ class CompoundBondMap
|
||||
}
|
||||
else
|
||||
result = i->second;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<IDType,uint32_t> mAtomIDIndex;
|
||||
std::map<IDType, uint32_t> mAtomIDIndex;
|
||||
std::vector<CompoundBondInfo> mCompounds;
|
||||
std::mutex mMutex;
|
||||
};
|
||||
|
||||
bool CompoundBondMap::bonded(const std::string &compoundID, const std::string& atomID1, const std::string& atomID2)
|
||||
bool CompoundBondMap::bonded(const std::string &compoundID, const std::string &atomID1, const std::string &atomID2)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
|
||||
@@ -310,32 +164,32 @@ bool CompoundBondMap::bonded(const std::string &compoundID, const std::string& a
|
||||
uint32_t a2 = getAtomID(atomID2);
|
||||
if (a1 > a2)
|
||||
std::swap(a1, a2);
|
||||
|
||||
for (auto &bi: mCompounds)
|
||||
|
||||
for (auto &bi : mCompounds)
|
||||
{
|
||||
if (bi.mID != id)
|
||||
continue;
|
||||
|
||||
|
||||
return bi.bonded(a1, a2);
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
// not found in our cache, calculate
|
||||
CompoundBondInfo bondInfo{ id };
|
||||
CompoundBondInfo bondInfo{id};
|
||||
|
||||
auto compound = mmcif::CompoundFactory::instance().create(compoundID);
|
||||
if (not compound)
|
||||
std::cerr << "Missing compound bond info for " << compoundID << std::endl;
|
||||
else
|
||||
{
|
||||
for (auto &atom: compound->bonds())
|
||||
for (auto &atom : compound->bonds())
|
||||
{
|
||||
uint32_t ca1 = getAtomID(atom.atomID[0]);
|
||||
uint32_t ca2 = getAtomID(atom.atomID[1]);
|
||||
if (ca1 > ca2)
|
||||
std::swap(ca1, ca2);
|
||||
|
||||
|
||||
bondInfo.mBonded.insert({ca1, ca2});
|
||||
result = result or (a1 == ca1 and a2 == ca2);
|
||||
}
|
||||
@@ -348,27 +202,27 @@ bool CompoundBondMap::bonded(const std::string &compoundID, const std::string& a
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BondMap::BondMap(const Structure& p)
|
||||
BondMap::BondMap(const Structure &p)
|
||||
{
|
||||
auto& compoundBondInfo = CompoundBondMap::instance();
|
||||
auto &compoundBondInfo = CompoundBondMap::instance();
|
||||
|
||||
auto atoms = p.atoms();
|
||||
dim = uint32_t(atoms.size());
|
||||
|
||||
// bond = std::vector<bool>(dim * (dim - 1), false);
|
||||
// bond = std::vector<bool>(dim * (dim - 1), false);
|
||||
|
||||
for (auto& atom: atoms)
|
||||
for (auto &atom : atoms)
|
||||
index[atom.id()] = uint32_t(index.size());
|
||||
|
||||
auto bindAtoms = [this](const std::string& a, const std::string& b)
|
||||
|
||||
auto bindAtoms = [this](const std::string &a, const std::string &b)
|
||||
{
|
||||
uint32_t ixa = index[a];
|
||||
uint32_t ixb = index[b];
|
||||
|
||||
|
||||
bond.insert(key(ixa, ixb));
|
||||
};
|
||||
|
||||
auto linkAtoms = [this,&bindAtoms](const std::string& a, const std::string& b)
|
||||
auto linkAtoms = [this, &bindAtoms](const std::string &a, const std::string &b)
|
||||
{
|
||||
bindAtoms(a, b);
|
||||
|
||||
@@ -376,20 +230,20 @@ BondMap::BondMap(const Structure& p)
|
||||
link[b].insert(a);
|
||||
};
|
||||
|
||||
cif::Datablock& db = p.getFile().data();
|
||||
cif::Datablock &db = p.getFile().data();
|
||||
|
||||
// collect all compounds first
|
||||
std::set<std::string> compounds;
|
||||
for (auto c: db["chem_comp"])
|
||||
for (auto c : db["chem_comp"])
|
||||
compounds.insert(c["id"].as<std::string>());
|
||||
|
||||
|
||||
// make sure we also have all residues in the polyseq
|
||||
for (auto m: db["entity_poly_seq"])
|
||||
for (auto m : db["entity_poly_seq"])
|
||||
{
|
||||
std::string c = m["mon_id"].as<std::string>();
|
||||
if (compounds.count(c))
|
||||
continue;
|
||||
|
||||
|
||||
if (cif::VERBOSE > 1)
|
||||
std::cerr << "Warning: mon_id " << c << " is missing in the chem_comp category" << std::endl;
|
||||
compounds.insert(c);
|
||||
@@ -398,59 +252,59 @@ BondMap::BondMap(const Structure& p)
|
||||
cif::Progress progress(compounds.size(), "Creating bond map");
|
||||
|
||||
// some helper indices to speed things up a bit
|
||||
std::map<std::tuple<std::string,int,std::string>,std::string> atomMapByAsymSeqAndAtom;
|
||||
for (auto& a: p.atoms())
|
||||
std::map<std::tuple<std::string, int, std::string>, std::string> atomMapByAsymSeqAndAtom;
|
||||
for (auto &a : p.atoms())
|
||||
{
|
||||
auto key = make_tuple(a.labelAsymID(), a.labelSeqID(), a.labelAtomID());
|
||||
atomMapByAsymSeqAndAtom[key] = a.id();
|
||||
}
|
||||
|
||||
|
||||
// first link all residues in a polyseq
|
||||
|
||||
|
||||
std::string lastAsymID;
|
||||
int lastSeqID = 0;
|
||||
for (auto r: db["pdbx_poly_seq_scheme"])
|
||||
for (auto r : db["pdbx_poly_seq_scheme"])
|
||||
{
|
||||
std::string asymID;
|
||||
int seqID;
|
||||
|
||||
cif::tie(asymID, seqID) = r.get("asym_id", "seq_id");
|
||||
|
||||
if (asymID != lastAsymID) // first in a new sequece
|
||||
if (asymID != lastAsymID) // first in a new sequece
|
||||
{
|
||||
lastAsymID = asymID;
|
||||
lastSeqID = seqID;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
auto c = atomMapByAsymSeqAndAtom[make_tuple(asymID, lastSeqID, "C")];
|
||||
auto n = atomMapByAsymSeqAndAtom[make_tuple(asymID, seqID, "N")];
|
||||
|
||||
if (not (c.empty() or n.empty()))
|
||||
if (not(c.empty() or n.empty()))
|
||||
bindAtoms(c, n);
|
||||
|
||||
|
||||
lastSeqID = seqID;
|
||||
}
|
||||
|
||||
for (auto l: db["struct_conn"])
|
||||
for (auto l : db["struct_conn"])
|
||||
{
|
||||
std::string asym1, asym2, atomId1, atomId2;
|
||||
int seqId1 = 0, seqId2 = 0;
|
||||
cif::tie(asym1, asym2, atomId1, atomId2, seqId1, seqId2) =
|
||||
l.get("ptnr1_label_asym_id", "ptnr2_label_asym_id",
|
||||
"ptnr1_label_atom_id", "ptnr2_label_atom_id",
|
||||
"ptnr1_label_seq_id", "ptnr2_label_seq_id");
|
||||
"ptnr1_label_atom_id", "ptnr2_label_atom_id",
|
||||
"ptnr1_label_seq_id", "ptnr2_label_seq_id");
|
||||
|
||||
std::string a = atomMapByAsymSeqAndAtom[make_tuple(asym1, seqId1, atomId1)];
|
||||
std::string b = atomMapByAsymSeqAndAtom[make_tuple(asym2, seqId2, atomId2)];
|
||||
|
||||
if (not (a.empty() or b.empty()))
|
||||
|
||||
if (not(a.empty() or b.empty()))
|
||||
linkAtoms(a, b);
|
||||
}
|
||||
|
||||
// then link all atoms in the compounds
|
||||
|
||||
for (auto c: compounds)
|
||||
|
||||
for (auto c : compounds)
|
||||
{
|
||||
if (c == "HOH" or c == "H2O" or c == "WAT")
|
||||
{
|
||||
@@ -459,7 +313,7 @@ BondMap::BondMap(const Structure& p)
|
||||
continue;
|
||||
}
|
||||
|
||||
auto bonded = [c, &compoundBondInfo](const Atom& a, const Atom& b)
|
||||
auto bonded = [c, &compoundBondInfo](const Atom &a, const Atom &b)
|
||||
{
|
||||
auto label_a = a.labelAtomID();
|
||||
auto label_b = b.labelAtomID();
|
||||
@@ -468,16 +322,17 @@ BondMap::BondMap(const Structure& p)
|
||||
};
|
||||
|
||||
// loop over poly_seq_scheme
|
||||
for (auto r: db["pdbx_poly_seq_scheme"].find(cif::Key("mon_id") == c))
|
||||
for (auto r : db["pdbx_poly_seq_scheme"].find(cif::Key("mon_id") == c))
|
||||
{
|
||||
std::string asymID;
|
||||
int seqID;
|
||||
cif::tie(asymID, seqID) = r.get("asym_id", "seq_id");
|
||||
|
||||
|
||||
std::vector<Atom> rAtoms;
|
||||
copy_if(atoms.begin(), atoms.end(), back_inserter(rAtoms),
|
||||
[&](auto& a) { return a.labelAsymID() == asymID and a.labelSeqID() == seqID; });
|
||||
|
||||
[&](auto &a)
|
||||
{ return a.labelAsymID() == asymID and a.labelSeqID() == seqID; });
|
||||
|
||||
for (uint32_t i = 0; i + 1 < rAtoms.size(); ++i)
|
||||
{
|
||||
for (uint32_t j = i + 1; j < rAtoms.size(); ++j)
|
||||
@@ -489,15 +344,16 @@ BondMap::BondMap(const Structure& p)
|
||||
}
|
||||
|
||||
// loop over pdbx_nonpoly_scheme
|
||||
for (auto r: db["pdbx_nonpoly_scheme"].find(cif::Key("mon_id") == c))
|
||||
for (auto r : db["pdbx_nonpoly_scheme"].find(cif::Key("mon_id") == c))
|
||||
{
|
||||
std::string asymID;
|
||||
cif::tie(asymID) = r.get("asym_id");
|
||||
|
||||
|
||||
std::vector<Atom> rAtoms;
|
||||
copy_if(atoms.begin(), atoms.end(), back_inserter(rAtoms),
|
||||
[&](auto& a) { return a.labelAsymID() == asymID; });
|
||||
|
||||
[&](auto &a)
|
||||
{ return a.labelAsymID() == asymID; });
|
||||
|
||||
for (uint32_t i = 0; i + 1 < rAtoms.size(); ++i)
|
||||
{
|
||||
for (uint32_t j = i + 1; j < rAtoms.size(); ++j)
|
||||
@@ -506,7 +362,7 @@ BondMap::BondMap(const Structure& p)
|
||||
{
|
||||
uint32_t ixa = index[rAtoms[i].id()];
|
||||
uint32_t ixb = index[rAtoms[j].id()];
|
||||
|
||||
|
||||
bond.insert(key(ixa, ixb));
|
||||
}
|
||||
}
|
||||
@@ -514,15 +370,16 @@ BondMap::BondMap(const Structure& p)
|
||||
}
|
||||
|
||||
// loop over pdbx_branch_scheme
|
||||
for (auto r: db["pdbx_branch_scheme"].find(cif::Key("mon_id") == c))
|
||||
for (auto r : db["pdbx_branch_scheme"].find(cif::Key("mon_id") == c))
|
||||
{
|
||||
std::string asymID;
|
||||
cif::tie(asymID) = r.get("asym_id");
|
||||
|
||||
|
||||
std::vector<Atom> rAtoms;
|
||||
copy_if(atoms.begin(), atoms.end(), back_inserter(rAtoms),
|
||||
[&](auto& a) { return a.labelAsymID() == asymID; });
|
||||
|
||||
[&](auto &a)
|
||||
{ return a.labelAsymID() == asymID; });
|
||||
|
||||
for (uint32_t i = 0; i + 1 < rAtoms.size(); ++i)
|
||||
{
|
||||
for (uint32_t j = i + 1; j < rAtoms.size(); ++j)
|
||||
@@ -531,31 +388,31 @@ BondMap::BondMap(const Structure& p)
|
||||
{
|
||||
uint32_t ixa = index[rAtoms[i].id()];
|
||||
uint32_t ixb = index[rAtoms[j].id()];
|
||||
|
||||
|
||||
bond.insert(key(ixa, ixb));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// start by creating an index for single bonds
|
||||
|
||||
std::multimap<uint32_t,uint32_t> b1_2;
|
||||
for (auto& bk: bond)
|
||||
|
||||
std::multimap<uint32_t, uint32_t> b1_2;
|
||||
for (auto &bk : bond)
|
||||
{
|
||||
uint32_t a, b;
|
||||
std::tie(a, b) = dekey(bk);
|
||||
|
||||
b1_2.insert({ a, b });
|
||||
b1_2.insert({ b, a });
|
||||
|
||||
b1_2.insert({a, b});
|
||||
b1_2.insert({b, a});
|
||||
}
|
||||
|
||||
std::multimap<uint32_t,uint32_t> b1_3;
|
||||
|
||||
std::multimap<uint32_t, uint32_t> b1_3;
|
||||
for (uint32_t i = 0; i < dim; ++i)
|
||||
{
|
||||
auto a = b1_2.equal_range(i);
|
||||
|
||||
|
||||
std::vector<uint32_t> s;
|
||||
for (auto j = a.first; j != a.second; ++j)
|
||||
s.push_back(j->second);
|
||||
@@ -566,12 +423,12 @@ BondMap::BondMap(const Structure& p)
|
||||
{
|
||||
uint32_t x = s[si1];
|
||||
uint32_t y = s[si2];
|
||||
|
||||
|
||||
if (isBonded(x, y))
|
||||
continue;
|
||||
|
||||
b1_3.insert({ x, y });
|
||||
b1_3.insert({ y, x });
|
||||
|
||||
b1_3.insert({x, y});
|
||||
b1_3.insert({y, x});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,48 +437,48 @@ BondMap::BondMap(const Structure& p)
|
||||
{
|
||||
auto a1 = b1_2.equal_range(i);
|
||||
auto a2 = b1_3.equal_range(i);
|
||||
|
||||
|
||||
for (auto ai1 = a1.first; ai1 != a1.second; ++ai1)
|
||||
{
|
||||
for (auto ai2 = a2.first; ai2 != a2.second; ++ai2)
|
||||
{
|
||||
uint32_t b1 = ai1->second;
|
||||
uint32_t b2 = ai2->second;
|
||||
|
||||
|
||||
if (isBonded(b1, b2))
|
||||
continue;
|
||||
|
||||
|
||||
bond_1_4.insert(key(b1, b2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> BondMap::linked(const Atom& a) const
|
||||
std::vector<std::string> BondMap::linked(const Atom &a) const
|
||||
{
|
||||
auto i = link.find(a.id());
|
||||
|
||||
|
||||
std::vector<std::string> result;
|
||||
|
||||
|
||||
if (i != link.end())
|
||||
result = std::vector<std::string>(i->second.begin(), i->second.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> BondMap::atomIDsForCompound(const std::string& compoundID)
|
||||
std::vector<std::string> BondMap::atomIDsForCompound(const std::string &compoundID)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
auto* compound = mmcif::CompoundFactory::instance().create(compoundID);
|
||||
auto *compound = mmcif::CompoundFactory::instance().create(compoundID);
|
||||
|
||||
if (compound == nullptr)
|
||||
throw BondMapException("Missing bond information for compound " + compoundID);
|
||||
|
||||
for (auto& compAtom: compound->atoms())
|
||||
for (auto &compAtom : compound->atoms())
|
||||
result.push_back(compAtom.id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mmcif
|
||||
|
||||
404
src/Cif++.cpp
404
src/Cif++.cpp
@@ -33,6 +33,7 @@
|
||||
#include <stack>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
@@ -351,7 +352,7 @@ namespace detail
|
||||
// --------------------------------------------------------------------
|
||||
// Datablock implementation
|
||||
|
||||
Datablock::Datablock(const std::string &name)
|
||||
Datablock::Datablock(const std::string_view name)
|
||||
: mName(name)
|
||||
, mValidator(nullptr)
|
||||
, mNext(nullptr)
|
||||
@@ -363,70 +364,81 @@ Datablock::~Datablock()
|
||||
delete mNext;
|
||||
}
|
||||
|
||||
std::string Datablock::firstItem(const std::string &tag) const
|
||||
auto Datablock::emplace(std::string_view name) -> std::tuple<iterator, bool>
|
||||
{
|
||||
std::string result;
|
||||
// LRU code
|
||||
|
||||
std::string catName, itemName;
|
||||
std::tie(catName, itemName) = splitTagName(tag);
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
for (auto &cat : mCategories)
|
||||
bool isNew = true;
|
||||
|
||||
auto i = begin();
|
||||
while (i != end())
|
||||
{
|
||||
if (iequals(cat.name(), catName))
|
||||
if (iequals(name, i->name()))
|
||||
{
|
||||
for (auto row : cat)
|
||||
isNew = false;
|
||||
|
||||
if (i != begin())
|
||||
{
|
||||
result = row[itemName].as<std::string>();
|
||||
break;
|
||||
auto n = std::next(i);
|
||||
mCategories.splice(begin(), mCategories, i, n);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Datablock::emplace(const std::string &name) -> std::tuple<iterator, bool>
|
||||
{
|
||||
bool isNew = false;
|
||||
iterator i = find_if(begin(), end(), [name](const Category &cat) -> bool
|
||||
{ return iequals(cat.name(), name); });
|
||||
|
||||
if (i == end())
|
||||
if (isNew)
|
||||
{
|
||||
isNew = true;
|
||||
i = mCategories.emplace(end(), *this, name, mValidator);
|
||||
mCategories.emplace(begin(), *this, std::string(name), mValidator);
|
||||
|
||||
for (auto &cat : mCategories)
|
||||
cat.updateLinks();
|
||||
}
|
||||
|
||||
return std::make_tuple(i, isNew);
|
||||
return std::make_tuple(begin(), isNew);
|
||||
}
|
||||
|
||||
Category &Datablock::operator[](const std::string &name)
|
||||
Category &Datablock::operator[](std::string_view name)
|
||||
{
|
||||
iterator i;
|
||||
std::tie(i, std::ignore) = emplace(name);
|
||||
return *i;
|
||||
}
|
||||
|
||||
Category *Datablock::get(const std::string &name)
|
||||
Category *Datablock::get(std::string_view name)
|
||||
{
|
||||
auto i = find_if(begin(), end(), [name](const Category &cat) -> bool
|
||||
{ return iequals(cat.name(), name); });
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
return i == end() ? nullptr : &*i;
|
||||
for (auto &cat : mCategories)
|
||||
{
|
||||
if (iequals(cat.name(), name))
|
||||
return &cat;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Category *Datablock::get(const std::string &name) const
|
||||
const Category *Datablock::get(std::string_view name) const
|
||||
{
|
||||
auto i = find_if(begin(), end(), [name](const Category &cat) -> bool
|
||||
{ return iequals(cat.name(), name); });
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
return i == end() ? nullptr : &*i;
|
||||
for (auto &cat : mCategories)
|
||||
{
|
||||
if (iequals(cat.name(), name))
|
||||
return &cat;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Datablock::isValid()
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
if (mValidator == nullptr)
|
||||
throw std::runtime_error("Validator not specified");
|
||||
|
||||
@@ -438,20 +450,26 @@ bool Datablock::isValid()
|
||||
|
||||
void Datablock::validateLinks() const
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
for (auto &cat : *this)
|
||||
cat.validateLinks();
|
||||
}
|
||||
|
||||
void Datablock::setValidator(Validator *v)
|
||||
void Datablock::setValidator(const Validator *v)
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
mValidator = v;
|
||||
|
||||
for (auto &cat : *this)
|
||||
cat.setValidator(v);
|
||||
}
|
||||
|
||||
void Datablock::add_software(const std::string &name, const std::string &classification, const std::string &versionNr, const std::string &versionDate)
|
||||
void Datablock::add_software(const std::string_view name, const std::string &classification, const std::string &versionNr, const std::string &versionDate)
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
Category &cat = operator[]("software");
|
||||
auto ordNr = cat.size() + 1;
|
||||
// TODO: should we check this ordinal number???
|
||||
@@ -465,12 +483,16 @@ void Datablock::add_software(const std::string &name, const std::string &classif
|
||||
|
||||
void Datablock::getTagOrder(std::vector<std::string> &tags) const
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
for (auto &cat : *this)
|
||||
cat.getTagOrder(tags);
|
||||
}
|
||||
|
||||
void Datablock::write(std::ostream &os)
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
os << "data_" << mName << std::endl
|
||||
<< "# " << std::endl;
|
||||
|
||||
@@ -505,6 +527,8 @@ void Datablock::write(std::ostream &os)
|
||||
|
||||
void Datablock::write(std::ostream &os, const std::vector<std::string> &order)
|
||||
{
|
||||
std::shared_lock lock(mLock);
|
||||
|
||||
os << "data_" << mName << std::endl
|
||||
<< "# " << std::endl;
|
||||
|
||||
@@ -580,6 +604,11 @@ void Datablock::write(std::ostream &os, const std::vector<std::string> &order)
|
||||
|
||||
bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
std::shared_lock lockA(dbA.mLock);
|
||||
std::shared_lock lockB(dbB.mLock);
|
||||
|
||||
std::vector<std::string> catA, catB;
|
||||
|
||||
for (auto &cat : dbA)
|
||||
@@ -605,14 +634,59 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB)
|
||||
|
||||
while (catA_i != catA.end() and catB_i != catB.end())
|
||||
{
|
||||
if (not iequals(*catA_i, *catB_i))
|
||||
return false;
|
||||
std::string nA = *catA_i;
|
||||
ba::to_lower(nA);
|
||||
|
||||
std::string nB = *catB_i;
|
||||
ba::to_lower(nB);
|
||||
|
||||
int d = nA.compare(nB);
|
||||
if (d > 0)
|
||||
{
|
||||
auto cat = dbB.get(*catB_i);
|
||||
|
||||
if (cat == nullptr)
|
||||
missingA.push_back(*catB_i);
|
||||
|
||||
++catA_i, ++catB_i;
|
||||
++catB_i;
|
||||
}
|
||||
else if (d < 0)
|
||||
{
|
||||
auto cat = dbA.get(*catA_i);
|
||||
|
||||
if (cat == nullptr)
|
||||
missingB.push_back(*catA_i);
|
||||
|
||||
++catA_i;
|
||||
}
|
||||
else
|
||||
++catA_i, ++catB_i;
|
||||
}
|
||||
|
||||
while (catA_i != catA.end())
|
||||
missingB.push_back(*catA_i++);
|
||||
|
||||
if (catA_i != catA.end() or catB_i != catB.end())
|
||||
return false;
|
||||
while (catB_i != catB.end())
|
||||
missingA.push_back(*catB_i++);
|
||||
|
||||
if (not (missingA.empty() and missingB.empty()))
|
||||
{
|
||||
if (cif::VERBOSE > 1)
|
||||
{
|
||||
std::cerr << "compare of datablocks failed" << std::endl;
|
||||
if (not missingA.empty())
|
||||
std::cerr << "Categories missing in A: " << ba::join(missingA, ", ") << std::endl
|
||||
<< std::endl;
|
||||
|
||||
if (not missingB.empty())
|
||||
std::cerr << "Categories missing in B: " << ba::join(missingB, ", ") << std::endl
|
||||
<< std::endl;
|
||||
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Second loop, now compare category values
|
||||
catA_i = catA.begin(), catB_i = catB.begin();
|
||||
@@ -633,13 +707,21 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB)
|
||||
else
|
||||
{
|
||||
if (not (*dbA.get(*catA_i) == *dbB.get(*catB_i)))
|
||||
return false;
|
||||
{
|
||||
if (cif::VERBOSE > 1)
|
||||
{
|
||||
std::cerr << "Compare of datablocks failed due to unequal values in category " << *catA_i << std::endl;
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
++catA_i;
|
||||
++catB_i;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const Datablock &data)
|
||||
@@ -1311,7 +1393,7 @@ RowSet &RowSet::orderBy(std::initializer_list<std::string> items)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
Category::Category(Datablock &db, const std::string &name, Validator *Validator)
|
||||
Category::Category(Datablock &db, const std::string_view name, const Validator *Validator)
|
||||
: mDb(db)
|
||||
, mName(name)
|
||||
, mValidator(Validator)
|
||||
@@ -1346,7 +1428,7 @@ Category::~Category()
|
||||
delete mIndex;
|
||||
}
|
||||
|
||||
void Category::setValidator(Validator *v)
|
||||
void Category::setValidator(const Validator *v)
|
||||
{
|
||||
mValidator = v;
|
||||
|
||||
@@ -1371,14 +1453,41 @@ void Category::setValidator(Validator *v)
|
||||
}
|
||||
else
|
||||
mCatValidator = nullptr;
|
||||
|
||||
updateLinks();
|
||||
}
|
||||
|
||||
bool Category::hasColumn(const std::string &name) const
|
||||
void Category::updateLinks()
|
||||
{
|
||||
mChildLinks.clear();
|
||||
mParentLinks.clear();
|
||||
|
||||
if (mValidator != nullptr)
|
||||
{
|
||||
for (auto link : mValidator->getLinksForParent(mName))
|
||||
{
|
||||
auto childCat = mDb.get(link->mChildCategory);
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
mChildLinks.push_back({ childCat, link });
|
||||
}
|
||||
|
||||
for (auto link : mValidator->getLinksForChild(mName))
|
||||
{
|
||||
auto parentCat = mDb.get(link->mParentCategory);
|
||||
if (parentCat == nullptr)
|
||||
continue;
|
||||
mParentLinks.push_back({ parentCat, link });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Category::hasColumn(std::string_view name) const
|
||||
{
|
||||
return getColumnIndex(name) < mColumns.size();
|
||||
}
|
||||
|
||||
size_t Category::getColumnIndex(const std::string &name) const
|
||||
size_t Category::getColumnIndex(std::string_view name) const
|
||||
{
|
||||
size_t result;
|
||||
|
||||
@@ -1392,7 +1501,7 @@ size_t Category::getColumnIndex(const std::string &name) const
|
||||
{
|
||||
auto iv = mCatValidator->getValidatorForItem(name);
|
||||
if (iv == nullptr)
|
||||
std::cerr << "Invalid name used '" + name + "' is not a known column in " + mName << std::endl;
|
||||
std::cerr << "Invalid name used '" << name << "' is not a known column in " + mName << std::endl;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1411,8 +1520,10 @@ std::vector<std::string> Category::getColumnNames() const
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t Category::addColumn(const std::string &name)
|
||||
size_t Category::addColumn(std::string_view name)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
size_t result = getColumnIndex(name);
|
||||
|
||||
if (result == mColumns.size())
|
||||
@@ -1423,10 +1534,10 @@ size_t Category::addColumn(const std::string &name)
|
||||
{
|
||||
itemValidator = mCatValidator->getValidatorForItem(name);
|
||||
if (itemValidator == nullptr)
|
||||
mValidator->reportError("tag " + name + " not allowed in Category " + mName, false);
|
||||
mValidator->reportError("tag " + std::string(name) + " not allowed in Category " + mName, false);
|
||||
}
|
||||
|
||||
mColumns.push_back({name, itemValidator});
|
||||
mColumns.push_back(ItemColumn{std::string(name), itemValidator});
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1814,12 +1925,8 @@ auto Category::erase(iterator pos) -> iterator
|
||||
|
||||
if (mValidator != nullptr)
|
||||
{
|
||||
for (auto &link : mValidator->getLinksForParent(mName))
|
||||
for (auto &&[childCat, link] : mChildLinks)
|
||||
{
|
||||
auto childCat = mDb.get(link->mChildCategory);
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
|
||||
Condition cond;
|
||||
|
||||
for (size_t ix = 0; ix < link->mParentKeys.size(); ++ix)
|
||||
@@ -1957,12 +2064,8 @@ bool Category::isOrphan(Row r)
|
||||
return false;
|
||||
|
||||
bool isOrphan = true;
|
||||
for (auto &link : mValidator->getLinksForChild(mName))
|
||||
for (auto &&[parentCat, link] : mParentLinks)
|
||||
{
|
||||
auto parentCat = mDb.get(link->mParentCategory);
|
||||
if (parentCat == nullptr)
|
||||
continue;
|
||||
|
||||
Condition cond;
|
||||
for (size_t ix = 0; ix < link->mChildKeys.size(); ++ix)
|
||||
{
|
||||
@@ -1993,12 +2096,8 @@ bool Category::hasChildren(Row r) const
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (auto &link : mValidator->getLinksForParent(mName))
|
||||
for (auto &&[childCat, link] : mChildLinks)
|
||||
{
|
||||
auto childCat = mDb.get(link->mChildCategory);
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
|
||||
Condition cond;
|
||||
|
||||
for (size_t ix = 0; ix < link->mParentKeys.size(); ++ix)
|
||||
@@ -2024,12 +2123,8 @@ bool Category::hasParents(Row r) const
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (auto &link : mValidator->getLinksForChild(mName))
|
||||
for (auto &&[parentCat, link] : mParentLinks)
|
||||
{
|
||||
auto parentCat = mDb.get(link->mParentCategory);
|
||||
if (parentCat == nullptr)
|
||||
continue;
|
||||
|
||||
Condition cond;
|
||||
|
||||
for (size_t ix = 0; ix < link->mChildKeys.size(); ++ix)
|
||||
@@ -2238,23 +2333,17 @@ bool Category::isValid()
|
||||
|
||||
void Category::validateLinks() const
|
||||
{
|
||||
auto &validator = getValidator();
|
||||
|
||||
for (auto linkValidator : validator.getLinksForChild(mName))
|
||||
for (auto &&[parentCat, link] : mParentLinks)
|
||||
{
|
||||
auto parent = mDb.get(linkValidator->mParentCategory);
|
||||
if (parent == nullptr)
|
||||
continue;
|
||||
|
||||
size_t missing = 0;
|
||||
for (auto r : *this)
|
||||
if (not hasParent(r, *parent, *linkValidator))
|
||||
if (not hasParent(r, *parentCat, *link))
|
||||
++missing;
|
||||
|
||||
if (missing)
|
||||
{
|
||||
std::cerr << "Links for " << linkValidator->mLinkGroupLabel << " are incomplete" << std::endl
|
||||
<< " There are " << missing << " items in " << mName << " that don't have matching parent items in " << parent->mName << std::endl;
|
||||
std::cerr << "Links for " << link->mLinkGroupLabel << " are incomplete" << std::endl
|
||||
<< " There are " << missing << " items in " << mName << " that don't have matching parent items in " << parentCat->mName << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2320,7 +2409,9 @@ std::set<size_t> Category::keyFieldsByIndex() const
|
||||
bool operator==(const Category &a, const Category &b)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
|
||||
bool result = true;
|
||||
|
||||
// set<std::string> tagsA(a.fields()), tagsB(b.fields());
|
||||
//
|
||||
// if (tagsA != tagsB)
|
||||
@@ -2354,7 +2445,7 @@ bool operator==(const Category &a, const Category &b)
|
||||
// a.reorderByIndex();
|
||||
// b.reorderByIndex();
|
||||
|
||||
auto rowEqual = [&](const cif::Row& a, const cif::Row& b)
|
||||
auto rowEqual = [&](const cif::Row& ra, const cif::Row& rb)
|
||||
{
|
||||
int d = 0;
|
||||
|
||||
@@ -2365,10 +2456,14 @@ bool operator==(const Category &a, const Category &b)
|
||||
|
||||
std::tie(tag, compare) = tags[kix];
|
||||
|
||||
d = compare(a[tag].c_str(), b[tag].c_str());
|
||||
d = compare(ra[tag].c_str(), rb[tag].c_str());
|
||||
|
||||
if (d != 0)
|
||||
{
|
||||
if (cif::VERBOSE > 1)
|
||||
std::cerr << "Values in _" << a.name() << '.' << tag << " are not equal: '" << ra[tag].c_str() << "' != '" << rb[tag].c_str() << '\'' << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return d == 0;
|
||||
@@ -2378,12 +2473,26 @@ bool operator==(const Category &a, const Category &b)
|
||||
while (ai != a.end() or bi != b.end())
|
||||
{
|
||||
if (ai == a.end() or bi == b.end())
|
||||
return false;
|
||||
{
|
||||
if (cif::VERBOSE > 1)
|
||||
{
|
||||
std::cerr << "Unequal number of rows in " << a.name() << std::endl;
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
cif::Row ra = *ai, rb = *bi;
|
||||
|
||||
if (not rowEqual(ra, rb))
|
||||
return false;
|
||||
{
|
||||
if (cif::VERBOSE > 1)
|
||||
result = false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> missingA, missingB, different;
|
||||
|
||||
@@ -2400,14 +2509,22 @@ bool operator==(const Category &a, const Category &b)
|
||||
const char* tb = rb[tag].c_str(); if (strcmp(tb, ".") == 0 or strcmp(tb, "?") == 0) tb = "";
|
||||
|
||||
if (compare(ta, tb) != 0)
|
||||
return false;
|
||||
{
|
||||
if (cif::VERBOSE > 1)
|
||||
{
|
||||
std::cerr << "Values in _" << a.name() << '.' << tag << " are not equal: '" << ta << "' != '" << tb << '\'' << std::endl;
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
++ai;
|
||||
++bi;
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// auto Category::iterator::operator++() -> iterator&
|
||||
@@ -2695,17 +2812,10 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
|
||||
row.assign(colIx, value, true);
|
||||
|
||||
// see if we need to update any child categories that depend on this value
|
||||
auto &validator = getValidator();
|
||||
auto &db = mDb;
|
||||
|
||||
for (auto parent : rows)
|
||||
{
|
||||
for (auto linked : validator.getLinksForParent(mName))
|
||||
for (auto &&[childCat, linked] : mChildLinks)
|
||||
{
|
||||
auto childCat = db.get(linked->mChildCategory);
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
|
||||
if (std::find(linked->mParentKeys.begin(), linked->mParentKeys.end(), tag) == linked->mParentKeys.end())
|
||||
continue;
|
||||
|
||||
@@ -2862,18 +2972,8 @@ void Row::assign(const std::vector<Item> &values)
|
||||
// auto iv = col.mValidator;
|
||||
if (mCascade)
|
||||
{
|
||||
auto &validator = cat->getValidator();
|
||||
auto &db = cat->db();
|
||||
|
||||
for (auto linked : validator.getLinksForParent(cat->mName))
|
||||
for (auto &&[childCat, linked] : cat->mChildLinks)
|
||||
{
|
||||
auto childCat = db.get(linked->mChildCategory);
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
|
||||
// if (find(linked->mParentKeys.begin(), linked->mParentKeys.end(), iv->mTag) == linked->mParentKeys.end())
|
||||
// continue;
|
||||
|
||||
Condition cond;
|
||||
std::string childTag;
|
||||
|
||||
@@ -2909,7 +3009,7 @@ void Row::assign(const Item &value, bool skipUpdateLinked)
|
||||
assign(value.name(), value.value(), skipUpdateLinked);
|
||||
}
|
||||
|
||||
void Row::assign(const std::string &name, const std::string &value, bool skipUpdateLinked)
|
||||
void Row::assign(std::string_view name, const std::string &value, bool skipUpdateLinked)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -3014,15 +3114,8 @@ void Row::assign(size_t column, const std::string &value, bool skipUpdateLinked)
|
||||
auto iv = col.mValidator;
|
||||
if (not skipUpdateLinked and iv != nullptr and mCascade)
|
||||
{
|
||||
auto &validator = cat->getValidator();
|
||||
auto &db = cat->db();
|
||||
|
||||
for (auto linked : validator.getLinksForParent(cat->mName))
|
||||
for (auto &&[childCat, linked] : cat->mChildLinks)
|
||||
{
|
||||
auto childCat = db.get(linked->mChildCategory);
|
||||
if (childCat == nullptr)
|
||||
continue;
|
||||
|
||||
if (find(linked->mParentKeys.begin(), linked->mParentKeys.end(), iv->mTag) == linked->mParentKeys.end())
|
||||
continue;
|
||||
|
||||
@@ -3201,18 +3294,13 @@ void Row::swap(size_t cix, ItemRow *a, ItemRow *b)
|
||||
auto parentColName = cat->getColumnName(cix);
|
||||
|
||||
// see if we need to update any child categories that depend on these values
|
||||
auto &validator = cat->getValidator();
|
||||
auto parentCatValidator = cat->getCatValidator();
|
||||
|
||||
for (auto &link : validator.getLinksForParent(cat->mName))
|
||||
for (auto &&[childCat, link] : cat->mChildLinks)
|
||||
{
|
||||
if (find(link->mParentKeys.begin(), link->mParentKeys.end(), parentColName) == link->mParentKeys.end())
|
||||
continue;
|
||||
|
||||
auto childCat = cat->db().get(link->mChildCategory);
|
||||
if (childCat == nullptr or childCat->empty())
|
||||
continue;
|
||||
|
||||
auto childCatValidator = childCat->getCatValidator();
|
||||
if (childCatValidator == nullptr)
|
||||
continue;
|
||||
@@ -3309,7 +3397,7 @@ void Row::swap(size_t cix, ItemRow *a, ItemRow *b)
|
||||
}
|
||||
}
|
||||
|
||||
size_t Row::ColumnForItemTag(const char *itemTag) const
|
||||
size_t Row::ColumnForItemTag(std::string_view itemTag) const
|
||||
{
|
||||
size_t result = 0;
|
||||
if (mData != nullptr)
|
||||
@@ -3424,7 +3512,6 @@ File::File(File &&rhs)
|
||||
File::~File()
|
||||
{
|
||||
delete mHead;
|
||||
delete mValidator;
|
||||
}
|
||||
|
||||
void File::append(Datablock *e)
|
||||
@@ -3501,7 +3588,7 @@ void File::save(const std::filesystem::path &p)
|
||||
|
||||
void File::load(std::istream &is)
|
||||
{
|
||||
Validator *saved = mValidator;
|
||||
auto saved = mValidator;
|
||||
setValidator(nullptr);
|
||||
|
||||
Parser p(is, *this);
|
||||
@@ -3516,7 +3603,7 @@ void File::load(std::istream &is)
|
||||
|
||||
void File::load(std::istream &is, const std::string &datablock)
|
||||
{
|
||||
Validator *saved = mValidator;
|
||||
auto saved = mValidator;
|
||||
setValidator(nullptr);
|
||||
|
||||
Parser p(is, *this);
|
||||
@@ -3549,7 +3636,7 @@ void File::write(std::ostream &os, const std::vector<std::string> &order)
|
||||
}
|
||||
}
|
||||
|
||||
Datablock *File::get(const std::string &name) const
|
||||
Datablock *File::get(std::string_view name) const
|
||||
{
|
||||
const Datablock *result = mHead;
|
||||
while (result != nullptr and not iequals(result->mName, name))
|
||||
@@ -3557,13 +3644,15 @@ Datablock *File::get(const std::string &name) const
|
||||
return const_cast<Datablock *>(result);
|
||||
}
|
||||
|
||||
Datablock &File::operator[](const std::string &name)
|
||||
Datablock &File::operator[](std::string_view name)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
Datablock *result = mHead;
|
||||
while (result != nullptr and not iequals(result->mName, name))
|
||||
result = result->mNext;
|
||||
if (result == nullptr)
|
||||
throw std::runtime_error("Datablock " + name + " does not exist");
|
||||
throw std::runtime_error("Datablock " + std::string(name) + " does not exist");
|
||||
return *result;
|
||||
}
|
||||
|
||||
@@ -3603,67 +3692,10 @@ void File::loadDictionary()
|
||||
|
||||
void File::loadDictionary(const char *dict)
|
||||
{
|
||||
fs::path dict_name(dict);
|
||||
|
||||
auto data = loadResource(dict);
|
||||
|
||||
if (not data and dict_name.extension().string() != ".dic")
|
||||
data = loadResource(dict_name.parent_path() / (dict_name.filename().string() + ".dic"));
|
||||
|
||||
if (data)
|
||||
loadDictionary(*data);
|
||||
else
|
||||
{
|
||||
// might be a compressed dictionary on disk
|
||||
fs::path p = dict;
|
||||
if (p.extension() == ".dic")
|
||||
p = p.parent_path() / (p.filename().string() + ".gz");
|
||||
else
|
||||
p = p.parent_path() / (p.filename().string() + ".dic.gz");
|
||||
|
||||
#if defined(CACHE_DIR) and defined(DATA_DIR)
|
||||
if (not fs::exists(p))
|
||||
{
|
||||
for (const char *dir : {CACHE_DIR, DATA_DIR})
|
||||
{
|
||||
auto p2 = fs::path(dir) / p;
|
||||
if (fs::exists(p2))
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fs::exists(p))
|
||||
{
|
||||
std::ifstream file(p, std::ios::binary);
|
||||
if (not file.is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
io::filtering_stream<io::input> in;
|
||||
in.push(io::gzip_decompressor());
|
||||
in.push(file);
|
||||
|
||||
loadDictionary(in);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dict_name.string() + ")");
|
||||
}
|
||||
setValidator(&ValidatorFactory::instance()[dict]);
|
||||
}
|
||||
|
||||
void File::loadDictionary(std::istream &is)
|
||||
{
|
||||
std::unique_ptr<Validator> v(new Validator());
|
||||
|
||||
DictParser p(*v, is);
|
||||
p.loadDictionary();
|
||||
|
||||
setValidator(v.release());
|
||||
}
|
||||
|
||||
void File::setValidator(Validator *v)
|
||||
void File::setValidator(const Validator *v)
|
||||
{
|
||||
mValidator = v;
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ size_t WriteContinuedLine(std::ostream& pdbFile, std::string header, int& count,
|
||||
|
||||
for (auto& line: lines)
|
||||
{
|
||||
ba::to_upper(line);
|
||||
// ba::to_upper(line);
|
||||
|
||||
pdbFile << header;
|
||||
|
||||
@@ -811,7 +811,7 @@ typedef RM<3> RM3;
|
||||
template<int N>
|
||||
std::ostream& operator<<(std::ostream& os, RM<N>&& rm)
|
||||
{
|
||||
os << "REMARK " << std::setw(3) << std::right << N << " " << rm.mDesc << (rm.mWidth > 0 ? std::left : std::right) << std::fixed << std::setw(abs(rm.mWidth)) << std::setprecision(rm.mPrecision);
|
||||
os << "REMARK " << std::setw(3) << std::right << N << " " << rm.mDesc << (rm.mWidth > 0 ? std::left : std::right) << std::fixed << std::setw(std::abs(rm.mWidth)) << std::setprecision(rm.mPrecision);
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -824,7 +824,7 @@ struct SEP
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, SEP&& sep)
|
||||
{
|
||||
os << sep.mText << (sep.mWidth > 0 ? std::left : std::right) << std::fixed << std::setw(abs(sep.mWidth)) << std::setprecision(sep.mPrecision);
|
||||
os << sep.mText << (sep.mWidth > 0 ? std::left : std::right) << std::fixed << std::setw(std::abs(sep.mWidth)) << std::setprecision(sep.mPrecision);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -123,11 +123,12 @@ const uint8_t kCharToLowerMap[256] =
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
bool iequals(const std::string &a, const std::string &b)
|
||||
bool iequals(std::string_view a, std::string_view b)
|
||||
{
|
||||
bool result = a.length() == b.length();
|
||||
for (auto ai = a.begin(), bi = b.begin(); result and ai != a.end() and bi != b.end(); ++ai, ++bi)
|
||||
result = tolower(*ai) == tolower(*bi);
|
||||
for (auto ai = a.begin(), bi = b.begin(); result and ai != a.end(); ++ai, ++bi)
|
||||
result = kCharToLowerMap[uint8_t(*ai)] == kCharToLowerMap[uint8_t(*bi)];
|
||||
// result = tolower(*ai) == tolower(*bi);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ bool iequals(const char *a, const char *b)
|
||||
return result and *a == *b;
|
||||
}
|
||||
|
||||
int icompare(const std::string &a, const std::string &b)
|
||||
int icompare(std::string_view a, std::string_view b)
|
||||
{
|
||||
int d = 0;
|
||||
auto ai = a.begin(), bi = b.begin();
|
||||
@@ -193,7 +194,7 @@ std::string toLowerCopy(const std::string &s)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<std::string, std::string> splitTagName(const std::string &tag)
|
||||
std::tuple<std::string, std::string> splitTagName(std::string_view tag)
|
||||
{
|
||||
if (tag.empty())
|
||||
throw std::runtime_error("empty tag");
|
||||
@@ -1243,6 +1244,9 @@ void addDataDirectory(std::filesystem::path dataDir)
|
||||
|
||||
void addFileResource(const std::string &name, std::filesystem::path dataFile)
|
||||
{
|
||||
if (not fs::exists(dataFile))
|
||||
throw std::runtime_error("Attempt to add a file resource for " + name + " that does not exist: " + dataFile.string());
|
||||
|
||||
gLocalResources[name] = dataFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,32 +24,39 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/CifParser.hpp"
|
||||
#include "cif++/CifValidator.hpp"
|
||||
|
||||
namespace ba = boost::algorithm;
|
||||
namespace fs = std::filesystem;
|
||||
namespace io = boost::iostreams;
|
||||
|
||||
extern int VERBOSE;
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
ValidationError::ValidationError(const std::string& msg)
|
||||
ValidationError::ValidationError(const std::string &msg)
|
||||
: mMsg(msg)
|
||||
{
|
||||
}
|
||||
|
||||
ValidationError::ValidationError(const std::string& cat, const std::string& item, const std::string& msg)
|
||||
ValidationError::ValidationError(const std::string &cat, const std::string &item, const std::string &msg)
|
||||
: mMsg("When validating _" + cat + '.' + item + ": " + msg)
|
||||
{
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
DDL_PrimitiveType mapToPrimitiveType(const std::string& s)
|
||||
DDL_PrimitiveType mapToPrimitiveType(std::string_view s)
|
||||
{
|
||||
DDL_PrimitiveType result;
|
||||
if (iequals(s, "char"))
|
||||
@@ -65,10 +72,10 @@ DDL_PrimitiveType mapToPrimitiveType(const std::string& s)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int ValidateType::compare(const char* a, const char* b) const
|
||||
int ValidateType::compare(const char *a, const char *b) const
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
|
||||
if (*a == 0)
|
||||
result = *b == 0 ? 0 : -1;
|
||||
else if (*b == 0)
|
||||
@@ -83,7 +90,7 @@ int ValidateType::compare(const char* a, const char* b) const
|
||||
{
|
||||
double da = strtod(a, nullptr);
|
||||
double db = strtod(b, nullptr);
|
||||
|
||||
|
||||
auto d = da - db;
|
||||
if (std::abs(d) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
@@ -94,13 +101,13 @@ int ValidateType::compare(const char* a, const char* b) const
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case DDL_PrimitiveType::UChar:
|
||||
case DDL_PrimitiveType::Char:
|
||||
{
|
||||
// CIF is guaranteed to have ascii only, therefore this primitive code will do
|
||||
// also, we're collapsing spaces
|
||||
|
||||
|
||||
auto ai = a, bi = b;
|
||||
for (;;)
|
||||
{
|
||||
@@ -115,7 +122,7 @@ int ValidateType::compare(const char* a, const char* b) const
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
char ca = *ai;
|
||||
char cb = *bi;
|
||||
|
||||
@@ -124,12 +131,12 @@ int ValidateType::compare(const char* a, const char* b) const
|
||||
ca = tolower(ca);
|
||||
cb = tolower(cb);
|
||||
}
|
||||
|
||||
|
||||
result = ca - cb;
|
||||
|
||||
|
||||
if (result != 0)
|
||||
break;
|
||||
|
||||
|
||||
if (ca == ' ')
|
||||
{
|
||||
while (ai[1] == ' ')
|
||||
@@ -137,21 +144,21 @@ int ValidateType::compare(const char* a, const char* b) const
|
||||
while (bi[1] == ' ')
|
||||
++bi;
|
||||
}
|
||||
|
||||
|
||||
++ai;
|
||||
++bi;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::invalid_argument& ex)
|
||||
catch (const std::invalid_argument &ex)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -165,13 +172,13 @@ int ValidateType::compare(const char* a, const char* b) const
|
||||
//
|
||||
// if (mType == nullptr and parent != nullptr)
|
||||
// mType = parent->mType;
|
||||
//
|
||||
//
|
||||
// if (parent != nullptr)
|
||||
// {
|
||||
// mLinked.push_back({parent, parentItem, childItem});
|
||||
//
|
||||
// parent->mChildren.insert(this);
|
||||
////
|
||||
////
|
||||
//// if (mCategory->mKeys == std::vector<std::string>{mTag})
|
||||
//// parent->mForeignKeys.insert(this);
|
||||
// }
|
||||
@@ -194,7 +201,7 @@ void ValidateItem::operator()(std::string value) const
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void ValidateCategory::addItemValidator(ValidateItem&& v)
|
||||
void ValidateCategory::addItemValidator(ValidateItem &&v)
|
||||
{
|
||||
if (v.mMandatory)
|
||||
mMandatoryFields.insert(v.mTag);
|
||||
@@ -206,10 +213,10 @@ void ValidateCategory::addItemValidator(ValidateItem&& v)
|
||||
std::cout << "Could not add validator for item " << v.mTag << " to category " << mName << std::endl;
|
||||
}
|
||||
|
||||
const ValidateItem* ValidateCategory::getValidatorForItem(std::string tag) const
|
||||
const ValidateItem *ValidateCategory::getValidatorForItem(std::string_view tag) const
|
||||
{
|
||||
const ValidateItem* result = nullptr;
|
||||
auto i = mItemValidators.find(ValidateItem{tag});
|
||||
const ValidateItem *result = nullptr;
|
||||
auto i = mItemValidators.find(ValidateItem{std::string(tag)});
|
||||
if (i != mItemValidators.end())
|
||||
result = &*i;
|
||||
else if (VERBOSE > 4)
|
||||
@@ -219,26 +226,29 @@ const ValidateItem* ValidateCategory::getValidatorForItem(std::string tag) const
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
Validator::Validator()
|
||||
Validator::Validator(std::string_view name, std::istream &is)
|
||||
: mName(name)
|
||||
{
|
||||
DictParser p(*this, is);
|
||||
p.loadDictionary();
|
||||
}
|
||||
|
||||
Validator::~Validator()
|
||||
{
|
||||
}
|
||||
|
||||
void Validator::addTypeValidator(ValidateType&& v)
|
||||
void Validator::addTypeValidator(ValidateType &&v)
|
||||
{
|
||||
auto r = mTypeValidators.insert(std::move(v));
|
||||
if (not r.second and VERBOSE > 4)
|
||||
std::cout << "Could not add validator for type " << v.mName << std::endl;
|
||||
}
|
||||
|
||||
const ValidateType* Validator::getValidatorForType(std::string typeCode) const
|
||||
const ValidateType *Validator::getValidatorForType(std::string_view typeCode) const
|
||||
{
|
||||
const ValidateType* result = nullptr;
|
||||
|
||||
auto i = mTypeValidators.find(ValidateType{ typeCode, DDL_PrimitiveType::Char, boost::regex() });
|
||||
const ValidateType *result = nullptr;
|
||||
|
||||
auto i = mTypeValidators.find(ValidateType{std::string(typeCode), DDL_PrimitiveType::Char, boost::regex()});
|
||||
if (i != mTypeValidators.end())
|
||||
result = &*i;
|
||||
else if (VERBOSE > 4)
|
||||
@@ -246,17 +256,17 @@ const ValidateType* Validator::getValidatorForType(std::string typeCode) const
|
||||
return result;
|
||||
}
|
||||
|
||||
void Validator::addCategoryValidator(ValidateCategory&& v)
|
||||
void Validator::addCategoryValidator(ValidateCategory &&v)
|
||||
{
|
||||
auto r = mCategoryValidators.insert(std::move(v));
|
||||
if (not r.second and VERBOSE > 4)
|
||||
std::cout << "Could not add validator for category " << v.mName << std::endl;
|
||||
}
|
||||
|
||||
const ValidateCategory* Validator::getValidatorForCategory(std::string category) const
|
||||
const ValidateCategory *Validator::getValidatorForCategory(std::string_view category) const
|
||||
{
|
||||
const ValidateCategory* result = nullptr;
|
||||
auto i = mCategoryValidators.find(ValidateCategory{category});
|
||||
const ValidateCategory *result = nullptr;
|
||||
auto i = mCategoryValidators.find(ValidateCategory{std::string(category)});
|
||||
if (i != mCategoryValidators.end())
|
||||
result = &*i;
|
||||
else if (VERBOSE > 4)
|
||||
@@ -264,16 +274,16 @@ const ValidateCategory* Validator::getValidatorForCategory(std::string category)
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidateItem* Validator::getValidatorForItem(std::string tag) const
|
||||
ValidateItem *Validator::getValidatorForItem(std::string_view tag) const
|
||||
{
|
||||
ValidateItem* result = nullptr;
|
||||
|
||||
ValidateItem *result = nullptr;
|
||||
|
||||
std::string cat, item;
|
||||
std::tie(cat, item) = splitTagName(tag);
|
||||
|
||||
auto* cv = getValidatorForCategory(cat);
|
||||
auto *cv = getValidatorForCategory(cat);
|
||||
if (cv != nullptr)
|
||||
result = const_cast<ValidateItem*>(cv->getValidatorForItem(item));
|
||||
result = const_cast<ValidateItem *>(cv->getValidatorForItem(item));
|
||||
|
||||
if (result == nullptr and VERBOSE > 4)
|
||||
std::cout << "No validator for item " << tag << std::endl;
|
||||
@@ -281,15 +291,15 @@ ValidateItem* Validator::getValidatorForItem(std::string tag) const
|
||||
return result;
|
||||
}
|
||||
|
||||
void Validator::addLinkValidator(ValidateLink&& v)
|
||||
void Validator::addLinkValidator(ValidateLink &&v)
|
||||
{
|
||||
assert(v.mParentKeys.size() == v.mChildKeys.size());
|
||||
if (v.mParentKeys.size() != v.mChildKeys.size())
|
||||
throw std::runtime_error("unequal number of keys for parent and child in link");
|
||||
|
||||
|
||||
auto pcv = getValidatorForCategory(v.mParentCategory);
|
||||
auto ccv = getValidatorForCategory(v.mChildCategory);
|
||||
|
||||
|
||||
if (pcv == nullptr)
|
||||
throw std::runtime_error("unknown parent category " + v.mParentCategory);
|
||||
|
||||
@@ -299,48 +309,48 @@ void Validator::addLinkValidator(ValidateLink&& v)
|
||||
for (size_t i = 0; i < v.mParentKeys.size(); ++i)
|
||||
{
|
||||
auto piv = pcv->getValidatorForItem(v.mParentKeys[i]);
|
||||
|
||||
|
||||
if (piv == nullptr)
|
||||
throw std::runtime_error("unknown parent tag _" + v.mParentCategory + '.' + v.mParentKeys[i]);
|
||||
|
||||
auto civ = ccv->getValidatorForItem(v.mChildKeys[i]);
|
||||
if (civ == nullptr)
|
||||
throw std::runtime_error("unknown child tag _" + v.mChildCategory + '.' + v.mChildKeys[i]);
|
||||
|
||||
|
||||
if (civ->mType == nullptr and piv->mType != nullptr)
|
||||
const_cast<ValidateItem*>(civ)->mType = piv->mType;
|
||||
}
|
||||
|
||||
const_cast<ValidateItem *>(civ)->mType = piv->mType;
|
||||
}
|
||||
|
||||
mLinkValidators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
std::vector<const ValidateLink*> Validator::getLinksForParent(const std::string& category) const
|
||||
std::vector<const ValidateLink *> Validator::getLinksForParent(std::string_view category) const
|
||||
{
|
||||
std::vector<const ValidateLink*> result;
|
||||
std::vector<const ValidateLink *> result;
|
||||
|
||||
for (auto& l: mLinkValidators)
|
||||
for (auto &l : mLinkValidators)
|
||||
{
|
||||
if (l.mParentCategory == category)
|
||||
result.push_back(&l);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const ValidateLink*> Validator::getLinksForChild(const std::string& category) const
|
||||
std::vector<const ValidateLink *> Validator::getLinksForChild(std::string_view category) const
|
||||
{
|
||||
std::vector<const ValidateLink*> result;
|
||||
std::vector<const ValidateLink *> result;
|
||||
|
||||
for (auto& l: mLinkValidators)
|
||||
for (auto &l : mLinkValidators)
|
||||
{
|
||||
if (l.mChildCategory == category)
|
||||
result.push_back(&l);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Validator::reportError(const std::string& msg, bool fatal)
|
||||
void Validator::reportError(const std::string &msg, bool fatal) const
|
||||
{
|
||||
if (mStrict or fatal)
|
||||
throw ValidationError(msg);
|
||||
@@ -348,4 +358,78 @@ void Validator::reportError(const std::string& msg, bool fatal)
|
||||
std::cerr << msg << std::endl;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
ValidatorFactory ValidatorFactory::sInstance;
|
||||
|
||||
ValidatorFactory::ValidatorFactory()
|
||||
{
|
||||
}
|
||||
|
||||
const Validator &ValidatorFactory::operator[](std::string_view dictionary)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
|
||||
for (auto &validator : mValidators)
|
||||
{
|
||||
if (iequals(validator.mName, dictionary))
|
||||
return validator;
|
||||
}
|
||||
|
||||
// not found, add it
|
||||
|
||||
fs::path dict_name(dictionary);
|
||||
|
||||
auto data = loadResource(dictionary);
|
||||
|
||||
if (not data and dict_name.extension().string() != ".dic")
|
||||
data = loadResource(dict_name.parent_path() / (dict_name.filename().string() + ".dic"));
|
||||
|
||||
if (data)
|
||||
mValidators.emplace_back(dictionary, *data);
|
||||
else
|
||||
{
|
||||
// might be a compressed dictionary on disk
|
||||
fs::path p = dictionary;
|
||||
if (p.extension() == ".dic")
|
||||
p = p.parent_path() / (p.filename().string() + ".gz");
|
||||
else
|
||||
p = p.parent_path() / (p.filename().string() + ".dic.gz");
|
||||
|
||||
#if defined(CACHE_DIR) and defined(DATA_DIR)
|
||||
if (not fs::exists(p))
|
||||
{
|
||||
for (const char *dir : {CACHE_DIR, DATA_DIR})
|
||||
{
|
||||
auto p2 = fs::path(dir) / p;
|
||||
if (fs::exists(p2))
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fs::exists(p))
|
||||
{
|
||||
std::ifstream file(p, std::ios::binary);
|
||||
if (not file.is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
io::filtering_stream<io::input> in;
|
||||
in.push(io::gzip_decompressor());
|
||||
in.push(file);
|
||||
|
||||
mValidators.emplace_back(dictionary, in);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dict_name.string() + ")");
|
||||
}
|
||||
|
||||
assert(iequals(mValidators.back().mName, dictionary));
|
||||
|
||||
return mValidators.back();
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -125,6 +125,11 @@ Compound::Compound(cif::Datablock &db)
|
||||
cif::tie(mID, mName, mType, mFormula, mFormulaWeight, mFormalCharge) =
|
||||
chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge");
|
||||
|
||||
// The name should not contain newline characters since that triggers validation errors later on
|
||||
ba::replace_all(mName, "\n", "");
|
||||
|
||||
mGroup = "non-polymer";
|
||||
|
||||
auto &chemCompAtom = db["chem_comp_atom"];
|
||||
for (auto row : chemCompAtom)
|
||||
{
|
||||
@@ -148,10 +153,11 @@ Compound::Compound(cif::Datablock &db)
|
||||
}
|
||||
}
|
||||
|
||||
Compound::Compound(cif::Datablock &db, const std::string &id, const std::string &name, const std::string &type)
|
||||
Compound::Compound(cif::Datablock &db, const std::string &id, const std::string &name, const std::string &type, const std::string &group)
|
||||
: mID(id)
|
||||
, mName(name)
|
||||
, mType(type)
|
||||
, mGroup(group)
|
||||
{
|
||||
auto &chemCompAtom = db["chem_comp_atom"];
|
||||
for (auto row : chemCompAtom)
|
||||
@@ -408,7 +414,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::filesystem::path &file, std:
|
||||
|
||||
auto &db = cifFile["comp_" + id];
|
||||
|
||||
mCompounds.push_back(new Compound(db, id, name, type));
|
||||
mCompounds.push_back(new Compound(db, id, name, type, group));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -457,7 +463,7 @@ Compound *CCDCompoundFactoryImpl::create(const std::string &id)
|
||||
{
|
||||
ccd = cif::loadResource("components.cif");
|
||||
if (not ccd)
|
||||
throw std::runtime_error("Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-dictionary-script to fetch the data.");
|
||||
throw std::runtime_error("Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-libcifpp-data to fetch the data.");
|
||||
}
|
||||
else
|
||||
ccd.reset(new std::ifstream(mCompoundsFile));
|
||||
@@ -484,7 +490,7 @@ Compound *CCDCompoundFactoryImpl::create(const std::string &id)
|
||||
{
|
||||
ccd = cif::loadResource("components.cif");
|
||||
if (not ccd)
|
||||
throw std::runtime_error("Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-dictionary-script to fetch the data.");
|
||||
throw std::runtime_error("Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-libcifpp-data to fetch the data.");
|
||||
}
|
||||
else
|
||||
ccd.reset(new std::ifstream(mCompoundsFile));
|
||||
@@ -614,7 +620,7 @@ Compound *CCP4CompoundFactoryImpl::create(const std::string &id)
|
||||
else
|
||||
type = "non-polymer";
|
||||
|
||||
mCompounds.push_back(new Compound(db, id, name, type));
|
||||
mCompounds.push_back(new Compound(db, id, name, type, group));
|
||||
result = mCompounds.back();
|
||||
}
|
||||
}
|
||||
@@ -636,17 +642,18 @@ void CompoundFactory::init(bool useThreadLocalInstanceOnly)
|
||||
CompoundFactory::CompoundFactory()
|
||||
: mImpl(nullptr)
|
||||
{
|
||||
auto ccd = cif::loadResource("components.cif");
|
||||
if (ccd)
|
||||
mImpl.reset(new CCDCompoundFactoryImpl(mImpl));
|
||||
else if (cif::VERBOSE)
|
||||
std::cerr << "CCD components.cif file was not found" << std::endl;
|
||||
|
||||
const char *clibd_mon = getenv("CLIBD_MON");
|
||||
if (clibd_mon != nullptr and fs::is_directory(clibd_mon))
|
||||
mImpl.reset(new CCP4CompoundFactoryImpl(clibd_mon));
|
||||
else if (cif::VERBOSE)
|
||||
std::cerr << "CCP4 monomers library not found, CLIBD_MON is not defined" << std::endl;
|
||||
|
||||
auto ccd = cif::loadResource("components.cif");
|
||||
if (ccd)
|
||||
mImpl.reset(new CCDCompoundFactoryImpl(mImpl));
|
||||
else if (cif::VERBOSE)
|
||||
std::cerr << "CCD components.cif file was not found" << std::endl;
|
||||
}
|
||||
|
||||
CompoundFactory::~CompoundFactory()
|
||||
|
||||
530
src/PDB2Cif.cpp
530
src/PDB2Cif.cpp
@@ -1540,7 +1540,8 @@ void PDBFileParser::ParseTitle()
|
||||
while (mRec->is("CAVEAT")) // 1 - 6 Record name "CAVEAT"
|
||||
{
|
||||
getCategory("database_PDB_caveat")->emplace({
|
||||
{"id", caveatID++}, {"text", std::string{mRec->vS(20)}} // 20 - 79 String comment Free text giving the reason for the CAVEAT.
|
||||
{"id", caveatID++},
|
||||
{"text", std::string{mRec->vS(20)}} // 20 - 79 String comment Free text giving the reason for the CAVEAT.
|
||||
});
|
||||
|
||||
GetNextRecord();
|
||||
@@ -1674,7 +1675,9 @@ void PDBFileParser::ParseTitle()
|
||||
|
||||
if (not(keywords.empty() and pdbxKeywords.empty()))
|
||||
{
|
||||
getCategory("struct_keywords")->emplace({{"entry_id", mStructureID}, {"pdbx_keywords", keywords}, {"text", pdbxKeywords}});
|
||||
getCategory("struct_keywords")->emplace({{"entry_id", mStructureID},
|
||||
{"pdbx_keywords", keywords},
|
||||
{"text", pdbxKeywords}});
|
||||
}
|
||||
|
||||
// EXPDTA
|
||||
@@ -1794,13 +1797,18 @@ void PDBFileParser::ParseTitle()
|
||||
sort(revdats.begin(), revdats.end());
|
||||
for (auto &revdat : revdats)
|
||||
{
|
||||
getCategory("database_PDB_rev")->emplace({{"num", revdat.revNum}, {"date", revdat.date}, {"date_original", revdat.dateOriginal}, {"replaces", revdat.replaces}, {"mod_type", revdat.modType}});
|
||||
getCategory("database_PDB_rev")->emplace({{"num", revdat.revNum},
|
||||
{"date", revdat.date},
|
||||
{"date_original", revdat.dateOriginal},
|
||||
{"replaces", revdat.replaces},
|
||||
{"mod_type", revdat.modType}});
|
||||
|
||||
for (auto &type : revdat.types)
|
||||
{
|
||||
if (type.empty())
|
||||
continue;
|
||||
getCategory("database_PDB_rev_record")->emplace({{"rev_num", revdat.revNum}, {"type", type}});
|
||||
getCategory("database_PDB_rev_record")->emplace({{"rev_num", revdat.revNum},
|
||||
{"type", type}});
|
||||
}
|
||||
}
|
||||
//*/
|
||||
@@ -2036,7 +2044,10 @@ void PDBFileParser::ParseRemarks()
|
||||
if (desc == "NULL")
|
||||
desc.clear();
|
||||
|
||||
getCategory("exptl_crystal")->emplace({{"id", 1}, {"density_Matthews", iequals(density_Matthews, "NULL") ? "" : density_Matthews}, {"density_percent_sol", iequals(densityPercentSol, "NULL") ? "" : densityPercentSol}, {"description", desc}});
|
||||
getCategory("exptl_crystal")->emplace({{"id", 1},
|
||||
{"density_Matthews", iequals(density_Matthews, "NULL") ? "" : density_Matthews},
|
||||
{"density_percent_sol", iequals(densityPercentSol, "NULL") ? "" : densityPercentSol},
|
||||
{"description", desc}});
|
||||
|
||||
// now try to parse the conditions
|
||||
const std::regex rx3(R"(TEMPERATURE +(\d+)K)"), rx4(R"(PH *(?:: *)?(\d+(?:\.\d+)?))") /*, rx5(R"(\b(\d+)C\b)")*/;
|
||||
@@ -2065,7 +2076,11 @@ void PDBFileParser::ParseRemarks()
|
||||
|
||||
if (not(method.empty() and temp.empty() and ph.empty() and (conditions.empty() or conditions == "NULL")))
|
||||
{
|
||||
getCategory("exptl_crystal_grow")->emplace({{"crystal_id", 1}, {"method", method}, {"temp", temp}, {"pH", ph}, {"pdbx_details", conditions}});
|
||||
getCategory("exptl_crystal_grow")->emplace({{"crystal_id", 1},
|
||||
{"method", method},
|
||||
{"temp", temp},
|
||||
{"pH", ph},
|
||||
{"pdbx_details", conditions}});
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2283,7 +2298,21 @@ void PDBFileParser::ParseRemarks()
|
||||
|
||||
std::string distance = vF(63, 71);
|
||||
|
||||
getCategory("pdbx_validate_close_contact")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", 1}, {"auth_atom_id_1", atom1}, {"auth_asym_id_1", std::string{chain1}}, {"auth_comp_id_1", res1}, {"auth_seq_id_1", seq1}, {"PDB_ins_code_1", iCode1}, {"label_alt_id_1", alt1}, {"auth_atom_id_2", atom2}, {"auth_asym_id_2", std::string{chain2}}, {"auth_comp_id_2", res2}, {"auth_seq_id_2", seq2}, {"PDB_ins_code_2", iCode2}, {"label_alt_id_2", alt2}, {"dist", distance}});
|
||||
getCategory("pdbx_validate_close_contact")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", 1},
|
||||
{"auth_atom_id_1", atom1},
|
||||
{"auth_asym_id_1", std::string{chain1}},
|
||||
{"auth_comp_id_1", res1},
|
||||
{"auth_seq_id_1", seq1},
|
||||
{"PDB_ins_code_1", iCode1},
|
||||
{"label_alt_id_1", alt1},
|
||||
{"auth_atom_id_2", atom2},
|
||||
{"auth_asym_id_2", std::string{chain2}},
|
||||
{"auth_comp_id_2", res2},
|
||||
{"auth_seq_id_2", seq2},
|
||||
{"PDB_ins_code_2", iCode2},
|
||||
{"label_alt_id_2", alt2},
|
||||
{"dist", distance}});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2320,7 +2349,12 @@ void PDBFileParser::ParseRemarks()
|
||||
|
||||
std::string distance = vF(63, 71);
|
||||
|
||||
getCategory("pdbx_validate_symm_contact")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", 1}, {"auth_atom_id_1", atom1}, {"auth_asym_id_1", std::string{chain1}}, {"auth_comp_id_1", res1}, {"auth_seq_id_1", seq1},
|
||||
getCategory("pdbx_validate_symm_contact")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", 1},
|
||||
{"auth_atom_id_1", atom1},
|
||||
{"auth_asym_id_1", std::string{chain1}},
|
||||
{"auth_comp_id_1", res1},
|
||||
{"auth_seq_id_1", seq1},
|
||||
// { "PDB_ins_code_1", "" },
|
||||
// { "label_alt_id_1", "" },
|
||||
{"site_symmetry_1", "1_555"},
|
||||
@@ -2371,7 +2405,21 @@ void PDBFileParser::ParseRemarks()
|
||||
if (iCode2 == " ")
|
||||
iCode2.clear();
|
||||
|
||||
getCategory("pdbx_validate_rmsd_bond")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", model ? model : 1}, {"auth_atom_id_1", atm1}, {"auth_asym_id_1", chainID1}, {"auth_comp_id_1", resNam1}, {"auth_seq_id_1", seqNum1}, {"PDB_ins_code_1", iCode1}, {"label_alt_id_1", alt1}, {"auth_atom_id_2", atm2}, {"auth_asym_id_2", chainID2}, {"auth_comp_id_2", resNam2}, {"auth_seq_id_2", seqNum2}, {"PDB_ins_code_2", iCode2}, {"label_alt_id_2", alt2}, {"bond_deviation", deviation}});
|
||||
getCategory("pdbx_validate_rmsd_bond")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", model ? model : 1},
|
||||
{"auth_atom_id_1", atm1},
|
||||
{"auth_asym_id_1", chainID1},
|
||||
{"auth_comp_id_1", resNam1},
|
||||
{"auth_seq_id_1", seqNum1},
|
||||
{"PDB_ins_code_1", iCode1},
|
||||
{"label_alt_id_1", alt1},
|
||||
{"auth_atom_id_2", atm2},
|
||||
{"auth_asym_id_2", chainID2},
|
||||
{"auth_comp_id_2", resNam2},
|
||||
{"auth_seq_id_2", seqNum2},
|
||||
{"PDB_ins_code_2", iCode2},
|
||||
{"label_alt_id_2", alt2},
|
||||
{"bond_deviation", deviation}});
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2403,7 +2451,24 @@ void PDBFileParser::ParseRemarks()
|
||||
if (deviation == "*****")
|
||||
deviation.clear();
|
||||
|
||||
getCategory("pdbx_validate_rmsd_angle")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", model ? model : 1}, {"auth_atom_id_1", atoms[0]}, {"auth_asym_id_1", chainID}, {"auth_comp_id_1", resNam}, {"auth_seq_id_1", seqNum}, {"PDB_ins_code_1", iCode}, {"auth_atom_id_2", atoms[1]}, {"auth_asym_id_2", chainID}, {"auth_comp_id_2", resNam}, {"auth_seq_id_2", seqNum}, {"PDB_ins_code_2", iCode}, {"auth_atom_id_3", atoms[2]}, {"auth_asym_id_3", chainID}, {"auth_comp_id_3", resNam}, {"auth_seq_id_3", seqNum}, {"PDB_ins_code_3", iCode}, {"angle_deviation", deviation}});
|
||||
getCategory("pdbx_validate_rmsd_angle")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", model ? model : 1},
|
||||
{"auth_atom_id_1", atoms[0]},
|
||||
{"auth_asym_id_1", chainID},
|
||||
{"auth_comp_id_1", resNam},
|
||||
{"auth_seq_id_1", seqNum},
|
||||
{"PDB_ins_code_1", iCode},
|
||||
{"auth_atom_id_2", atoms[1]},
|
||||
{"auth_asym_id_2", chainID},
|
||||
{"auth_comp_id_2", resNam},
|
||||
{"auth_seq_id_2", seqNum},
|
||||
{"PDB_ins_code_2", iCode},
|
||||
{"auth_atom_id_3", atoms[2]},
|
||||
{"auth_asym_id_3", chainID},
|
||||
{"auth_comp_id_3", resNam},
|
||||
{"auth_seq_id_3", seqNum},
|
||||
{"PDB_ins_code_3", iCode},
|
||||
{"angle_deviation", deviation}});
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2432,7 +2497,14 @@ void PDBFileParser::ParseRemarks()
|
||||
std::string psi = vF(27, 35);
|
||||
std::string phi = vF(37, 45);
|
||||
|
||||
getCategory("pdbx_validate_torsion")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", model ? model : 1}, {"auth_comp_id", resNam}, {"auth_asym_id", chainID}, {"auth_seq_id", seqNum}, {"PDB_ins_code", iCode}, {"phi", phi}, {"psi", psi}});
|
||||
getCategory("pdbx_validate_torsion")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", model ? model : 1},
|
||||
{"auth_comp_id", resNam},
|
||||
{"auth_asym_id", chainID},
|
||||
{"auth_seq_id", seqNum},
|
||||
{"PDB_ins_code", iCode},
|
||||
{"phi", phi},
|
||||
{"psi", psi}});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2463,7 +2535,17 @@ void PDBFileParser::ParseRemarks()
|
||||
|
||||
std::string omega = vF(54, 60);
|
||||
|
||||
getCategory("pdbx_validate_peptide_omega")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", model ? model : 1}, {"auth_comp_id_1", resNam1}, {"auth_asym_id_1", chainID1}, {"auth_seq_id_1", seqNum1}, {"PDB_ins_code_1", iCode1}, {"auth_comp_id_2", resNam2}, {"auth_asym_id_2", chainID2}, {"auth_seq_id_2", seqNum2}, {"PDB_ins_code_2", iCode2}, {"omega", omega}});
|
||||
getCategory("pdbx_validate_peptide_omega")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", model ? model : 1},
|
||||
{"auth_comp_id_1", resNam1},
|
||||
{"auth_asym_id_1", chainID1},
|
||||
{"auth_seq_id_1", seqNum1},
|
||||
{"PDB_ins_code_1", iCode1},
|
||||
{"auth_comp_id_2", resNam2},
|
||||
{"auth_asym_id_2", chainID2},
|
||||
{"auth_seq_id_2", seqNum2},
|
||||
{"PDB_ins_code_2", iCode2},
|
||||
{"omega", omega}});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2486,7 +2568,14 @@ void PDBFileParser::ParseRemarks()
|
||||
std::string rmsd = vF(32, 36);
|
||||
std::string type = vS(41);
|
||||
|
||||
getCategory("pdbx_validate_planes")->emplace({{"id", std::to_string(++id)}, {"PDB_model_num", model ? model : 1}, {"auth_comp_id", resNam}, {"auth_asym_id", chainID}, {"auth_seq_id", seqNum}, {"PDB_ins_code", iCode}, {"rmsd", rmsd}, {"type", type}});
|
||||
getCategory("pdbx_validate_planes")->emplace({{"id", std::to_string(++id)},
|
||||
{"PDB_model_num", model ? model : 1},
|
||||
{"auth_comp_id", resNam},
|
||||
{"auth_asym_id", chainID},
|
||||
{"auth_seq_id", seqNum},
|
||||
{"PDB_ins_code", iCode},
|
||||
{"rmsd", rmsd},
|
||||
{"type", type}});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2566,7 +2655,13 @@ void PDBFileParser::ParseRemarks()
|
||||
throw std::runtime_error("Invalid REMARK 800, no SITE record for id " + id);
|
||||
|
||||
// next record, store what we have
|
||||
getCategory("struct_site")->emplace({{"id", id}, {"details", desc}, {"pdbx_auth_asym_id", pdbxAuthAsymID}, {"pdbx_auth_comp_id", pdbxAuthCompID}, {"pdbx_auth_seq_id", pdbxAuthSeqID}, {"pdbx_num_residues", site->vI(16, 17)}, {"pdbx_evidence_code", evidence}});
|
||||
getCategory("struct_site")->emplace({{"id", id},
|
||||
{"details", desc},
|
||||
{"pdbx_auth_asym_id", pdbxAuthAsymID},
|
||||
{"pdbx_auth_comp_id", pdbxAuthCompID},
|
||||
{"pdbx_auth_seq_id", pdbxAuthSeqID},
|
||||
{"pdbx_num_residues", site->vI(16, 17)},
|
||||
{"pdbx_evidence_code", evidence}});
|
||||
};
|
||||
|
||||
for (; mRec->is("REMARK 800"); GetNextRecord())
|
||||
@@ -2680,7 +2775,8 @@ void PDBFileParser::ParseRemarks()
|
||||
GetNextRecord();
|
||||
}
|
||||
|
||||
getCategory("pdbx_database_remark")->emplace({{"id", remarkNr}, {"text", s.str()}});
|
||||
getCategory("pdbx_database_remark")->emplace({{"id", remarkNr},
|
||||
{"text", s.str()}});
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -2694,7 +2790,10 @@ void PDBFileParser::ParseRemarks()
|
||||
|
||||
if (not(compoundDetails.empty() and sequenceDetails.empty() and sourceDetails.empty()))
|
||||
{
|
||||
getCategory("pdbx_entry_details")->emplace({{"entry_id", mStructureID}, {"compound_details", compoundDetails}, {"sequence_details", sequenceDetails}, {"source_details", sourceDetails}});
|
||||
getCategory("pdbx_entry_details")->emplace({{"entry_id", mStructureID},
|
||||
{"compound_details", compoundDetails},
|
||||
{"sequence_details", sequenceDetails},
|
||||
{"source_details", sourceDetails}});
|
||||
}
|
||||
|
||||
// store remark 200 info (special case)
|
||||
@@ -2774,7 +2873,10 @@ void PDBFileParser::ParseRemark200()
|
||||
if (mRemark200[sw.b].empty())
|
||||
continue;
|
||||
|
||||
getCategory("software")->emplace({{"name", mRemark200[sw.b]}, {"classification", sw.a}, {"version", "."}, {"pdbx_ordinal", mNextSoftwareOrd++}});
|
||||
getCategory("software")->emplace({{"name", mRemark200[sw.b]},
|
||||
{"classification", sw.a},
|
||||
{"version", "."},
|
||||
{"pdbx_ordinal", mNextSoftwareOrd++}});
|
||||
}
|
||||
|
||||
std::string scatteringType;
|
||||
@@ -2812,10 +2914,19 @@ void PDBFileParser::ParseRemark200()
|
||||
collectionDate.clear();
|
||||
}
|
||||
|
||||
getCategory("diffrn_detector")->emplace({{"diffrn_id", diffrnNr}, {"detector", rm200("DETECTOR TYPE", diffrnNr)}, {"type", rm200("DETECTOR MANUFACTURER", diffrnNr)}, {"pdbx_collection_date", collectionDate}, {"details", rm200("OPTICS", diffrnNr)}});
|
||||
getCategory("diffrn_detector")->emplace({{"diffrn_id", diffrnNr},
|
||||
{"detector", rm200("DETECTOR TYPE", diffrnNr)},
|
||||
{"type", rm200("DETECTOR MANUFACTURER", diffrnNr)},
|
||||
{"pdbx_collection_date", collectionDate},
|
||||
{"details", rm200("OPTICS", diffrnNr)}});
|
||||
|
||||
if (inRM200({"MONOCHROMATIC OR LAUE (M/L)", "MONOCHROMATOR", "DIFFRACTION PROTOCOL"}) or not scatteringType.empty())
|
||||
getCategory("diffrn_radiation")->emplace({{"diffrn_id", diffrnNr}, {"wavelength_id", 1}, {"pdbx_monochromatic_or_laue_m_l", rm200("MONOCHROMATIC OR LAUE (M/L)", diffrnNr)}, {"monochromator", rm200("MONOCHROMATOR", diffrnNr)}, {"pdbx_diffrn_protocol", rm200("DIFFRACTION PROTOCOL", diffrnNr)}, {"pdbx_scattering_type", scatteringType}});
|
||||
getCategory("diffrn_radiation")->emplace({{"diffrn_id", diffrnNr},
|
||||
{"wavelength_id", 1},
|
||||
{"pdbx_monochromatic_or_laue_m_l", rm200("MONOCHROMATIC OR LAUE (M/L)", diffrnNr)},
|
||||
{"monochromator", rm200("MONOCHROMATOR", diffrnNr)},
|
||||
{"pdbx_diffrn_protocol", rm200("DIFFRACTION PROTOCOL", diffrnNr)},
|
||||
{"pdbx_scattering_type", scatteringType}});
|
||||
|
||||
std::vector<std::string> wavelengths;
|
||||
std::string wl = rm200("WAVELENGTH OR RANGE (A)", diffrnNr);
|
||||
@@ -2856,7 +2967,9 @@ void PDBFileParser::ParseRemark200()
|
||||
if (ba::ends_with(wl, "A"))
|
||||
wl.erase(wl.length() - 1, 1);
|
||||
|
||||
getCategory("diffrn_radiation_wavelength")->emplace({{"id", wavelengthNr++}, {"wavelength", wl.empty() ? "." : wl}, {"wt", "1.0"}});
|
||||
getCategory("diffrn_radiation_wavelength")->emplace({{"id", wavelengthNr++},
|
||||
{"wavelength", wl.empty() ? "." : wl},
|
||||
{"wt", "1.0"}});
|
||||
}
|
||||
|
||||
if (inRM200({"METHOD USED TO DETERMINE THE STRUCTURE", "STARTING MODEL"}))
|
||||
@@ -2899,7 +3012,15 @@ void PDBFileParser::ParseRemark200()
|
||||
|
||||
if (inRM200({"HIGHEST RESOLUTION SHELL, RANGE HIGH (A)"})) // that one field is mandatory...
|
||||
{
|
||||
getCategory("reflns_shell")->emplace({{"d_res_high", mRemark200["HIGHEST RESOLUTION SHELL, RANGE HIGH (A)"]}, {"d_res_low", mRemark200["HIGHEST RESOLUTION SHELL, RANGE LOW (A)"]}, {"percent_possible_all", mRemark200["COMPLETENESS FOR SHELL (%)"]}, {"Rmerge_I_obs", mRemark200["R MERGE FOR SHELL (I)"]}, {"pdbx_Rsym_value", mRemark200["R SYM FOR SHELL (I)"]}, {"meanI_over_sigI_obs", mRemark200["<I/SIGMA(I)> FOR SHELL"]}, {"pdbx_redundancy", mRemark200["DATA REDUNDANCY IN SHELL"]}, {"pdbx_ordinal", 1}, {"pdbx_diffrn_id", 1}});
|
||||
getCategory("reflns_shell")->emplace({{"d_res_high", mRemark200["HIGHEST RESOLUTION SHELL, RANGE HIGH (A)"]},
|
||||
{"d_res_low", mRemark200["HIGHEST RESOLUTION SHELL, RANGE LOW (A)"]},
|
||||
{"percent_possible_all", mRemark200["COMPLETENESS FOR SHELL (%)"]},
|
||||
{"Rmerge_I_obs", mRemark200["R MERGE FOR SHELL (I)"]},
|
||||
{"pdbx_Rsym_value", mRemark200["R SYM FOR SHELL (I)"]},
|
||||
{"meanI_over_sigI_obs", mRemark200["<I/SIGMA(I)> FOR SHELL"]},
|
||||
{"pdbx_redundancy", mRemark200["DATA REDUNDANCY IN SHELL"]},
|
||||
{"pdbx_ordinal", 1},
|
||||
{"pdbx_diffrn_id", 1}});
|
||||
}
|
||||
else if (inRM200({"HIGHEST RESOLUTION SHELL, RANGE LOW (A)", "COMPLETENESS FOR SHELL (%)",
|
||||
"R MERGE FOR SHELL (I)", "R SYM FOR SHELL (I)", "<I/SIGMA(I)> FOR SHELL", "DATA REDUNDANCY IN SHELL"}))
|
||||
@@ -3091,7 +3212,11 @@ void PDBFileParser::ParseRemark350()
|
||||
else
|
||||
details = "author_and_software_defined_assembly";
|
||||
|
||||
getCategory("pdbx_struct_assembly")->emplace({{"id", biomolecule}, {"details", details}, {"method_details", values["SOFTWARE USED"]}, {"oligomeric_details", oligomer}, {"oligomeric_count", count > 0 ? std::to_string(count) : ""}});
|
||||
getCategory("pdbx_struct_assembly")->emplace({{"id", biomolecule},
|
||||
{"details", details},
|
||||
{"method_details", values["SOFTWARE USED"]},
|
||||
{"oligomeric_details", oligomer},
|
||||
{"oligomeric_count", count > 0 ? std::to_string(count) : ""}});
|
||||
|
||||
auto cat = getCategory("pdbx_struct_assembly_prop");
|
||||
|
||||
@@ -3115,21 +3240,23 @@ void PDBFileParser::ParseRemark350()
|
||||
|
||||
boost::format fmt("%12.10f");
|
||||
|
||||
getCategory("pdbx_struct_oper_list")->emplace({{"id", operID}, {"type", mat == std::vector<double>{1, 0, 0, 0, 1, 0, 0, 0, 1} and vec == std::vector<double>{0, 0, 0} ? "identity operation" : "crystal symmetry operation"},
|
||||
// { "name", "" },
|
||||
// { "symmetryOperation", "" },
|
||||
{"matrix[1][1]", (fmt % mat[0]).str()},
|
||||
{"matrix[1][2]", (fmt % mat[1]).str()},
|
||||
{"matrix[1][3]", (fmt % mat[2]).str()},
|
||||
{"vector[1]", (fmt % vec[0]).str()},
|
||||
{"matrix[2][1]", (fmt % mat[3]).str()},
|
||||
{"matrix[2][2]", (fmt % mat[4]).str()},
|
||||
{"matrix[2][3]", (fmt % mat[5]).str()},
|
||||
{"vector[2]", (fmt % vec[1]).str()},
|
||||
{"matrix[3][1]", (fmt % mat[6]).str()},
|
||||
{"matrix[3][2]", (fmt % mat[7]).str()},
|
||||
{"matrix[3][3]", (fmt % mat[8]).str()},
|
||||
{"vector[3]", (fmt % vec[2]).str()}});
|
||||
getCategory("pdbx_struct_oper_list")->emplace({
|
||||
{"id", operID},
|
||||
{"type", mat == std::vector<double>{1, 0, 0, 0, 1, 0, 0, 0, 1} and vec == std::vector<double>{0, 0, 0} ? "identity operation" : "crystal symmetry operation"},
|
||||
// { "name", "" },
|
||||
// { "symmetryOperation", "" },
|
||||
{"matrix[1][1]", (fmt % mat[0]).str()},
|
||||
{"matrix[1][2]", (fmt % mat[1]).str()},
|
||||
{"matrix[1][3]", (fmt % mat[2]).str()},
|
||||
{"vector[1]", (fmt % vec[0]).str()},
|
||||
{"matrix[2][1]", (fmt % mat[3]).str()},
|
||||
{"matrix[2][2]", (fmt % mat[4]).str()},
|
||||
{"matrix[2][3]", (fmt % mat[5]).str()},
|
||||
{"vector[2]", (fmt % vec[1]).str()},
|
||||
{"matrix[3][1]", (fmt % mat[6]).str()},
|
||||
{"matrix[3][2]", (fmt % mat[7]).str()},
|
||||
{"matrix[3][3]", (fmt % mat[8]).str()},
|
||||
{"vector[3]", (fmt % vec[2]).str()}});
|
||||
|
||||
mat.clear();
|
||||
vec.clear();
|
||||
@@ -3140,7 +3267,9 @@ void PDBFileParser::ParseRemark350()
|
||||
if (not(vec.empty() and mat.empty()))
|
||||
throw std::runtime_error("Invalid REMARK 350");
|
||||
|
||||
getCategory("pdbx_struct_assembly_gen")->emplace({{"assembly_id", biomolecule}, {"oper_expression", ba::join(operExpression, ",")}, {"asym_id_list", ba::join(asymIdList, ",")}});
|
||||
getCategory("pdbx_struct_assembly_gen")->emplace({{"assembly_id", biomolecule},
|
||||
{"oper_expression", ba::join(operExpression, ",")},
|
||||
{"asym_id_list", ba::join(asymIdList, ",")}});
|
||||
|
||||
biomolecule = stoi(m[1].str());
|
||||
asymIdList.clear();
|
||||
@@ -3154,7 +3283,9 @@ void PDBFileParser::ParseRemark350()
|
||||
|
||||
if (not operExpression.empty())
|
||||
{
|
||||
getCategory("pdbx_struct_assembly_gen")->emplace({{"assembly_id", biomolecule}, {"oper_expression", ba::join(operExpression, ",")}, {"asym_id_list", ba::join(asymIdList, ",")}});
|
||||
getCategory("pdbx_struct_assembly_gen")->emplace({{"assembly_id", biomolecule},
|
||||
{"oper_expression", ba::join(operExpression, ",")},
|
||||
{"asym_id_list", ba::join(asymIdList, ",")}});
|
||||
}
|
||||
|
||||
mRec = saved;
|
||||
@@ -3641,10 +3772,11 @@ void PDBFileParser::ConstructEntities()
|
||||
mAsymID2EntityID[asymID] = entityID;
|
||||
|
||||
getCategory("struct_asym")->emplace({
|
||||
{"id", asymID}, {"pdbx_blank_PDB_chainid_flag", chain.mDbref.chainID == ' ' ? "Y" : "N"},
|
||||
// pdbx_modified
|
||||
{"id", asymID},
|
||||
{"pdbx_blank_PDB_chainid_flag", chain.mDbref.chainID == ' ' ? "Y" : "N"},
|
||||
// pdbx_modified
|
||||
{"entity_id", entityID},
|
||||
// details
|
||||
// details
|
||||
});
|
||||
|
||||
int seqNr = 1;
|
||||
@@ -3708,7 +3840,32 @@ void PDBFileParser::ConstructEntities()
|
||||
{
|
||||
srcMethod = "man";
|
||||
|
||||
getCategory("entity_src_gen")->emplace({{"entity_id", mMolID2EntityID[cmp.mMolID]}, {"pdbx_src_id", structRefID}, {"gene_src_common_name", cmp.mSource["ORGANISM_COMMON"]}, {"pdbx_gene_src_gene", cmp.mSource["GENE"]}, {"gene_src_strain", cmp.mSource["STRAIN"]}, {"gene_src_tissue", cmp.mSource["TISSUE"]}, {"gene_src_tissue_fraction", cmp.mSource["TISSUE_FRACTION"]}, {"pdbx_gene_src_cell_line", cmp.mSource["CELL_LINE"]}, {"pdbx_gene_src_organelle", cmp.mSource["ORGANELLE"]}, {"pdbx_gene_src_cell", cmp.mSource["CELL"]}, {"pdbx_gene_src_cellular_location", cmp.mSource["CELLULAR_LOCATION"]}, {"host_org_common_name", cmp.mSource["EXPRESSION_SYSTEM_COMMON"]}, {"pdbx_gene_src_scientific_name", cmp.mSource["ORGANISM_SCIENTIFIC"]}, {"pdbx_gene_src_ncbi_taxonomy_id", cmp.mSource["ORGANISM_TAXID"]}, {"pdbx_host_org_scientific_name", cmp.mSource["EXPRESSION_SYSTEM"]}, {"pdbx_host_org_ncbi_taxonomy_id", cmp.mSource["EXPRESSION_SYSTEM_TAXID"]}, {"pdbx_host_org_strain", cmp.mSource["EXPRESSION_SYSTEM_STRAIN"]}, {"pdbx_host_org_variant", cmp.mSource["EXPRESSION_SYSTEM_VARIANT"]}, {"pdbx_host_org_cell_line", cmp.mSource["EXPRESSION_SYSTEM_CELL_LINE"]}, {"pdbx_host_org_cellular_location", cmp.mSource["EXPRESSION_SYSTEM_CELLULAR_LOCATION"]}, {"pdbx_host_org_vector_type", cmp.mSource["EXPRESSION_SYSTEM_VECTOR_TYPE"]}, {"pdbx_host_org_vector", cmp.mSource["EXPRESSION_SYSTEM_VECTOR"]}, {"pdbx_host_org_gene", cmp.mSource["EXPRESSION_SYSTEM_GENE"]}, {"plasmid_name", cmp.mSource["EXPRESSION_SYSTEM_PLASMID"]}, {"pdbx_description", cmp.mSource["OTHER_DETAILS"]}});
|
||||
getCategory("entity_src_gen")->emplace({
|
||||
{"entity_id", mMolID2EntityID[cmp.mMolID]},
|
||||
{"pdbx_src_id", structRefID},
|
||||
{"gene_src_common_name", cmp.mSource["ORGANISM_COMMON"]},
|
||||
{"pdbx_gene_src_gene", cmp.mSource["GENE"]},
|
||||
{"gene_src_strain", cmp.mSource["STRAIN"]},
|
||||
{"gene_src_tissue", cmp.mSource["TISSUE"]},
|
||||
{"gene_src_tissue_fraction", cmp.mSource["TISSUE_FRACTION"]},
|
||||
{"pdbx_gene_src_cell_line", cmp.mSource["CELL_LINE"]},
|
||||
{"pdbx_gene_src_organelle", cmp.mSource["ORGANELLE"]},
|
||||
{"pdbx_gene_src_cell", cmp.mSource["CELL"]},
|
||||
{"pdbx_gene_src_cellular_location", cmp.mSource["CELLULAR_LOCATION"]},
|
||||
{"host_org_common_name", cmp.mSource["EXPRESSION_SYSTEM_COMMON"]},
|
||||
{"pdbx_gene_src_scientific_name", cmp.mSource["ORGANISM_SCIENTIFIC"]},
|
||||
{"pdbx_gene_src_ncbi_taxonomy_id", cmp.mSource["ORGANISM_TAXID"]},
|
||||
{"pdbx_host_org_scientific_name", cmp.mSource["EXPRESSION_SYSTEM"]},
|
||||
{"pdbx_host_org_ncbi_taxonomy_id", cmp.mSource["EXPRESSION_SYSTEM_TAXID"]},
|
||||
{"pdbx_host_org_strain", cmp.mSource["EXPRESSION_SYSTEM_STRAIN"]},
|
||||
{"pdbx_host_org_variant", cmp.mSource["EXPRESSION_SYSTEM_VARIANT"]},
|
||||
{"pdbx_host_org_cell_line", cmp.mSource["EXPRESSION_SYSTEM_CELL_LINE"]},
|
||||
{"pdbx_host_org_cellular_location", cmp.mSource["EXPRESSION_SYSTEM_CELLULAR_LOCATION"]},
|
||||
{"pdbx_host_org_vector_type", cmp.mSource["EXPRESSION_SYSTEM_VECTOR_TYPE"]},
|
||||
{"pdbx_host_org_vector", cmp.mSource["EXPRESSION_SYSTEM_VECTOR"]},
|
||||
{"pdbx_host_org_gene", cmp.mSource["EXPRESSION_SYSTEM_GENE"]},
|
||||
{"plasmid_name", cmp.mSource["EXPRESSION_SYSTEM_PLASMID"]},
|
||||
{"pdbx_description", cmp.mSource["OTHER_DETAILS"]}});
|
||||
}
|
||||
else if (not cmp.mSource["ORGANISM_SCIENTIFIC"].empty())
|
||||
{
|
||||
@@ -3741,7 +3898,10 @@ void PDBFileParser::ConstructEntities()
|
||||
|
||||
if (not cmp.mInfo["SYNONYM"].empty())
|
||||
{
|
||||
getCategory("entity_name_com")->emplace({{"entity_id", mMolID2EntityID[cmp.mMolID]}, {"name", cmp.mInfo["SYNONYM"]}});
|
||||
getCategory("entity_name_com")->emplace({
|
||||
{"entity_id", mMolID2EntityID[cmp.mMolID]},
|
||||
{"name", cmp.mInfo["SYNONYM"]}
|
||||
});
|
||||
}
|
||||
|
||||
std::string desc = cmp.mInfo["MOLECULE"];
|
||||
@@ -3761,7 +3921,11 @@ void PDBFileParser::ConstructEntities()
|
||||
if (ci != mChains.end() and not ci->mDbref.dbIdCode.empty())
|
||||
{
|
||||
getCategory("struct_ref")->emplace({
|
||||
{"id", structRefID}, {"entity_id", mMolID2EntityID[cmp.mMolID]}, {"db_name", ci->mDbref.database}, {"db_code", ci->mDbref.dbIdCode}, {"pdbx_db_accession", ci->mDbref.dbAccession},
|
||||
{"id", structRefID},
|
||||
{"entity_id", mMolID2EntityID[cmp.mMolID]},
|
||||
{"db_name", ci->mDbref.database},
|
||||
{"db_code", ci->mDbref.dbIdCode},
|
||||
{"pdbx_db_accession", ci->mDbref.dbAccession},
|
||||
// { "pdbx_align_begin", ci->mDbref.dbSeqBegin }
|
||||
});
|
||||
}
|
||||
@@ -3810,7 +3974,23 @@ void PDBFileParser::ConstructEntities()
|
||||
{
|
||||
}
|
||||
|
||||
getCategory("struct_ref_seq")->emplace({{"align_id", structRefSeqAlignID}, {"ref_id", structRefID}, {"pdbx_PDB_id_code", dbref.PDBIDCode}, {"pdbx_strand_id", std::string{chain.mDbref.chainID}}, {"seq_align_beg", seqAlignBeg}, {"pdbx_seq_align_beg_ins_code", insToStr(dbref.insertBegin)}, {"seq_align_end", seqAlignEnd}, {"pdbx_seq_align_end_ins_code", insToStr(dbref.insertEnd)}, {"pdbx_db_accession", dbref.dbAccession}, {"db_align_beg", dbref.dbSeqBegin}, {"pdbx_db_align_beg_ins_code", insToStr(dbref.dbinsBeg)}, {"db_align_end", dbref.dbSeqEnd}, {"pdbx_db_align_end_ins_code", insToStr(dbref.dbinsEnd)}, {"pdbx_auth_seq_align_beg", dbref.seqBegin}, {"pdbx_auth_seq_align_end", dbref.seqEnd}});
|
||||
getCategory("struct_ref_seq")->emplace({
|
||||
{"align_id", structRefSeqAlignID},
|
||||
{"ref_id", structRefID},
|
||||
{"pdbx_PDB_id_code", dbref.PDBIDCode},
|
||||
{"pdbx_strand_id", std::string{chain.mDbref.chainID}},
|
||||
{"seq_align_beg", seqAlignBeg},
|
||||
{"pdbx_seq_align_beg_ins_code", insToStr(dbref.insertBegin)},
|
||||
{"seq_align_end", seqAlignEnd},
|
||||
{"pdbx_seq_align_end_ins_code", insToStr(dbref.insertEnd)},
|
||||
{"pdbx_db_accession", dbref.dbAccession},
|
||||
{"db_align_beg", dbref.dbSeqBegin},
|
||||
{"pdbx_db_align_beg_ins_code", insToStr(dbref.dbinsBeg)},
|
||||
{"db_align_end", dbref.dbSeqEnd},
|
||||
{"pdbx_db_align_end_ins_code", insToStr(dbref.dbinsEnd)},
|
||||
{"pdbx_auth_seq_align_beg", dbref.seqBegin},
|
||||
{"pdbx_auth_seq_align_end", dbref.seqEnd}
|
||||
});
|
||||
|
||||
// write the struct_ref_seq_dif
|
||||
for (auto &seqadv : mSeqadvs)
|
||||
@@ -3832,7 +4012,21 @@ void PDBFileParser::ConstructEntities()
|
||||
|
||||
seqNum = std::to_string(labelSeq);
|
||||
|
||||
getCategory("struct_ref_seq_dif")->emplace({{"align_id", structRefSeqAlignID}, {"pdbx_PDB_id_code", dbref.PDBIDCode}, {"mon_id", seqadv.resName}, {"pdbx_pdb_strand_id", seqadv.chainID}, {"seq_num", seqNum}, {"pdbx_pdb_ins_code", seqadv.iCode == ' ' ? std::string{} : std::string{seqadv.iCode}}, {"pdbx_seq_db_name", seqadv.database}, {"pdbx_seq_db_accession_code", seqadv.dbAccession}, {"db_mon_id", seqadv.dbRes}, {"pdbx_seq_db_seq_num", seqadv.dbSeq}, {"details", seqadv.conflict}, {"pdbx_auth_seq_num", seqadv.seqNum}, {"pdbx_ordinal", ++mPdbxDifOrdinal}});
|
||||
getCategory("struct_ref_seq_dif")->emplace({
|
||||
{"align_id", structRefSeqAlignID},
|
||||
{"pdbx_PDB_id_code", dbref.PDBIDCode},
|
||||
{"mon_id", seqadv.resName},
|
||||
{"pdbx_pdb_strand_id", seqadv.chainID},
|
||||
{"seq_num", seqNum},
|
||||
{"pdbx_pdb_ins_code", seqadv.iCode == ' ' ? std::string{} : std::string{seqadv.iCode}},
|
||||
{"pdbx_seq_db_name", seqadv.database},
|
||||
{"pdbx_seq_db_accession_code", seqadv.dbAccession},
|
||||
{"db_mon_id", seqadv.dbRes},
|
||||
{"pdbx_seq_db_seq_num", seqadv.dbSeq},
|
||||
{"details", seqadv.conflict},
|
||||
{"pdbx_auth_seq_num", seqadv.seqNum},
|
||||
{"pdbx_ordinal", ++mPdbxDifOrdinal}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3932,15 +4126,23 @@ void PDBFileParser::ConstructEntities()
|
||||
else if (mightBeDNA and not mightBePolyPeptide)
|
||||
type = "polyribonucleotide";
|
||||
|
||||
getCategory("entity_poly")->emplace({{"entity_id", mMolID2EntityID[cmp.mMolID]}, {"pdbx_seq_one_letter_code", seq}, {"pdbx_seq_one_letter_code_can", seqCan}, {"nstd_monomer", (nstdMonomer ? "yes" : "no")}, {"pdbx_strand_id", ba::join(chains, ",")}, {"nstd_linkage", nonstandardLinkage ? "yes" : "no"}, {"type", type}});
|
||||
getCategory("entity_poly")->emplace({{"entity_id", mMolID2EntityID[cmp.mMolID]},
|
||||
{"pdbx_seq_one_letter_code", seq},
|
||||
{"pdbx_seq_one_letter_code_can", seqCan},
|
||||
{"nstd_monomer", (nstdMonomer ? "yes" : "no")},
|
||||
{"pdbx_strand_id", ba::join(chains, ",")},
|
||||
{"nstd_linkage", nonstandardLinkage ? "yes" : "no"},
|
||||
{"type", type}});
|
||||
}
|
||||
|
||||
if (not(structTitle.empty() and structDescription.empty()))
|
||||
{
|
||||
getCategory("struct")->emplace({{"entry_id", mStructureID},
|
||||
{"title", ba::join(structTitle, ", ")},
|
||||
{"pdbx_descriptor", ba::join(structDescription, ", ")},
|
||||
{"pdbx_model_type_details", mModelTypeDetails}});
|
||||
getCategory("struct")->emplace({
|
||||
{"entry_id", mStructureID},
|
||||
{"title", ba::join(structTitle, ", ")},
|
||||
{"pdbx_descriptor", ba::join(structDescription, ", ")},
|
||||
{"pdbx_model_type_details", mModelTypeDetails}
|
||||
});
|
||||
}
|
||||
|
||||
// build sugar trees first
|
||||
@@ -4026,7 +4228,9 @@ void PDBFileParser::ConstructEntities()
|
||||
std::string name = mHetnams[hetID];
|
||||
if (name.empty() and hetID == mWaterHetID)
|
||||
name = "water";
|
||||
getCategory("pdbx_entity_nonpoly")->emplace({{"entity_id", entityID}, {"name", name}, {"comp_id", hetID}});
|
||||
getCategory("pdbx_entity_nonpoly")->emplace({{"entity_id", entityID},
|
||||
{"name", name},
|
||||
{"comp_id", hetID}});
|
||||
}
|
||||
|
||||
// create an asym for this het/chain combo, if needed
|
||||
@@ -4063,7 +4267,8 @@ void PDBFileParser::ConstructEntities()
|
||||
{
|
||||
writtenAsyms.insert(asymID);
|
||||
getCategory("struct_asym")->emplace({
|
||||
{"id", asymID}, {"pdbx_blank_PDB_chainid_flag", het.chainID == ' ' ? "Y" : "N"},
|
||||
{"id", asymID},
|
||||
{"pdbx_blank_PDB_chainid_flag", het.chainID == ' ' ? "Y" : "N"},
|
||||
// pdbx_modified
|
||||
{"entity_id", mHet2EntityID[hetID]},
|
||||
// details
|
||||
@@ -4078,12 +4283,18 @@ void PDBFileParser::ConstructEntities()
|
||||
if (iCode.empty())
|
||||
iCode = {'.'};
|
||||
|
||||
getCategory("pdbx_nonpoly_scheme")->emplace({{"asym_id", asymID}, {"entity_id", mHet2EntityID[hetID]}, {"mon_id", hetID}, {"ndb_seq_num", seqNr}, {"pdb_seq_num", het.seqNum},
|
||||
// { "auth_seq_num", het.seqNum }, // ????
|
||||
{"pdb_mon_id", hetID},
|
||||
// { "auth_mon_id", hetID },
|
||||
{"pdb_strand_id", std::string{het.chainID}},
|
||||
{"pdb_ins_code", iCode}});
|
||||
getCategory("pdbx_nonpoly_scheme")->emplace({
|
||||
{"asym_id", asymID},
|
||||
{"entity_id", mHet2EntityID[hetID]},
|
||||
{"mon_id", hetID},
|
||||
{"ndb_seq_num", seqNr},
|
||||
{"pdb_seq_num", het.seqNum},
|
||||
// { "auth_seq_num", het.seqNum }, // ????
|
||||
{"pdb_mon_id", hetID},
|
||||
// { "auth_mon_id", hetID },
|
||||
{"pdb_strand_id", std::string{het.chainID}},
|
||||
{"pdb_ins_code", iCode}
|
||||
});
|
||||
|
||||
// mapping needed?
|
||||
mChainSeq2AsymSeq[std::make_tuple(het.chainID, het.seqNum, het.iCode)] = std::make_tuple(asymID, seqNr, false);
|
||||
@@ -4113,7 +4324,18 @@ void PDBFileParser::ConstructEntities()
|
||||
continue;
|
||||
}
|
||||
|
||||
getCategory("pdbx_struct_mod_residue")->emplace({{"id", modResID++}, {"label_asym_id", asymID}, {"label_seq_id", seq}, {"label_comp_id", resName}, {"auth_asym_id", std::string(1, chainID)}, {"auth_seq_id", seqNum}, {"auth_comp_id", resName}, {"PDB_ins_code", iCode == ' ' ? "" : std::string{iCode}}, {"parent_comp_id", stdRes}, {"details", comment}});
|
||||
getCategory("pdbx_struct_mod_residue")->emplace({
|
||||
{"id", modResID++},
|
||||
{"label_asym_id", asymID},
|
||||
{"label_seq_id", seq},
|
||||
{"label_comp_id", resName},
|
||||
{"auth_asym_id", std::string(1, chainID)},
|
||||
{"auth_seq_id", seqNum},
|
||||
{"auth_comp_id", resName},
|
||||
{"PDB_ins_code", iCode == ' ' ? "" : std::string{iCode}},
|
||||
{"parent_comp_id", stdRes},
|
||||
{"details", comment}
|
||||
});
|
||||
|
||||
modResSet.insert(resName);
|
||||
}
|
||||
@@ -4162,7 +4384,12 @@ void PDBFileParser::ConstructEntities()
|
||||
if (modResSet.count(cc))
|
||||
nstd = "n";
|
||||
|
||||
getCategory("chem_comp")->emplace({{"id", cc}, {"name", name}, {"formula", formula}, {"formula_weight", formulaWeight}, {"mon_nstd_flag", nstd}, {"type", type}});
|
||||
getCategory("chem_comp")->emplace({{"id", cc},
|
||||
{"name", name},
|
||||
{"formula", formula},
|
||||
{"formula_weight", formulaWeight},
|
||||
{"mon_nstd_flag", nstd},
|
||||
{"type", type}});
|
||||
}
|
||||
|
||||
getCategory("chem_comp")->reorderByIndex();
|
||||
@@ -4195,16 +4422,39 @@ void PDBFileParser::ConstructEntities()
|
||||
|
||||
if (unobs.atoms.empty())
|
||||
{
|
||||
getCategory("pdbx_unobs_or_zero_occ_residues")->emplace({{"id", std::to_string(++idRes)}, {"polymer_flag", isPolymer ? "Y" : "N"}, {"occupancy_flag", 1}, {"PDB_model_num", unobs.modelNr ? unobs.modelNr : 1}, {"auth_asym_id", std::string{unobs.chain}}, {"auth_comp_id", unobs.res}, {"auth_seq_id", unobs.seq}, {"PDB_ins_code", unobs.iCode == ' ' ? "" : std::string{unobs.iCode}}, {"label_asym_id", asymID}, {"label_comp_id", compID}, // TODO: change to correct comp_id
|
||||
{"label_seq_id", seqNr > 0 ? std::to_string(seqNr) : ""}});
|
||||
getCategory("pdbx_unobs_or_zero_occ_residues")->emplace({
|
||||
{"id", std::to_string(++idRes)},
|
||||
{"polymer_flag", isPolymer ? "Y" : "N"},
|
||||
{"occupancy_flag", 1},
|
||||
{"PDB_model_num", unobs.modelNr ? unobs.modelNr : 1},
|
||||
{"auth_asym_id", std::string{unobs.chain}},
|
||||
{"auth_comp_id", unobs.res},
|
||||
{"auth_seq_id", unobs.seq},
|
||||
{"PDB_ins_code", unobs.iCode == ' ' ? "" : std::string{unobs.iCode}},
|
||||
{"label_asym_id", asymID},
|
||||
{"label_comp_id", compID}, // TODO: change to correct comp_id
|
||||
{"label_seq_id", seqNr > 0 ? std::to_string(seqNr) : ""}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &atom : unobs.atoms)
|
||||
{
|
||||
getCategory("pdbx_unobs_or_zero_occ_atoms")->emplace({{"id", std::to_string(++idAtom)}, {"polymer_flag", isPolymer ? "Y" : "N"}, {"occupancy_flag", 1}, {"PDB_model_num", unobs.modelNr ? unobs.modelNr : 1}, {"auth_asym_id", std::string{unobs.chain}}, {"auth_comp_id", unobs.res}, {"auth_seq_id", unobs.seq}, {"PDB_ins_code", unobs.iCode == ' ' ? "" : std::string{unobs.iCode}}, {"auth_atom_id", atom}, {"label_asym_id", asymID}, {"label_comp_id", compID}, // TODO: change to correct comp_id
|
||||
{"label_seq_id", seqNr > 0 ? std::to_string(seqNr) : ""},
|
||||
{"label_atom_id", atom}});
|
||||
getCategory("pdbx_unobs_or_zero_occ_atoms")->emplace({
|
||||
{"id", std::to_string(++idAtom)},
|
||||
{"polymer_flag", isPolymer ? "Y" : "N"},
|
||||
{"occupancy_flag", 1},
|
||||
{"PDB_model_num", unobs.modelNr ? unobs.modelNr : 1},
|
||||
{"auth_asym_id", std::string{unobs.chain}},
|
||||
{"auth_comp_id", unobs.res},
|
||||
{"auth_seq_id", unobs.seq},
|
||||
{"PDB_ins_code", unobs.iCode == ' ' ? "" : std::string{unobs.iCode}},
|
||||
{"auth_atom_id", atom},
|
||||
{"label_asym_id", asymID},
|
||||
{"label_comp_id", compID}, // TODO: change to correct comp_id
|
||||
{"label_seq_id", seqNr > 0 ? std::to_string(seqNr) : ""},
|
||||
{"label_atom_id", atom}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4288,14 +4538,18 @@ void PDBFileParser::ConstructSugarTrees(int &asymNr)
|
||||
{"src_method", "man"},
|
||||
{"pdbx_description", branchName}});
|
||||
|
||||
getCategory("pdbx_entity_branch")->emplace({{"entity_id", entityID}, {"type", "oligosaccharide"}});
|
||||
getCategory("pdbx_entity_branch")->emplace({{"entity_id", entityID},
|
||||
{"type", "oligosaccharide"}});
|
||||
|
||||
int num = 0;
|
||||
std::map<ATOM_REF, int> branch_list;
|
||||
|
||||
for (auto &s : sugarTree)
|
||||
{
|
||||
getCategory("pdbx_entity_branch_list")->emplace({{"entity_id", entityID}, {"comp_id", s.c1.resName}, {"num", ++num}, {"hetero", ci.size() == 1 ? "n" : "y"}});
|
||||
getCategory("pdbx_entity_branch_list")->emplace({{"entity_id", entityID},
|
||||
{"comp_id", s.c1.resName},
|
||||
{"num", ++num},
|
||||
{"hetero", ci.size() == 1 ? "n" : "y"}});
|
||||
|
||||
branch_list[s.c1] = num;
|
||||
}
|
||||
@@ -4327,7 +4581,10 @@ void PDBFileParser::ConstructSugarTrees(int &asymNr)
|
||||
|
||||
std::string asymID = cif::cifIdForNumber(asymNr++);
|
||||
|
||||
getCategory("struct_asym")->emplace({{"id", asymID}, {"pdbx_blank_PDB_chainid_flag", si->chainID == ' ' ? "Y" : "N"}, {"pdbx_modified", "N"}, {"entity_id", entityID}});
|
||||
getCategory("struct_asym")->emplace({{"id", asymID},
|
||||
{"pdbx_blank_PDB_chainid_flag", si->chainID == ' ' ? "Y" : "N"},
|
||||
{"pdbx_modified", "N"},
|
||||
{"entity_id", entityID}});
|
||||
|
||||
std::string iCode{si->iCode};
|
||||
ba::trim(iCode);
|
||||
@@ -4337,7 +4594,19 @@ void PDBFileParser::ConstructSugarTrees(int &asymNr)
|
||||
int num = 0;
|
||||
for (auto s : sugarTree)
|
||||
{
|
||||
getCategory("pdbx_branch_scheme")->emplace({{"asym_id", asymID}, {"entity_id", entityID}, {"mon_id", s.c1.resName}, {"num", ++num}, {"pdb_asym_id", asymID}, {"pdb_mon_id", s.c1.resName}, {"pdb_seq_num", num}, {"auth_asym_id", std::string{s.c1.chainID}}, {"auth_mon_id", s.next.resName}, {"auth_seq_num", s.c1.resSeq}, {"hetero", ci.size() == 1 ? "n" : "y"}});
|
||||
getCategory("pdbx_branch_scheme")->emplace({
|
||||
{"asym_id", asymID},
|
||||
{"entity_id", entityID},
|
||||
{"mon_id", s.c1.resName},
|
||||
{"num", ++num},
|
||||
{"pdb_asym_id", asymID},
|
||||
{"pdb_mon_id", s.c1.resName},
|
||||
{"pdb_seq_num", num},
|
||||
{"auth_asym_id", std::string{s.c1.chainID}},
|
||||
{"auth_mon_id", s.next.resName},
|
||||
{"auth_seq_num", s.c1.resSeq},
|
||||
{"hetero", ci.size() == 1 ? "n" : "y"}
|
||||
});
|
||||
|
||||
auto k = std::make_tuple(s.c1.chainID, s.c1.resSeq, s.c1.iCode);
|
||||
assert(mChainSeq2AsymSeq.count(k) == 0);
|
||||
@@ -4506,7 +4775,10 @@ void PDBFileParser::ParseSecondaryStructure()
|
||||
|
||||
if (sense != 0)
|
||||
{
|
||||
getCategory("struct_sheet_order")->emplace({{"sheet_id", sheetID}, {"range_id_1", rangeID}, {"range_id_2", rangeID + 1}, {"sense", sense == -1 ? "anti-parallel" : "parallel"}});
|
||||
getCategory("struct_sheet_order")->emplace({{"sheet_id", sheetID},
|
||||
{"range_id_1", rangeID},
|
||||
{"range_id_2", rangeID + 1},
|
||||
{"sense", sense == -1 ? "anti-parallel" : "parallel"}});
|
||||
}
|
||||
|
||||
std::string begAsymID, endAsymID;
|
||||
@@ -4559,17 +4831,30 @@ void PDBFileParser::ParseSecondaryStructure()
|
||||
std::cerr << "skipping unmatched pdbx_struct_sheet_hbond record" << std::endl;
|
||||
}
|
||||
else
|
||||
getCategory("pdbx_struct_sheet_hbond")->emplace({{"sheet_id", sheetID}, {"range_id_1", rangeID}, {"range_id_2", rangeID + 1}, {"range_1_label_atom_id", vS(57, 60)}, {"range_1_label_comp_id", vS(61, 63)}, {"range_1_label_asym_id", r1AsymID}, {"range_1_label_seq_id", r1Seq}, {"range_1_PDB_ins_code", vS(70, 70)}, {"range_1_auth_atom_id", vS(57, 60)}, {"range_1_auth_comp_id", vS(61, 63)}, {"range_1_auth_asym_id", vS(65, 65)}, {"range_1_auth_seq_id", vI(66, 69)},
|
||||
getCategory("pdbx_struct_sheet_hbond")->emplace({
|
||||
{"sheet_id", sheetID},
|
||||
{"range_id_1", rangeID},
|
||||
{"range_id_2", rangeID + 1},
|
||||
{"range_1_label_atom_id", vS(57, 60)},
|
||||
{"range_1_label_comp_id", vS(61, 63)},
|
||||
{"range_1_label_asym_id", r1AsymID},
|
||||
{"range_1_label_seq_id", r1Seq},
|
||||
{"range_1_PDB_ins_code", vS(70, 70)},
|
||||
{"range_1_auth_atom_id", vS(57, 60)},
|
||||
{"range_1_auth_comp_id", vS(61, 63)},
|
||||
{"range_1_auth_asym_id", vS(65, 65)},
|
||||
{"range_1_auth_seq_id", vI(66, 69)},
|
||||
|
||||
{"range_2_label_atom_id", vS(42, 45)},
|
||||
{"range_2_label_comp_id", vS(46, 48)},
|
||||
{"range_2_label_asym_id", r2AsymID},
|
||||
{"range_2_label_seq_id", r2Seq},
|
||||
{"range_2_PDB_ins_code", vS(55, 55)},
|
||||
{"range_2_auth_atom_id", vS(42, 45)},
|
||||
{"range_2_auth_comp_id", vS(46, 48)},
|
||||
{"range_2_auth_asym_id", vS(50, 50)},
|
||||
{"range_2_auth_seq_id", vI(51, 54)}});
|
||||
{"range_2_label_atom_id", vS(42, 45)},
|
||||
{"range_2_label_comp_id", vS(46, 48)},
|
||||
{"range_2_label_asym_id", r2AsymID},
|
||||
{"range_2_label_seq_id", r2Seq},
|
||||
{"range_2_PDB_ins_code", vS(55, 55)},
|
||||
{"range_2_auth_atom_id", vS(42, 45)},
|
||||
{"range_2_auth_comp_id", vS(46, 48)},
|
||||
{"range_2_auth_asym_id", vS(50, 50)},
|
||||
{"range_2_auth_seq_id", vI(51, 54)}
|
||||
});
|
||||
}
|
||||
|
||||
if (sense != 0)
|
||||
@@ -4798,7 +5083,8 @@ void PDBFileParser::ParseConnectivtyAnnotation()
|
||||
continue;
|
||||
}
|
||||
|
||||
getCategory("struct_conn")->emplace({{"id", type + std::to_string(linkNr)}, {"conn_type_id", type},
|
||||
getCategory("struct_conn")->emplace({{"id", type + std::to_string(linkNr)},
|
||||
{"conn_type_id", type},
|
||||
|
||||
// { "ccp4_link_id", ccp4LinkID },
|
||||
|
||||
@@ -4871,7 +5157,24 @@ void PDBFileParser::ParseConnectivtyAnnotation()
|
||||
std::string iCode1str = iCode1 == ' ' ? std::string() : std::string{iCode1};
|
||||
std::string iCode2str = iCode2 == ' ' ? std::string() : std::string{iCode2};
|
||||
|
||||
getCategory("struct_mon_prot_cis")->emplace({{"pdbx_id", serNum}, {"label_comp_id", pep1}, {"label_seq_id", lResSeq1}, {"label_asym_id", lAsym1}, {"label_alt_id", "."}, {"pdbx_PDB_ins_code", iCode1str}, {"auth_comp_id", pep1}, {"auth_seq_id", seqNum1}, {"auth_asym_id", std::string{chainID1}}, {"pdbx_label_comp_id_2", pep2}, {"pdbx_label_seq_id_2", lResSeq2}, {"pdbx_label_asym_id_2", lAsym2}, {"pdbx_PDB_ins_code_2", iCode2str}, {"pdbx_auth_comp_id_2", pep2}, {"pdbx_auth_seq_id_2", seqNum2}, {"pdbx_auth_asym_id_2", std::string{chainID2}}, {"pdbx_PDB_model_num", modNum}, {"pdbx_omega_angle", measure}});
|
||||
getCategory("struct_mon_prot_cis")->emplace({{"pdbx_id", serNum},
|
||||
{"label_comp_id", pep1},
|
||||
{"label_seq_id", lResSeq1},
|
||||
{"label_asym_id", lAsym1},
|
||||
{"label_alt_id", "."},
|
||||
{"pdbx_PDB_ins_code", iCode1str},
|
||||
{"auth_comp_id", pep1},
|
||||
{"auth_seq_id", seqNum1},
|
||||
{"auth_asym_id", std::string{chainID1}},
|
||||
{"pdbx_label_comp_id_2", pep2},
|
||||
{"pdbx_label_seq_id_2", lResSeq2},
|
||||
{"pdbx_label_asym_id_2", lAsym2},
|
||||
{"pdbx_PDB_ins_code_2", iCode2str},
|
||||
{"pdbx_auth_comp_id_2", pep2},
|
||||
{"pdbx_auth_seq_id_2", seqNum2},
|
||||
{"pdbx_auth_asym_id_2", std::string{chainID2}},
|
||||
{"pdbx_PDB_model_num", modNum},
|
||||
{"pdbx_omega_angle", measure}});
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -4964,7 +5267,9 @@ void PDBFileParser::ParseCrystallographic()
|
||||
{
|
||||
}
|
||||
|
||||
getCategory("symmetry")->emplace({{"entry_id", mStructureID}, {"space_group_name_H-M", spaceGroup}, {"Int_Tables_number", intTablesNr}});
|
||||
getCategory("symmetry")->emplace({{"entry_id", mStructureID},
|
||||
{"space_group_name_H-M", spaceGroup},
|
||||
{"Int_Tables_number", intTablesNr}});
|
||||
|
||||
GetNextRecord();
|
||||
}
|
||||
@@ -5056,7 +5361,20 @@ void PDBFileParser::ParseCoordinateTransformation()
|
||||
GetNextRecord(); // transformations of the molecule are
|
||||
} // contained in the datablock. Otherwise, blank.
|
||||
|
||||
getCategory("struct_ncs_oper")->emplace({{"id", serial}, {"matrix[1][1]", m[0][0]}, {"matrix[1][2]", m[0][1]}, {"matrix[1][3]", m[0][2]}, {"matrix[2][1]", m[1][0]}, {"matrix[2][2]", m[1][1]}, {"matrix[2][3]", m[1][2]}, {"matrix[3][1]", m[2][0]}, {"matrix[3][2]", m[2][1]}, {"matrix[3][3]", m[2][2]}, {"vector[1]", v[0]}, {"vector[2]", v[1]}, {"vector[3]", v[2]}, {"code", igiven ? "given" : ""}});
|
||||
getCategory("struct_ncs_oper")->emplace({{"id", serial},
|
||||
{"matrix[1][1]", m[0][0]},
|
||||
{"matrix[1][2]", m[0][1]},
|
||||
{"matrix[1][3]", m[0][2]},
|
||||
{"matrix[2][1]", m[1][0]},
|
||||
{"matrix[2][2]", m[1][1]},
|
||||
{"matrix[2][3]", m[1][2]},
|
||||
{"matrix[3][1]", m[2][0]},
|
||||
{"matrix[3][2]", m[2][1]},
|
||||
{"matrix[3][3]", m[2][2]},
|
||||
{"vector[1]", v[0]},
|
||||
{"vector[2]", v[1]},
|
||||
{"vector[3]", v[2]},
|
||||
{"code", igiven ? "given" : ""}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5215,7 +5533,27 @@ void PDBFileParser::ParseCoordinate(int modelNr)
|
||||
}
|
||||
}
|
||||
|
||||
getCategory("atom_site")->emplace({{"group_PDB", groupPDB}, {"id", mAtomID}, {"type_symbol", element}, {"label_atom_id", name}, {"label_alt_id", altLoc != ' ' ? std::string{altLoc} : "."}, {"label_comp_id", resName}, {"label_asym_id", asymID}, {"label_entity_id", entityID}, {"label_seq_id", (isResseq and seqID > 0) ? std::to_string(seqID) : "."}, {"pdbx_PDB_ins_code", iCode == ' ' ? "" : std::string{iCode}}, {"Cartn_x", x}, {"Cartn_y", y}, {"Cartn_z", z}, {"occupancy", occupancy}, {"B_iso_or_equiv", tempFactor}, {"pdbx_formal_charge", charge}, {"auth_seq_id", resSeq}, {"auth_comp_id", resName}, {"auth_asym_id", std::string{chainID}}, {"auth_atom_id", name}, {"pdbx_PDB_model_num", modelNr}});
|
||||
getCategory("atom_site")->emplace({{"group_PDB", groupPDB},
|
||||
{"id", mAtomID},
|
||||
{"type_symbol", element},
|
||||
{"label_atom_id", name},
|
||||
{"label_alt_id", altLoc != ' ' ? std::string{altLoc} : "."},
|
||||
{"label_comp_id", resName},
|
||||
{"label_asym_id", asymID},
|
||||
{"label_entity_id", entityID},
|
||||
{"label_seq_id", (isResseq and seqID > 0) ? std::to_string(seqID) : "."},
|
||||
{"pdbx_PDB_ins_code", iCode == ' ' ? "" : std::string{iCode}},
|
||||
{"Cartn_x", x},
|
||||
{"Cartn_y", y},
|
||||
{"Cartn_z", z},
|
||||
{"occupancy", occupancy},
|
||||
{"B_iso_or_equiv", tempFactor},
|
||||
{"pdbx_formal_charge", charge},
|
||||
{"auth_seq_id", resSeq},
|
||||
{"auth_comp_id", resName},
|
||||
{"auth_asym_id", std::string{chainID}},
|
||||
{"auth_atom_id", name},
|
||||
{"pdbx_PDB_model_num", modelNr}});
|
||||
|
||||
InsertAtomType(element);
|
||||
|
||||
@@ -5237,7 +5575,23 @@ void PDBFileParser::ParseCoordinate(int modelNr)
|
||||
auto f = [](float f) -> std::string
|
||||
{ return (boost::format("%6.4f") % f).str(); };
|
||||
|
||||
getCategory("atom_site_anisotrop")->emplace({{"id", mAtomID}, {"type_symbol", element}, {"pdbx_label_atom_id", name}, {"pdbx_label_alt_id", altLoc != ' ' ? std::string{altLoc} : "."}, {"pdbx_label_comp_id", resName}, {"pdbx_label_asym_id", asymID}, {"pdbx_label_seq_id", (isResseq and seqID > 0) ? std::to_string(seqID) : "."}, {"U[1][1]", f(u11 / 10000.f)}, {"U[2][2]", f(u22 / 10000.f)}, {"U[3][3]", f(u33 / 10000.f)}, {"U[1][2]", f(u12 / 10000.f)}, {"U[1][3]", f(u13 / 10000.f)}, {"U[2][3]", f(u23 / 10000.f)}, {"pdbx_auth_seq_id", resSeq}, {"pdbx_auth_comp_id", resName}, {"pdbx_auth_asym_id", std::string{chainID}}, {"pdbx_auth_atom_id", name}});
|
||||
getCategory("atom_site_anisotrop")->emplace({{"id", mAtomID},
|
||||
{"type_symbol", element},
|
||||
{"pdbx_label_atom_id", name},
|
||||
{"pdbx_label_alt_id", altLoc != ' ' ? std::string{altLoc} : "."},
|
||||
{"pdbx_label_comp_id", resName},
|
||||
{"pdbx_label_asym_id", asymID},
|
||||
{"pdbx_label_seq_id", (isResseq and seqID > 0) ? std::to_string(seqID) : "."},
|
||||
{"U[1][1]", f(u11 / 10000.f)},
|
||||
{"U[2][2]", f(u22 / 10000.f)},
|
||||
{"U[3][3]", f(u33 / 10000.f)},
|
||||
{"U[1][2]", f(u12 / 10000.f)},
|
||||
{"U[1][3]", f(u13 / 10000.f)},
|
||||
{"U[2][3]", f(u23 / 10000.f)},
|
||||
{"pdbx_auth_seq_id", resSeq},
|
||||
{"pdbx_auth_comp_id", resName},
|
||||
{"pdbx_auth_asym_id", std::string{chainID}},
|
||||
{"pdbx_auth_atom_id", name}});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
289
src/Point.cpp
289
src/Point.cpp
@@ -28,11 +28,248 @@
|
||||
#include <valarray>
|
||||
|
||||
#include "cif++/Point.hpp"
|
||||
#include "cif++/Matrix.hpp"
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// We're using expression templates here
|
||||
|
||||
template <typename M>
|
||||
class MatrixExpression
|
||||
{
|
||||
public:
|
||||
uint32_t dim_m() const { return static_cast<const M&>(*this).dim_m(); }
|
||||
uint32_t dim_n() const { return static_cast<const M&>(*this).dim_n(); }
|
||||
|
||||
double &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
return static_cast<M&>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return static_cast<const M&>(*this).operator()(i, j);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
// element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
|
||||
class Matrix : public MatrixExpression<Matrix>
|
||||
{
|
||||
public:
|
||||
template <typename M2>
|
||||
Matrix(const MatrixExpression<M2> &m)
|
||||
: m_m(m.dim_m())
|
||||
, m_n(m.dim_n())
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_m; ++i)
|
||||
{
|
||||
for (uint32_t j = 0; j < m_n; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
Matrix(size_t m, size_t n, double v = 0)
|
||||
: m_m(m)
|
||||
, m_n(n)
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
Matrix() = default;
|
||||
Matrix(Matrix &&m) = default;
|
||||
Matrix(const Matrix &m) = default;
|
||||
Matrix &operator=(Matrix &&m) = default;
|
||||
Matrix &operator=(const Matrix &m) = default;
|
||||
|
||||
uint32_t dim_m() const { return m_m; }
|
||||
uint32_t dim_n() const { return m_n; }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
double &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_m = 0, m_n = 0;
|
||||
std::vector<double> m_data;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class SymmetricMatrix : public MatrixExpression<SymmetricMatrix>
|
||||
{
|
||||
public:
|
||||
SymmetricMatrix(uint32_t n, double v = 0)
|
||||
: m_n(n)
|
||||
, m_data((m_n * (m_n + 1)) / 2)
|
||||
{
|
||||
std::fill(m_data.begin(), m_data.end(), v);
|
||||
}
|
||||
|
||||
SymmetricMatrix() = default;
|
||||
SymmetricMatrix(SymmetricMatrix &&m) = default;
|
||||
SymmetricMatrix(const SymmetricMatrix &m) = default;
|
||||
SymmetricMatrix &operator=(SymmetricMatrix &&m) = default;
|
||||
SymmetricMatrix &operator=(const SymmetricMatrix &m) = default;
|
||||
|
||||
uint32_t dim_m() const { return m_n; }
|
||||
uint32_t dim_n() const { return m_n; }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
: m_data[(i * (i + 1)) / 2 + j];
|
||||
}
|
||||
|
||||
double &operator()(uint32_t i, uint32_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
assert(j < m_n);
|
||||
return m_data[(j * (j + 1)) / 2 + i];
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
std::vector<double> m_data;
|
||||
};
|
||||
|
||||
class IdentityMatrix : public MatrixExpression<IdentityMatrix>
|
||||
{
|
||||
public:
|
||||
IdentityMatrix(uint32_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t dim_m() const { return m_n; }
|
||||
uint32_t dim_n() const { return m_n; }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return i == j ? 1 : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// matrix functions, implemented as expression templates
|
||||
|
||||
template<typename M1, typename M2>
|
||||
class MatrixSubtraction : public MatrixExpression<MatrixSubtraction<M1, M2>>
|
||||
{
|
||||
public:
|
||||
MatrixSubtraction(const M1 &m1, const M2 &m2)
|
||||
: m_m1(m1), m_m2(m2)
|
||||
{
|
||||
assert(m_m1.dim_m() == m_m2.dim_m());
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
uint32_t dim_m() const { return m_m1.dim_m(); }
|
||||
uint32_t dim_n() const { return m_m1.dim_n(); }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M1 &m_m1;
|
||||
const M2 &m_m2;
|
||||
};
|
||||
|
||||
template<typename M1, typename M2>
|
||||
MatrixSubtraction<M1, M2> operator-(const MatrixExpression<M1> &m1, const MatrixExpression<M2> &m2)
|
||||
{
|
||||
return MatrixSubtraction(*static_cast<const M1*>(&m1), *static_cast<const M2*>(&m2));
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
class MatrixMultiplication : public MatrixExpression<MatrixMultiplication<M>>
|
||||
{
|
||||
public:
|
||||
MatrixMultiplication(const M &m, double v)
|
||||
: m_m(m), m_v(v)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t dim_m() const { return m_m.dim_m(); }
|
||||
uint32_t dim_n() const { return m_m.dim_n(); }
|
||||
|
||||
double operator()(uint32_t i, uint32_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
double m_v;
|
||||
};
|
||||
|
||||
template<typename M>
|
||||
MatrixMultiplication<M> operator*(const MatrixExpression<M> &m, double v)
|
||||
{
|
||||
return MatrixMultiplication(*static_cast<const M*>(&m), v);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template<class M1>
|
||||
Matrix Cofactors(const M1& m)
|
||||
{
|
||||
Matrix cf(m.dim_m(), m.dim_m());
|
||||
|
||||
const size_t ixs[4][3] =
|
||||
{
|
||||
{ 1, 2, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 1, 2 }
|
||||
};
|
||||
|
||||
for (size_t x = 0; x < 4; ++x)
|
||||
{
|
||||
const size_t* ix = ixs[x];
|
||||
|
||||
for (size_t y = 0; y < 4; ++y)
|
||||
{
|
||||
const size_t* iy = ixs[y];
|
||||
|
||||
cf(x, y) =
|
||||
m(ix[0], iy[0]) * m(ix[1], iy[1]) * m(ix[2], iy[2]) +
|
||||
m(ix[0], iy[1]) * m(ix[1], iy[2]) * m(ix[2], iy[0]) +
|
||||
m(ix[0], iy[2]) * m(ix[1], iy[0]) * m(ix[2], iy[1]) -
|
||||
m(ix[0], iy[2]) * m(ix[1], iy[1]) * m(ix[2], iy[0]) -
|
||||
m(ix[0], iy[1]) * m(ix[1], iy[0]) * m(ix[2], iy[2]) -
|
||||
m(ix[0], iy[0]) * m(ix[1], iy[2]) * m(ix[2], iy[1]);
|
||||
|
||||
if ((x + y) % 2 == 1)
|
||||
cf(x, y) *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
Quaternion Normalize(Quaternion q)
|
||||
@@ -102,14 +339,14 @@ Point CenterPoints(std::vector<Point>& Points)
|
||||
return t;
|
||||
}
|
||||
|
||||
Point Centroid(std::vector<Point>& Points)
|
||||
Point Centroid(const std::vector<Point>& pts)
|
||||
{
|
||||
Point result;
|
||||
|
||||
for (Point& pt : Points)
|
||||
for (auto &pt : pts)
|
||||
result += pt;
|
||||
|
||||
result /= static_cast<float>(Points.size());
|
||||
result /= static_cast<float>(pts.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -175,7 +412,7 @@ double LargestDepressedQuarticSolution(double a, double b, double c)
|
||||
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);
|
||||
Matrix M(3, 3, 0);
|
||||
|
||||
for (uint32_t i = 0; i < pa.size(); ++i)
|
||||
{
|
||||
@@ -188,7 +425,7 @@ Quaternion AlignPoints(const std::vector<Point>& pa, const std::vector<Point>& p
|
||||
}
|
||||
|
||||
// Now calculate N, a symmetric 4x4 Matrix
|
||||
SymmetricMatrix<double> N(4);
|
||||
SymmetricMatrix N(4);
|
||||
|
||||
N(0, 0) = M(0, 0) + M(1, 1) + M(2, 2);
|
||||
N(0, 1) = M(1, 2) - M(2, 1);
|
||||
@@ -225,6 +462,7 @@ Quaternion AlignPoints(const std::vector<Point>& pa, const std::vector<Point>& p
|
||||
M(1, 2) * M(2, 0) * M(0, 1) +
|
||||
M(2, 1) * M(1, 0) * M(0, 2));
|
||||
|
||||
// E is the determinant of N:
|
||||
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)) +
|
||||
@@ -234,47 +472,22 @@ Quaternion AlignPoints(const std::vector<Point>& pa, const std::vector<Point>& p
|
||||
(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);
|
||||
double lambda = LargestDepressedQuarticSolution(C, D, E);
|
||||
|
||||
// calculate t = (N - λI)
|
||||
Matrix<double> li = IdentityMatrix<double>(4) * lm;
|
||||
Matrix<double> t = N - li;
|
||||
Matrix t = N - IdentityMatrix(4) * lambda;
|
||||
|
||||
// calculate a Matrix of cofactors for t
|
||||
Matrix<double> cf(4, 4);
|
||||
Matrix cf = Cofactors(t);
|
||||
|
||||
const uint32_t ixs[4][3] =
|
||||
int maxR = 0;
|
||||
for (int r = 1; r < 4; ++r)
|
||||
{
|
||||
{ 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))
|
||||
if (std::abs(cf(r, 0)) > std::abs(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));
|
||||
Quaternion q(cf(maxR, 0), cf(maxR, 1), cf(maxR, 2), cf(maxR, 3));
|
||||
q = Normalize(q);
|
||||
|
||||
return q;
|
||||
|
||||
@@ -897,7 +897,6 @@ void CalculateBetaSheets(std::vector<Res>& inResidues, DSSP_Statistics& stats)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TODO: improve alpha helix calculation by better recognizing pi-helices
|
||||
|
||||
void CalculateAlphaHelices(std::vector<Res>& inResidues, DSSP_Statistics& stats, bool inPreferPiHelices = true)
|
||||
{
|
||||
|
||||
@@ -216,9 +216,9 @@ struct AtomImpl
|
||||
, mLocation(i.mLocation)
|
||||
, mRefcount(1)
|
||||
, mRow(i.mRow)
|
||||
, mCachedRefs(i.mCachedRefs)
|
||||
, mCompound(i.mCompound)
|
||||
, mRadius(i.mRadius)
|
||||
, mCachedProperties(i.mCachedProperties)
|
||||
, mSymmetryCopy(i.mSymmetryCopy)
|
||||
, mClone(true)
|
||||
// , mRTop(i.mRTop), mD(i.mD)
|
||||
@@ -270,9 +270,9 @@ struct AtomImpl
|
||||
, mLocation(loc)
|
||||
, mRefcount(1)
|
||||
, mRow(impl.mRow)
|
||||
, mCachedRefs(impl.mCachedRefs)
|
||||
, mCompound(impl.mCompound)
|
||||
, mRadius(impl.mRadius)
|
||||
, mCachedProperties(impl.mCachedProperties)
|
||||
, mSymmetryCopy(true)
|
||||
, mSymmetryOperator(sym_op)
|
||||
{
|
||||
@@ -317,13 +317,15 @@ struct AtomImpl
|
||||
auto cat = mDb.get("atom_site_anisotrop");
|
||||
if (cat)
|
||||
{
|
||||
auto r = cat->find1(cif::Key("id") == mID);
|
||||
|
||||
if (not r.empty())
|
||||
try
|
||||
{
|
||||
result = true;
|
||||
auto r = cat->find1(cif::Key("id") == mID);
|
||||
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]");
|
||||
result = true;
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,9 +340,9 @@ struct AtomImpl
|
||||
|
||||
if (not mClone)
|
||||
{
|
||||
mRow["Cartn_x"] = p.getX();
|
||||
mRow["Cartn_y"] = p.getY();
|
||||
mRow["Cartn_z"] = p.getZ();
|
||||
property("Cartn_x", std::to_string(p.getX()));
|
||||
property("Cartn_y", std::to_string(p.getY()));
|
||||
property("Cartn_z", std::to_string(p.getZ()));
|
||||
}
|
||||
|
||||
// boost::format kPosFmt("%.3f");
|
||||
@@ -382,26 +384,31 @@ struct AtomImpl
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
const std::string &property(const std::string &name) const
|
||||
const std::string property(const std::string_view name) const
|
||||
{
|
||||
static std::string kEmptyString;
|
||||
|
||||
auto i = mCachedProperties.find(name);
|
||||
if (i == mCachedProperties.end())
|
||||
for (auto &&[tag, ref] : mCachedRefs)
|
||||
{
|
||||
auto v = mRow[name];
|
||||
if (v.empty())
|
||||
return kEmptyString;
|
||||
|
||||
return mCachedProperties[name] = v.as<std::string>();
|
||||
if (tag == name)
|
||||
return ref.as<std::string>();
|
||||
}
|
||||
else
|
||||
return i->second;
|
||||
|
||||
mCachedRefs.emplace_back(name, mRow[name]);
|
||||
return std::get<1>(mCachedRefs.back()).as<std::string>();
|
||||
}
|
||||
|
||||
void property(const std::string &name, const std::string &value)
|
||||
void property(const std::string_view name, const std::string &value)
|
||||
{
|
||||
mRow[name] = value;
|
||||
for (auto &&[tag, ref] : mCachedRefs)
|
||||
{
|
||||
if (tag != name)
|
||||
continue;
|
||||
|
||||
ref = value;
|
||||
return;
|
||||
}
|
||||
|
||||
mCachedRefs.emplace_back(name, mRow[name]);
|
||||
std::get<1>(mCachedRefs.back()) = value;
|
||||
}
|
||||
|
||||
int compare(const AtomImpl &b) const
|
||||
@@ -432,9 +439,11 @@ struct AtomImpl
|
||||
Point mLocation;
|
||||
int mRefcount;
|
||||
cif::Row mRow;
|
||||
|
||||
mutable std::vector<std::tuple<std::string,cif::detail::ItemReference>> mCachedRefs;
|
||||
|
||||
mutable const Compound *mCompound = nullptr;
|
||||
float mRadius = std::nanf("4");
|
||||
mutable std::map<std::string, std::string> mCachedProperties;
|
||||
|
||||
bool mSymmetryCopy = false;
|
||||
bool mClone = false;
|
||||
@@ -533,25 +542,25 @@ const cif::Row Atom::getRowAniso() const
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string Atom::property<std::string>(const std::string &name) const
|
||||
std::string Atom::property<std::string>(const std::string_view name) const
|
||||
{
|
||||
return impl()->property(name);
|
||||
}
|
||||
|
||||
template <>
|
||||
int Atom::property<int>(const std::string &name) const
|
||||
int Atom::property<int>(const std::string_view name) const
|
||||
{
|
||||
auto v = impl()->property(name);
|
||||
return v.empty() ? 0 : stoi(v);
|
||||
}
|
||||
|
||||
template <>
|
||||
float Atom::property<float>(const std::string &name) const
|
||||
float Atom::property<float>(const std::string_view name) const
|
||||
{
|
||||
return stof(impl()->property(name));
|
||||
}
|
||||
|
||||
void Atom::property(const std::string &name, const std::string &value)
|
||||
void Atom::property(const std::string_view name, const std::string &value)
|
||||
{
|
||||
impl()->property(name, value);
|
||||
}
|
||||
@@ -1736,7 +1745,7 @@ File::~File()
|
||||
delete mImpl;
|
||||
}
|
||||
|
||||
cif::Datablock& File::createDatablock(const std::string &name)
|
||||
cif::Datablock& File::createDatablock(const std::string_view name)
|
||||
{
|
||||
auto db = new cif::Datablock(name);
|
||||
|
||||
@@ -1790,6 +1799,33 @@ Structure::Structure(File &f, size_t modelNr, StructureOpenOptions options)
|
||||
|
||||
auto &atomCat = (*db)["atom_site"];
|
||||
|
||||
loadAtomsForModel(options);
|
||||
|
||||
// Check to see if we should actually load another model?
|
||||
if (mAtoms.empty() and mModelNr == 1)
|
||||
{
|
||||
std::optional<size_t> model_nr;
|
||||
cif::tie(model_nr) = atomCat.front().get("pdbx_PDB_model_num");
|
||||
if (model_nr and *model_nr != mModelNr)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
std::cerr << "No atoms loaded for model 1, trying model " << *model_nr << std::endl;
|
||||
mModelNr = *model_nr;
|
||||
loadAtomsForModel(options);
|
||||
}
|
||||
}
|
||||
|
||||
if (mAtoms.empty())
|
||||
std::cerr << "Warning: no atoms loaded" << std::endl;
|
||||
else
|
||||
loadData();
|
||||
}
|
||||
|
||||
void Structure::loadAtomsForModel(StructureOpenOptions options)
|
||||
{
|
||||
auto db = mFile.impl().mDb;
|
||||
auto &atomCat = (*db)["atom_site"];
|
||||
|
||||
for (auto &a : atomCat)
|
||||
{
|
||||
std::string id, type_symbol;
|
||||
@@ -1805,10 +1841,9 @@ Structure::Structure(File &f, size_t modelNr, StructureOpenOptions options)
|
||||
|
||||
mAtoms.emplace_back(new AtomImpl(*db, id, a));
|
||||
}
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
||||
Structure::Structure(const Structure &s)
|
||||
: mFile(s.mFile)
|
||||
, mModelNr(s.mModelNr)
|
||||
@@ -1952,6 +1987,58 @@ Atom Structure::getAtomByLabel(const std::string &atomID, const std::string &asy
|
||||
throw std::out_of_range("Could not find atom with specified label");
|
||||
}
|
||||
|
||||
Atom Structure::getAtomByPosition(Point p) const
|
||||
{
|
||||
double distance = std::numeric_limits<double>::max();
|
||||
size_t index = std::numeric_limits<size_t>::max();
|
||||
|
||||
for (size_t i = 0; i < mAtoms.size(); ++i)
|
||||
{
|
||||
auto &a = mAtoms.at(i);
|
||||
|
||||
auto d = Distance(a.location(), p);
|
||||
if (d < distance)
|
||||
{
|
||||
distance = d;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < mAtoms.size())
|
||||
return mAtoms.at(index);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Atom Structure::getAtomByPositionAndType(Point p, std::string_view type, std::string_view res_type) const
|
||||
{
|
||||
double distance = std::numeric_limits<double>::max();
|
||||
size_t index = std::numeric_limits<size_t>::max();
|
||||
|
||||
for (size_t i = 0; i < mAtoms.size(); ++i)
|
||||
{
|
||||
auto &a = mAtoms.at(i);
|
||||
|
||||
if (a.labelCompID() != res_type)
|
||||
continue;
|
||||
|
||||
if (a.labelAtomID() != type)
|
||||
continue;
|
||||
|
||||
auto d = Distance(a.location(), p);
|
||||
if (d < distance)
|
||||
{
|
||||
distance = d;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < mAtoms.size())
|
||||
return mAtoms.at(index);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const Residue &Structure::getResidue(const std::string &asymID, const std::string &compID, int seqID) const
|
||||
{
|
||||
for (auto &poly : mPolymers)
|
||||
@@ -1988,12 +2075,35 @@ const Residue &Structure::getResidue(const std::string &asymID, const std::strin
|
||||
throw std::out_of_range("Could not find residue " + asymID + '/' + std::to_string(seqID));
|
||||
}
|
||||
|
||||
Residue &Structure::getResidue(const std::string &asymID, const std::string &compID, int seqID)
|
||||
{
|
||||
return const_cast<Residue&>(const_cast<Structure const&>(*this).getResidue(asymID, compID, seqID));
|
||||
}
|
||||
|
||||
const Residue &Structure::getResidue(const std::string &asymID) const
|
||||
{
|
||||
for (auto &res : mNonPolymers)
|
||||
{
|
||||
if (res.asymID() != asymID)
|
||||
continue;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
throw std::out_of_range("Could not find residue " + asymID);
|
||||
}
|
||||
|
||||
Residue &Structure::getResidue(const std::string &asymID)
|
||||
{
|
||||
return const_cast<Residue&>(const_cast<Structure const&>(*this).getResidue(asymID));
|
||||
}
|
||||
|
||||
File &Structure::getFile() const
|
||||
{
|
||||
return mFile;
|
||||
}
|
||||
|
||||
cif::Category &Structure::category(const char *name) const
|
||||
cif::Category &Structure::category(std::string_view name) const
|
||||
{
|
||||
auto &db = datablock();
|
||||
return db[name];
|
||||
@@ -2326,7 +2436,7 @@ void Structure::moveAtom(Atom &a, Point p)
|
||||
a.location(p);
|
||||
}
|
||||
|
||||
void Structure::changeResidue(const Residue &res, const std::string &newCompound,
|
||||
void Structure::changeResidue(Residue &res, const std::string &newCompound,
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
@@ -2390,6 +2500,8 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
|
||||
else
|
||||
insertCompound(newCompound, false);
|
||||
|
||||
res.setCompoundID(newCompound);
|
||||
|
||||
auto &atomSites = db["atom_site"];
|
||||
auto atoms = res.atoms();
|
||||
|
||||
@@ -2411,8 +2523,15 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
|
||||
if (r.size() != 1)
|
||||
continue;
|
||||
|
||||
if (a1 != a2)
|
||||
r.front()["label_atom_id"] = a2;
|
||||
if (a2.empty() or a2 == ".")
|
||||
removeAtom(*i);
|
||||
else if (a1 != a2)
|
||||
{
|
||||
auto ra = r.front();
|
||||
ra["label_atom_id"] = a2;
|
||||
ra["auth_atom_id"] = a2;
|
||||
ra["type_symbol"] = AtomTypeTraits(compound->getAtomByID(a2).typeSymbol).symbol();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto a : atoms)
|
||||
|
||||
@@ -90,4 +90,66 @@ int GetSpacegroupNumber(std::string spacegroup)
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
int GetSpacegroupNumber(std::string spacegroup, SpacegroupName type)
|
||||
{
|
||||
if (spacegroup == "P 21 21 2 A")
|
||||
spacegroup = "P 21 21 2 (a)";
|
||||
else if (spacegroup.empty())
|
||||
throw std::runtime_error("No spacegroup, cannot continue");
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (type == SpacegroupName::full)
|
||||
{
|
||||
const size_t N = kNrOfSpaceGroups;
|
||||
int32_t L = 0, R = static_cast<int32_t>(N - 1);
|
||||
while (L <= R)
|
||||
{
|
||||
int32_t i = (L + R) / 2;
|
||||
|
||||
int d = spacegroup.compare(kSpaceGroups[i].name);
|
||||
|
||||
if (d > 0)
|
||||
L = i + 1;
|
||||
else if (d < 0)
|
||||
R = i - 1;
|
||||
else
|
||||
{
|
||||
result = kSpaceGroups[i].nr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == SpacegroupName::xHM)
|
||||
{
|
||||
for (auto &sg : kSpaceGroups)
|
||||
{
|
||||
if (sg.xHM == spacegroup)
|
||||
{
|
||||
result = sg.nr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &sg : kSpaceGroups)
|
||||
{
|
||||
if (sg.Hall == spacegroup)
|
||||
{
|
||||
result = sg.nr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not found, see if we can find a match based on xHM name
|
||||
if (result == 0)
|
||||
throw std::runtime_error("Spacegroup name " + spacegroup + " was not found in table");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
253
test/HEM.cif
Normal file
253
test/HEM.cif
Normal file
@@ -0,0 +1,253 @@
|
||||
data_HEM
|
||||
#
|
||||
|
||||
_chem_comp.id HEM
|
||||
_chem_comp.name "PROTOPORPHYRIN IX CONTAINING FE"
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.pdbx_type HETAIN
|
||||
_chem_comp.formula "C34 H32 Fe N4 O4"
|
||||
_chem_comp.mon_nstd_parent_comp_id ?
|
||||
_chem_comp.pdbx_synonyms HEME
|
||||
_chem_comp.pdbx_formal_charge 0
|
||||
_chem_comp.pdbx_initial_date 1999-07-08
|
||||
_chem_comp.pdbx_modified_date 2020-06-17
|
||||
_chem_comp.pdbx_ambiguous_flag Y
|
||||
_chem_comp.pdbx_release_status REL
|
||||
_chem_comp.pdbx_replaced_by ?
|
||||
_chem_comp.pdbx_replaces MHM
|
||||
_chem_comp.formula_weight 616.487
|
||||
_chem_comp.one_letter_code ?
|
||||
_chem_comp.three_letter_code HEM
|
||||
_chem_comp.pdbx_model_coordinates_details ?
|
||||
_chem_comp.pdbx_model_coordinates_missing_flag N
|
||||
_chem_comp.pdbx_ideal_coordinates_details Corina
|
||||
_chem_comp.pdbx_ideal_coordinates_missing_flag N
|
||||
_chem_comp.pdbx_model_coordinates_db_code 3IA3
|
||||
_chem_comp.pdbx_subcomponent_list ?
|
||||
_chem_comp.pdbx_processing_site RCSB
|
||||
# #
|
||||
loop_
|
||||
_chem_comp_atom.comp_id
|
||||
_chem_comp_atom.atom_id
|
||||
_chem_comp_atom.alt_atom_id
|
||||
_chem_comp_atom.type_symbol
|
||||
_chem_comp_atom.charge
|
||||
_chem_comp_atom.pdbx_align
|
||||
_chem_comp_atom.pdbx_aromatic_flag
|
||||
_chem_comp_atom.pdbx_leaving_atom_flag
|
||||
_chem_comp_atom.pdbx_stereo_config
|
||||
_chem_comp_atom.model_Cartn_x
|
||||
_chem_comp_atom.model_Cartn_y
|
||||
_chem_comp_atom.model_Cartn_z
|
||||
_chem_comp_atom.pdbx_model_Cartn_x_ideal
|
||||
_chem_comp_atom.pdbx_model_Cartn_y_ideal
|
||||
_chem_comp_atom.pdbx_model_Cartn_z_ideal
|
||||
_chem_comp_atom.pdbx_component_atom_id
|
||||
_chem_comp_atom.pdbx_component_comp_id
|
||||
_chem_comp_atom.pdbx_ordinal
|
||||
HEM CHA CHA C 0 1 N N N 2.748 -19.531 39.896 -2.161 -0.125 0.490 CHA HEM 1
|
||||
HEM CHB CHB C 0 1 N N N 3.258 -17.744 35.477 1.458 -3.419 0.306 CHB HEM 2
|
||||
HEM CHC CHC C 0 1 N N N 1.703 -21.900 33.637 4.701 0.169 -0.069 CHC HEM 3
|
||||
HEM CHD CHD C 0 1 N N N 1.149 -23.677 38.059 1.075 3.460 0.018 CHD HEM 4
|
||||
HEM C1A C1A C 0 1 Y N N 3.031 -18.673 38.872 -1.436 -1.305 0.380 C1A HEM 5
|
||||
HEM C2A C2A C 0 1 Y N N 3.578 -17.325 39.013 -2.015 -2.587 0.320 C2A HEM 6
|
||||
HEM C3A C3A C 0 1 Y N N 3.705 -16.820 37.785 -1.009 -3.500 0.270 C3A HEM 7
|
||||
HEM C4A C4A C 0 1 Y N N 3.256 -17.863 36.862 0.216 -2.803 0.298 C4A HEM 8
|
||||
HEM CMA CMA C 0 1 N N N 4.227 -15.469 37.393 -1.175 -4.996 0.197 CMA HEM 9
|
||||
HEM CAA CAA C 0 1 N N N 3.945 -16.670 40.296 -3.490 -2.893 0.314 CAA HEM 10
|
||||
HEM CBA CBA C 0 1 N N N 5.391 -17.138 40.581 -3.998 -2.926 -1.129 CBA HEM 11
|
||||
HEM CGA CGA C 0 1 N N N 6.095 -16.663 41.825 -5.473 -3.232 -1.136 CGA HEM 12
|
||||
HEM O1A O1A O 0 1 N N N 7.098 -15.928 41.683 -6.059 -3.405 -0.094 O1A HEM 13
|
||||
HEM O2A O2A O 0 1 N N N 5.657 -17.040 42.940 -6.137 -3.311 -2.300 O2A HEM 14
|
||||
HEM C1B C1B C 0 1 N N N 2.888 -18.698 34.579 2.664 -2.707 0.308 C1B HEM 15
|
||||
HEM C2B C2B C 0 1 N N N 2.933 -18.535 33.146 3.937 -3.328 0.418 C2B HEM 16
|
||||
HEM C3B C3B C 0 1 N N N 2.499 -19.716 32.632 4.874 -2.341 0.314 C3B HEM 17
|
||||
HEM C4B C4B C 0 1 N N N 2.187 -20.580 33.743 4.117 -1.079 0.139 C4B HEM 18
|
||||
HEM CMB CMB C 0 1 N N N 3.391 -17.290 32.422 4.203 -4.798 0.613 CMB HEM 19
|
||||
HEM CAB CAB C 0 1 N N N 2.345 -20.140 31.217 6.339 -2.497 0.365 CAB HEM 20
|
||||
HEM CBB CBB C 0 1 N N N 1.755 -19.492 30.233 6.935 -3.419 -0.385 CBB HEM 21
|
||||
HEM C1C C1C C 0 1 Y N N 1.395 -22.786 34.659 3.964 1.345 -0.174 C1C HEM 22
|
||||
HEM C2C C2C C 0 1 Y N N 0.854 -24.130 34.500 4.531 2.601 -0.445 C2C HEM 23
|
||||
HEM C3C C3C C 0 1 Y N N 0.689 -24.626 35.757 3.510 3.536 -0.437 C3C HEM 24
|
||||
HEM C4C C4C C 0 1 Y N N 1.139 -23.583 36.674 2.304 2.846 -0.139 C4C HEM 25
|
||||
HEM CMC CMC C 0 1 N N N 0.550 -24.782 33.175 5.991 2.880 -0.697 CMC HEM 26
|
||||
HEM CAC CAC C 0 1 N N N 0.164 -25.943 36.196 3.649 4.981 -0.692 CAC HEM 27
|
||||
HEM CBC CBC C 0 1 N N N 0.498 -27.158 35.750 4.201 5.407 -1.823 CBC HEM 28
|
||||
HEM C1D C1D C 0 1 N N N 1.550 -22.718 38.980 -0.102 2.753 0.298 C1D HEM 29
|
||||
HEM C2D C2D C 0 1 N N N 1.513 -22.879 40.415 -1.382 3.388 0.641 C2D HEM 30
|
||||
HEM C3D C3D C 0 1 N N N 1.951 -21.691 40.929 -2.283 2.389 0.774 C3D HEM 31
|
||||
HEM C4D C4D C 0 1 N N N 2.277 -20.826 39.811 -1.561 1.137 0.511 C4D HEM 32
|
||||
HEM CMD CMD C 0 1 N N N 1.055 -24.094 41.156 -1.639 4.863 0.811 CMD HEM 33
|
||||
HEM CAD CAD C 0 1 N N N 2.048 -21.326 42.352 -3.741 2.532 1.123 CAD HEM 34
|
||||
HEM CBD CBD C 0 1 N N N 0.741 -20.498 42.530 -4.573 2.563 -0.160 CBD HEM 35
|
||||
HEM CGD CGD C 0 1 N N N 0.578 -19.987 43.892 -6.032 2.706 0.189 CGD HEM 36
|
||||
HEM O1D O1D O 0 1 N N N 1.387 -19.103 44.303 -6.372 2.776 1.347 O1D HEM 37
|
||||
HEM O2D O2D O 0 1 N N N -0.401 -20.468 44.537 -6.954 2.755 -0.785 O2D HEM 38
|
||||
HEM NA NA N 0 1 Y N N 2.863 -18.969 37.554 -0.068 -1.456 0.321 NA HEM 39
|
||||
HEM NB NB N 0 1 N N N 2.439 -19.944 34.911 2.820 -1.386 0.207 NB HEM 40
|
||||
HEM NC NC N 0 1 Y N N 1.537 -22.509 35.976 2.604 1.506 -0.033 NC HEM 41
|
||||
HEM ND ND N 0 1 N N N 2.008 -21.465 38.663 -0.276 1.431 0.298 ND HEM 42
|
||||
HEM FE FE FE 0 0 N N N 2.196 -20.749 36.814 1.010 0.157 -0.060 FE HEM 43
|
||||
HEM HHB HHB H 0 1 N N N 3.587 -16.798 35.072 1.498 -4.508 0.309 HHB HEM 44
|
||||
HEM HHC HHC H 0 1 N N N 1.553 -22.268 32.633 5.786 0.229 -0.153 HHC HEM 45
|
||||
HEM HHD HHD H 0 1 N N N 0.802 -24.613 38.472 1.018 4.543 -0.083 HHD HEM 46
|
||||
HEM HMA HMA H 0 1 N N N 5.316 -15.524 37.249 -1.220 -5.306 -0.847 HMA HEM 47
|
||||
HEM HMAA HMAA H 0 0 N N N 3.749 -15.149 36.455 -0.328 -5.480 0.683 HMAA HEM 48
|
||||
HEM HMAB HMAB H 0 0 N N N 3.998 -14.743 38.187 -2.097 -5.285 0.702 HMAB HEM 49
|
||||
HEM HAA HAA H 0 1 N N N 3.905 -15.575 40.197 -3.662 -3.862 0.782 HAA HEM 50
|
||||
HEM HAAA HAAA H 0 0 N N N 3.268 -16.991 41.102 -4.024 -2.121 0.869 HAAA HEM 51
|
||||
HEM HBA HBA H 0 1 N N N 5.368 -18.237 40.627 -3.825 -1.956 -1.597 HBA HEM 52
|
||||
HEM HBAA HBAA H 0 0 N N N 6.004 -16.819 39.725 -3.464 -3.697 -1.684 HBAA HEM 53
|
||||
HEM HMB HMB H 0 1 N N N 3.319 -17.449 31.336 3.256 -5.336 0.660 HMB HEM 54
|
||||
HEM HMBA HMBA H 0 0 N N N 2.753 -16.442 32.711 4.794 -5.175 -0.222 HMBA HEM 55
|
||||
HEM HMBB HMBB H 0 0 N N N 4.435 -17.072 32.692 4.752 -4.948 1.543 HMBB HEM 56
|
||||
HEM HAB HAB H 0 1 N N N 2.770 -21.100 30.963 6.927 -1.863 1.011 HAB HEM 57
|
||||
HEM HBB HBB H 0 1 N N N 1.719 -19.927 29.245 7.994 -3.600 -0.277 HBB HEM 58
|
||||
HEM HBBA HBBA H 0 0 N N N 1.308 -18.526 30.414 6.360 -3.987 -1.102 HBBA HEM 59
|
||||
HEM HMC HMC H 0 1 N N N 0.153 -25.793 33.346 6.554 1.949 -0.639 HMC HEM 60
|
||||
HEM HMCA HMCA H 0 0 N N N -0.196 -24.182 32.634 6.110 3.316 -1.689 HMCA HEM 61
|
||||
HEM HMCB HMCB H 0 0 N N N 1.472 -24.846 32.578 6.362 3.578 0.053 HMCB HEM 62
|
||||
HEM HAC HAC H 0 1 N N N -0.583 -25.916 36.975 3.303 5.694 0.042 HAC HEM 63
|
||||
HEM HBC HBC H 0 1 N N N 0.027 -28.035 36.169 4.614 4.696 -2.523 HBC HEM 64
|
||||
HEM HBCA HBCA H 0 0 N N N 1.239 -27.263 34.971 4.235 6.464 -2.043 HBCA HEM 65
|
||||
HEM HMD HMD H 0 1 N N N 1.142 -23.919 42.238 -0.715 5.415 0.639 HMD HEM 66
|
||||
HEM HMDA HMDA H 0 0 N N N 0.006 -24.304 40.902 -2.394 5.185 0.094 HMDA HEM 67
|
||||
HEM HMDB HMDB H 0 0 N N N 1.680 -24.954 40.872 -1.994 5.055 1.824 HMDB HEM 68
|
||||
HEM HAD HAD H 0 1 N N N 2.055 -22.216 42.999 -4.052 1.687 1.738 HAD HEM 69
|
||||
HEM HADA HADA H 0 0 N N N 2.943 -20.719 42.554 -3.893 3.459 1.677 HADA HEM 70
|
||||
HEM HBD HBD H 0 1 N N N 0.767 -19.646 41.835 -4.262 3.408 -0.775 HBD HEM 71
|
||||
HEM HBDA HBDA H 0 0 N N N -0.119 -21.141 42.290 -4.421 1.636 -0.714 HBDA HEM 72
|
||||
HEM H2A H2A H 0 1 N N N 6.201 -16.682 43.632 -7.082 -3.510 -2.254 H2A HEM 73
|
||||
HEM H2D H2D H 0 1 N N N -0.445 -20.063 45.395 -7.877 2.847 -0.512 H2D HEM 74
|
||||
HEM HHA HHA H 0 1 N N N 2.913 -19.150 40.893 -3.246 -0.188 0.567 HHA HEM 75
|
||||
# #
|
||||
loop_
|
||||
_chem_comp_bond.comp_id
|
||||
_chem_comp_bond.atom_id_1
|
||||
_chem_comp_bond.atom_id_2
|
||||
_chem_comp_bond.value_order
|
||||
_chem_comp_bond.pdbx_aromatic_flag
|
||||
_chem_comp_bond.pdbx_stereo_config
|
||||
_chem_comp_bond.pdbx_ordinal
|
||||
HEM CHA C1A SING N N 1
|
||||
HEM CHA C4D DOUB N N 2
|
||||
HEM CHA HHA SING N N 3
|
||||
HEM CHB C4A SING N N 4
|
||||
HEM CHB C1B DOUB N N 5
|
||||
HEM CHB HHB SING N N 6
|
||||
HEM CHC C4B SING N N 7
|
||||
HEM CHC C1C DOUB N N 8
|
||||
HEM CHC HHC SING N N 9
|
||||
HEM CHD C4C DOUB N N 10
|
||||
HEM CHD C1D SING N N 11
|
||||
HEM CHD HHD SING N N 12
|
||||
HEM C1A C2A DOUB Y N 13
|
||||
HEM C1A NA SING Y N 14
|
||||
HEM C2A C3A SING Y N 15
|
||||
HEM C2A CAA SING N N 16
|
||||
HEM C3A C4A DOUB Y N 17
|
||||
HEM C3A CMA SING N N 18
|
||||
HEM C4A NA SING Y N 19
|
||||
HEM CMA HMA SING N N 20
|
||||
HEM CMA HMAA SING N N 21
|
||||
HEM CMA HMAB SING N N 22
|
||||
HEM CAA CBA SING N N 23
|
||||
HEM CAA HAA SING N N 24
|
||||
HEM CAA HAAA SING N N 25
|
||||
HEM CBA CGA SING N N 26
|
||||
HEM CBA HBA SING N N 27
|
||||
HEM CBA HBAA SING N N 28
|
||||
HEM CGA O1A DOUB N N 29
|
||||
HEM CGA O2A SING N N 30
|
||||
HEM C1B C2B SING N N 31
|
||||
HEM C1B NB SING N N 32
|
||||
HEM C2B C3B DOUB N N 33
|
||||
HEM C2B CMB SING N N 34
|
||||
HEM C3B C4B SING N N 35
|
||||
HEM C3B CAB SING N N 36
|
||||
HEM C4B NB DOUB N N 37
|
||||
HEM CMB HMB SING N N 38
|
||||
HEM CMB HMBA SING N N 39
|
||||
HEM CMB HMBB SING N N 40
|
||||
HEM CAB CBB DOUB N N 41
|
||||
HEM CAB HAB SING N N 42
|
||||
HEM CBB HBB SING N N 43
|
||||
HEM CBB HBBA SING N N 44
|
||||
HEM C1C C2C SING Y N 45
|
||||
HEM C1C NC SING Y N 46
|
||||
HEM C2C C3C DOUB Y N 47
|
||||
HEM C2C CMC SING N N 48
|
||||
HEM C3C C4C SING Y N 49
|
||||
HEM C3C CAC SING N N 50
|
||||
HEM C4C NC SING Y N 51
|
||||
HEM CMC HMC SING N N 52
|
||||
HEM CMC HMCA SING N N 53
|
||||
HEM CMC HMCB SING N N 54
|
||||
HEM CAC CBC DOUB N N 55
|
||||
HEM CAC HAC SING N N 56
|
||||
HEM CBC HBC SING N N 57
|
||||
HEM CBC HBCA SING N N 58
|
||||
HEM C1D C2D SING N N 59
|
||||
HEM C1D ND DOUB N N 60
|
||||
HEM C2D C3D DOUB N N 61
|
||||
HEM C2D CMD SING N N 62
|
||||
HEM C3D C4D SING N N 63
|
||||
HEM C3D CAD SING N N 64
|
||||
HEM C4D ND SING N N 65
|
||||
HEM CMD HMD SING N N 66
|
||||
HEM CMD HMDA SING N N 67
|
||||
HEM CMD HMDB SING N N 68
|
||||
HEM CAD CBD SING N N 69
|
||||
HEM CAD HAD SING N N 70
|
||||
HEM CAD HADA SING N N 71
|
||||
HEM CBD CGD SING N N 72
|
||||
HEM CBD HBD SING N N 73
|
||||
HEM CBD HBDA SING N N 74
|
||||
HEM CGD O1D DOUB N N 75
|
||||
HEM CGD O2D SING N N 76
|
||||
HEM O2A H2A SING N N 77
|
||||
HEM O2D H2D SING N N 78
|
||||
HEM FE NA SING N N 79
|
||||
HEM FE NB SING N N 80
|
||||
HEM FE NC SING N N 81
|
||||
HEM FE ND SING N N 82
|
||||
# #
|
||||
loop_
|
||||
_pdbx_chem_comp_descriptor.comp_id
|
||||
_pdbx_chem_comp_descriptor.type
|
||||
_pdbx_chem_comp_descriptor.program
|
||||
_pdbx_chem_comp_descriptor.program_version
|
||||
_pdbx_chem_comp_descriptor.descriptor
|
||||
HEM SMILES ACDLabs 12.01 "C=1c3c(c(c4C=C5C(=C(C=6C=C7C(=C(C8=CC=2C(=C(C=1N=2[Fe](n34)(N5=6)N78)CCC(=O)O)C)\C=C)C)\C=C)C)C)CCC(=O)O"
|
||||
HEM InChI InChI 1.03 "InChI=1S/C34H34N4O4.Fe/c1-7-21-17(3)25-13-26-19(5)23(9-11-33(39)40)31(37-26)16-32-24(10-12-34(41)42)20(6)28(38-32)15-30-22(8-2)18(4)27(36-30)14-29(21)35-25;/h7-8,13-16H,1-2,9-12H2,3-6H3,(H4,35,36,37,38,39,40,41,42);/q;+2/p-2/b25-13-,26-13-,27-14-,28-15-,29-14-,30-15-,31-16-,32-16-;"
|
||||
HEM InChIKey InChI 1.03 KABFMIBPWCXCRK-RGGAHWMASA-L
|
||||
HEM SMILES_CANONICAL CACTVS 3.385 "CC1=C(CCC(O)=O)C2=Cc3n4[Fe]5|6|N2=C1C=c7n5c(=CC8=N|6C(=Cc4c(C)c3CCC(O)=O)C(=C8C=C)C)c(C)c7C=C"
|
||||
HEM SMILES CACTVS 3.385 "CC1=C(CCC(O)=O)C2=Cc3n4[Fe]5|6|N2=C1C=c7n5c(=CC8=N|6C(=Cc4c(C)c3CCC(O)=O)C(=C8C=C)C)c(C)c7C=C"
|
||||
HEM SMILES_CANONICAL "OpenEye OEToolkits" 1.7.6 "Cc1c2n3c(c1CCC(=O)O)C=C4C(=C(C5=[N]4[Fe]36[N]7=C(C=C8N6C(=C5)C(=C8C)C=C)C(=C(C7=C2)C)C=C)C)CCC(=O)O"
|
||||
HEM SMILES "OpenEye OEToolkits" 1.7.6 "Cc1c2n3c(c1CCC(=O)O)C=C4C(=C(C5=[N]4[Fe]36[N]7=C(C=C8N6C(=C5)C(=C8C)C=C)C(=C(C7=C2)C)C=C)C)CCC(=O)O"
|
||||
# #
|
||||
loop_
|
||||
_pdbx_chem_comp_identifier.comp_id
|
||||
_pdbx_chem_comp_identifier.type
|
||||
_pdbx_chem_comp_identifier.program
|
||||
_pdbx_chem_comp_identifier.program_version
|
||||
_pdbx_chem_comp_identifier.identifier
|
||||
HEM "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.6.1 "3-[(5Z,10Z,14Z,19Z)-18-(2-carboxyethyl)-8,13-bis(ethenyl)-3,7,12,17-tetramethyl-21,23-dihydroporphyrin-2-yl]propanoic acid"
|
||||
HEM "SYSTEMATIC NAME" ACDLabs 12.01 "[3,3'-(7,12-diethenyl-3,8,13,17-tetramethylporphyrin-2,18-diyl-kappa~4~N~21~,N~22~,N~23~,N~24~)dipropanoato(2-)]iron"
|
||||
# #
|
||||
loop_
|
||||
_pdbx_chem_comp_audit.comp_id
|
||||
_pdbx_chem_comp_audit.action_type
|
||||
_pdbx_chem_comp_audit.date
|
||||
_pdbx_chem_comp_audit.processing_site
|
||||
HEM "Create component" 1999-07-08 RCSB
|
||||
HEM "Other modification" 2016-01-20 RCSB
|
||||
HEM "Modify synonyms" 2020-06-05 PDBE
|
||||
#
|
||||
_pdbx_chem_comp_synonyms.ordinal 1
|
||||
_pdbx_chem_comp_synonyms.comp_id HEM
|
||||
_pdbx_chem_comp_synonyms.name HEME
|
||||
_pdbx_chem_comp_synonyms.provenance ?
|
||||
_pdbx_chem_comp_synonyms.type ?
|
||||
##
|
||||
|
||||
188
test/REA.cif
Normal file
188
test/REA.cif
Normal file
@@ -0,0 +1,188 @@
|
||||
data_REA
|
||||
#
|
||||
_chem_comp.id REA
|
||||
_chem_comp.name "RETINOIC ACID"
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.pdbx_type HETAIN
|
||||
_chem_comp.formula "C20 H28 O2"
|
||||
_chem_comp.mon_nstd_parent_comp_id ?
|
||||
_chem_comp.pdbx_synonyms ?
|
||||
_chem_comp.pdbx_formal_charge 0
|
||||
_chem_comp.pdbx_initial_date 1999-07-08
|
||||
_chem_comp.pdbx_modified_date 2016-10-18
|
||||
_chem_comp.pdbx_ambiguous_flag N
|
||||
_chem_comp.pdbx_release_status REL
|
||||
_chem_comp.pdbx_replaced_by ?
|
||||
_chem_comp.pdbx_replaces 3KV
|
||||
_chem_comp.formula_weight 300.435
|
||||
_chem_comp.one_letter_code ?
|
||||
_chem_comp.three_letter_code REA
|
||||
_chem_comp.pdbx_model_coordinates_details ?
|
||||
_chem_comp.pdbx_model_coordinates_missing_flag N
|
||||
_chem_comp.pdbx_ideal_coordinates_details Corina
|
||||
_chem_comp.pdbx_ideal_coordinates_missing_flag N
|
||||
_chem_comp.pdbx_model_coordinates_db_code 1CBS
|
||||
_chem_comp.pdbx_subcomponent_list ?
|
||||
_chem_comp.pdbx_processing_site RCSB
|
||||
#
|
||||
loop_
|
||||
_chem_comp_atom.comp_id
|
||||
_chem_comp_atom.atom_id
|
||||
_chem_comp_atom.alt_atom_id
|
||||
_chem_comp_atom.type_symbol
|
||||
_chem_comp_atom.charge
|
||||
_chem_comp_atom.pdbx_align
|
||||
_chem_comp_atom.pdbx_aromatic_flag
|
||||
_chem_comp_atom.pdbx_leaving_atom_flag
|
||||
_chem_comp_atom.pdbx_stereo_config
|
||||
_chem_comp_atom.model_Cartn_x
|
||||
_chem_comp_atom.model_Cartn_y
|
||||
_chem_comp_atom.model_Cartn_z
|
||||
_chem_comp_atom.pdbx_model_Cartn_x_ideal
|
||||
_chem_comp_atom.pdbx_model_Cartn_y_ideal
|
||||
_chem_comp_atom.pdbx_model_Cartn_z_ideal
|
||||
_chem_comp_atom.pdbx_component_atom_id
|
||||
_chem_comp_atom.pdbx_component_comp_id
|
||||
_chem_comp_atom.pdbx_ordinal
|
||||
REA C1 C1 C 0 1 N N N 21.972 29.831 16.739 -4.684 0.932 -0.497 C1 REA 1
|
||||
REA C2 C2 C 0 1 N N N 20.921 30.524 15.841 -5.837 0.190 -1.176 C2 REA 2
|
||||
REA C3 C3 C 0 1 N N N 20.245 29.635 14.848 -6.441 -0.798 -0.171 C3 REA 3
|
||||
REA C4 C4 C 0 1 N N N 19.555 28.479 15.488 -5.418 -1.903 0.100 C4 REA 4
|
||||
REA C5 C5 C 0 1 N N N 20.389 27.812 16.587 -4.082 -1.301 0.429 C5 REA 5
|
||||
REA C6 C6 C 0 1 N N N 21.425 28.446 17.218 -3.756 -0.048 0.161 C6 REA 6
|
||||
REA C7 C7 C 0 1 N N N 22.242 27.851 18.297 -2.457 0.396 0.516 C7 REA 7
|
||||
REA C8 C8 C 0 1 N N N 21.868 26.977 19.240 -1.363 -0.229 0.007 C8 REA 8
|
||||
REA C9 C9 C 0 1 N N N 22.705 26.434 20.286 -0.076 0.257 0.298 C9 REA 9
|
||||
REA C10 C10 C 0 1 N N N 22.159 25.536 21.131 1.022 -0.370 -0.213 C10 REA 10
|
||||
REA C11 C11 C 0 1 N N N 22.875 24.924 22.234 2.306 0.115 0.077 C11 REA 11
|
||||
REA C12 C12 C 0 1 N N N 22.237 24.026 22.990 3.405 -0.513 -0.435 C12 REA 12
|
||||
REA C13 C13 C 0 1 N N N 22.856 23.377 24.125 4.689 -0.028 -0.144 C13 REA 13
|
||||
REA C14 C14 C 0 1 N N N 22.135 22.473 24.834 5.787 -0.655 -0.656 C14 REA 14
|
||||
REA C15 C15 C 0 1 N N N 22.563 21.710 26.016 7.077 -0.265 -0.244 C15 REA 15
|
||||
REA C16 C16 C 0 1 N N N 22.238 30.737 17.948 -5.246 1.886 0.559 C16 REA 16
|
||||
REA C17 C17 C 0 1 N N N 23.292 29.620 15.948 -3.911 1.737 -1.544 C17 REA 17
|
||||
REA C18 C18 C 0 1 N N N 19.791 26.449 16.947 -3.056 -2.175 1.103 C18 REA 18
|
||||
REA C19 C19 C 0 1 N N N 24.181 26.841 20.385 0.090 1.471 1.175 C19 REA 19
|
||||
REA C20 C20 C 0 1 N N N 24.303 23.747 24.489 4.855 1.186 0.733 C20 REA 20
|
||||
REA O1 O1 O 0 1 N N N 23.640 21.075 25.978 7.210 0.553 0.648 O1 REA 21
|
||||
REA O2 O2 O 0 1 N N N 21.840 21.712 27.037 8.166 -0.798 -0.840 O2 REA 22
|
||||
REA H21 H21 H 0 1 N N N 20.147 30.955 16.494 -6.598 0.905 -1.490 H21 REA 23
|
||||
REA H22 H22 H 0 1 N N N 21.425 31.330 15.288 -5.462 -0.353 -2.044 H22 REA 24
|
||||
REA H31 H31 H 0 1 N N N 19.501 30.227 14.295 -6.673 -0.278 0.759 H31 REA 25
|
||||
REA H32 H32 H 0 1 N N N 21.001 29.250 14.148 -7.349 -1.234 -0.586 H32 REA 26
|
||||
REA H41 H41 H 0 1 N N N 18.613 28.835 15.931 -5.756 -2.511 0.938 H41 REA 27
|
||||
REA H42 H42 H 0 1 N N N 19.335 27.730 14.713 -5.322 -2.531 -0.786 H42 REA 28
|
||||
REA H7 H7 H 0 1 N N N 23.276 28.162 18.329 -2.337 1.230 1.191 H7 REA 29
|
||||
REA H8 H8 H 0 1 N N N 20.840 26.645 19.217 -1.482 -1.100 -0.622 H8 REA 30
|
||||
REA H10 H10 H 0 1 N N N 21.127 25.256 20.977 0.903 -1.241 -0.842 H10 REA 31
|
||||
REA H11 H11 H 0 1 N N N 23.902 25.189 22.440 2.425 0.985 0.706 H11 REA 32
|
||||
REA H12 H12 H 0 1 N N N 21.216 23.774 22.743 3.286 -1.383 -1.063 H12 REA 33
|
||||
REA H14 H14 H 0 1 N N N 21.127 22.292 24.490 5.667 -1.451 -1.376 H14 REA 34
|
||||
REA H161 H161 H 0 0 N N N 22.984 30.265 18.604 -5.802 1.316 1.303 H161 REA 35
|
||||
REA H162 H162 H 0 0 N N N 22.618 31.709 17.601 -4.426 2.415 1.044 H162 REA 36
|
||||
REA H163 H163 H 0 0 N N N 21.302 30.887 18.506 -5.911 2.605 0.081 H163 REA 37
|
||||
REA H171 H171 H 0 0 N N N 24.033 29.127 16.595 -4.598 2.394 -2.077 H171 REA 38
|
||||
REA H172 H172 H 0 0 N N N 23.095 28.989 15.069 -3.146 2.335 -1.050 H172 REA 39
|
||||
REA H173 H173 H 0 0 N N N 23.683 30.595 15.620 -3.439 1.054 -2.251 H173 REA 40
|
||||
REA H181 H181 H 0 0 N N N 20.397 25.979 17.736 -3.448 -3.187 1.201 H181 REA 41
|
||||
REA H182 H182 H 0 0 N N N 18.761 26.584 17.308 -2.145 -2.194 0.503 H182 REA 42
|
||||
REA H183 H183 H 0 0 N N N 19.786 25.804 16.056 -2.831 -1.775 2.092 H183 REA 43
|
||||
REA H191 H191 H 0 0 N N N 24.647 26.327 21.238 0.171 1.159 2.216 H191 REA 44
|
||||
REA H192 H192 H 0 0 N N N 24.702 26.559 19.458 0.993 2.008 0.885 H192 REA 45
|
||||
REA H193 H193 H 0 0 N N N 24.252 27.929 20.529 -0.774 2.125 1.058 H193 REA 46
|
||||
REA H201 H201 H 0 0 N N N 24.620 23.168 25.369 5.026 0.871 1.762 H201 REA 47
|
||||
REA H202 H202 H 0 0 N N N 24.965 23.516 23.641 5.707 1.771 0.386 H202 REA 48
|
||||
REA H203 H203 H 0 0 N N N 24.360 24.822 24.717 3.952 1.795 0.685 H203 REA 49
|
||||
REA HO2 HO2 H 0 1 N N N 22.244 21.180 27.713 9.006 -0.469 -0.490 HO2 REA 50
|
||||
#
|
||||
loop_
|
||||
_chem_comp_bond.comp_id
|
||||
_chem_comp_bond.atom_id_1
|
||||
_chem_comp_bond.atom_id_2
|
||||
_chem_comp_bond.value_order
|
||||
_chem_comp_bond.pdbx_aromatic_flag
|
||||
_chem_comp_bond.pdbx_stereo_config
|
||||
_chem_comp_bond.pdbx_ordinal
|
||||
REA C1 C2 SING N N 1
|
||||
REA C1 C6 SING N N 2
|
||||
REA C1 C16 SING N N 3
|
||||
REA C1 C17 SING N N 4
|
||||
REA C2 C3 SING N N 5
|
||||
REA C2 H21 SING N N 6
|
||||
REA C2 H22 SING N N 7
|
||||
REA C3 C4 SING N N 8
|
||||
REA C3 H31 SING N N 9
|
||||
REA C3 H32 SING N N 10
|
||||
REA C4 C5 SING N N 11
|
||||
REA C4 H41 SING N N 12
|
||||
REA C4 H42 SING N N 13
|
||||
REA C5 C6 DOUB N N 14
|
||||
REA C5 C18 SING N N 15
|
||||
REA C6 C7 SING N N 16
|
||||
REA C7 C8 DOUB N E 17
|
||||
REA C7 H7 SING N N 18
|
||||
REA C8 C9 SING N N 19
|
||||
REA C8 H8 SING N N 20
|
||||
REA C9 C10 DOUB N E 21
|
||||
REA C9 C19 SING N N 22
|
||||
REA C10 C11 SING N N 23
|
||||
REA C10 H10 SING N N 24
|
||||
REA C11 C12 DOUB N E 25
|
||||
REA C11 H11 SING N N 26
|
||||
REA C12 C13 SING N N 27
|
||||
REA C12 H12 SING N N 28
|
||||
REA C13 C14 DOUB N E 29
|
||||
REA C13 C20 SING N N 30
|
||||
REA C14 C15 SING N N 31
|
||||
REA C14 H14 SING N N 32
|
||||
REA C15 O1 DOUB N N 33
|
||||
REA C15 O2 SING N N 34
|
||||
REA C16 H161 SING N N 35
|
||||
REA C16 H162 SING N N 36
|
||||
REA C16 H163 SING N N 37
|
||||
REA C17 H171 SING N N 38
|
||||
REA C17 H172 SING N N 39
|
||||
REA C17 H173 SING N N 40
|
||||
REA C18 H181 SING N N 41
|
||||
REA C18 H182 SING N N 42
|
||||
REA C18 H183 SING N N 43
|
||||
REA C19 H191 SING N N 44
|
||||
REA C19 H192 SING N N 45
|
||||
REA C19 H193 SING N N 46
|
||||
REA C20 H201 SING N N 47
|
||||
REA C20 H202 SING N N 48
|
||||
REA C20 H203 SING N N 49
|
||||
REA O2 HO2 SING N N 50
|
||||
#
|
||||
loop_
|
||||
_pdbx_chem_comp_descriptor.comp_id
|
||||
_pdbx_chem_comp_descriptor.type
|
||||
_pdbx_chem_comp_descriptor.program
|
||||
_pdbx_chem_comp_descriptor.program_version
|
||||
_pdbx_chem_comp_descriptor.descriptor
|
||||
REA SMILES ACDLabs 12.01 "C1(CCCC(=C1\C=C\C(=C\C=C\C(=C\C(=O)O)C)C)C)(C)C"
|
||||
REA InChI InChI 1.03 "InChI=1S/C20H28O2/c1-15(8-6-9-16(2)14-19(21)22)11-12-18-17(3)10-7-13-20(18,4)5/h6,8-9,11-12,14H,7,10,13H2,1-5H3,(H,21,22)/b9-6+,12-11+,15-8+,16-14+"
|
||||
REA InChIKey InChI 1.03 SHGAZHPCJJPHSC-YCNIQYBTSA-N
|
||||
REA SMILES_CANONICAL CACTVS 3.385 "CC1=C(\C=C\C(C)=C\C=C\C(C)=C\C(O)=O)C(C)(C)CCC1"
|
||||
REA SMILES CACTVS 3.385 "CC1=C(C=CC(C)=CC=CC(C)=CC(O)=O)C(C)(C)CCC1"
|
||||
REA SMILES_CANONICAL "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)/C=C/C(=C/C=C/C(=C/C(=O)O)/C)/C"
|
||||
REA SMILES "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)C=CC(=CC=CC(=CC(=O)O)C)C"
|
||||
#
|
||||
loop_
|
||||
_pdbx_chem_comp_identifier.comp_id
|
||||
_pdbx_chem_comp_identifier.type
|
||||
_pdbx_chem_comp_identifier.program
|
||||
_pdbx_chem_comp_identifier.program_version
|
||||
_pdbx_chem_comp_identifier.identifier
|
||||
REA "SYSTEMATIC NAME" ACDLabs 12.01 "retinoic acid"
|
||||
REA "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.7.6 "(2E,4E,6E,8E)-3,7-dimethyl-9-(2,6,6-trimethylcyclohexen-1-yl)nona-2,4,6,8-tetraenoic acid"
|
||||
#
|
||||
loop_
|
||||
_pdbx_chem_comp_audit.comp_id
|
||||
_pdbx_chem_comp_audit.action_type
|
||||
_pdbx_chem_comp_audit.date
|
||||
_pdbx_chem_comp_audit.processing_site
|
||||
REA "Create component" 1999-07-08 RCSB
|
||||
REA "Modify descriptor" 2011-06-04 RCSB
|
||||
REA "Other modification" 2016-10-18 RCSB
|
||||
#
|
||||
@@ -18,7 +18,6 @@ int main(int argc, char* argv[])
|
||||
desc.add_options()
|
||||
("input,i", po::value<std::string>(), "Input file")
|
||||
("help,h", "Display help message")
|
||||
("version", "Print version")
|
||||
("verbose,v", "Verbose output")
|
||||
("debug,d", po::value<int>(), "Debug level (for even more verbose output)");
|
||||
|
||||
@@ -29,12 +28,6 @@ int main(int argc, char* argv[])
|
||||
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("version"))
|
||||
{
|
||||
std::cout << argv[0] << " version " PACKAGE_VERSION << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (vm.count("help") or vm.count("input") == 0)
|
||||
{
|
||||
std::cerr << desc << std::endl;
|
||||
|
||||
@@ -20,9 +20,13 @@ int main(int argc, char* argv[])
|
||||
if (argc == 3)
|
||||
testdir = argv[2];
|
||||
|
||||
if (std::filesystem::exists(testdir / ".."/"data"/"components.cif"))
|
||||
cif::addFileResource("components.cif", testdir / ".."/"data"/"components.cif");
|
||||
if (std::filesystem::exists(testdir / ".." / "data" / "ccd-subset.cif"))
|
||||
cif::addFileResource("components.cif", testdir / ".." / "data" / "ccd-subset.cif");
|
||||
|
||||
if (std::filesystem::exists(testdir / ".." / "rsrc" / "mmcif_pdbx_v50.dic"))
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", testdir / ".." / "rsrc" / "mmcif_pdbx_v50.dic");
|
||||
|
||||
mmcif::CompoundFactory::instance().pushDictionary(testdir / "REA.cif");
|
||||
mmcif::CompoundFactory::instance().pushDictionary(testdir / "RXA.cif");
|
||||
|
||||
mmcif::File f(testdir / ".."/"examples"/"1cbs.cif.gz");
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define BOOST_TEST_MODULE Structure_Test
|
||||
#define BOOST_TEST_ALTERNATIVE_INIT_API
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -52,16 +52,23 @@ cif::File operator""_cf(const char* text, size_t length)
|
||||
|
||||
std::filesystem::path gTestDir = std::filesystem::current_path();
|
||||
|
||||
BOOST_AUTO_TEST_CASE(init)
|
||||
bool init_unit_test()
|
||||
{
|
||||
// not a test, just initialize test dir
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
// 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];
|
||||
|
||||
// do this now, avoids the need for installing
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx_v50.dic");
|
||||
|
||||
// initialize CCD location
|
||||
if (std::filesystem::exists(gTestDir / ".."/"data"/"components.cif"))
|
||||
cif::addFileResource("components.cif", gTestDir / ".."/"data"/"components.cif");
|
||||
cif::addFileResource("components.cif", gTestDir / ".." / "data" / "ccd-subset.cif");
|
||||
|
||||
mmcif::CompoundFactory::instance().pushDictionary(gTestDir / "HEM.cif");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -70,9 +77,6 @@ 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
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define BOOST_TEST_MODULE LibCifPP_Test
|
||||
#define BOOST_TEST_ALTERNATIVE_INIT_API
|
||||
// #define BOOST_TEST_MODULE LibCifPP_Test
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -32,6 +33,10 @@
|
||||
// #include "cif++/DistanceMap.hpp"
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/BondMap.hpp"
|
||||
#include "cif++/CifValidator.hpp"
|
||||
|
||||
namespace tt = boost::test_tools;
|
||||
|
||||
|
||||
std::filesystem::path gTestDir = std::filesystem::current_path(); // filled in first test
|
||||
|
||||
@@ -53,23 +58,27 @@ cif::File operator""_cf(const char* text, size_t length)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(init)
|
||||
bool init_unit_test()
|
||||
{
|
||||
// not a test, just initialize test dir
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
// 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];
|
||||
|
||||
// do this now, avoids the need for installing
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx_v50.dic");
|
||||
|
||||
// initialize CCD location
|
||||
cif::addFileResource("components.cif", gTestDir / ".." / "data" / "ccd-subset.cif");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ut1)
|
||||
{
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
// do this now, avoids the need for installing
|
||||
cif::addFileResource("mmcif_pdbx_v50.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx_v50.dic");
|
||||
|
||||
// using namespace mmcif;
|
||||
|
||||
auto f = R"(data_TEST
|
||||
@@ -254,8 +263,10 @@ save__cat_2.desc
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
cif::Validator validator("test", is_dict);
|
||||
|
||||
cif::File f;
|
||||
f.loadDictionary(is_dict);
|
||||
f.setValidator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -382,8 +393,10 @@ save__cat_1.c
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
cif::Validator validator("test", is_dict);
|
||||
|
||||
cif::File f;
|
||||
f.loadDictionary(is_dict);
|
||||
f.setValidator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -530,8 +543,10 @@ save__cat_2.desc
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
cif::Validator validator("test", is_dict);
|
||||
|
||||
cif::File f;
|
||||
f.loadDictionary(is_dict);
|
||||
f.setValidator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -736,8 +751,10 @@ save__cat_2.parent_id3
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
cif::Validator validator("test", is_dict);
|
||||
|
||||
cif::File f;
|
||||
f.loadDictionary(is_dict);
|
||||
f.setValidator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -958,8 +975,10 @@ cat_2 3 cat_2:cat_1:3
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
cif::Validator validator("test", is_dict);
|
||||
|
||||
cif::File f;
|
||||
f.loadDictionary(is_dict);
|
||||
f.setValidator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1384,9 +1403,10 @@ cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
||||
} buffer(const_cast<char*>(dict), sizeof(dict) - 1);
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
cif::Validator validator("test", is_dict);
|
||||
|
||||
cif::File f;
|
||||
f.loadDictionary(is_dict);
|
||||
f.setValidator(&validator);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1527,8 +1547,6 @@ BOOST_AUTO_TEST_CASE(bondmap_1)
|
||||
{
|
||||
cif::VERBOSE = 2;
|
||||
|
||||
cif::addFileResource("components.cif", gTestDir / ".." / "data" / "components.cif");
|
||||
|
||||
// sections taken from CCD compounds.cif
|
||||
auto components = R"(
|
||||
data_ASN
|
||||
@@ -1684,4 +1702,58 @@ BOOST_AUTO_TEST_CASE(reading_file_1)
|
||||
|
||||
cif::File file;
|
||||
BOOST_CHECK_THROW(file.load(is), std::runtime_error);
|
||||
}
|
||||
}
|
||||
|
||||
// 3d tests
|
||||
|
||||
using namespace mmcif;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(t1)
|
||||
{
|
||||
// std::random_device rnd;
|
||||
// std::mt19937 gen(rnd());
|
||||
// std::uniform_real_distribution<float> dis(0, 1);
|
||||
|
||||
// Quaternion q{ dis(gen), dis(gen), dis(gen), dis(gen) };
|
||||
// q = Normalize(q);
|
||||
|
||||
// Quaternion q{ 0.1, 0.2, 0.3, 0.4 };
|
||||
Quaternion q{ 0.5, 0.5, 0.5, 0.5 };
|
||||
q = Normalize(q);
|
||||
|
||||
const auto &&[angle0, axis0] = QuaternionToAngleAxis(q);
|
||||
|
||||
std::vector<Point> p1{
|
||||
{ 16.979, 13.301, 44.555 },
|
||||
{ 18.150, 13.525, 43.680 },
|
||||
{ 18.656, 14.966, 43.784 },
|
||||
{ 17.890, 15.889, 44.078 },
|
||||
{ 17.678, 13.270, 42.255 },
|
||||
{ 16.248, 13.734, 42.347 },
|
||||
{ 15.762, 13.216, 43.724 }
|
||||
};
|
||||
|
||||
auto p2 = p1;
|
||||
|
||||
Point c1 = CenterPoints(p1);
|
||||
|
||||
for (auto &p : p2)
|
||||
p.rotate(q);
|
||||
|
||||
Point c2 = CenterPoints(p2);
|
||||
|
||||
auto q2 = AlignPoints(p1, p2);
|
||||
|
||||
const auto &&[angle, axis] = QuaternionToAngleAxis(q2);
|
||||
|
||||
BOOST_TEST(std::fmod(360 + angle, 360) == std::fmod(360 - angle0, 360), tt::tolerance(0.01));
|
||||
|
||||
for (auto &p : p1)
|
||||
p.rotate(q2);
|
||||
|
||||
float rmsd = RMSd(p1, p2);
|
||||
|
||||
BOOST_TEST(rmsd < 1e-5);
|
||||
|
||||
// std::cout << "rmsd: " << RMSd(p1, p2) << std::endl;
|
||||
}
|
||||
|
||||
47
tools/update-dictionary-script
Normal file
47
tools/update-dictionary-script
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -f /etc/libcifpp.conf ] ; then
|
||||
. /etc/libcifpp.conf
|
||||
fi
|
||||
|
||||
# check to see if we're supposed to run at all
|
||||
if [ "$update" != "true" ] ; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# if cache directory doesn't exist, exit.
|
||||
if ! [ -d /var/cache/libcifpp ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
fetch_dictionary () {
|
||||
dict=$1
|
||||
source=$2
|
||||
|
||||
wget -O${dict}.gz ${source}
|
||||
|
||||
# be careful not to nuke an existing dictionary file
|
||||
# extract to a temporary file first
|
||||
|
||||
gunzip -c ${dict}.gz > ${dict}-tmp
|
||||
|
||||
# then move the extracted file to the final location
|
||||
|
||||
mv ${dict}-tmp ${dict}
|
||||
|
||||
# and clean up afterwards
|
||||
|
||||
rm ${dict}.gz
|
||||
}
|
||||
|
||||
# fetch the dictionaries
|
||||
|
||||
fetch_dictionary "/var/cache/libcifpp/mmcif_pdbx_v50.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
|
||||
fetch_dictionary "/var/cache/libcifpp/components.cif" "ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
|
||||
Reference in New Issue
Block a user