Commit a96b1e07 by Maarten L. Hekkelman

Merge remote-tracking branch 'origin/develop' into trunk

parents f48c31bc d85ab93a
...@@ -27,11 +27,12 @@ cmake_minimum_required(VERSION 3.23) ...@@ -27,11 +27,12 @@ cmake_minimum_required(VERSION 3.23)
# set the project name # set the project name
project( project(
libcifpp libcifpp
VERSION 7.0.4 VERSION 7.0.5
LANGUAGES CXX) LANGUAGES CXX)
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(FindAtomic)
include(CheckFunctionExists) include(CheckFunctionExists)
include(CheckIncludeFiles) include(CheckIncludeFiles)
include(CheckLibraryExists) include(CheckLibraryExists)
...@@ -41,8 +42,6 @@ include(GenerateExportHeader) ...@@ -41,8 +42,6 @@ include(GenerateExportHeader)
include(CTest) include(CTest)
include(FetchContent) include(FetchContent)
message(STATUS "DESTDIR is '${DESTDIR}'")
# When building with ninja-multiconfig, build both debug and release by default # When building with ninja-multiconfig, build both debug and release by default
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
set(CMAKE_CROSS_CONFIGS "Debug;Release") set(CMAKE_CROSS_CONFIGS "Debug;Release")
...@@ -188,10 +187,6 @@ if(GXX_LIBSTDCPP) ...@@ -188,10 +187,6 @@ if(GXX_LIBSTDCPP)
endif() endif()
endif() endif()
set(CMAKE_THREAD_PREFER_PTHREAD)
set(THREADS_PREFER_PTHREAD_FLAG)
find_package(Threads)
if(MSVC) if(MSVC)
# Avoid linking the shared library of zlib Search ZLIB_ROOT first if it is # Avoid linking the shared library of zlib Search ZLIB_ROOT first if it is
# set. # set.
...@@ -221,6 +216,7 @@ if(MSVC) ...@@ -221,6 +216,7 @@ if(MSVC)
endif() endif()
find_package(ZLIB QUIET) find_package(ZLIB QUIET)
find_package(Threads)
if(NOT ZLIB_FOUND) if(NOT ZLIB_FOUND)
message(FATAL_ERROR "The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)") message(FATAL_ERROR "The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)")
...@@ -260,6 +256,8 @@ if(CIFPP_RECREATE_SYMOP_DATA) ...@@ -260,6 +256,8 @@ if(CIFPP_RECREATE_SYMOP_DATA)
add_executable(symop-map-generator add_executable(symop-map-generator
"${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp") "${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp")
target_compile_features(symop-map-generator PUBLIC cxx_std_20)
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
COMMAND COMMAND
...@@ -331,7 +329,7 @@ set(project_headers ...@@ -331,7 +329,7 @@ set(project_headers
include/cif++/validate.hpp include/cif++/validate.hpp
) )
add_library(cifpp STATIC) add_library(cifpp)
add_library(cifpp::cifpp ALIAS cifpp) add_library(cifpp::cifpp ALIAS cifpp)
target_sources(cifpp target_sources(cifpp
...@@ -371,7 +369,7 @@ target_include_directories( ...@@ -371,7 +369,7 @@ target_include_directories(
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
PRIVATE "${BOOST_REGEX_INCLUDE_DIR}" "${EIGEN_INCLUDE_DIR}") PRIVATE "${BOOST_REGEX_INCLUDE_DIR}" "${EIGEN_INCLUDE_DIR}")
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB) target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB std::atomic)
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
target_link_options(cifpp PRIVATE -undefined dynamic_lookup) target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
...@@ -444,6 +442,10 @@ if(CIFPP_DATA_DIR) ...@@ -444,6 +442,10 @@ if(CIFPP_DATA_DIR)
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}") target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
endif() endif()
if(NOT PROJECT_IS_TOP_LEVEL)
set(CIFPP_SHARE_DIR ${CIFPP_DATA_DIR} PARENT_SCOPE)
endif()
if(UNIX AND NOT BUILD_FOR_CCP4) if(UNIX AND NOT BUILD_FOR_CCP4)
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local") if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local")
set(CIFPP_CACHE_DIR set(CIFPP_CACHE_DIR
...@@ -464,75 +466,72 @@ else() ...@@ -464,75 +466,72 @@ else()
unset(CIFPP_CACHE_DIR) unset(CIFPP_CACHE_DIR)
endif() endif()
# Avoid full installation in case we are not the top level target # Install rules
if(PROJECT_IS_TOP_LEVEL OR BUILD_FOR_CCP4) install(TARGETS cifpp
# Install rules EXPORT cifpp
install(TARGETS cifpp FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
EXPORT cifpp
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(MSVC AND BUILD_SHARED_LIBS) if(MSVC AND BUILD_SHARED_LIBS)
install( install(
FILES $<TARGET_PDB_FILE:cifpp> FILES $<TARGET_PDB_FILE:cifpp>
DESTINATION ${CMAKE_INSTALL_LIBDIR} DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL) OPTIONAL)
endif() endif()
# Clean up old config files (with old names) # Clean up old config files (with old names)
file(GLOB OLD_CONFIG_FILES file(GLOB OLD_CONFIG_FILES
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppConfig*.cmake ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppConfig*.cmake
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppTargets*.cmake) ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppTargets*.cmake)
if(OLD_CONFIG_FILES) if(OLD_CONFIG_FILES)
message( message(
STATUS "Installation will remove old config files: ${OLD_CONFIG_FILES}") STATUS "Installation will remove old config files: ${OLD_CONFIG_FILES}")
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})") install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
endif() endif()
install(EXPORT cifpp install(EXPORT cifpp
NAMESPACE cifpp:: NAMESPACE cifpp::
FILE "cifpp-targets.cmake" FILE "cifpp-targets.cmake"
DESTINATION lib/cmake/cifpp) DESTINATION lib/cmake/cifpp)
if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD) install(
install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic ${COMPONENTS_CIF} DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
endif() if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD)
install(FILES ${COMPONENTS_CIF}
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
endif()
set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cifpp-config.cmake.in) set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
configure_package_config_file( configure_package_config_file(
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake ${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
INSTALL_DESTINATION lib/cmake/cifpp INSTALL_DESTINATION lib/cmake/cifpp
PATH_VARS CIFPP_DATA_DIR) PATH_VARS CIFPP_DATA_DIR)
install( install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake" FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
DESTINATION lib/cmake/cifpp) DESTINATION lib/cmake/cifpp)
set_target_properties( set_target_properties(
cifpp cifpp
PROPERTIES VERSION ${PROJECT_VERSION} PROPERTIES VERSION ${PROJECT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
INTERFACE_cifpp_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) INTERFACE_cifpp_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
set_property( set_property(
TARGET cifpp TARGET cifpp
APPEND APPEND
PROPERTY COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION) PROPERTY COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION)
write_basic_package_version_file( write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion) COMPATIBILITY AnyNewerVersion)
else()
# Set this variable so that consumers can find the files in rsrc
set(CIFPP_SHARE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/rsrc PARENT_SCOPE)
endif()
if(BUILD_TESTING) if(BUILD_TESTING)
add_subdirectory(test) add_subdirectory(test)
......
...@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) ...@@ -52,7 +52,7 @@ int main(int argc, char *argv[])
if (file.empty()) if (file.empty())
{ {
std::cerr << "Empty file" << std::endl; std::cerr << "Empty file\n";
exit(1); exit(1);
} }
...@@ -66,8 +66,8 @@ int main(int argc, char *argv[]) ...@@ -66,8 +66,8 @@ int main(int argc, char *argv[])
auto n = atom_site.count(cif::key("label_atom_id") == "OXT"); auto n = atom_site.count(cif::key("label_atom_id") == "OXT");
std::cout << "File contains " << atom_site.size() << " atoms of which " std::cout << "File contains " << atom_site.size() << " atoms of which "
<< n << (n == 1 ? " is" : " are") << " OXT" << std::endl << n << (n == 1 ? " is" : " are") << " OXT\n"
<< "residues with an OXT are:" << std::endl; << "residues with an OXT are:\n";
// Loop over all atoms with atom-id "OXT" and print out some info. // Loop over all atoms with atom-id "OXT" and print out some info.
// That info is extracted using structured binding in C++ // That info is extracted using structured binding in C++
...@@ -76,7 +76,7 @@ int main(int argc, char *argv[]) ...@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
cif::key("label_atom_id") == "OXT", cif::key("label_atom_id") == "OXT",
"label_asym_id", "label_comp_id", "label_seq_id")) "label_asym_id", "label_comp_id", "label_seq_id"))
{ {
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl; std::cout << asym << ' ' << comp << ' ' << seqnr << '\n';
} }
return 0; return 0;
......
Version 7.0.5
- Fix case where category index was not updated for updated value
Version 7.0.4 Version 7.0.4
- Do not install headers and library in case we're not the top project - Do not install headers and library in case we're not the top project
......
# Simple check to see if we need a library for std::atomic
if(TARGET std::atomic)
return()
endif()
cmake_minimum_required(VERSION 3.10)
include(CMakePushCheckState)
include(CheckIncludeFileCXX)
include(CheckCXXSourceRuns)
cmake_push_check_state()
check_include_file_cxx("atomic" _CXX_ATOMIC_HAVE_HEADER)
mark_as_advanced(_CXX_ATOMIC_HAVE_HEADER)
set(code [[
#include <atomic>
int main(int argc, char** argv) {
std::atomic<long long> s;
++s;
return 0;
}
]])
check_cxx_source_runs("${code}" _CXX_ATOMIC_BUILTIN)
if(_CXX_ATOMIC_BUILTIN)
set(_found 1)
else()
list(APPEND CMAKE_REQUIRED_LIBRARIES atomic)
list(APPEND FOLLY_LINK_LIBRARIES atomic)
check_cxx_source_runs("${code}" _CXX_ATOMIC_LIB_NEEDED)
if (NOT _CXX_ATOMIC_LIB_NEEDED)
message(FATAL_ERROR "unable to link C++ std::atomic code: you may need \
to install GNU libatomic")
else()
set(_found 1)
endif()
endif()
if(_found)
add_library(std::atomic INTERFACE IMPORTED)
set_property(TARGET std::atomic APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14)
if(_CXX_ATOMIC_BUILTIN)
# Nothing to add...
elseif(_CXX_ATOMIC_LIB_NEEDED)
set_target_properties(std::atomic PROPERTIES IMPORTED_LIBNAME atomic)
set(STDCPPATOMIC_LIBRARY atomic)
endif()
endif()
cmake_pop_check_state()
set(Atomic_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::atomic" FORCE)
mark_as_advanced(Atomic_FOUND)
if(Atomic_FIND_REQUIRED AND NOT Atomic_FOUND)
message(FATAL_ERROR "Cannot run simple program using std::atomic")
endif()
...@@ -13,7 +13,7 @@ int main(int argc, char *argv[]) ...@@ -13,7 +13,7 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
cif::file file = cif::pdb::read(argv[1]); cif::file file(argv[1]);
if (file.empty()) if (file.empty())
{ {
......
...@@ -138,7 +138,7 @@ struct compound_bond ...@@ -138,7 +138,7 @@ struct compound_bond
/// This information is derived from the CDD by default. /// This information is derived from the CDD by default.
/// ///
/// To create compounds, you use the factory method. You can add your own /// To create compounds, you use the factory method. You can add your own
/// compound definitions by calling the addExtraComponents function and /// compound definitions by calling the push_dictionary function and
/// pass it a valid CCD formatted file. /// pass it a valid CCD formatted file.
class compound class compound
......
...@@ -1285,6 +1285,19 @@ condition operator==(const key &key, const std::optional<T> &v) ...@@ -1285,6 +1285,19 @@ condition operator==(const key &key, const std::optional<T> &v)
} }
/** /**
* @brief Create a condition to search any item for a value @a v if @a v contains a value
* compare to null if not.
*/
template <typename T>
condition operator!=(const key &key, const std::optional<T> &v)
{
if (v.has_value())
return condition(new detail::not_condition_impl(condition(new detail::key_equals_condition_impl({ key.m_item_name, *v }))));
else
return condition(new detail::not_condition_impl(condition(new detail::key_is_empty_condition_impl(key.m_item_name))));
}
/**
* @brief Operator to create a boolean opposite of the condition in @a rhs * @brief Operator to create a boolean opposite of the condition in @a rhs
*/ */
inline condition operator not(condition &&rhs) inline condition operator not(condition &&rhs)
......
...@@ -378,7 +378,7 @@ struct item_handle ...@@ -378,7 +378,7 @@ struct item_handle
template <typename T> template <typename T>
item_handle &operator=(T &&value) item_handle &operator=(T &&value)
{ {
assign_value(item{ "", std::move(value) }.value()); assign_value(item{ "", std::forward<T>(value) }.value());
return *this; return *this;
} }
......
...@@ -350,7 +350,12 @@ class atom ...@@ -350,7 +350,12 @@ class atom
std::string get_pdb_ins_code() const { return get_property("pdbx_PDB_ins_code"); } ///< Return the pdb_ins_code property std::string get_pdb_ins_code() const { return get_property("pdbx_PDB_ins_code"); } ///< Return the pdb_ins_code property
/// Return true if this atom is an alternate /// Return true if this atom is an alternate
bool is_alternate() const { return not get_label_alt_id().empty(); } bool is_alternate() const
{
if (auto alt_id = get_label_alt_id(); alt_id.empty() or alt_id == ".")
return false;
return true;
}
/// Convenience method to return a string that might be ID in PDB space /// Convenience method to return a string that might be ID in PDB space
std::string pdb_id() const std::string pdb_id() const
...@@ -550,6 +555,9 @@ class residue ...@@ -550,6 +555,9 @@ class residue
/// \brief Return true if this residue has alternate atoms /// \brief Return true if this residue has alternate atoms
bool has_alternate_atoms() const; bool has_alternate_atoms() const;
/// \brief Return true if this residue has alternate atoms for the atom \a atomID
bool has_alternate_atoms_for(const std::string &atomID) const;
/// \brief Return the list of unique alt ID's present in this residue /// \brief Return the list of unique alt ID's present in this residue
std::set<std::string> get_alternate_ids() const; std::set<std::string> get_alternate_ids() const;
...@@ -572,6 +580,10 @@ class residue ...@@ -572,6 +580,10 @@ class residue
m_auth_seq_id == rhs.m_auth_seq_id); m_auth_seq_id == rhs.m_auth_seq_id);
} }
/// @brief Create a new atom and add it to the list
/// @return newly created atom
virtual atom create_new_atom(atom_type inType, const std::string &inAtomID, point inLocation);
protected: protected:
/** @cond */ /** @cond */
residue() {} residue() {}
...@@ -672,6 +684,8 @@ class monomer : public residue ...@@ -672,6 +684,8 @@ class monomer : public residue
return m_polymer == rhs.m_polymer and m_index == rhs.m_index; return m_polymer == rhs.m_polymer and m_index == rhs.m_index;
} }
atom create_new_atom(atom_type inType, const std::string &inAtomID, point inLocation) override;
private: private:
const polymer *m_polymer; const polymer *m_polymer;
std::size_t m_index; std::size_t m_index;
...@@ -1091,6 +1105,9 @@ class structure ...@@ -1091,6 +1105,9 @@ class structure
/// \brief emplace the moved atom @a atom /// \brief emplace the moved atom @a atom
atom &emplace_atom(atom &&atom); atom &emplace_atom(atom &&atom);
/// \brief Reorder atom_site atoms based on 'natural' ordering
void reorder_atoms();
private: private:
friend polymer; friend polymer;
friend residue; friend residue;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -1321,7 +1321,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie ...@@ -1321,7 +1321,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
std::string oldValue{ parent[item_name].text() }; std::string oldValue{ parent[item_name].text() };
std::string value{ value_provider(oldValue) }; std::string value{ value_provider(oldValue) };
parent.assign(colIx, value, false); update_value(parent.get_row(), colIx, value, false, false);
for (auto &&[childCat, linked] : m_child_links) for (auto &&[childCat, linked] : m_child_links)
{ {
...@@ -1444,8 +1444,7 @@ void category::update_value(row *row, uint16_t item, std::string_view value, boo ...@@ -1444,8 +1444,7 @@ void category::update_value(row *row, uint16_t item, std::string_view value, boo
// before updating // before updating
bool reinsert = false; bool reinsert = false;
if (updateLinked and // an update of an Item's value if (m_index != nullptr and key_item_indices().count(item))
m_index != nullptr and key_item_indices().count(item))
{ {
reinsert = m_index->find(*this, row); reinsert = m_index->find(*this, row);
if (reinsert) if (reinsert)
...@@ -1698,6 +1697,12 @@ void category::swap_item(uint16_t item_ix, row_handle &a, row_handle &b) ...@@ -1698,6 +1697,12 @@ void category::swap_item(uint16_t item_ix, row_handle &a, row_handle &b)
auto &ra = *a.m_row; auto &ra = *a.m_row;
auto &rb = *b.m_row; auto &rb = *b.m_row;
while (ra.size() <= item_ix)
ra.emplace_back("");
while (rb.size() <= item_ix)
rb.emplace_back("");
std::swap(ra.at(item_ix), rb.at(item_ix)); std::swap(ra.at(item_ix), rb.at(item_ix));
} }
......
...@@ -496,7 +496,7 @@ compound *compound_factory_impl::create(const std::string &id) ...@@ -496,7 +496,7 @@ compound *compound_factory_impl::create(const std::string &id)
m_index = parser.index_datablocks(); m_index = parser.index_datablocks();
if (cif::VERBOSE > 1) if (cif::VERBOSE > 1)
std::cout << " done" << std::endl; std::cout << " done\n";
// reload the resource, perhaps this should be improved... // reload the resource, perhaps this should be improved...
if (m_file.empty()) if (m_file.empty())
...@@ -519,7 +519,7 @@ compound *compound_factory_impl::create(const std::string &id) ...@@ -519,7 +519,7 @@ compound *compound_factory_impl::create(const std::string &id)
parser.parse_single_datablock(id, m_index); parser.parse_single_datablock(id, m_index);
if (cif::VERBOSE > 1) if (cif::VERBOSE > 1)
std::cout << " done" << std::endl; std::cout << " done\n";
if (not file.empty()) if (not file.empty())
{ {
...@@ -545,20 +545,20 @@ class local_compound_factory_impl : public compound_factory_impl ...@@ -545,20 +545,20 @@ class local_compound_factory_impl : public compound_factory_impl
: compound_factory_impl(next) : compound_factory_impl(next)
, m_local_file(file) , m_local_file(file)
{ {
const std::regex peptideRx("(?:[lmp]-)?peptide", std::regex::icase); // const std::regex peptideRx("(?:[lmp]-)?peptide", std::regex::icase);
for (const auto &[id, name, threeLetterCode, group] : // for (const auto &[id, name, threeLetterCode, group] :
file["comp_list"]["chem_comp"].rows<std::string, std::string, std::string, std::string>("id", "name", "three_letter_code", "group")) // file["comp_list"]["chem_comp"].rows<std::string, std::string, std::string, std::string>("id", "name", "three_letter_code", "group"))
{ // {
auto &rdb = m_local_file["comp_" + id]; // auto &rdb = m_local_file["comp_" + id];
if (rdb.empty()) // if (rdb.empty())
{ // {
std::cerr << "Missing data in restraint file for id " + id + '\n'; // // std::cerr << "Missing data in restraint file for id " + id + '\n';
continue; // continue;
} // }
construct_compound(rdb, id, name, threeLetterCode, group); // construct_compound(rdb, id, name, threeLetterCode, group);
} // }
} }
compound *create(const std::string &id) override; compound *create(const std::string &id) override;
......
...@@ -49,6 +49,7 @@ void datablock::set_validator(const validator *v) ...@@ -49,6 +49,7 @@ void datablock::set_validator(const validator *v)
} }
catch (const std::exception &) catch (const std::exception &)
{ {
m_validator = nullptr;
throw_with_nested(std::runtime_error("Error while setting validator in datablock " + m_name)); throw_with_nested(std::runtime_error("Error while setting validator in datablock " + m_name));
} }
} }
......
...@@ -31,11 +31,32 @@ namespace cif ...@@ -31,11 +31,32 @@ namespace cif
{ {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// TODO: This is wrong. A validator should be assigned to datablocks,
// not to a file. Since audit_conform is a category specifying the
// content of a datablock. Not the entire file.
void file::set_validator(const validator *v) void file::set_validator(const validator *v)
{ {
m_validator = v; m_validator = v;
for (auto &db : *this) for (bool first = true; auto &db : *this)
db.set_validator(v); {
try
{
db.set_validator(v);
}
catch (const std::exception &e)
{
if (first)
throw;
// Accept failure on secondary datablocks
// now that many mmCIF files have invalid
// restraint data concatenated.
std::cerr << e.what() << '\n';
}
first = false;
}
} }
bool file::is_valid() const bool file::is_valid() const
...@@ -78,12 +99,12 @@ bool file::validate_links() const ...@@ -78,12 +99,12 @@ bool file::validate_links() const
{ {
if (m_validator == nullptr) if (m_validator == nullptr)
std::runtime_error("No validator loaded explicitly, cannot continue"); std::runtime_error("No validator loaded explicitly, cannot continue");
bool result = true; bool result = true;
for (auto &db : *this) for (auto &db : *this)
result = db.validate_links() and result; result = db.validate_links() and result;
return result; return result;
} }
...@@ -97,7 +118,7 @@ void file::load_dictionary() ...@@ -97,7 +118,7 @@ void file::load_dictionary()
std::string name = audit_conform->front().get<std::string>("dict_name"); std::string name = audit_conform->front().get<std::string>("dict_name");
if (name == "mmcif_pdbx_v50") if (name == "mmcif_pdbx_v50")
name = "mmcif_pdbx.dic"; // we had a bug here in libcifpp... name = "mmcif_pdbx.dic"; // we had a bug here in libcifpp...
if (not name.empty()) if (not name.empty())
{ {
...@@ -125,7 +146,8 @@ void file::load_dictionary(std::string_view name) ...@@ -125,7 +146,8 @@ void file::load_dictionary(std::string_view name)
bool file::contains(std::string_view name) const bool file::contains(std::string_view name) const
{ {
return std::find_if(begin(), end(), [name](const datablock &db) { return iequals(db.name(), name); }) != end(); return std::find_if(begin(), end(), [name](const datablock &db)
{ return iequals(db.name(), name); }) != end();
} }
datablock &file::operator[](std::string_view name) datablock &file::operator[](std::string_view name)
......
...@@ -144,9 +144,11 @@ void checkEntities(datablock &db) ...@@ -144,9 +144,11 @@ void checkEntities(datablock &db)
if (comp_id.has_value()) if (comp_id.has_value())
{ {
auto compound = cf.create(*comp_id); auto compound = cf.create(*comp_id);
assert(compound);
if (not compound) if (not compound)
throw std::runtime_error("missing information for compound " + *comp_id); {
std::cerr << "missing information for compound " << *comp_id << "\n";
continue;
}
formula_weight = compound->formula_weight(); formula_weight = compound->formula_weight();
} }
} }
...@@ -416,6 +418,8 @@ void checkAtomRecords(datablock &db) ...@@ -416,6 +418,8 @@ void checkAtomRecords(datablock &db)
for (int id : db["entity"].find<int>("type"_key == "polymer", "id")) for (int id : db["entity"].find<int>("type"_key == "polymer", "id"))
polymer_entities.insert(id); polymer_entities.insert(id);
std::set<std::string> missingCompounds;
for (auto row : atom_site) for (auto row : atom_site)
{ {
residue_key_type k = row.get<std::optional<std::string>, residue_key_type k = row.get<std::optional<std::string>,
...@@ -446,11 +450,18 @@ void checkAtomRecords(datablock &db) ...@@ -446,11 +450,18 @@ void checkAtomRecords(datablock &db)
std::string asym_id = get_asym_id(k); std::string asym_id = get_asym_id(k);
std::string comp_id = get_comp_id(k); std::string comp_id = get_comp_id(k);
if (missingCompounds.contains(comp_id))
continue;
bool is_polymer = polymer_entities.contains(row["label_entity_id"].as<int>()); bool is_polymer = polymer_entities.contains(row["label_entity_id"].as<int>());
auto compound = cf.create(comp_id); auto compound = cf.create(comp_id);
if (not compound) if (not compound)
throw std::runtime_error("Missing compound information for " + comp_id); {
missingCompounds.insert(comp_id);
std::cerr << "Missing compound information for " << comp_id << "\n";
continue;
}
auto chem_comp_entry = chem_comp.find_first("id"_key == comp_id); auto chem_comp_entry = chem_comp.find_first("id"_key == comp_id);
...@@ -590,18 +601,18 @@ void checkAtomAnisotropRecords(datablock &db) ...@@ -590,18 +601,18 @@ void checkAtomAnisotropRecords(datablock &db)
row["type_symbol"] = parent["type_symbol"].text(); row["type_symbol"] = parent["type_symbol"].text();
} }
if (row["pdbx_auth_alt_id"].empty()) if (row["pdbx_auth_alt_id"].empty() and not parent["pdbx_auth_alt_id"].empty())
row["pdbx_auth_alt_id"] = parent["pdbx_auth_alt_id"].text(); row["pdbx_auth_alt_id"] = parent["pdbx_auth_alt_id"].text();
if (row["pdbx_label_seq_id"].empty()) if (row["pdbx_label_seq_id"].empty() and not parent["pdbx_label_seq_id"].empty())
row["pdbx_label_seq_id"] = parent["label_seq_id"].text(); row["pdbx_label_seq_id"] = parent["label_seq_id"].text();
if (row["pdbx_label_asym_id"].empty()) if (row["pdbx_label_asym_id"].empty() and not parent["pdbx_label_asym_id"].empty())
row["pdbx_label_asym_id"] = parent["label_asym_id"].text(); row["pdbx_label_asym_id"] = parent["label_asym_id"].text();
if (row["pdbx_label_atom_id"].empty()) if (row["pdbx_label_atom_id"].empty() and not parent["pdbx_label_atom_id"].empty())
row["pdbx_label_atom_id"] = parent["label_atom_id"].text(); row["pdbx_label_atom_id"] = parent["label_atom_id"].text();
if (row["pdbx_label_comp_id"].empty()) if (row["pdbx_label_comp_id"].empty() and not parent["pdbx_label_comp_id"].empty())
row["pdbx_label_comp_id"] = parent["label_comp_id"].text(); row["pdbx_label_comp_id"] = parent["label_comp_id"].text();
if (row["pdbx_PDB_model_num"].empty()) // if (row["pdbx_PDB_model_num"].empty() and not parent["pdbx_PDB_model_num"].empty())
row["pdbx_PDB_model_num"] = parent["pdbx_PDB_model_num"].text(); // row["pdbx_PDB_model_num"] = parent["pdbx_PDB_model_num"].text();
} }
if (not to_be_deleted.empty()) if (not to_be_deleted.empty())
...@@ -811,6 +822,18 @@ void createEntityPoly(datablock &db) ...@@ -811,6 +822,18 @@ void createEntityPoly(datablock &db)
non_std_monomer = true; non_std_monomer = true;
} }
else
{
// c_type = "other";
letter_can = c->one_letter_code();
if (letter_can == 0)
letter_can = 'X';
letter = '(' + comp_id + ')';
non_std_monomer = true;
}
if (type.empty()) if (type.empty())
type = c_type; type = c_type;
...@@ -877,7 +900,7 @@ void createEntityPoly(datablock &db) ...@@ -877,7 +900,7 @@ void createEntityPoly(datablock &db)
void createEntityPolySeq(datablock &db) void createEntityPolySeq(datablock &db)
{ {
if (db.get("entity_poly") == nullptr) if (auto cat = db.get("entity_poly"); cat == nullptr or cat->empty())
createEntityPoly(db); createEntityPoly(db);
using namespace literals; using namespace literals;
...@@ -928,7 +951,10 @@ void createEntityPolySeq(datablock &db) ...@@ -928,7 +951,10 @@ void createEntityPolySeq(datablock &db)
void createPdbxPolySeqScheme(datablock &db) void createPdbxPolySeqScheme(datablock &db)
{ {
if (db.get("entity_poly_seq") == nullptr) if (auto cat = db.get("entity_poly"); cat == nullptr or cat->empty())
createEntityPoly(db);
if (auto cat = db.get("entity_poly_seq"); cat == nullptr or cat->empty())
createEntityPolySeq(db); createEntityPolySeq(db);
using namespace literals; using namespace literals;
...@@ -1065,7 +1091,7 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary) ...@@ -1065,7 +1091,7 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
// ... and any additional datablock will contain compound information // ... and any additional datablock will contain compound information
cif::compound_source cs(file); cif::compound_source cs(file);
if (db.get("atom_site") == nullptr) if (auto cat = db.get("atom_site"); cat == nullptr or cat->empty())
throw std::runtime_error("Cannot reconstruct PDBx file, atom data missing"); throw std::runtime_error("Cannot reconstruct PDBx file, atom data missing");
auto &validator = validator_factory::instance()[dictionary]; auto &validator = validator_factory::instance()[dictionary];
...@@ -1073,7 +1099,7 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary) ...@@ -1073,7 +1099,7 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
std::string entry_id; std::string entry_id;
// Phenix files do not have an entry record // Phenix files do not have an entry record
if (db.get("entry") == nullptr) if (auto cat = db.get("entry"); cat == nullptr or cat->empty())
{ {
entry_id = db.name(); entry_id = db.name();
category entry("entry"); category entry("entry");
...@@ -1327,19 +1353,19 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary) ...@@ -1327,19 +1353,19 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
// Now create any missing categories // Now create any missing categories
// Next make sure we have struct_asym records // Next make sure we have struct_asym records
if (db.get("struct_asym") == nullptr) if (auto cat = db.get("struct_asym"); cat == nullptr or cat->empty())
createStructAsym(db); createStructAsym(db);
if (db.get("entity") == nullptr) if (auto cat = db.get("entity"); cat == nullptr or cat->empty())
createEntity(db); createEntity(db);
// fill in missing formula_weight, e.g. // fill in missing formula_weight, e.g.
checkEntities(db); checkEntities(db);
if (db.get("pdbx_poly_seq_scheme") == nullptr) if (auto cat = db.get("pdbx_poly_seq_scheme"); cat == nullptr or cat->empty())
createPdbxPolySeqScheme(db); createPdbxPolySeqScheme(db);
if (db.get("ndb_poly_seq_scheme") != nullptr) if (auto cat = db.get("ndb_poly_seq_scheme"); cat == nullptr or cat->empty())
comparePolySeqSchemes(db); comparePolySeqSchemes(db);
// skip unknown categories for now // skip unknown categories for now
......
...@@ -189,6 +189,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro ...@@ -189,6 +189,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
for (auto asym_id : struct_asym.find<std::string>("entity_id"_key == entity_id, "id")) for (auto asym_id : struct_asym.find<std::string>("entity_id"_key == entity_id, "id"))
{ {
if (pdbx_poly_seq_scheme.count( if (pdbx_poly_seq_scheme.count(
"entity_id"_key == entity_id and
"asym_id"_key == asym_id and "asym_id"_key == asym_id and
"mon_id"_key == mon_id and "mon_id"_key == mon_id and
"seq_id"_key == num and "seq_id"_key == num and
...@@ -202,6 +203,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro ...@@ -202,6 +203,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
for (const auto &[seq_id, mon_id, hetero] : pdbx_poly_seq_scheme.find<int, std::string, bool>("entity_id"_key == entity_id, "seq_id", "mon_id", "hetero")) for (const auto &[seq_id, mon_id, hetero] : pdbx_poly_seq_scheme.find<int, std::string, bool>("entity_id"_key == entity_id, "seq_id", "mon_id", "hetero"))
{ {
if (entity_poly_seq.count( if (entity_poly_seq.count(
"entity_id"_key == entity_id and
"mon_id"_key == mon_id and "mon_id"_key == mon_id and
"num"_key == seq_id and "num"_key == seq_id and
"hetero"_key == hetero) != 1) "hetero"_key == hetero) != 1)
......
...@@ -235,7 +235,7 @@ void progress_bar_impl::print_progress() ...@@ -235,7 +235,7 @@ void progress_bar_impl::print_progress()
float progress = static_cast<float>(m_consumed) / m_max_value; float progress = static_cast<float>(m_consumed) / m_max_value;
if (width < kMinBarWidth) if (width < kMinBarWidth)
std::cout << (100 * progress) << '%' << std::endl; std::cout << (100 * progress) << "%\n";
else else
{ {
uint32_t bar_width = 7 * width / 10; uint32_t bar_width = 7 * width / 10;
...@@ -329,7 +329,7 @@ void progress_bar_impl::print_done() ...@@ -329,7 +329,7 @@ void progress_bar_impl::print_done()
if (msg.length() < width) if (msg.length() < width)
msg += std::string(width - msg.length(), ' '); msg += std::string(width - msg.length(), ' ');
std::cout << '\r' << msg << std::endl; std::cout << '\r' << msg << '\n';
} }
progress_bar::progress_bar(int64_t inMax, const std::string &inAction) progress_bar::progress_bar(int64_t inMax, const std::string &inAction)
......
# We're using the older version 2 of Catch2 # We're using the older version 2 of Catch2
find_package(Catch2 QUIET) if(NOT(Catch2_FOUND OR TARGET Catch2))
find_package(Catch2 QUIET)
if(NOT Catch2_FOUND) if(NOT Catch2_FOUND)
FetchContent_Declare( include(FetchContent)
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.13.9)
FetchContent_MakeAvailable(Catch2) FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.13.9)
set(Catch2_VERSION "2.13.9") FetchContent_MakeAvailable(Catch2)
set(Catch2_VERSION "2.13.9")
endif()
endif() endif()
list( list(
...@@ -49,8 +53,7 @@ foreach(CIFPP_TEST IN LISTS CIFPP_tests) ...@@ -49,8 +53,7 @@ foreach(CIFPP_TEST IN LISTS CIFPP_tests)
target_compile_definitions(${CIFPP_TEST} PUBLIC CATCH22=1) target_compile_definitions(${CIFPP_TEST} PUBLIC CATCH22=1)
endif() endif()
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp::cifpp target_link_libraries(${CIFPP_TEST} PRIVATE cifpp::cifpp Catch2::Catch2)
Catch2::Catch2)
target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}") target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}")
if(MSVC) if(MSVC)
......
...@@ -157,7 +157,7 @@ TEST_CASE("dh_q_0") ...@@ -157,7 +157,7 @@ TEST_CASE("dh_q_0")
}; };
auto a = cif::dihedral_angle(t[0], t[1], t[2], p); auto a = cif::dihedral_angle(t[0], t[1], t[2], p);
REQUIRE_THAT(a, Catch::Matchers::WithinRel(0, 0.01f)); REQUIRE_THAT(a, Catch::Matchers::WithinRel(0.f, 0.01f));
auto q = cif::construct_from_angle_axis(90, axis); auto q = cif::construct_from_angle_axis(90, axis);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment