diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27df91541c..1b38aa0e73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: run: | sudo apt-get update -qq sudo apt-get install -qq libboost-all-dev swig libhdf5-dev libeigen3-dev \ - cmake libcgal-dev libcgal-qt5-dev \ + cmake libcgal-dev libcgal-qt5-dev libcereal-dev \ libfftw3-dev libopencv-dev libgsl-dev libann-dev \ libprotobuf-dev protobuf-compiler \ libopenmpi-dev python3-dev python3-numpy python3-protobuf \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 2aa0cd53e1..8a5e4d7f01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,7 +232,7 @@ include_directories("${CMAKE_BINARY_DIR}/include") set(IMP_ALL_DEPENDS_VARS BOOST.FILESYSTEM_LIBRARIES BOOST.SYSTEM_LIBRARIES BOOST.THREAD_LIBRARIES BOOST.PROGRAMOPTIONS_LIBRARIES BOOST.REGEX_LIBRARIES BOOST.GRAPH_LIBRARIES BOOST.RANDOM_LIBRARIES - BOOST.SERIALIZATION_LIBRARIES CACHE INTERNAL "" FORCE) + CACHE INTERNAL "" FORCE) imp_execute_process("setup" ${CMAKE_BINARY_DIR} COMMAND ${PYTHON_EXECUTABLE} @@ -269,7 +269,7 @@ else() endif() set(Boost_NO_BOOST_CMAKE ON) -find_package(Boost 1.53.0 COMPONENTS system filesystem thread program_options serialization REQUIRED) +find_package(Boost 1.53.0 COMPONENTS system filesystem thread program_options REQUIRED) if("${Boost_SYSTEM_LIBRARY_RELEASE}" MATCHES ".*NOTFOUND.*") message(FATAL_ERROR "Boost is required to build IMP.") endif() @@ -311,13 +311,6 @@ link_directories(${Boost_LIBRARY_DIRS}) set(BOOST.FILESYSTEM_LIBRARIES ${Boost_FILESYSTEM_LIBRARY_RELEASE}) set(BOOST.SYSTEM_LIBRARIES ${Boost_SYSTEM_LIBRARY_RELEASE}) set(BOOST.THREAD_LIBRARIES ${Boost_THREAD_LIBRARY_RELEASE}) -if(IMP_STATIC) -# Boost.Serialization needs pthread, but order is important with static -# libraries; we must link pthread *after* serialization -set(BOOST.SERIALIZATION_LIBRARIES ${Boost_SERIALIZATION_LIBRARY_RELEASE} -lpthread) -else() -set(BOOST.SERIALIZATION_LIBRARIES ${Boost_SERIALIZATION_LIBRARY_RELEASE}) -endif() set(BOOST.PROGRAMOPTIONS_LIBRARIES ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE}) set(BOOST.REGEX_LIBRARIES ${Boost_REGEX_LIBRARY_RELEASE}) set(BOOST.GRAPH_LIBRARIES ${Boost_GRAPH_LIBRARY_RELEASE}) @@ -340,6 +333,9 @@ find_package(Eigen3 3.0 REQUIRED) # b) we're not going to fix, since Eigen isn't our code. include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR}) +find_package(cereal REQUIRED) +include_directories(SYSTEM ${cereal_INCLUDE_DIRS}) + add_custom_target("IMP-version" COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/build/make_version.py @@ -437,9 +433,9 @@ if(IMP_DOXYGEN_FOUND) COMMENT "Building documentation") add_custom_target(IMP-doc-install - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_BINARY_DIR}/doc/manual" "${CMAKE_INSTALL_FULL_DOCDIR}/manual" + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/build/copy_directory_deref.py "${CMAKE_BINARY_DIR}/doc/manual" "${CMAKE_INSTALL_FULL_DOCDIR}/manual" COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/doxygen/manual-tags.xml" "${CMAKE_INSTALL_FULL_DOCDIR}" - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_BINARY_DIR}/doc/ref" "${CMAKE_INSTALL_FULL_DOCDIR}/ref" + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/build/copy_directory_deref.py "${CMAKE_BINARY_DIR}/doc/ref" "${CMAKE_INSTALL_FULL_DOCDIR}/ref" COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/doxygen/ref-tags.xml" "${CMAKE_INSTALL_FULL_DOCDIR}" DEPENDS "IMP-doc" COMMENT "Installing documentation to ${CMAKE_INSTALL_FULL_DOCDIR}") @@ -484,7 +480,7 @@ foreach(cmakefile ${CMAKE_BINARY_DIR}/IMPConfig.cmake ${CMAKE_BINARY_DIR}/cmake/IMPConfig.cmake) foreach(var IMP_LIB_TYPE IMP_NO_SWIG_DEPENDENCIES IMP_STATIC IMP_MAX_CHECKS IMP_MAX_LOG IMP_SWIG_LIBRARIES EIGEN3_INCLUDE_DIR - Boost_INCLUDE_DIR ${IMP_ALL_DEPENDS_VARS}) + cereal_INCLUDE_DIRS Boost_INCLUDE_DIR ${IMP_ALL_DEPENDS_VARS}) file(APPEND "${cmakefile}" "SET(${var} \"${${var}}\" CACHE INTERNAL \"\" FORCE)\n") endforeach() diff --git a/ChangeLog.md b/ChangeLog.md index 7839cb73ed..1a7d6ba124 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,42 @@ ChangeLog {#changelog} ========= +# 2.19.0 - 2023-06-22 # {#changelog_2_19_0} +- Most IMP Value and Object types can now be serialized (or pickled in Python). + For example, this can be used to save the current state of an IMP::Model + or an IMP.pmi.macros.ReplicaExchange object to be restored later or passed + to a separate process. Building IMP from source code now requires the + cereal library. +- Information on most IMP restraints, sampling protocols, input files and + analysis/clustering is now stored in the RMF file. Ultimately this can be + used to generate an IHM mmCIF file directly from the RMF. +- IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint now + requires the `linker` argument, which specifies the chemistry of the linker. +- IMP.pmi.macros.ReplicaExchange0 has been removed. + Use IMP.pmi.macros.ReplicaExchange instead. +- The undocumented IMP::core::ConjugateGradients::set_threshold() method is + now deprecated; use set_gradient_threshold() instead. +- Rigid body members are now handled correctly by IMP::atom::destroy(), + and can be removed from their rigid body with a new + IMP::core::RigidBody::remove_member() method. +- The IMP::em2d::CenteredMat and IMP::em2d::Fine2DRegistrationRestraint + classes have been moved to the IMP::em2d::internal namespace, as they + are implementation details. +- Windows builds now require MS Visual Studio 2015 or later (for full C++11 + support). The following macro for pre-C++11 environments is no longer + needed and is deprecated: `IMP_NOEXCEPT`. +- The following pre-C++11 compatibility macros and headers are removed: + `IMP_NULLPTR`, `IMP_NULLPTR_T`, `IMP_OVERRIDE`, `IMP_FINAL`, `IMP_UNIQUE_PTR`, + `IMP_FOREACH`, `IMP/nullptr.h`, and `IMP/nullptr_macros.h`. +- The deprecated IMP::em::emreal type has been removed. +- The deprecated IMP::isd::Weight::get_nstates_key() method has been removed. +- The deprecated IMP.npc.npc_restraints module has been removed. Use + IMP.pmi.restraints.npc or IMP.pmi1.restraints.npc instead. +- The deprecated IMP::core::{Singleton,Pair,Triplet,Quad}Constraint constructors + that take Particle/ParticlePair/ParticleTriplet/ParticleQuad have been + removed. Use the constructors that take a Model and ParticleIndex (etc.) + instead. + # 2.18.0 - 2022-12-15 # {#changelog_2_18_0} - The Windows .exe installer now supports Python 3.11. - The IMP::em::emreal type is deprecated; use plain `double` instead. diff --git a/README.md b/README.md index 241c1920ca..5aba1317a2 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ new shell. Copyright and License information ================================= -IMP is Copyright 2007-2022 IMP Inventors. The IMP Inventors are +IMP is Copyright 2007-2023 IMP Inventors. The IMP Inventors are Andrej Sali, Ben Webb, Daniel Russel, Keren Lasker, Dina Schneidman, Javier Velázquez-Muriel, Friedrich Förster, Elina Tjioe, Hao Fan, Seung Joong Kim, Yannick Spill, Riccardo Pellarin. diff --git a/VERSION b/VERSION index cf8690732f..ef0f38abe1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.18.0 +2.19.0 diff --git a/cmake_modules/Findcereal.cmake b/cmake_modules/Findcereal.cmake new file mode 100644 index 0000000000..e7ea28d4c6 --- /dev/null +++ b/cmake_modules/Findcereal.cmake @@ -0,0 +1,32 @@ +# Try to find Cereal +# +# The following variables are set: +# cereal_FOUND +# cereal_INCLUDE_DIRS - directories with Cereal headers +# cereal_DEFINITIONS - Cereal compiler flags + +find_path(cereal_header_paths_tmp + NAMES + cereal.hpp + PATH_SUFFIXES + include + cereal/include + cereal + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${CEREAL_ROOT_DIR} + ${CEREAL_ROOT_DIR}/include + ${CEREAL_ROOT_DIR}/cereal/include + $ENV{CEREAL_ROOT_DIR} + $ENV{CEREAL_ROOT_DIR}/include + $ENV{CEREAL_ROOT_DIR}/cereal + ) + +get_filename_component(cereal_INCLUDE_DIRS ${cereal_header_paths_tmp} PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(cereal + REQUIRED_VARS cereal_INCLUDE_DIRS + ) + +mark_as_advanced(cereal_FOUND) diff --git a/doc/manual/cmake_config.md b/doc/manual/cmake_config.md index b542dc7075..0d3f3c2820 100644 --- a/doc/manual/cmake_config.md +++ b/doc/manual/cmake_config.md @@ -101,7 +101,7 @@ For each dependency CMake will first try to find the header and library files for that dependency, reporting success if it finds them. Next, it will often try to build a small C or C++ test program that uses those headers and libraries. If this fails the dependency cannot be used (and CMake will, -somewhat confusing, report that the dependency was first found and then not +somewhat confusingly, report that the dependency was first found and then not found). To fix issues like this, check the CMake error log in `CMakeFiles/CMakeError.log` to see what failed. In some cases this can be fixed by modifying the flags passed to the C or C++ compiler. For example, diff --git a/doc/manual/code_conventions.md b/doc/manual/code_conventions.md index 30209e3afd..1bb7eb96ac 100644 --- a/doc/manual/code_conventions.md +++ b/doc/manual/code_conventions.md @@ -122,7 +122,7 @@ As a result, such functions do not need to obey all the coding conventions # C++ 11 {#codeconv_cxx11} Latest %IMP requires a compiler that supports C++ 11, unlike older versions. -Thus, C++ 11 features, such as the `override`, `final`, `auto` and `nullptr` -keywords, and range-based for loops, can be used where appropriate. -The old compatibility macros (such as `IMP_OVERRIDE`, `IMP_FINAL`, -`IMP_NULLPTR` and `IMP_FOREACH`) should no longer be used. +Thus, C++ 11 features, such as the `override`, `final`, `auto`, `noexcept` +and `nullptr` keywords, and range-based for loops, can be used where +appropriate. The old compatibility macros (such as `IMP_OVERRIDE`, `IMP_FINAL`, +`IMP_NOEXCEPT`, `IMP_NULLPTR` and `IMP_FOREACH`) should no longer be used. diff --git a/doc/manual/extdepends.md b/doc/manual/extdepends.md index 168a405980..d54ddd3db0 100644 --- a/doc/manual/extdepends.md +++ b/doc/manual/extdepends.md @@ -23,6 +23,14 @@ your code in a new module, rather than adding it to an existing module. That way, people that elect not to install that dependency will only be deprived of your code, not of the existing module. +Try not to require the very latest version of a dependency, as again that may +make it harder for people to use. (If necessary, you can use preprocessor +macros so that your code works with both old and new versions of a dependency; +for examples, look in the C++ code for `BOOST_VERSION`.) We try to make %IMP +work with the versions of packages available in the oldest supported versions +of RedHat Enterprise Linux (RHEL), Ubuntu LTS, and macOS. For example, RHEL 7 +ships with Boost 1.53 and Python 2.7, so %IMP works with both of those. + # Simple dependencies # {#extdep_simple} The simplest way to add a C/C++ dependency `foo` is to create a file diff --git a/doc/manual/install_windows.md b/doc/manual/install_windows.md index c508ff52f5..b27347ec41 100644 --- a/doc/manual/install_windows.md +++ b/doc/manual/install_windows.md @@ -3,11 +3,9 @@ Building from source code on Windows {#install_windows} We build and test %IMP on Windows, built with the Microsoft Visual Studio compilers (we use Visual Studio -Express 2010 SP1 for the 32-bit Windows `.exe` installer, and -VS Express 2012 for the 64-bit `.exe` installer; for the +2015 for both the 32-bit and 64-bit Windows `.exe` installers; for the [Anaconda packages](https://integrativemodeling.org/download-anaconda.html), -both 32-bit and 64-bit, -we use VS 2008 SP1 for Python 2.7 and VS 2015 for Python 3.5). +which are built by [conda-forge](https://conda-forge.org/), VS 2019 is used). One complication is that different packages are compiled with different versions of Visual Studio, and mixing the different runtimes (`msvc*.dll`) can cause odd behavior; therefore, we recommend building most @@ -18,11 +16,10 @@ We recommend building within the Anaconda environment, since many of the dependencies are already built, and the procedure is scripted so it is more easily reproducible: - - Install the right version of Microsoft Visual Studio Express (it is free, + - Install the right version of Microsoft Visual Studio (it is free, but registration with Microsoft is required). Current Anaconda policy is to build packages using the same version of Visual Studio that was used - to build Python. This means VS 2008 for Python 2.7 and VS 2015 for - Python 3.5, for example. + to build Python. - Get and install [Miniconda](https://conda.io/miniconda.html) or the full Anaconda environment. - Install necessary conda packages for development: @@ -31,7 +28,7 @@ easily reproducible: `cd` to the directory above the `foo` directory containing the [conda build recipe](https://docs.conda.io/projects/conda-build/en/latest/concepts/recipe.html) then build it with - `conda build --python=2.7 foo` + `conda build --python=3.9 foo` - Feel free to refer to [our conda recipes](https://github.com/salilab/conda-recipes) for IMP and all needed dependencies. In particular, each recipe contains @@ -41,14 +38,14 @@ easily reproducible: If you want to build outside of the Anaconda environment, the basic procedure we employed is as follows: - - Install Microsoft Visual Studio Express (it is free, but registration with + - Install Microsoft Visual Studio (it is free, but registration with Microsoft is required). - Get and install [cmake](https://cmake.org). - Get [Python](https://www.python.org) (make sure you get the 32-bit version if you're going to build %IMP for 32-bit Windows). - Get and install the - [zlib package](http://gnuwin32.sourceforge.net/packages/zlib.htm) + [zlib package](https://gnuwin32.sourceforge.net/packages/zlib.htm) (both the "complete package, except sources" and the "sources" installers). - The package without sources can be installed anywhere; we chose the default location of `C:\Program Files\GnuWin32`. The sources, however, @@ -57,7 +54,7 @@ we employed is as follows: - We found that the zconf.h header included with zlib erroneously includes unistd.h, which doesn't exist on Windows, so we commented out that line (in both packages). - - Download the [Boost source code](http://www.boost.org) + - Download the [Boost source code](https://www.boost.org) (we extracted it into `C:\Program Files\boost_1_53_0`), then - Open a Visual Studio Command Prompt, and cd into the directory where Boost was extracted @@ -65,21 +62,21 @@ we employed is as follows: - You may need to help the compiler find the zlib header file with `set INCLUDE=C:\Program Files\GnuWin32\include` - Run `bjam link=shared runtime-link=shared -sNO_ZLIB=0 -sZLIB_SOURCE=C:\zlib\1.2.3\zlib-1.2.3` - - Get and install [SWIG for Windows](http://www.swig.org) + - Get and install [SWIG for Windows](https://www.swig.org) - Get the [HDF5 source code](https://www.hdfgroup.org/downloads/hdf5/) - Make a 'build' subdirectory, then run from a command prompt in that subdirectory something similar to `cmake.exe -G "Visual Studio 10" -DHDF5_ENABLE_SZIP_SUPPORT:BOOL=OFF -DHDF5_ENABLE_Z_LIB_SUPPORT:BOOL=ON -DHDF5_BUILD_HL_LIB:BOOL=ON -DZLIB_INCLUDE_DIR="C:\Program Files\GnuWin32\include" -DZLIB_LIBRARY="C:\Program Files\GnuWin32\lib\zlib.lib" -DBUILD_SHARED_LIBS:BOOL=ON ..` - Open the resulting HDF5 solution file in Visual Studio, change to Release configuration, then build the hdf5 project. - - (Optional) [Build CGAL from source code](http://www.cgal.org/windows_installation.html). + - (Optional) [Build CGAL from source code](https://www.cgal.org/download/windows.html). - (Optional) Download the [FFTW DLLs](http://www.fftw.org/install/windows.html) and follow the instructions at that website to make .lib import libraries needed for Visual Studio. - Copy `libfftw3-3.lib` to `fftw3.lib` and `libfftw3-3.dll` to `fftw3.dll` to help cmake find it - (Optional) Get the - [GSL source code](http://gnuwin32.sourceforge.net/packages/gsl.htm) + [GSL source code](https://gnuwin32.sourceforge.net/packages/gsl.htm) and build it: - Open the libgsl project file in the `src\gsl\1.8\gsl-1.8\VC8` subdirectory @@ -90,12 +87,12 @@ we employed is as follows: (we recommend removing the _dll suffix and the lib prefix when you do this so that cmake has an easier time finding them, i.e. call them gsl.lib and gslcblas.lib). - - (Optional) Get [numpy and scipy](http://www.scipy.org) to match your + - (Optional) Get [numpy and scipy](https://scipy.org) to match your Python version. - (Optional) Get and install [libTAU](https://integrativemodeling.org/libTAU.html) - Copy `libTAU.lib` to `TAU.lib` to help cmake find it. - - (Optional) Get the [OpenCV source code](http://opencv.org/) + - (Optional) Get the [OpenCV source code](https://opencv.org/) and build it by [following these instructions](https://docs.opencv.org/3.4.15/d3/d52/tutorial_windows_install.html#tutorial_windows_install_build) - Copy each `opencv_*.lib` to a similar file without the version extension (e.g. copy `opencv_ml244.lib` to `opencv_ml.lib`) to help cmake find it diff --git a/doc/manual/installation.md b/doc/manual/installation.md index 8fdd1d1716..6ba571cccc 100644 --- a/doc/manual/installation.md +++ b/doc/manual/installation.md @@ -16,6 +16,19 @@ Binaries are [also available for our latest nightly builds](https://integrativem please check out the [nightly builds results page](https://integrativemodeling.org/nightly/results/) to see if the code is currently stable enough for your purposes. +# Google Colab {#installation_colab} + +To experiment with IMP on [Google Colaboratory](https://colab.research.google.com), use the following code snippet: + +\code{.unparsed} +!echo "deb https://integrativemodeling.org/latest/download $(lsb_release -cs)/" > /etc/apt/sources.list.d/salilab.list +!wget -O /etc/apt/trusted.gpg.d/salilab.asc https://salilab.org/~ben/pubkey256.asc +!apt update +!apt install imp +import sys +sys.path.append('/usr/lib/python3.8/dist-packages') +\endcode + # Source code installation {#installation_source} ## Prerequisites {#installation_prereqs} @@ -23,15 +36,15 @@ to see if the code is currently stable enough for your purposes. In order to build %IMP from source, you will need: - A C++ compiler that supports the C++11 standard, such as gcc, clang, - or Microsoft Visual Studio 2012 or later. + or Microsoft Visual Studio 2015 or later. - [CMake](https://cmake.org) (2.8.12 or later; 3.14 or later is recommended) - [Boost](https://www.boost.org) (1.53 or later; Boost.Iostreams must be built with its [zlib filter enabled](https://www.boost.org/doc/libs/1_67_0/libs/iostreams/doc/installation.html)) - [Eigen](https://eigen.tuxfamily.org/) (3.0 or later) -- [HDF5](https://support.hdfgroup.org/HDF5/) (1.8 or later; 1.10 or 1.12 - should also work) -- [Python](https://www.python.org) (2.7 or later, or any version of Python 3) -- [SWIG](http://www.swig.org) (3 or later) +- [HDF5](https://support.hdfgroup.org/HDF5/) (1.8 or later) +- [cereal](https://uscilab.github.io/cereal/) +- [Python](https://www.python.org) (3.6 or later, or 2.7) +- [SWIG](https://www.swig.org/) (3 or later) The following prerequisites are _optional_; without them some parts of %IMP will not build, and some will not function optimally. @@ -39,8 +52,8 @@ will not build, and some will not function optimally. - The [NumPy](https://numpy.org/) library is strongly recommended; if %IMP is built with NumPy, many operations that transfer data between C++ and Python become more efficient. -- [Doxygen](http://www.doxygen.org/) (only exactly version 1.8.6 is supported) - and [Graphviz](http://www.graphviz.org/): required for building +- [Doxygen](https://www.doxygen.nl/) (only exactly version 1.8.6 is supported) + and [Graphviz](https://www.graphviz.org/): required for building documentation. - [Modeller](\ref modeller): needed to use the IMP.modeller module. - [CGAL](\ref CGAL): enables faster geometric operations, such as @@ -59,9 +72,9 @@ will not build, and some will not function optimally. - [Protobuf](https://github.com/google/protobuf): needed to use the IMP.npctransport module. - An [MPI](@ref IMP::mpi) library is needed to use the IMP.mpi module. -- The [scipy](https://scipy.org/download/), - [scikit-learn](http://scikit-learn.org/stable/install.html), - and [matplotlib](http://matplotlib.org/downloads.html) +- The [scipy](https://scipy.org/install/), + [scikit-learn](https://scikit-learn.org/stable/install.html), + and [matplotlib](https://matplotlib.org/stable/users/installing/index.html) Python libraries are also recommended. - [Chimera](https://www.cgl.ucsf.edu/chimera/download.html) or [ChimeraX](https://www.rbvi.ucsf.edu/chimerax/) are recommended @@ -115,6 +128,14 @@ such as sudo port install boost cgal cmake fftw gmp gperftools graphviz gsl eigen hdf5 mpfr ninja opencv protobuf-cpp swig swig-python (as in brew, some of these packages may be optional) +- [Conda](https://docs.conda.io/en/latest/) Once you installed conda (typically via the Miniconda or Anaconda distributions), do + + conda create -n IMP_BUILD -c conda-forge python cxx-compiler c-compiler llvm-openmp swig cmake ninja numpy rmf ihm boost-cpp hdf5 libprotobuf protobuf libopencv eigen fftw gsl libcblas cgal-cpp gmp mpfr mpich numpy + conda activate IMP_BUILD + + As in brew and Macports, some of these packages may be optional. In addition, cgal may not be identified by cmake. IMP will still run just fine. Either way, a solution could be setting the CGAL_DIR environment variable to $CONDA_PREFIX/lib/cmake/CGAL/ before running cmake, or adding a -DCGAL_DIR=$CONDA_PREFIX/lib/cmake/CGAL flag to the cmake command line ($CONDA_PREFIX is an environment variable that points to the folder of the active conda environment). + + - or [Fink](http://www.finkproject.org/) (not supported) ### Getting prerequisites on Windows {#installation_prereqs_windows} diff --git a/doc/manual/licenses.md b/doc/manual/licenses.md index 07bc0d8eec..ab42a85cd4 100644 --- a/doc/manual/licenses.md +++ b/doc/manual/licenses.md @@ -1,7 +1,7 @@ Copyright and licenses {#licenses} ====================== -%IMP is Copyright 2007-2022 %IMP Inventors. The %IMP Inventors are +%IMP is Copyright 2007-2023 %IMP Inventors. The %IMP Inventors are Andrej Sali, Ben Webb, Daniel Russel, Keren Lasker, Dina Schneidman, Javier Velázquez-Muriel, Friedrich Förster, Elina Tjioe, Hao Fan, Seung Joong Kim, Yannick Spill, Riccardo Pellarin. diff --git a/doc/manual/mainpage.dox b/doc/manual/mainpage.dox index ed3db2ebf1..b5929db38a 100644 --- a/doc/manual/mainpage.dox +++ b/doc/manual/mainpage.dox @@ -77,6 +77,7 @@ complex might want to skip ahead to - [Debugging and testing your code](@ref testing) - [Writing examples](@ref write_examples) - [Exporting C++ code to Python](@ref swig) + - [Serialization](@ref serialization) - [Code coverage](@ref coverage) - [Profiling your code](@ref profiling) - [Deprecation](@ref deprecation) diff --git a/doc/manual/serialization.md b/doc/manual/serialization.md new file mode 100644 index 0000000000..a8bbb885e0 --- /dev/null +++ b/doc/manual/serialization.md @@ -0,0 +1,47 @@ +Serialization {#serialization} +============= + +Most %IMP types can be serialized - that is, the internal state of an object, +such as the values of its member variables, can be written to or read in from +a file, string or stream. This allows for individual objects or an entire %IMP +run to be saved and later restored, or to be sent from one machine to another. +In Python, the objects can be loaded or saved using the `pickle` module. + +Serialization uses a compact binary format. However, it is not heavily +optimized for size. If a smaller file size is desired, the Python `pickle` +file can be compressed with a general-purpose compression tool such as `gzip`. + +Note that IMP::Model is handled specially due to its large size. Objects that +refer to the model (such as restraints or particles) will only include the ID +of the model in the serialization stream, not the model itself. +On deserialization these objects will be reassociated with the model by matching +the ID. This requires that the model be deserialized before any of these other +objects. To ensure this, `pickle` a tuple, list, or other ordered Python +container containing the model before any other object. + +Serialization relies on the excellent +[cereal](https://uscilab.github.io/cereal/) library, which is required to +build %IMP. + +To add serialization to a new class, simply add a suitable serialization +function, as per the +[cereal docs](https://uscilab.github.io/cereal/serialization_functions.html). +Most %IMP classes define a `serialize` private method. The class will also +need a default constructor (i.e. one that takes no arguments) if it does not +already have one. If the class is visible to Python, make sure pickle support +is enabled by using the `IMP_SWIG_OBJECT_SERIALIZE` or +`IMP_SWIG_VALUE_SERIALIZE` macros in the SWIG interface. + +If a class is polymorphic - i.e. it is a subclass that is referenced somewhere +by a base class pointer, such as a `Restraint` subclass - then the +serialization subsystem will need to store the name of the subclass in the +serialized output and will need to know how to access derived class +information. This is done by adding the `IMP_OBJECT_SERIALIZE_DECL` and +`IMP_OBJECT_SERIALIZE_IMPL` macros to the `.h` file and `.cpp` file +respectively. (These macros are used instead of cereal's `CEREAL_REGISTER_TYPE` +macro.) + +The serialization format is subject to change. It should not be considered +portable between different machines (e.g. 32-bit and 64-bit, or Linux and +Windows) or between different %IMP versions, although this could be addressed +in future if necessary. diff --git a/modules/algebra/benchmark/benchmark_rotate.cpp b/modules/algebra/benchmark/benchmark_rotate.cpp index 722f3e37cc..6f6b877141 100644 --- a/modules/algebra/benchmark/benchmark_rotate.cpp +++ b/modules/algebra/benchmark/benchmark_rotate.cpp @@ -2,7 +2,6 @@ * Copyright 2007-2022 IMP Inventors. All rights reserved. */ #include -#include #include #include #include diff --git a/modules/algebra/include/BoundingBoxD.h b/modules/algebra/include/BoundingBoxD.h index 6421c23c68..ed3e1e0f75 100644 --- a/modules/algebra/include/BoundingBoxD.h +++ b/modules/algebra/include/BoundingBoxD.h @@ -13,7 +13,7 @@ #include "internal/utility.h" #include "algebra_macros.h" #include -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -159,10 +159,10 @@ class BoundingBoxD { private: VectorD b_[2]; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & b_[0] & b_[1]; + template void serialize(Archive &ar) { + ar(b_[0], b_[1]); } }; //! See BoundingBoxD diff --git a/modules/algebra/include/Cone3D.h b/modules/algebra/include/Cone3D.h index 6060e5a767..ba3cb7feb1 100644 --- a/modules/algebra/include/Cone3D.h +++ b/modules/algebra/include/Cone3D.h @@ -16,7 +16,7 @@ #include "GeometricPrimitiveD.h" #include #include -#include +#include #include #include "constants.h" @@ -58,10 +58,10 @@ class IMPALGEBRAEXPORT Cone3D : public GeometricPrimitiveD<3> { Segment3D seg_; double radius_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & seg_ & radius_; + template void serialize(Archive &ar) { + ar(seg_, radius_); } }; diff --git a/modules/algebra/include/Cylinder3D.h b/modules/algebra/include/Cylinder3D.h index a4084c9a6e..1119cb474f 100644 --- a/modules/algebra/include/Cylinder3D.h +++ b/modules/algebra/include/Cylinder3D.h @@ -14,7 +14,7 @@ #include "Segment3D.h" #include "GeometricPrimitiveD.h" #include -#include +#include #include #include "constants.h" @@ -68,10 +68,10 @@ class IMPALGEBRAEXPORT Cylinder3D : public GeometricPrimitiveD<3> { Segment3D s_; double radius_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & s_ & radius_; + template void serialize(Archive &ar) { + ar(s_, radius_); } }; diff --git a/modules/algebra/include/Ellipsoid3D.h b/modules/algebra/include/Ellipsoid3D.h index d0775cbdc9..c14734b11e 100644 --- a/modules/algebra/include/Ellipsoid3D.h +++ b/modules/algebra/include/Ellipsoid3D.h @@ -14,7 +14,7 @@ #include "Transformation3D.h" #include "ReferenceFrame3D.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -35,10 +35,10 @@ class IMPALGEBRAEXPORT Ellipsoid3D : public GeometricPrimitiveD<3> { ReferenceFrame3D rf_; Vector3D radii_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & rf_ & radii_; + template void serialize(Archive &ar) { + ar(rf_, radii_); } }; diff --git a/modules/algebra/include/Gaussian3D.h b/modules/algebra/include/Gaussian3D.h index 7a39de2dae..a24ed32975 100644 --- a/modules/algebra/include/Gaussian3D.h +++ b/modules/algebra/include/Gaussian3D.h @@ -14,7 +14,7 @@ #include "ReferenceFrame3D.h" #include #include -#include +#include #include IMPALGEBRA_BEGIN_NAMESPACE @@ -26,10 +26,10 @@ class Gaussian3D : public GeometricPrimitiveD<3> { ReferenceFrame3D tr_; Vector3D variances_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & tr_ & variances_; + template void serialize(Archive &ar) { + ar(tr_, variances_); } public: diff --git a/modules/algebra/include/Line3D.h b/modules/algebra/include/Line3D.h index ab2712d036..17905b1510 100644 --- a/modules/algebra/include/Line3D.h +++ b/modules/algebra/include/Line3D.h @@ -14,7 +14,7 @@ #include "BoundingBoxD.h" #include "algebra_macros.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE //! Simple implementation of lines in 3D @@ -29,10 +29,10 @@ IMPALGEBRA_BEGIN_NAMESPACE class IMPALGEBRAEXPORT Line3D : public GeometricPrimitiveD<3> { Vector3D l_, m_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & l_ & m_; + template void serialize(Archive &ar) { + ar(l_, m_); } public: diff --git a/modules/algebra/include/LinearFit.h b/modules/algebra/include/LinearFit.h index 829267c2b2..9858ce527e 100644 --- a/modules/algebra/include/LinearFit.h +++ b/modules/algebra/include/LinearFit.h @@ -11,7 +11,7 @@ #include "Vector2D.h" #include "GeometricPrimitiveD.h" -#include +#include #include IMPALGEBRA_BEGIN_NAMESPACE @@ -51,10 +51,10 @@ class IMPALGEBRAEXPORT LinearFit2D : public GeometricPrimitiveD<2> { double a_, b_; double error_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & a_ & b_ & error_; + template void serialize(Archive &ar) { + ar(a_, b_, error_); } }; diff --git a/modules/algebra/include/ParabolicFit.h b/modules/algebra/include/ParabolicFit.h index fbe5c67fab..be567e1373 100644 --- a/modules/algebra/include/ParabolicFit.h +++ b/modules/algebra/include/ParabolicFit.h @@ -11,7 +11,7 @@ #include "Vector2D.h" #include "GeometricPrimitiveD.h" -#include +#include #include IMPALGEBRA_BEGIN_NAMESPACE @@ -53,10 +53,10 @@ class IMPALGEBRAEXPORT ParabolicFit2D : public GeometricPrimitiveD<2> { double a_, b_, c_; double error_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & a_ & b_ & c_ & error_; + template void serialize(Archive &ar) { + ar(a_, b_, c_, error_); } }; diff --git a/modules/algebra/include/Plane3D.h b/modules/algebra/include/Plane3D.h index 342bce2b9c..056a4d427f 100644 --- a/modules/algebra/include/Plane3D.h +++ b/modules/algebra/include/Plane3D.h @@ -12,7 +12,7 @@ #include "Vector3D.h" #include "BoundingBoxD.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -58,10 +58,10 @@ class Plane3D : public GeometricPrimitiveD<3> { double distance_; Vector3D normal_; // normal to plane - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & distance_ & normal_; + template void serialize(Archive &ar) { + ar(distance_, normal_); } }; diff --git a/modules/algebra/include/ReferenceFrame3D.h b/modules/algebra/include/ReferenceFrame3D.h index 817b245630..eef83adb37 100644 --- a/modules/algebra/include/ReferenceFrame3D.h +++ b/modules/algebra/include/ReferenceFrame3D.h @@ -10,8 +10,7 @@ #define IMPALGEBRA_REFERENCE_FRAME_3D_H #include -#include -#include +#include #include "Transformation3D.h" IMPALGEBRA_BEGIN_NAMESPACE @@ -25,21 +24,17 @@ class IMPALGEBRAEXPORT ReferenceFrame3D { mutable bool has_inverse_; mutable Transformation3D tri_; -#ifndef SWIG - friend class boost::serialization::access; + friend class cereal::access; - template void save(Archive &ar, const unsigned int) const { - ar << tr_; + template void save(Archive &ar) const { + ar(tr_); } - template void load(Archive &ar, const unsigned int) { - ar >> tr_; + template void load(Archive &ar) { + ar(tr_); has_inverse_ = false; } - BOOST_SERIALIZATION_SPLIT_MEMBER() -#endif - const Transformation3D &get_inverse() const { if (!has_inverse_) { tri_ = tr_.get_inverse(); diff --git a/modules/algebra/include/Reflection3D.h b/modules/algebra/include/Reflection3D.h index 821c799d93..c4531fe7a8 100644 --- a/modules/algebra/include/Reflection3D.h +++ b/modules/algebra/include/Reflection3D.h @@ -11,7 +11,7 @@ #include #include "Plane3D.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -19,10 +19,10 @@ IMPALGEBRA_BEGIN_NAMESPACE class Reflection3D : public GeometricPrimitiveD<3> { Plane3D pl_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & pl_; + template void serialize(Archive &ar) { + ar(pl_); } public: diff --git a/modules/algebra/include/Rotation2D.h b/modules/algebra/include/Rotation2D.h index 28b162e26b..07794d1f79 100644 --- a/modules/algebra/include/Rotation2D.h +++ b/modules/algebra/include/Rotation2D.h @@ -15,8 +15,7 @@ #include "constants.h" #include #include -#include -#include +#include #include //#include @@ -87,21 +86,17 @@ class Rotation2D : public GeometricPrimitiveD<2> { double c_; // cosine of the angle double s_; // sine of the angle -#ifndef SWIG - friend class boost::serialization::access; + friend class cereal::access; - template void save(Archive &ar, const unsigned int) const { - ar << angle_; + template void save(Archive &ar) const { + ar(angle_); } - template void load(Archive &ar, const unsigned int) { + template void load(Archive &ar) { double a; - ar >> a; + ar(a); set_angle(a); } - - BOOST_SERIALIZATION_SPLIT_MEMBER() -#endif }; //! Build an identity rotation in 2D diff --git a/modules/algebra/include/Rotation3D.h b/modules/algebra/include/Rotation3D.h index 55715b5884..eb62ff8a97 100644 --- a/modules/algebra/include/Rotation3D.h +++ b/modules/algebra/include/Rotation3D.h @@ -13,8 +13,7 @@ #include "utility.h" #include "constants.h" #include "GeometricPrimitiveD.h" -#include -#include +#include #include #include @@ -55,21 +54,19 @@ class IMPALGEBRAEXPORT Rotation3D : public GeometricPrimitiveD<3> { mutable bool has_cache_; mutable Vector3D matrix_[3]; - friend class boost::serialization::access; + friend class cereal::access; template - void save(Archive &ar, const unsigned int) const { - ar << v_; + void save(Archive &ar) const { + ar(v_); } template - void load(Archive &ar, const unsigned int) { - ar >> v_; + void load(Archive &ar) { + ar(v_); has_cache_ = false; } - BOOST_SERIALIZATION_SPLIT_MEMBER() - IMP_NO_SWIG(friend Rotation3D compose(const Rotation3D &a, const Rotation3D &b)); void fill_cache() const { @@ -595,10 +592,10 @@ IMPALGEBRAEXPORT Rotation3D class FixedXYZ : public GeometricPrimitiveD<3> { double v_[3]; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & v_[0] & v_[1] & v_[2]; + template void serialize(Archive &ar) { + ar(v_[0], v_[1], v_[2]); } public: diff --git a/modules/algebra/include/Segment3D.h b/modules/algebra/include/Segment3D.h index 01a1fbe796..1b2b2131d1 100644 --- a/modules/algebra/include/Segment3D.h +++ b/modules/algebra/include/Segment3D.h @@ -14,7 +14,7 @@ #include "algebra_macros.h" #include "GeometricPrimitiveD.h" #include -#include +#include #include "constants.h" IMPALGEBRA_BEGIN_NAMESPACE @@ -41,10 +41,10 @@ class IMPALGEBRAEXPORT Segment3D : public GeometricPrimitiveD<3> { private: Vector3D p_[2]; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & p_[0] & p_[1]; + template void serialize(Archive &ar) { + ar(p_[0], p_[1]); } }; diff --git a/modules/algebra/include/SphereD.h b/modules/algebra/include/SphereD.h index 352891987a..52ed96cdb0 100644 --- a/modules/algebra/include/SphereD.h +++ b/modules/algebra/include/SphereD.h @@ -14,7 +14,7 @@ #include "VectorD.h" #include "utility.h" #include "GeometricPrimitiveD.h" -#include +#include #include IMPALGEBRA_BEGIN_NAMESPACE @@ -24,11 +24,11 @@ IMPALGEBRA_BEGIN_NAMESPACE */ template class SphereD : public GeometricPrimitiveD { - friend class boost::serialization::access; + friend class cereal::access; template - void serialize(Archive &ar, const unsigned int) { - ar & center_ & radius_; + void serialize(Archive &ar) { + ar(center_, radius_); } public: diff --git a/modules/algebra/include/SpherePatch3D.h b/modules/algebra/include/SpherePatch3D.h index f912d52fa2..b238f7fe1e 100644 --- a/modules/algebra/include/SpherePatch3D.h +++ b/modules/algebra/include/SpherePatch3D.h @@ -11,7 +11,7 @@ #include "Sphere3D.h" #include "Plane3D.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -43,10 +43,10 @@ class IMPALGEBRAEXPORT SpherePatch3D : public GeometricPrimitiveD<3> { Sphere3D sph_; Plane3D crossing_plane_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & sph_ & crossing_plane_; + template void serialize(Archive &ar) { + ar(sph_, crossing_plane_); } }; diff --git a/modules/algebra/include/SphericalVector3D.h b/modules/algebra/include/SphericalVector3D.h index d249a6a125..cf6757e38c 100644 --- a/modules/algebra/include/SphericalVector3D.h +++ b/modules/algebra/include/SphericalVector3D.h @@ -14,7 +14,7 @@ #include "constants.h" #include #include "GeometricPrimitiveD.h" -#include +#include #include IMPALGEBRA_BEGIN_NAMESPACE @@ -75,10 +75,10 @@ class IMPALGEBRAEXPORT SphericalVector3D : public GeometricPrimitiveD<3> { void set_cartesian_coordinates(const Vector3D& v); double v_[3]; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & v_[0] & v_[1] & v_[2]; + template void serialize(Archive &ar) { + ar(v_[0], v_[1], v_[2]); } }; diff --git a/modules/algebra/include/Transformation2D.h b/modules/algebra/include/Transformation2D.h index ecbcba7c2a..d55cfb1dcd 100644 --- a/modules/algebra/include/Transformation2D.h +++ b/modules/algebra/include/Transformation2D.h @@ -13,7 +13,7 @@ #include "Vector2D.h" #include "Rotation2D.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -115,10 +115,10 @@ class IMPALGEBRAEXPORT Transformation2D : public GeometricPrimitiveD<2> { Vector2D trans_; // translation Rotation2D rot_; // rotation - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & trans_ & rot_; + template void serialize(Archive &ar) { + ar(trans_, rot_); } }; diff --git a/modules/algebra/include/Transformation3D.h b/modules/algebra/include/Transformation3D.h index 3ce96bb89b..30d2f795e9 100644 --- a/modules/algebra/include/Transformation3D.h +++ b/modules/algebra/include/Transformation3D.h @@ -15,7 +15,7 @@ #include "Rotation3D.h" #include "BoundingBoxD.h" #include "GeometricPrimitiveD.h" -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -119,10 +119,10 @@ class IMPALGEBRAEXPORT Transformation3D : public GeometricPrimitiveD<3> { Vector3D trans_; // translation Rotation3D rot_; // rotation - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & trans_ & rot_; + template void serialize(Archive &ar) { + ar(trans_, rot_); } }; diff --git a/modules/algebra/include/Triangle3D.h b/modules/algebra/include/Triangle3D.h index 9f7a15ff5f..b9cce95d23 100644 --- a/modules/algebra/include/Triangle3D.h +++ b/modules/algebra/include/Triangle3D.h @@ -14,7 +14,7 @@ #include "algebra_macros.h" #include "GeometricPrimitiveD.h" #include -#include +#include #include "constants.h" IMPALGEBRA_BEGIN_NAMESPACE @@ -38,10 +38,10 @@ class IMPALGEBRAEXPORT Triangle3D : public GeometricPrimitiveD<3> { private: Vector3D p_[3]; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & p_[0] & p_[1] & p_[2]; + template void serialize(Archive &ar) { + ar(p_[0], p_[1], p_[2]); } }; diff --git a/modules/algebra/include/UnitSimplexD.h b/modules/algebra/include/UnitSimplexD.h index 973305e149..22d3e36a64 100644 --- a/modules/algebra/include/UnitSimplexD.h +++ b/modules/algebra/include/UnitSimplexD.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -68,9 +68,9 @@ class UnitSimplexBaseD : public GeometricPrimitiveD { */ template class UnitSimplexD : public UnitSimplexBaseD { - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) {} + template void serialize(Archive &ar) {} public: UnitSimplexD() { IMP_USAGE_CHECK(D > 0, "Dimension must be positive."); } @@ -87,10 +87,10 @@ class UnitSimplexD : public UnitSimplexBaseD { */ template <> class UnitSimplexD<-1> : public UnitSimplexBaseD<-1> { - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & d_; + template void serialize(Archive &ar) { + ar(d_); } public: diff --git a/modules/algebra/include/VectorBaseD.h b/modules/algebra/include/VectorBaseD.h index 885ba415b4..b18608cbe5 100644 --- a/modules/algebra/include/VectorBaseD.h +++ b/modules/algebra/include/VectorBaseD.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "internal/vector.h" #include @@ -26,14 +26,18 @@ #include #include -#if IMP_HAS_CHECKS >= IMP_USAGE +#if IMP_HAS_CHECKS >= IMP_INTERNAL #define IMP_ALGEBRA_VECTOR_CHECK check_vector() +#else +#define IMP_ALGEBRA_VECTOR_CHECK +#endif + +#if IMP_HAS_CHECKS >= IMP_USAGE #define IMP_ALGEBRA_VECTOR_CHECK_INDEX(i) check_index(i) #define IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o) \ check_compatible_vector(o); \ o.check_vector() #else -#define IMP_ALGEBRA_VECTOR_CHECK #define IMP_ALGEBRA_VECTOR_CHECK_INDEX(i) #define IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o) #endif @@ -49,11 +53,11 @@ IMPALGEBRA_BEGIN_NAMESPACE */ template class VectorBaseD : public GeometricPrimitiveD { - friend class boost::serialization::access; + friend class cereal::access; template - void serialize(Archive &ar, const unsigned int) { - ar & data_; + void serialize(Archive &ar) { + ar(data_); } void check_vector() const { diff --git a/modules/algebra/include/VectorD.h b/modules/algebra/include/VectorD.h index 7c0c1cada7..4952f2c28d 100644 --- a/modules/algebra/include/VectorD.h +++ b/modules/algebra/include/VectorD.h @@ -27,14 +27,18 @@ #include #include -#if IMP_HAS_CHECKS >= IMP_USAGE +#if IMP_HAS_CHECKS >= IMP_INTERNAL #define IMP_ALGEBRA_VECTOR_CHECK check_vector() +#else +#define IMP_ALGEBRA_VECTOR_CHECK +#endif + +#if IMP_HAS_CHECKS >= IMP_USAGE #define IMP_ALGEBRA_VECTOR_CHECK_INDEX(i) check_index(i) #define IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o) \ check_compatible_vector(o); \ o.check_vector() #else -#define IMP_ALGEBRA_VECTOR_CHECK #define IMP_ALGEBRA_VECTOR_CHECK_INDEX(i) #define IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o) #endif diff --git a/modules/algebra/include/connolly_surface.h b/modules/algebra/include/connolly_surface.h index 68833df06d..79dd92d791 100644 --- a/modules/algebra/include/connolly_surface.h +++ b/modules/algebra/include/connolly_surface.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -26,10 +26,10 @@ class ConnollySurfacePoint { double area; algebra::Vector3D normal; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & atom[0] & atom[1] & atom[2] & surface_point & area & normal; + template void serialize(Archive &ar) { + ar(atom[0], atom[1], atom[2], surface_point, area, normal); } public: diff --git a/modules/algebra/include/eigen_analysis.h b/modules/algebra/include/eigen_analysis.h index 85b04609ea..50ad9b5b66 100644 --- a/modules/algebra/include/eigen_analysis.h +++ b/modules/algebra/include/eigen_analysis.h @@ -15,7 +15,7 @@ #include "IMP/algebra/ReferenceFrame3D.h" #include #include -#include +#include IMPALGEBRA_BEGIN_NAMESPACE @@ -66,10 +66,10 @@ class PrincipalComponentAnalysisD : public GeometricPrimitiveD { VectorD eigen_values_; VectorD centroid_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & eigen_vecs_ & eigen_values_ & centroid_; + template void serialize(Archive &ar) { + ar(eigen_vecs_, eigen_values_, centroid_); } }; diff --git a/modules/algebra/include/grid_embeddings.h b/modules/algebra/include/grid_embeddings.h index 7c5f8e6c80..e935abb258 100644 --- a/modules/algebra/include/grid_embeddings.h +++ b/modules/algebra/include/grid_embeddings.h @@ -16,8 +16,7 @@ #include "Vector3D.h" #include "BoundingBoxD.h" #include -#include -#include +#include #include #include #include @@ -34,22 +33,17 @@ class DefaultEmbeddingD { // inverse VectorD inverse_unit_cell_; -#ifndef SWIG - friend class boost::serialization::access; + friend class cereal::access; - template void save(Archive &ar, const unsigned int) const { - ar << origin_ << unit_cell_; + template void save(Archive &ar) const { + ar(origin_, unit_cell_); } - template void load(Archive &ar, const unsigned int) { - ar >> origin_; - ar >> unit_cell_; + template void load(Archive &ar) { + ar(origin_, unit_cell_); set_unit_cell(unit_cell_); // sets inverse } - BOOST_SERIALIZATION_SPLIT_MEMBER() -#endif - template VectorD get_elementwise_product(VectorD v0, const O &v1) const { for (unsigned int i = 0; i < get_dimension(); ++i) { @@ -194,10 +188,10 @@ class LogEmbeddingD { VectorD unit_cell_; VectorD base_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & origin_ & unit_cell_ & base_; + template void serialize(Archive &ar) { + ar(origin_, unit_cell_, base_); } template diff --git a/modules/algebra/include/grid_indexes.h b/modules/algebra/include/grid_indexes.h index 1b22be7f6b..d2661933a8 100644 --- a/modules/algebra/include/grid_indexes.h +++ b/modules/algebra/include/grid_indexes.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include // for swig wrappers #include @@ -31,10 +31,10 @@ template class ExtendedGridIndexD : public Value { internal::VectorData data_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & data_; + template void serialize(Archive &ar) { + ar(data_); } int compare(const ExtendedGridIndexD& o) const { @@ -170,10 +170,10 @@ template class GridIndexD : public Value { internal::VectorData data_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & data_; + template void serialize(Archive &ar) { + ar(data_); } int compare(const GridIndexD& o) const { diff --git a/modules/algebra/include/grid_ranges.h b/modules/algebra/include/grid_ranges.h index ed5f0d8279..0fadbeada2 100644 --- a/modules/algebra/include/grid_ranges.h +++ b/modules/algebra/include/grid_ranges.h @@ -16,7 +16,7 @@ #include "Vector3D.h" #include "BoundingBoxD.h" #include -#include +#include #include #include @@ -27,9 +27,9 @@ IMPALGEBRA_BEGIN_NAMESPACE */ template class UnboundedGridRangeD { - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) {} + template void serialize(Archive &ar) {} public: typedef GridIndexD Index; @@ -103,10 +103,10 @@ template class BoundedGridRangeD { ExtendedGridIndexD d_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & d_; + template void serialize(Archive &ar) { + ar(d_); } void set_number_of_voxels(Ints bds) { diff --git a/modules/algebra/include/internal/vector.h b/modules/algebra/include/internal/vector.h index 9e5a49a230..481f864056 100644 --- a/modules/algebra/include/internal/vector.h +++ b/modules/algebra/include/internal/vector.h @@ -9,8 +9,7 @@ #include #include #include -#include -#include +#include #include IMPALGEBRA_BEGIN_INTERNAL_NAMESPACE @@ -46,12 +45,12 @@ template class VectorData { T storage_[D]; - friend class boost::serialization::access; + friend class cereal::access; template - void serialize(Archive &ar, const unsigned int) { + void serialize(Archive &ar) { for (auto &i: storage_) { - ar & i; + ar(i); } } @@ -103,28 +102,26 @@ class VectorData { boost::scoped_array storage_; unsigned int d_; - friend class boost::serialization::access; + friend class cereal::access; template - void save(Archive &ar, const unsigned int) const { - ar << d_; + void save(Archive &ar) const { + ar(d_); for (unsigned i = 0; i < d_; ++i) { - ar << storage_[i]; + ar(storage_[i]); } } template - void load(Archive &ar, const unsigned int) { - ar >> d_; + void load(Archive &ar) { + ar(d_); storage_.reset(new T[d_]); T *data = get_data(); for (unsigned i = 0; i < d_; ++i) { - ar >> *(data + i); + ar(*(data + i)); } } - BOOST_SERIALIZATION_SPLIT_MEMBER() - public: VectorData(int d) : storage_(new T[d]), d_(d) {} VectorData(const VectorData &o) { diff --git a/modules/algebra/pyext/include/IMP_algebra.types.i b/modules/algebra/pyext/include/IMP_algebra.types.i index 31d9c39729..d8fe27c840 100644 --- a/modules/algebra/pyext/include/IMP_algebra.types.i +++ b/modules/algebra/pyext/include/IMP_algebra.types.i @@ -381,7 +381,7 @@ struct ConvertEigenMatrix { NULL, NULL, NPY_ARRAY_F_CONTIGUOUS, NULL)); if (t.rows()*t.cols() > 0) { PyObject *obj = ret; - memcpy(PyArray_DATA(obj), t.data(), + memcpy(PyArray_DATA((PyArrayObject *)obj), t.data(), t.rows() * t.cols() * sizeof(typename M::Scalar)); } return ret.release(); @@ -452,7 +452,7 @@ struct ConvertEigenVector { ? NPY_DOUBLE : NPY_FLOAT)); if (t.rows() > 0) { PyObject *obj = ret; - memcpy(PyArray_DATA(obj), t.data(), + memcpy(PyArray_DATA((PyArrayObject *)obj), t.data(), t.rows() * sizeof(typename M::Scalar)); } return ret.release(); diff --git a/modules/algebra/pyext/swig.i-in b/modules/algebra/pyext/swig.i-in index f15bd5a779..a9071cbd34 100644 --- a/modules/algebra/pyext/swig.i-in +++ b/modules/algebra/pyext/swig.i-in @@ -1,7 +1,5 @@ %{ #include -#include -#include %} %include "IMP/algebra/geometric_primitive_macros.h" diff --git a/modules/algebra/test/medium_test_connolly.py b/modules/algebra/test/medium_test_connolly.py index db60bf9a24..3747ee6cad 100644 --- a/modules/algebra/test/medium_test_connolly.py +++ b/modules/algebra/test/medium_test_connolly.py @@ -3,7 +3,6 @@ import IMP.atom import IMP.core import IMP.algebra -import os class Tests(IMP.test.TestCase): @@ -49,5 +48,6 @@ def test_molecule(self): sps_area = sum([s.get_area() for s in sps]) self.assertAlmostEqual(sps_area, 5478.68, delta=.2) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_bounding_box.py b/modules/algebra/test/test_bounding_box.py index 53c9c5ce09..80644065ec 100644 --- a/modules/algebra/test/test_bounding_box.py +++ b/modules/algebra/test/test_bounding_box.py @@ -1,7 +1,6 @@ import IMP import IMP.test import IMP.algebra -import math import io import pickle @@ -118,7 +117,7 @@ def test_default_3d(self): def test_bounding_box_nd(self): """Test BoundingBox operations for unusual N""" - for N in (-1,1,2,4,5,6): + for N in (-1, 1, 2, 4, 5, 6): if N == -1: clsdim = 'K' dim = 5 diff --git a/modules/algebra/test/test_cone.py b/modules/algebra/test/test_cone.py index af3bc02cae..4406fbba5f 100644 --- a/modules/algebra/test/test_cone.py +++ b/modules/algebra/test/test_cone.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math import pickle @@ -34,13 +33,13 @@ def test_cone_construction(self): self.assertAlmostEqual(cone.get_height(), 5.0, delta=1e-4) p = cone.get_base_plane() self.assertAlmostEqual(p.get_height(cone.get_tip()), 5.0, delta=1e-5) - self.assertLess((cone.get_direction() - IMP.algebra.Vector3D(0,0,1)).get_magnitude(), 0.01) + self.assertLess((cone.get_direction() - IMP.algebra.Vector3D(0, 0, 1)).get_magnitude(), 0.01) self.assertLess((cone.get_tip() - s.get_point(0)).get_magnitude(), 0.01) self.assertTrue(cone.get_contains(IMP.algebra.Vector3D(0.0, 0.0, 3.0))) self.assertTrue(cone.get_contains(IMP.algebra.Vector3D(0.5, 0.5, 3.0))) self.assertFalse(cone.get_contains(IMP.algebra.Vector3D(0.5, 0.5, 0.0))) self.assertFalse( - cone.get_contains(IMP.algebra.Vector3D(1.0, 1.0, -3.0))) + cone.get_contains(IMP.algebra.Vector3D(1.0, 1.0, -3.0))) print(cone) def test_sphere_patch2(self): @@ -79,10 +78,10 @@ def _assert_equal(self, a, b): def test_pickle(self): """Test (un-)pickle of Cone3D""" s1 = IMP.algebra.Segment3D(IMP.algebra.Vector3D(0.0, 0.0, 0.0), - IMP.algebra.Vector3D(0.0, 0.0, 5.0)) + IMP.algebra.Vector3D(0.0, 0.0, 5.0)) cone1 = IMP.algebra.Cone3D(s1, 4.0) s2 = IMP.algebra.Segment3D(IMP.algebra.Vector3D(1.0, 2.0, 3.0), - IMP.algebra.Vector3D(0.0, 0.0, 5.0)) + IMP.algebra.Vector3D(0.0, 0.0, 5.0)) cone2 = IMP.algebra.Cone3D(s2, 6.0) cone2.foo = 'bar' dump = pickle.dumps((cone1, cone2)) diff --git a/modules/algebra/test/test_cylinder.py b/modules/algebra/test/test_cylinder.py index ea539716ef..aa6fd9f75f 100644 --- a/modules/algebra/test/test_cylinder.py +++ b/modules/algebra/test/test_cylinder.py @@ -134,7 +134,7 @@ def test_random_cylinder_sampling(self): m = 100000 for i in range(m): v = IMP.algebra.get_random_vector_in(c) - if(inner_box.get_contains(v)): + if inner_box.get_contains(v): n = n + 1 # assert probabilistically (using Chernoff bound, m is good enough) from IMP.algebra import get_volume diff --git a/modules/algebra/test/test_dynamic_nn.py b/modules/algebra/test/test_dynamic_nn.py index e0f8033d82..7a4e20c049 100644 --- a/modules/algebra/test/test_dynamic_nn.py +++ b/modules/algebra/test/test_dynamic_nn.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math class Tests(IMP.test.TestCase): @@ -35,5 +34,7 @@ def test_nn_query(self): if IMP.algebra.get_distance(vecs[i], j) < i * .98 and ij != i: print(ij, j, IMP.algebra.get_distance(vecs[i], j)) self.assertIn(ij, n1) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_eigen.py b/modules/algebra/test/test_eigen.py index e6747228d4..a8ed9dee5b 100644 --- a/modules/algebra/test/test_eigen.py +++ b/modules/algebra/test/test_eigen.py @@ -1,8 +1,5 @@ import IMP.test import IMP.algebra -import io -import os -import math if IMP.IMP_KERNEL_HAS_NUMPY: import numpy import numpy.testing diff --git a/modules/algebra/test/test_eigen_analysis.py b/modules/algebra/test/test_eigen_analysis.py index 0fac744fc6..e158b56036 100644 --- a/modules/algebra/test/test_eigen_analysis.py +++ b/modules/algebra/test/test_eigen_analysis.py @@ -104,5 +104,6 @@ def test_that_pca_is_invariant_to_rotation(self): ed2.get_principal_value(2), delta=0.2) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_ellipsoid3d.py b/modules/algebra/test/test_ellipsoid3d.py index c809b8ffc5..e378bdbd38 100644 --- a/modules/algebra/test/test_ellipsoid3d.py +++ b/modules/algebra/test/test_ellipsoid3d.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math import pickle @@ -32,7 +31,7 @@ def test_ref_frame(self): def test_construction(self): """Check Ellipsoid construction""" r = IMP.algebra.get_rotation_about_axis( - IMP.algebra.Vector3D(0., 0., 0.), .1) + IMP.algebra.Vector3D(0., 0., 0.), .1) e = IMP.algebra.Ellipsoid3D(IMP.algebra.Vector3D(0.0, 1.0, 2.0), 5.0, 8.0, 10.0, r) self.assertEqual([x for x in e.get_radii()], [5., 8., 10.]) @@ -44,11 +43,11 @@ def test_construction(self): def test_pickle(self): """Test (un-)pickle of Ellipsoid3D""" r1 = IMP.algebra.get_rotation_about_axis( - IMP.algebra.Vector3D(0., 0., 0.), .1) + IMP.algebra.Vector3D(0., 0., 0.), .1) e1 = IMP.algebra.Ellipsoid3D(IMP.algebra.Vector3D(0.0, 1.0, 2.0), 5.0, 8.0, 10.0, r1) r2 = IMP.algebra.get_rotation_about_axis( - IMP.algebra.Vector3D(0., 1., 0.), .1) + IMP.algebra.Vector3D(0., 1., 0.), .1) e2 = IMP.algebra.Ellipsoid3D(IMP.algebra.Vector3D(1.0, 2.0, 0.0), 6.0, 9.0, 11.0, r2) e2.foo = 'bar' diff --git a/modules/algebra/test/test_endian.py b/modules/algebra/test/test_endian.py index 138e58d247..0bad446f43 100644 --- a/modules/algebra/test/test_endian.py +++ b/modules/algebra/test/test_endian.py @@ -2,6 +2,7 @@ import IMP.test import IMP.algebra + class Tests(IMP.test.TestCase): def test_endian(self): @@ -12,5 +13,6 @@ def test_endian(self): # (we don't have any machines that are PDP-endian) self.assertNotEqual(big, little) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_gaussian.py b/modules/algebra/test/test_gaussian.py index 68652bd3e4..fce401749e 100644 --- a/modules/algebra/test/test_gaussian.py +++ b/modules/algebra/test/test_gaussian.py @@ -17,10 +17,11 @@ def test_constructor(self): g = IMP.algebra.Gaussian3D(rf, var) sio = BytesIO() g.show(sio) + def check_gauss(g): g_rf = g.get_reference_frame() self.assertLess(IMP.algebra.get_distance( - g_rf.get_transformation_to().get_translation(), t), 1e-4) + g_rf.get_transformation_to().get_translation(), t), 1e-4) self.assertLess(IMP.algebra.get_distance(g.get_variances(), var), 1e-4) self.assertLess(IMP.algebra.get_distance(g.get_center(), t), 1e-4) diff --git a/modules/algebra/test/test_geom_alignment.py b/modules/algebra/test/test_geom_alignment.py index d1c4ef8b8d..fed594b721 100644 --- a/modules/algebra/test/test_geom_alignment.py +++ b/modules/algebra/test/test_geom_alignment.py @@ -10,15 +10,15 @@ class Tests(IMP.test.TestCase): def test_flip(self): """Test alignment that requires flipping the rotation matrix""" - f = [IMP.algebra.Vector3D(-5,0,0), - IMP.algebra.Vector3D(0,0,0), - IMP.algebra.Vector3D(5,0,0)] + f = [IMP.algebra.Vector3D(-5, 0, 0), + IMP.algebra.Vector3D(0, 0, 0), + IMP.algebra.Vector3D(5, 0, 0)] t = [IMP.algebra.Vector3D(70.9405, 5.8230, 89.6219), IMP.algebra.Vector3D(68.6298, 9.8629, 91.4493), IMP.algebra.Vector3D(66.3191, 13.9028, 93.2769)] tr = IMP.algebra.get_transformation_aligning_first_to_second(f, t) - for fi,ti in zip(f, t): - self.assertLess(IMP.algebra.get_distance(tr*fi, ti), 0.1) + for fi, ti in zip(f, t): + self.assertLess(IMP.algebra.get_distance(tr * fi, ti), 0.1) def _produce_point_sets(self, tr): vs = [] diff --git a/modules/algebra/test/test_grid.py b/modules/algebra/test/test_grid.py index af219a1342..7e3d93a8bf 100644 --- a/modules/algebra/test/test_grid.py +++ b/modules/algebra/test/test_grid.py @@ -1,9 +1,6 @@ from __future__ import print_function import IMP.test import IMP.algebra -import io -import os -import math class Tests(IMP.test.TestCase): diff --git a/modules/algebra/test/test_inverse.py b/modules/algebra/test/test_inverse.py index 71026cb397..abbfaf1b80 100644 --- a/modules/algebra/test/test_inverse.py +++ b/modules/algebra/test/test_inverse.py @@ -26,5 +26,6 @@ def test_inverse(self): self.assertEqual((v1_t_inv - self.v1).get_magnitude() < 0.01, True) self.assertEqual((v2_t_inv - self.v2).get_magnitude() < 0.01, True) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_log_grid.py b/modules/algebra/test/test_log_grid.py index d1e96ea1df..e9d870f2bb 100644 --- a/modules/algebra/test/test_log_grid.py +++ b/modules/algebra/test/test_log_grid.py @@ -1,9 +1,6 @@ from __future__ import print_function import IMP.test import IMP.algebra -import io -import os -import math displayit = False if displayit: @@ -60,10 +57,10 @@ def test_embedding(self): def test_default_embedding_pickle(self): """Test (un-)pickle of DefaultEmbedding3D""" - e1 = IMP.algebra.DefaultEmbedding3D(IMP.algebra.Vector3D(1,2,3), - IMP.algebra.Vector3D(2,4,5)) - e2 = IMP.algebra.DefaultEmbedding3D(IMP.algebra.Vector3D(4,5,6), - IMP.algebra.Vector3D(7,8,9)) + e1 = IMP.algebra.DefaultEmbedding3D(IMP.algebra.Vector3D(1, 2, 3), + IMP.algebra.Vector3D(2, 4, 5)) + e2 = IMP.algebra.DefaultEmbedding3D(IMP.algebra.Vector3D(4, 5, 6), + IMP.algebra.Vector3D(7, 8, 9)) e2.foo = 'bar' dump = pickle.dumps((e1, e2)) newe1, newe2 = pickle.loads(dump) @@ -82,12 +79,12 @@ def test_default_embedding_pickle(self): def test_log_embedding_pickle(self): """Test (un-)pickle of LogEmbedding3D""" - e1 = IMP.algebra.LogEmbedding3D(IMP.algebra.Vector3D(1,2,3), - IMP.algebra.Vector3D(2,4,5), - IMP.algebra.Vector3D(7,8,9)) - e2 = IMP.algebra.LogEmbedding3D(IMP.algebra.Vector3D(4,5,6), - IMP.algebra.Vector3D(7,8,9), - IMP.algebra.Vector3D(17,18,19)) + e1 = IMP.algebra.LogEmbedding3D(IMP.algebra.Vector3D(1, 2, 3), + IMP.algebra.Vector3D(2, 4, 5), + IMP.algebra.Vector3D(7, 8, 9)) + e2 = IMP.algebra.LogEmbedding3D(IMP.algebra.Vector3D(4, 5, 6), + IMP.algebra.Vector3D(7, 8, 9), + IMP.algebra.Vector3D(17, 18, 19)) e2.foo = 'bar' dump = pickle.dumps((e1, e2)) newe1, newe2 = pickle.loads(dump) @@ -106,8 +103,8 @@ def test_log_embedding_pickle(self): def test_grid_index_pickle(self): """Test (un-)pickle of GridIndex3D""" - g1 = IMP.algebra.GridIndex3D(1,2,3) - g2 = IMP.algebra.GridIndex3D(4,5,6) + g1 = IMP.algebra.GridIndex3D(1, 2, 3) + g2 = IMP.algebra.GridIndex3D(4, 5, 6) g2.foo = 'bar' dump = pickle.dumps((g1, g2)) newg1, newg2 = pickle.loads(dump) @@ -124,8 +121,8 @@ def test_grid_index_pickle(self): def test_extended_grid_index_pickle(self): """Test (un-)pickle of ExtendedGridIndex3D""" - g1 = IMP.algebra.ExtendedGridIndex3D(1,2,3) - g2 = IMP.algebra.ExtendedGridIndex3D(4,5,6) + g1 = IMP.algebra.ExtendedGridIndex3D(1, 2, 3) + g2 = IMP.algebra.ExtendedGridIndex3D(4, 5, 6) g2.foo = 'bar' dump = pickle.dumps((g1, g2)) newg1, newg2 = pickle.loads(dump) @@ -154,8 +151,8 @@ def test_unbounded_grid_range_pickle(self): def test_bounded_grid_range_pickle(self): """Test (un-)pickle of BoundedGridRange3D""" - g1 = IMP.algebra.BoundedGridRange3D([1,2,3]) - g2 = IMP.algebra.BoundedGridRange3D([4,5,6]) + g1 = IMP.algebra.BoundedGridRange3D([1, 2, 3]) + g2 = IMP.algebra.BoundedGridRange3D([4, 5, 6]) g2.foo = 'bar' dump = pickle.dumps((g1, g2)) newg1, newg2 = pickle.loads(dump) diff --git a/modules/algebra/test/test_nearest_neighbor.py b/modules/algebra/test/test_nearest_neighbor.py index 65a36abf57..3543c430a9 100644 --- a/modules/algebra/test/test_nearest_neighbor.py +++ b/modules/algebra/test/test_nearest_neighbor.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math def get_nn(vs, i): @@ -78,5 +77,6 @@ def test_nn_functionality(self): # print self.assertNotEqual(rnn.index(cnn), -1) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_plane.py b/modules/algebra/test/test_plane.py index faa6d057fe..5163f40999 100644 --- a/modules/algebra/test/test_plane.py +++ b/modules/algebra/test/test_plane.py @@ -1,10 +1,10 @@ import IMP import IMP.test import IMP.algebra -import math import pickle from io import BytesIO + class Tests(IMP.test.TestCase): def test_trivial_constructor(self): @@ -14,7 +14,7 @@ def test_trivial_constructor(self): def test_area_methods(self): """Test namespace methods for Plane3D""" p = IMP.algebra.Plane3D(5.0, IMP.algebra.Vector3D(0.0, 1.0, 0.0)) - self.assertGreater(IMP.algebra.get_area(p), 1e20) # infinite area + self.assertGreater(IMP.algebra.get_area(p), 1e20) # infinite area bb = IMP.algebra.get_bounding_box(p) g = IMP.algebra.get_plane_3d_geometry(p) self.assertLess(IMP.algebra.get_distance(p.get_normal(), @@ -26,13 +26,13 @@ def test_plane(self): IMP.algebra.Vector3D(0.0, 1.0, 0.0)) sio = BytesIO() p.show(sio) - self.assertLess(IMP.algebra.get_distance(p.get_normal(), - IMP.algebra.Vector3D(0., 1., 0.)), .1) - self.assertLess(IMP.algebra.get_distance(p.get_point_on_plane(), - IMP.algebra.Vector3D(0., 5., 0.)), .1) + self.assertLess(IMP.algebra.get_distance( + p.get_normal(), IMP.algebra.Vector3D(0., 1., 0.)), .1) + self.assertLess(IMP.algebra.get_distance( + p.get_point_on_plane(), IMP.algebra.Vector3D(0., 5., 0.)), .1) pr = p.get_projected(IMP.algebra.Vector3D(5., 0., 0.)) - self.assertLess(IMP.algebra.get_distance(pr, - IMP.algebra.Vector3D(5., 5., 0.)), .1) + self.assertLess(IMP.algebra.get_distance( + pr, IMP.algebra.Vector3D(5., 5., 0.)), .1) self.assertAlmostEqual(p.get_height(IMP.algebra.Vector3D(0., 14., 0.)), 9.0, delta=1e-4) self.assertTrue(p.get_is_above(IMP.algebra.Vector3D(0., 14., 0.))) @@ -41,10 +41,10 @@ def test_plane(self): opp = p.get_opposite() self.assertAlmostEqual(opp.get_distance_from_origin(), -5.0, delta=1e-4) self.assertAlmostEqual(IMP.algebra.get_distance( - p, IMP.algebra.Vector3D(0., 1., 40.)), 4.0, delta=1e-4) + p, IMP.algebra.Vector3D(0., 1., 40.)), 4.0, delta=1e-4) ref = IMP.algebra.get_reflected(p, IMP.algebra.Vector3D(0., 1., 40.)) - self.assertLess(IMP.algebra.get_distance(ref, - IMP.algebra.Vector3D(0., 9., 40.)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + ref, IMP.algebra.Vector3D(0., 9., 40.)), 1e-4) def test_pickle(self): """Test (un-)pickle of Plane3D""" diff --git a/modules/algebra/test/test_random_ball.py b/modules/algebra/test/test_random_ball.py index 494c5397cb..27d1f41d16 100644 --- a/modules/algebra/test/test_random_ball.py +++ b/modules/algebra/test/test_random_ball.py @@ -1,8 +1,6 @@ from __future__ import print_function import IMP.test import IMP.algebra -#import IMP.display -import math import IMP.statistics @@ -12,12 +10,9 @@ def test_circle(self): """Test the creation of points on a circle""" s2 = IMP.algebra.Sphere2D(IMP.algebra.Vector2D(.5, .5), 1.5) h = IMP.statistics.Histogram2D(.1, IMP.algebra.get_bounding_box(s2)) - #w= IMP.display.PymolWriter("pts2d.pym") for i in range(0, 10000): pt = IMP.algebra.get_random_vector_on(s2) pt3 = IMP.algebra.Vector3D(pt[0], pt[1], 0) - #g= IMP.display.SphereGeometry(IMP.algebra.Sphere3D(pt3, .01)) - # w.add_geometry(g) h.add(pt) center = h.get_mean() std = h.get_standard_deviation(center) @@ -30,11 +25,8 @@ def test_sphere(self): """Test the creation of points on a sphere""" s2 = IMP.algebra.Sphere3D(IMP.algebra.Vector3D(.75, .75, .75), .7) h = IMP.statistics.Histogram3D(.1, IMP.algebra.get_bounding_box(s2)) - #w= IMP.display.PymolWriter("pts2d.pym") for i in range(0, 10000): pt = IMP.algebra.get_random_vector_on(s2) - #g= IMP.display.SphereGeometry(IMP.algebra.Sphere3D(pt, .01)) - # w.add_geometry(g) h.add(pt) center = h.get_mean() std = h.get_standard_deviation(center) @@ -43,5 +35,6 @@ def test_sphere(self): self.assertAlmostEqual(center[i], .75, delta=.016) self.assertAlmostEqual(std[i], .58 * .7, delta=.05) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_random_chain.py b/modules/algebra/test/test_random_chain.py index 03990597ca..8f8435aea2 100644 --- a/modules/algebra/test/test_random_chain.py +++ b/modules/algebra/test/test_random_chain.py @@ -1,7 +1,5 @@ import IMP.test import IMP.algebra -import math -import itertools class Tests(IMP.test.TestCase): @@ -56,5 +54,7 @@ def test_random_chain_obst(self): for c in chain: self.assertFalse(IMP.algebra.get_interiors_intersect( ss[i], IMP.algebra.Sphere3D(c, .9 * r))) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_random_rotations.py b/modules/algebra/test/test_random_rotations.py index 06b601d4a9..9422940f68 100644 --- a/modules/algebra/test/test_random_rotations.py +++ b/modules/algebra/test/test_random_rotations.py @@ -2,8 +2,6 @@ import IMP import IMP.test import IMP.algebra -import random -import math class Tests(IMP.test.TestCase): @@ -28,12 +26,11 @@ def test_uniform_random(self): r0 = r.get_rotated(pts[0]) r1 = r.get_rotated(pts[1]) print(".color red") - print(".sphere " + str(r0[0]) + " " + str(r0[1]) + " " + str(r0[2])\ - + " .1") + print(".sphere " + str(r0[0]) + " " + str(r0[1]) + " " + str(r0[2]) + + " .1") print(".color blue") - print(".sphere " + str(.5 * r1[0]) + " " + str(.5 * r1[1]) + " " \ - + str(.5 * r1[2])\ - + " .1") + print(".sphere " + str(.5 * r1[0]) + " " + str(.5 * r1[1]) + " " + + str(.5 * r1[2]) + " .1") c0 = IMP.algebra.get_zero_vector_3d() c1 = c0 diff --git a/modules/algebra/test/test_reference_frame_3d.py b/modules/algebra/test/test_reference_frame_3d.py index 4ff0c6d615..9bc95bf012 100644 --- a/modules/algebra/test/test_reference_frame_3d.py +++ b/modules/algebra/test/test_reference_frame_3d.py @@ -3,17 +3,18 @@ import IMP.algebra import pickle + class Tests(IMP.test.TestCase): def test_get_global_ref(self): """Test get_global_reference_frame()""" T = IMP.algebra.Transformation3D V = IMP.algebra.Vector3D idrot = IMP.algebra.get_identity_rotation_3d() - r1 = IMP.algebra.ReferenceFrame3D(T(idrot, V(1,2,3))) - r2 = IMP.algebra.ReferenceFrame3D(T(idrot, V(4,5,6))) + r1 = IMP.algebra.ReferenceFrame3D(T(idrot, V(1, 2, 3))) + r2 = IMP.algebra.ReferenceFrame3D(T(idrot, V(4, 5, 6))) r3 = r1.get_global_reference_frame(r2) v3 = r3.get_transformation_to().get_translation() - self.assertLess(IMP.algebra.get_distance(v3, V(5,7,9)), 1e-4) + self.assertLess(IMP.algebra.get_distance(v3, V(5, 7, 9)), 1e-4) def test_pickle(self): """Test (un-)pickle of ReferenceFrame3D""" diff --git a/modules/algebra/test/test_reflection_3d.py b/modules/algebra/test/test_reflection_3d.py index 62a4abcb2e..264dd7f6ab 100644 --- a/modules/algebra/test/test_reflection_3d.py +++ b/modules/algebra/test/test_reflection_3d.py @@ -15,8 +15,8 @@ def test_reflection3d(self): sio = io.BytesIO() r.show(sio) v = r.get_reflected(IMP.algebra.Vector3D(20., 0., 0.)) - self.assertLess(IMP.algebra.get_distance(v, - IMP.algebra.Vector3D(20,10,0)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + v, IMP.algebra.Vector3D(20, 10, 0)), 1e-4) def test_pickle(self): """Test (un-)pickle of Reflection3D""" diff --git a/modules/algebra/test/test_rigid_transformation.py b/modules/algebra/test/test_rigid_transformation.py index 2878134606..5210bb5fc2 100644 --- a/modules/algebra/test/test_rigid_transformation.py +++ b/modules/algebra/test/test_rigid_transformation.py @@ -1,7 +1,6 @@ import IMP import IMP.test import IMP.algebra -import math class Tests(IMP.test.TestCase): @@ -60,5 +59,6 @@ def test_delta(self): self.assertAlmostEqual(q_id[2], 0.0) self.assertAlmostEqual(q_id[3], 0.0) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_rotation_2d.py b/modules/algebra/test/test_rotation_2d.py index 4309d69899..08a11085c1 100644 --- a/modules/algebra/test/test_rotation_2d.py +++ b/modules/algebra/test/test_rotation_2d.py @@ -5,6 +5,7 @@ import io import pickle + class Tests(IMP.test.TestCase): def test_get_random(self): @@ -19,10 +20,10 @@ def test_get_rotated_vector(self): dr = IMP.algebra.Rotation2D() r = IMP.algebra.Rotation2D(math.pi / 2.) self.assertRaisesInternalException(dr.get_rotated, - IMP.algebra.Vector2D(1,2)) - v = r.get_rotated(IMP.algebra.Vector2D(1,2)) - self.assertLess(IMP.algebra.get_distance(v, IMP.algebra.Vector2D(-2,1)), - 1e-4) + IMP.algebra.Vector2D(1, 2)) + v = r.get_rotated(IMP.algebra.Vector2D(1, 2)) + self.assertLess(IMP.algebra.get_distance( + v, IMP.algebra.Vector2D(-2, 1)), 1e-4) def test_get_rotated_point(self): """Test get_rotated() with a point""" @@ -30,8 +31,8 @@ def test_get_rotated_point(self): r = IMP.algebra.Rotation2D(math.pi / 2.) self.assertRaisesInternalException(dr.get_rotated, 1, 2) v = r.get_rotated(1, 2) - self.assertLess(IMP.algebra.get_distance(v, IMP.algebra.Vector2D(-2,1)), - 1e-4) + self.assertLess(IMP.algebra.get_distance( + v, IMP.algebra.Vector2D(-2, 1)), 1e-4) def test_get_inverse(self): """Test get_inverse()""" diff --git a/modules/algebra/test/test_rotation_3d.py b/modules/algebra/test/test_rotation_3d.py index bbaecd76b5..f5ac7b169c 100644 --- a/modules/algebra/test/test_rotation_3d.py +++ b/modules/algebra/test/test_rotation_3d.py @@ -15,10 +15,6 @@ def __init__(self, x_index, q_index, x_base, q_base): self.x = x_base self.qi = q_index self.q = q_base - # print self.xi - # print self.qi - #self.x.show(); print - # print self.q def __call__(self, v): self.q[self.qi] = v @@ -153,11 +149,9 @@ def test_rotation(self): def test_deriv(self): """Check the quaternion derivatives""" - #r= IMP.algebra.Rotation3D(1,0,0,0) r = IMP.algebra.get_random_rotation_3d() x = IMP.algebra.get_random_vector_in( IMP.algebra.get_unit_bounding_box_3d()) - # x=IMP.algebra.Vector3D(1,0,0) for qi in range(0, 4): for xi in range(0, 3): print("qi=" + str(qi) + " and xi= " + str(xi)) @@ -309,7 +303,7 @@ def test_interpolate(self): def test_about_point(self): """Test get_rotation_about_point()""" r0 = IMP.algebra.get_random_rotation_3d() - v = IMP.algebra.Vector3D(1,2,3) + v = IMP.algebra.Vector3D(1, 2, 3) t = IMP.algebra.get_rotation_about_point(v, r0) # Rotating a point about itself should not move it self.assertLess(IMP.algebra.get_distance(v, t * v), 1e-6) diff --git a/modules/algebra/test/test_segment.py b/modules/algebra/test/test_segment.py index 307a9821ae..919fb0db39 100644 --- a/modules/algebra/test/test_segment.py +++ b/modules/algebra/test/test_segment.py @@ -9,47 +9,47 @@ def test_constructor(self): """Test construction of Segment3D objects""" V = IMP.algebra.Vector3D s = IMP.algebra.Segment3D() - s = IMP.algebra.Segment3D(V(1,2,3), V(4,5,6)) - self.assertLess(IMP.algebra.get_distance(s.get_point(0), V(1,2,3)), + s = IMP.algebra.Segment3D(V(1, 2, 3), V(4, 5, 6)) + self.assertLess(IMP.algebra.get_distance(s.get_point(0), V(1, 2, 3)), 1e-4) - self.assertLess(IMP.algebra.get_distance(s.get_point(1), V(4,5,6)), + self.assertLess(IMP.algebra.get_distance(s.get_point(1), V(4, 5, 6)), 1e-4) self.assertRaisesUsageException(s.get_point, 2) - self.assertLess(IMP.algebra.get_distance(s.get_middle_point(), - V(2.5,3.5,4.5)), 1e-4) - self.assertLess(IMP.algebra.get_distance(s.get_direction(), - V(0.57735, 0.57735, 0.57735)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + s.get_middle_point(), V(2.5, 3.5, 4.5)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + s.get_direction(), V(0.57735, 0.57735, 0.57735)), 1e-4) def test_projection(self): """Test projection onto Segment3D objects""" V = IMP.algebra.Vector3D - s = IMP.algebra.Segment3D(V(0,0,0), V(4,0,0)) - p = IMP.algebra.get_relative_projection_on_segment(s, V(1,2,3)) + s = IMP.algebra.Segment3D(V(0, 0, 0), V(4, 0, 0)) + p = IMP.algebra.get_relative_projection_on_segment(s, V(1, 2, 3)) self.assertAlmostEqual(p, 0.25, delta=1e-4) def test_distance(self): """Test distance from Segment3D objects""" V = IMP.algebra.Vector3D - s = IMP.algebra.Segment3D(V(0,0,0), V(4,0,0)) - self.assertAlmostEqual(IMP.algebra.get_distance(s, V(1,0,3)), 3.0, + s = IMP.algebra.Segment3D(V(0, 0, 0), V(4, 0, 0)) + self.assertAlmostEqual(IMP.algebra.get_distance(s, V(1, 0, 3)), 3.0, delta=1e-4) - s2 = IMP.algebra.Segment3D(V(5,0,0), V(5,0,8)) + s2 = IMP.algebra.Segment3D(V(5, 0, 0), V(5, 0, 8)) self.assertAlmostEqual(IMP.algebra.get_distance(s, s2), 1.0, delta=1e-4) def test_namespace_methods(self): """Test namespace methods""" V = IMP.algebra.Vector3D - s = IMP.algebra.Segment3D(V(0,0,0), V(4,0,0)) + s = IMP.algebra.Segment3D(V(0, 0, 0), V(4, 0, 0)) bb = IMP.algebra.get_bounding_box(s) - self.assertLess(IMP.algebra.get_distance(bb.get_corner(0), V(0,0,0)), + self.assertLess(IMP.algebra.get_distance(bb.get_corner(0), V(0, 0, 0)), 1e-4) - self.assertLess(IMP.algebra.get_distance(bb.get_corner(1), V(4,0,0)), + self.assertLess(IMP.algebra.get_distance(bb.get_corner(1), V(4, 0, 0)), 1e-4) s2 = IMP.algebra.get_segment_3d_geometry(s) - self.assertLess(IMP.algebra.get_distance(s2.get_point(0), V(0,0,0)), + self.assertLess(IMP.algebra.get_distance(s2.get_point(0), V(0, 0, 0)), 1e-4) - self.assertLess(IMP.algebra.get_distance(s2.get_point(1), V(4,0,0)), + self.assertLess(IMP.algebra.get_distance(s2.get_point(1), V(4, 0, 0)), 1e-4) def _assert_equal(self, a, b): diff --git a/modules/algebra/test/test_serialize.cpp b/modules/algebra/test/test_serialize.cpp index 076ce00735..08d43f3598 100644 --- a/modules/algebra/test/test_serialize.cpp +++ b/modules/algebra/test/test_serialize.cpp @@ -1,27 +1,20 @@ #include -#include -#include -#include #include #include +#include int main(int argc, char *argv[]) { IMP::setup_from_argv(argc, argv, "Test vector serialization"); std::ostringstream ofs; IMP::algebra::Vector3D v(1,2,3); - boost::archive::text_oarchive oa(ofs); - oa << v << v << v << v << v << v; - - std::ostringstream bofs; - IMP::algebra::Vector3D v2(4,5,6); - boost::archive::binary_oarchive boa(bofs); - boa << v2 << v2 << v2 << v2 << v2 << v2; + cereal::BinaryOutputArchive oa(ofs); + oa(v, v, v, v, v, v); std::istringstream ifs(ofs.str()); - boost::archive::text_iarchive ia(ifs); + cereal::BinaryInputArchive ia(ifs); IMP::algebra::Vector3D newv; - ia >> newv; + ia(newv); assert(int(newv[0]) == 1); assert(int(newv[1]) == 2); diff --git a/modules/algebra/test/test_shortest_segment.py b/modules/algebra/test/test_shortest_segment.py index 6b9ca859f0..6900f91a4d 100644 --- a/modules/algebra/test/test_shortest_segment.py +++ b/modules/algebra/test/test_shortest_segment.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math class Tests(IMP.test.TestCase): @@ -39,19 +38,19 @@ def test_too_short(self): sa = S(V(0, 0, 0), V(0, 0, 0)) sb = S(V(1, 0, 0), V(1, 0, 10)) ssab = ss(sa, sb) - self.assertLess(IMP.algebra.get_distance(ssab.get_point(0), V(0,0,0)), + self.assertLess(IMP.algebra.get_distance(ssab.get_point(0), V(0, 0, 0)), 1e-3) - self.assertLess(IMP.algebra.get_distance(ssab.get_point(1), V(1,0,0)), + self.assertLess(IMP.algebra.get_distance(ssab.get_point(1), V(1, 0, 0)), 1e-3) ssba = ss(sb, sa) - self.assertLess(IMP.algebra.get_distance(ssba.get_point(0), V(1,0,0)), + self.assertLess(IMP.algebra.get_distance(ssba.get_point(0), V(1, 0, 0)), 1e-3) - self.assertLess(IMP.algebra.get_distance(ssba.get_point(1), V(0,0,0)), + self.assertLess(IMP.algebra.get_distance(ssba.get_point(1), V(0, 0, 0)), 1e-3) ssaa = ss(sa, S(V(1, 0, 0), V(1, 0, 0))) - self.assertLess(IMP.algebra.get_distance(ssaa.get_point(0), V(0,0,0)), + self.assertLess(IMP.algebra.get_distance(ssaa.get_point(0), V(0, 0, 0)), 1e-3) - self.assertLess(IMP.algebra.get_distance(ssaa.get_point(1), V(1,0,0)), + self.assertLess(IMP.algebra.get_distance(ssaa.get_point(1), V(1, 0, 0)), 1e-3) def test_non_parallel(self): @@ -62,9 +61,9 @@ def test_non_parallel(self): sa = S(V(0, 0, 0), V(0, 0, 10)) sb = S(V(3, 0, 4), V(10, 0, 4)) ssab = ss(sa, sb) - self.assertLess(IMP.algebra.get_distance(ssab.get_point(0), V(0,0,4)), + self.assertLess(IMP.algebra.get_distance(ssab.get_point(0), V(0, 0, 4)), 1e-3) - self.assertLess(IMP.algebra.get_distance(ssab.get_point(1), V(3,0,4)), + self.assertLess(IMP.algebra.get_distance(ssab.get_point(1), V(3, 0, 4)), 1e-3) def test_parallel_no_overlap(self): @@ -77,5 +76,6 @@ def test_parallel_no_overlap(self): ssab = ss(sa, sb) self.assertAlmostEqual(ssab.get_length(), 10, delta=.1) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_sphere.py b/modules/algebra/test/test_sphere.py index 6ea8ad50a4..4965748af1 100644 --- a/modules/algebra/test/test_sphere.py +++ b/modules/algebra/test/test_sphere.py @@ -27,7 +27,7 @@ def test_sphere_construction(self): def test_random_vector_2d(self): """Test random vectors on a 2D sphere (circle)""" - s = IMP.algebra.Sphere2D(IMP.algebra.Vector2D(1,2), 3) + s = IMP.algebra.Sphere2D(IMP.algebra.Vector2D(1, 2), 3) v = IMP.algebra.get_random_vector_in(s) self.assertLess(IMP.algebra.get_distance(v, s.get_center()), 3. + 1e-6) @@ -90,8 +90,8 @@ def test_io(self): """Check I/O of Sphere3Ds""" V = IMP.algebra.Vector3D S = IMP.algebra.Sphere3D - vs1 = [S(V(1,2,3), 4), - S(V(4,5,6), 7)] + vs1 = [S(V(1, 2, 3), 4), + S(V(4, 5, 6), 7)] sio = io.BytesIO() IMP.algebra.write_spheres(vs1, sio) @@ -109,7 +109,7 @@ def test_io(self): def test_sphere_nd(self): """Test SphereD operations for unusual N""" - for N in (-1,1,2,4,5,6): + for N in (-1, 1, 2, 4, 5, 6): if N == -1: clsdim = 'K' dim = 5 diff --git a/modules/algebra/test/test_sphere_cover.py b/modules/algebra/test/test_sphere_cover.py index de93f022d4..09d3c751dc 100644 --- a/modules/algebra/test/test_sphere_cover.py +++ b/modules/algebra/test/test_sphere_cover.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math class Tests(IMP.test.TestCase): @@ -21,8 +20,8 @@ def test_get_uniform_surface_cover(self): print("the sample 1") for p in points: sampled_centroid = sampled_centroid + p - print(".sphere " + str(p[0]) + " " + str(p[1]) + " " + str(p[2])\ - + " .1") + print(".sphere " + str(p[0]) + " " + str(p[1]) + " " + str(p[2]) + + " .1") sampled_centroid.show() sampled_centroid = sampled_centroid * (1.0 / len(points)) sampled_centroid.show() @@ -45,8 +44,8 @@ def test_get_uniform_surface_cover_not_on_000(self): print("the sample") for i in range(len(points)): sampled_centroid = sampled_centroid + points[i] - print(".dotat " + str(points[i][0]) + " "\ - + str(points[i][1]) + " " + str(points[i][2])) + print(".dotat " + str(points[i][0]) + " " + + str(points[i][1]) + " " + str(points[i][2])) sampled_centroid = sampled_centroid * (1.0 / len(points)) sampled_centroid.show() center.show() diff --git a/modules/algebra/test/test_sphere_patch.py b/modules/algebra/test/test_sphere_patch.py index 6d3769aaa1..c2e2275e55 100644 --- a/modules/algebra/test/test_sphere_patch.py +++ b/modules/algebra/test/test_sphere_patch.py @@ -1,7 +1,6 @@ import IMP import IMP.test import IMP.algebra -import math from io import BytesIO import pickle @@ -23,28 +22,27 @@ def test_sphere_patch_construction(self): # Not implemented self.assertRaises(Exception, IMP.algebra.get_area, patch) g = IMP.algebra.get_sphere_patch_3d_geometry(patch) - self.assertLess(IMP.algebra.get_distance(patch.get_plane().get_normal(), - g.get_plane().get_normal()), - 1e-4) self.assertLess(IMP.algebra.get_distance( - patch.get_sphere().get_center(), - g.get_sphere().get_center()), 1e-4) + patch.get_plane().get_normal(), g.get_plane().get_normal()), 1e-4) + self.assertLess(IMP.algebra.get_distance( + patch.get_sphere().get_center(), + g.get_sphere().get_center()), 1e-4) bb = IMP.algebra.get_bounding_box(patch) - self.assertLess(IMP.algebra.get_distance(bb.get_corner(0), - IMP.algebra.Vector3D(-5,-5,-5)), 1e-4) - self.assertLess(IMP.algebra.get_distance(bb.get_corner(1), - IMP.algebra.Vector3D(5,5,5)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + bb.get_corner(0), IMP.algebra.Vector3D(-5, -5, -5)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + bb.get_corner(1), IMP.algebra.Vector3D(5, 5, 5)), 1e-4) p = patch.get_boundary_point() - self.assertLess(IMP.algebra.get_distance(p, - IMP.algebra.Vector3D(3.53553, 3.53553, 0)), 1e-3) + self.assertLess(IMP.algebra.get_distance( + p, IMP.algebra.Vector3D(3.53553, 3.53553, 0)), 1e-3) sio = BytesIO() patch.show(sio) self.assertEqual(sio.getvalue(), b'(0 0 0: 5)(0: 0 0 1)') self.assertTrue(patch.get_plane().get_is_above( - IMP.algebra.Vector3D(1., 0., 1.))) + IMP.algebra.Vector3D(1., 0., 1.))) self.assertTrue(patch.get_contains(IMP.algebra.Vector3D(0.0, 1.0, 0.4))) self.assertFalse(patch.get_contains( - IMP.algebra.Vector3D(0.0, 1.0, -0.4))) + IMP.algebra.Vector3D(0.0, 1.0, -0.4))) def test_get_uniform_surface_cover(self): """Check uniform cover on a patch of a sphere""" diff --git a/modules/algebra/test/test_transformation_2d.py b/modules/algebra/test/test_transformation_2d.py index 9072bf96cc..0fe674794d 100644 --- a/modules/algebra/test/test_transformation_2d.py +++ b/modules/algebra/test/test_transformation_2d.py @@ -15,8 +15,8 @@ def test_identity(self): """Test Transformation2D identity""" t = IMP.algebra.get_identity_transformation_2d() self.assertAlmostEqual(t.get_rotation().get_angle(), 0., delta=1e-4) - self.assertLess(IMP.algebra.get_distance(t.get_translation(), - IMP.algebra.Vector2D(0,0)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + t.get_translation(), IMP.algebra.Vector2D(0, 0)), 1e-4) def test_rotate_about_point(self): """Test rotation about a 2D point""" @@ -24,34 +24,34 @@ def test_rotate_about_point(self): r = IMP.algebra.Rotation2D(math.pi / 2.) t = IMP.algebra.get_rotation_about_point(p, r) n = t * IMP.algebra.Vector2D(2., 3.) - self.assertLess(IMP.algebra.get_distance(n, - IMP.algebra.Vector2D(0,3)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + n, IMP.algebra.Vector2D(0, 3)), 1e-4) def test_inverse(self): """Test inverse of Transformation2D""" t = IMP.algebra.Transformation2D(IMP.algebra.Rotation2D(math.pi / 2.), - IMP.algebra.Vector2D(1,2)) + IMP.algebra.Vector2D(1, 2)) t2 = t.get_inverse() self.assertAlmostEqual(t2.get_rotation().get_angle(), -math.pi / 2., delta=1e-4) - self.assertLess(IMP.algebra.get_distance(t2.get_translation(), - IMP.algebra.Vector2D(-2,1)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + t2.get_translation(), IMP.algebra.Vector2D(-2, 1)), 1e-4) t2 = t * t.get_inverse() self.assertAlmostEqual(t2.get_rotation().get_angle(), 0., delta=1e-4) - self.assertLess(IMP.algebra.get_distance(t2.get_translation(), - IMP.algebra.Vector2D(0,0)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + t2.get_translation(), IMP.algebra.Vector2D(0, 0)), 1e-4) def test_compose(self): """Test compose of Transformation2Ds""" t = IMP.algebra.Transformation2D(IMP.algebra.Rotation2D(math.pi / 2.), - IMP.algebra.Vector2D(1,2)) + IMP.algebra.Vector2D(1, 2)) t2 = IMP.algebra.Transformation2D(IMP.algebra.Rotation2D(math.pi / 2.), - IMP.algebra.Vector2D(4,3)) + IMP.algebra.Vector2D(4, 3)) t3 = IMP.algebra.compose(t, t2) self.assertAlmostEqual(t3.get_rotation().get_angle(), math.pi, delta=1e-4) - self.assertLess(IMP.algebra.get_distance(t3.get_translation(), - IMP.algebra.Vector2D(-2,6)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + t3.get_translation(), IMP.algebra.Vector2D(-2, 6)), 1e-4) def test_operations(self): """Test operations on a Transformation2D""" @@ -60,33 +60,32 @@ def test_operations(self): t = IMP.algebra.Transformation2D(r, v) t.show() t2 = IMP.algebra.Transformation2D(IMP.algebra.Rotation2D(math.pi / 2.), - IMP.algebra.Vector2D(4,3)) - o = t.get_transformed(IMP.algebra.Vector2D(3,4)) - self.assertLess(IMP.algebra.get_distance(o, - IMP.algebra.Vector2D(-3,5)), 1e-4) - o = t * IMP.algebra.Vector2D(3,4) - self.assertLess(IMP.algebra.get_distance(o, - IMP.algebra.Vector2D(-3,5)), 1e-4) + IMP.algebra.Vector2D(4, 3)) + o = t.get_transformed(IMP.algebra.Vector2D(3, 4)) + self.assertLess(IMP.algebra.get_distance( + o, IMP.algebra.Vector2D(-3, 5)), 1e-4) + o = t * IMP.algebra.Vector2D(3, 4) + self.assertLess(IMP.algebra.get_distance( + o, IMP.algebra.Vector2D(-3, 5)), 1e-4) tt2 = t * t2 self.assertAlmostEqual(tt2.get_rotation().get_angle(), math.pi, delta=1e-4) - self.assertLess(IMP.algebra.get_distance(tt2.get_translation(), - IMP.algebra.Vector2D(-2,6)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + tt2.get_translation(), IMP.algebra.Vector2D(-2, 6)), 1e-4) t *= t2 self.assertAlmostEqual(t.get_rotation().get_angle(), math.pi, delta=1e-4) - self.assertLess(IMP.algebra.get_distance(t.get_translation(), - IMP.algebra.Vector2D(-2,6)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + t.get_translation(), IMP.algebra.Vector2D(-2, 6)), 1e-4) t = IMP.algebra.Transformation2D(r, v) - tt2 = t/t2 + tt2 = t / t2 self.assertAlmostEqual(tt2.get_rotation().get_angle(), 0., delta=1e-4) - self.assertLess(IMP.algebra.get_distance(tt2.get_translation(), - IMP.algebra.Vector2D(-3,-1)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + tt2.get_translation(), IMP.algebra.Vector2D(-3, -1)), 1e-4) t /= t2 self.assertAlmostEqual(t.get_rotation().get_angle(), 0., delta=1e-4) - self.assertLess(IMP.algebra.get_distance(t.get_translation(), - IMP.algebra.Vector2D(-3,-1)), 1e-4) - + self.assertLess(IMP.algebra.get_distance( + t.get_translation(), IMP.algebra.Vector2D(-3, -1)), 1e-4) def test_transformation_from_point_sets(self): """Check building a Transformation2D from point sets""" @@ -100,8 +99,7 @@ def test_transformation_from_point_sets(self): set1 = [x1, x2] set2 = [y1, y2] self.assertRaisesUsageException( - IMP.algebra.get_transformation_aligning_pair, - set1, [y1]) + IMP.algebra.get_transformation_aligning_pair, set1, [y1]) T = IMP.algebra.get_transformation_aligning_pair(set1, set2) self.assertAlmostEqual(angle_applied, T.get_rotation().get_angle(), delta=.01) @@ -113,9 +111,9 @@ def test_transformation_from_point_sets(self): def test_pickle(self): """Test (un-)pickle of Transformation2D""" t1 = IMP.algebra.Transformation2D(IMP.algebra.Rotation2D(math.pi / 4.), - IMP.algebra.Vector2D(1,2)) + IMP.algebra.Vector2D(1, 2)) t2 = IMP.algebra.Transformation2D(IMP.algebra.Rotation2D(math.pi / 2.), - IMP.algebra.Vector2D(4,3)) + IMP.algebra.Vector2D(4, 3)) t2.foo = 'bar' tdump = pickle.dumps((t1, t2)) diff --git a/modules/algebra/test/test_transformation_3d.py b/modules/algebra/test/test_transformation_3d.py index 63cc716c91..8a38b5a72f 100644 --- a/modules/algebra/test/test_transformation_3d.py +++ b/modules/algebra/test/test_transformation_3d.py @@ -149,14 +149,14 @@ def test_build_from2D(self): def test_get_transformed_bb(self): """Check get_transformed() for a BoundingBox3D""" V = IMP.algebra.Vector3D - bb = IMP.algebra.BoundingBox3D(V(1,2,3), V(4,5,6)) - r = IMP.algebra.get_rotation_about_axis(V(0,1,0), math.pi / 2.) - t = IMP.algebra.Transformation3D(r, V(10,20,30)) + bb = IMP.algebra.BoundingBox3D(V(1, 2, 3), V(4, 5, 6)) + r = IMP.algebra.get_rotation_about_axis(V(0, 1, 0), math.pi / 2.) + t = IMP.algebra.Transformation3D(r, V(10, 20, 30)) nbb = IMP.algebra.get_transformed(bb, t) self.assertLess(IMP.algebra.get_distance(nbb.get_corner(0), - V(13, 22, 26)), 1e-4) + V(13, 22, 26)), 1e-4) self.assertLess(IMP.algebra.get_distance(nbb.get_corner(1), - V(16, 25, 29)), 1e-4) + V(16, 25, 29)), 1e-4) def test_pickle(self): """Test (un-)pickle of Transformation3D""" diff --git a/modules/algebra/test/test_triangle3d.py b/modules/algebra/test/test_triangle3d.py index d32d22e0ce..5d6dd9ca5e 100644 --- a/modules/algebra/test/test_triangle3d.py +++ b/modules/algebra/test/test_triangle3d.py @@ -1,9 +1,9 @@ import IMP import IMP.test import IMP.algebra -import math import io + class Tests(IMP.test.TestCase): def test_triangle_construction(self): @@ -56,12 +56,13 @@ def test_triangle_trans(self): V(0.4, 0.0, 5.0)) t = IMP.algebra.get_transformation_from_first_triangle_to_second(t1, t2) v = t.get_translation() - self.assertLess(IMP.algebra.get_distance(v, V(0.4,0,0)), 1e-4) + self.assertLess(IMP.algebra.get_distance(v, V(0.4, 0, 0)), 1e-4) r = t.get_rotation().get_quaternion() self.assertAlmostEqual(r[0], 0.5, delta=1e-5) self.assertAlmostEqual(r[1], 0.5, delta=1e-5) self.assertAlmostEqual(r[2], 0.5, delta=1e-5) self.assertAlmostEqual(r[3], 0.5, delta=1e-5) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_uniform_rotation.py b/modules/algebra/test/test_uniform_rotation.py index 3a3b267add..34f3b7cc1b 100644 --- a/modules/algebra/test/test_uniform_rotation.py +++ b/modules/algebra/test/test_uniform_rotation.py @@ -26,8 +26,8 @@ def test_euler_angles(self): theta1 = eu_angles.get_theta() rot1 = IMP.algebra.get_rotation_from_fixed_zxz(phi1, theta1, psi1) print("Test #%3d:" % i, end=' ') - print("phi %5.2f / %5.2f theta %5.2f / %5.2f psi %5.2f / %5.2f" \ - % (phi, phi1, theta, theta1, psi, psi1)) + print("phi %5.2f / %5.2f theta %5.2f / %5.2f psi %5.2f / %5.2f" + % (phi, phi1, theta, theta1, psi, psi1)) self.assertAlmostEqual(IMP.algebra.get_distance(rot, rot1), 0, 3) print() @@ -36,5 +36,6 @@ def test_euler_sampling(self): print("number of rots", len(rots)) self.assertEqual(552, len(rots)) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_unit_simplex.py b/modules/algebra/test/test_unit_simplex.py index 92b26a6e7e..973a8eea89 100644 --- a/modules/algebra/test/test_unit_simplex.py +++ b/modules/algebra/test/test_unit_simplex.py @@ -1,5 +1,4 @@ from __future__ import print_function -import math import numpy as np diff --git a/modules/algebra/test/test_vector.py b/modules/algebra/test/test_vector.py index 0d6630af1c..03c7248d63 100644 --- a/modules/algebra/test/test_vector.py +++ b/modules/algebra/test/test_vector.py @@ -1,14 +1,14 @@ import IMP import IMP.test import IMP.algebra -import math import io + class Tests(IMP.test.TestCase): def test_vector_nd(self): """Test VectorD operations for unusual N""" - for N in (-1,1,2,4,5,6): + for N in (-1, 1, 2, 4, 5, 6): if N == -1: clsdim = 'K' dim = 5 @@ -36,5 +36,6 @@ def test_vector_nd(self): sio = io.BytesIO() v.show(sio) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_vector3d.py b/modules/algebra/test/test_vector3d.py index 9fa44fd59b..85eba60279 100644 --- a/modules/algebra/test/test_vector3d.py +++ b/modules/algebra/test/test_vector3d.py @@ -15,8 +15,8 @@ def test_magnitude(self): self.assertEqual(v.get_squared_magnitude(), 14.0) self.assertAlmostEqual(v.get_magnitude(), math.sqrt(14.0), places=1) - @IMP.test.skipIf(IMP.get_check_level() < IMP.USAGE, - "No check in fast mode") + @IMP.test.skipIf(IMP.get_check_level() < IMP.USAGE_AND_INTERNAL, + "No check in fast or release mode") def test_uninit(self): """Check use of uninitialized Vector3D""" v = IMP.algebra.Vector3D() diff --git a/modules/algebra/test/test_vector4d.py b/modules/algebra/test/test_vector4d.py index d1d18489eb..929f78c5c5 100644 --- a/modules/algebra/test/test_vector4d.py +++ b/modules/algebra/test/test_vector4d.py @@ -100,5 +100,6 @@ def test_rotation_from_vector4d(self): v2 = IMP.algebra.Vector4D(1.0, 2.0, 3.0, 10.0) r2 = IMP.algebra.get_rotation_from_vector4d(v2) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_vector_metric.py b/modules/algebra/test/test_vector_metric.py index 0c1e32f359..1454ea8447 100644 --- a/modules/algebra/test/test_vector_metric.py +++ b/modules/algebra/test/test_vector_metric.py @@ -9,19 +9,20 @@ def test_euc_vector_metric(self): """Check Euclidean vector metric""" m = IMP.algebra.EuclideanVectorKDMetric("foo") V = IMP.algebra.VectorKD - vs = [ V(1,2,3), V(5,6,7), V(10,11,12) ] + vs = [V(1, 2, 3), V(5, 6, 7), V(10, 11, 12)] self.assertAlmostEqual(m.get_distance(vs[0], vs[1]), 6.928, delta=1e-3) - self.assertLess(IMP.algebra.get_distance(m.get_centroid(vs), - V(5.33333,6.33333,7.33333)), 1e-4) + self.assertLess(IMP.algebra.get_distance( + m.get_centroid(vs), V(5.33333, 6.33333, 7.33333)), 1e-4) def test_max_vector_metric(self): """Check max vector metric""" m = IMP.algebra.MaxVectorKDMetric("foo") V = IMP.algebra.VectorKD - vs = [ V(1,2,3), V(5,6,7), V(10,11,12) ] + vs = [V(1, 2, 3), V(5, 6, 7), V(10, 11, 12)] self.assertAlmostEqual(m.get_distance(vs[0], vs[1]), 4.0, delta=1e-3) self.assertLess(IMP.algebra.get_distance(m.get_centroid(vs), - V(5.5,6.5,7.5)), 1e-4) + V(5.5, 6.5, 7.5)), 1e-4) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_vector_on_box.py b/modules/algebra/test/test_vector_on_box.py index e1595d153c..dc05aa7699 100644 --- a/modules/algebra/test/test_vector_on_box.py +++ b/modules/algebra/test/test_vector_on_box.py @@ -1,7 +1,6 @@ from __future__ import print_function import IMP.test import IMP.algebra -import math def in_box(lb, ub, pt): @@ -36,5 +35,6 @@ def test_magnitude(self): self.assertTrue(in_box(olb, oub, rv)) self.assertFalse(in_box(ilb, iub, rv)) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_vectorkd.py b/modules/algebra/test/test_vectorkd.py index 3edfe23936..bf9151664b 100644 --- a/modules/algebra/test/test_vectorkd.py +++ b/modules/algebra/test/test_vectorkd.py @@ -20,8 +20,8 @@ def test_unit_vector(self): self.assertAlmostEqual(v_unit.get_magnitude(), 1.0, places=6) # tests that a tiny vector is converted to a random unit vector for i in range(1, 5): - tiny_v = IMP.algebra.VectorKD \ - ([1.0e-16, 2.0e-16, 3.0e-16, 4.0e-16, 5.0e-16, 6.0e-16]) + tiny_v = IMP.algebra.VectorKD( + [1.0e-16, 2.0e-16, 3.0e-16, 4.0e-16, 5.0e-16, 6.0e-16]) tiny_v_unit = tiny_v.get_unit_vector() self.assertAlmostEqual(tiny_v_unit.get_magnitude(), 1.0, places=6) @@ -43,6 +43,7 @@ def test_component(self): self.assertEqual(v[4], 30.0) self.assertRaises(IndexError, lambda: v[5]) self.assertRaises(IndexError, lambda: v[-6]) + def test_set(ind): v[ind] = 0. self.assertRaises(IndexError, test_set, 5) diff --git a/modules/algebra/test/test_vol.py b/modules/algebra/test/test_vol.py index 14e05b3099..faa6aee919 100644 --- a/modules/algebra/test/test_vol.py +++ b/modules/algebra/test/test_vol.py @@ -2,7 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math class Tests(IMP.test.TestCase): @@ -35,5 +34,6 @@ def test_enc(self): self.assertLess(sp[1], 30 * 30 * 30) self.assertGreater(sp[1], 25 * 25 * 25) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_xyz.py b/modules/algebra/test/test_xyz.py index 21e06a03f8..68de8db629 100644 --- a/modules/algebra/test/test_xyz.py +++ b/modules/algebra/test/test_xyz.py @@ -35,5 +35,6 @@ def test_cylinder_construction(self): self.assertAlmostEqual(q[2], 0., delta=.1) self.assertAlmostEqual(q[3], 0., delta=.1) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/algebra/test/test_zyz.py b/modules/algebra/test/test_zyz.py index 9a88203201..37cbb767d7 100644 --- a/modules/algebra/test/test_zyz.py +++ b/modules/algebra/test/test_zyz.py @@ -2,8 +2,6 @@ import IMP import IMP.test import IMP.algebra -import math -import random class Tests(IMP.test.TestCase): diff --git a/modules/atom/benchmark/benchmark_pdb.cpp b/modules/atom/benchmark/benchmark_pdb.cpp index 244ba91ec0..89db797042 100644 --- a/modules/atom/benchmark/benchmark_pdb.cpp +++ b/modules/atom/benchmark/benchmark_pdb.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/modules/atom/benchmark/benchmark_refiners.cpp b/modules/atom/benchmark/benchmark_refiners.cpp index c712401289..8b967a0cb9 100644 --- a/modules/atom/benchmark/benchmark_refiners.cpp +++ b/modules/atom/benchmark/benchmark_refiners.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/modules/atom/examples/Diffusion_decorator.py b/modules/atom/examples/Diffusion_decorator.py new file mode 100644 index 0000000000..0af08bd20b --- /dev/null +++ b/modules/atom/examples/Diffusion_decorator.py @@ -0,0 +1,35 @@ +## \example atom/Diffusion_decorator.py +# This is a simple example using the Diffusion decorator to set the coordinates +# and translational diffusion coefficient of some particles + +import IMP +import IMP.core +import IMP.atom +import IMP.algebra +import sys + +C0=[0,1,2] # in A +C1=[1,2,3] # in A +D1 = 3.0 # in A^2/fs +R0=5 # in A +IMP.setup_from_argv(sys.argv, "Diffusion decorator example") +m = IMP.Model() + +# Setup a diffusion particle with an implicitly-set diffusion coefficient +# using the Stokes-Einstein equation, treating radius as the Stokes radius +p0 = m.add_particle("diffusion0") +xyzr0 = IMP.core.XYZR.setup_particle(m, p0, + IMP.algebra.Sphere3D(C0, R0)) +d0 = IMP.atom.Diffusion.setup_particle(m, p0) +print("D automatically set to {:.2e} A^2/fs for radius {:.1f} A" + .format(d0.get_diffusion_coefficient(), xyzr0.get_radius())) + +# Explicitly change the diffusion coefficient: +d0.set_diffusion_coefficient(d0.get_diffusion_coefficient()/2.0) +print("D reset to {:.2e} A^2/fs".format(d0.get_diffusion_coefficient())) + +# Setup a diffusion particle with an explicitly-set diffusion coefficient +p1 = m.add_particle("diffusion1") +d1 = IMP.atom.Diffusion.setup_particle(m, p1, C1, D1) +print("D explicitly set to {:.2e} A^2/fs for coordinates {} A" + .format(d1.get_diffusion_coefficient(), d1.get_coordinates())) diff --git a/modules/atom/include/CHARMMParameters.h b/modules/atom/include/CHARMMParameters.h index 7c67cbe39f..6f2aed6d85 100644 --- a/modules/atom/include/CHARMMParameters.h +++ b/modules/atom/include/CHARMMParameters.h @@ -13,6 +13,7 @@ #include "ForceFieldParameters.h" #include "charmm_topology.h" #include "atom_macros.h" +#include #include #include @@ -35,10 +36,10 @@ struct CHARMMBondParameters { }); private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & force_constant & ideal; + template void serialize(Archive &ar) { + ar(force_constant, ideal); } }; @@ -56,10 +57,10 @@ struct CHARMMDihedralParameters { }); private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & force_constant & multiplicity & ideal; + template void serialize(Archive &ar) { + ar(force_constant, multiplicity, ideal); } }; diff --git a/modules/atom/include/Chain.h b/modules/atom/include/Chain.h index ff928e4407..9547b6237c 100644 --- a/modules/atom/include/Chain.h +++ b/modules/atom/include/Chain.h @@ -108,7 +108,7 @@ class IMPATOMEXPORT Chain : public Hierarchy { /** Usually the primary sequence of a chain can be uniquely deduced by iterating over all child Residue decorators and querying their type. However, this may not be possible in all cases (e.g. if there are gaps - in the sequence or parts that are not explictly represented). + in the sequence or parts that are not explicitly represented). \note The sequence set here should be consistent with that of any children of this Chain. This is not currently enforced. diff --git a/modules/atom/include/Diffusion.h b/modules/atom/include/Diffusion.h index 8296a8baf4..82a1c6f891 100644 --- a/modules/atom/include/Diffusion.h +++ b/modules/atom/include/Diffusion.h @@ -21,25 +21,37 @@ IMPATOM_BEGIN_NAMESPACE //! A decorator for a diffusing particle with a diffusion coefficient. -/** \ingroup helper - \ingroup decorators - \see BrownianDynamics - - Diffusion is used to decorate a diffusing particle with a diffusion - coefficient D. D is assumed to be in units of \f$A^2/fs\f$. +/** Diffusion is used to decorate a particle with XYZ coordinates (since it + inhertis from XYZ) and a translational diffusion coefficient D. + D is specified in units of \f$A^2/fs\f$, and it is used by eg + IMP's Brownian dynamics simulator. It can be set explicitly or inferred + implicitly from the radius. + \ingroup helper + \ingroup decorators + \include Diffusion_decorator.py \see RigidBodyDiffusion + \see BrownianDynamics */ class IMPATOMEXPORT Diffusion : public IMP::core::XYZ { static void do_setup_particle(Model *m, ParticleIndex pi, Float D) { - IMP_USAGE_CHECK(XYZ::get_is_setup(m, pi), - "Particle must already be an XYZ particle"); + if(!XYZ::get_is_setup(m,pi)) + { + XYZ::setup_particle(m, pi, algebra::Vector3D(0,0,0)); + } m->add_attribute(get_diffusion_coefficient_key(), pi, D); } static void do_setup_particle(Model *m, ParticleIndex pi, const algebra::Vector3D &v, Float D) { - XYZ::setup_particle(m, pi, v); + if(XYZ::get_is_setup(m,pi)) + { + XYZ(m,pi).set_coordinates(v); + } + else + { + XYZ::setup_particle(m, pi, v); + } do_setup_particle(m, pi, D); } @@ -55,30 +67,36 @@ class IMPATOMEXPORT Diffusion : public IMP::core::XYZ { public: IMP_DECORATOR_METHODS(Diffusion, IMP::core::XYZ); - /** - Decorates the particle as a Diffusion particle with a - diffusion coefficient D. - */ + //! Setup the particle with the specified diffusion coefficient + /** + If the particle does not have coordinates, it is decorated as XYZ + and its coordinates are set to [0,0,0], otherwise the coordinates + remain the same. + */ IMP_DECORATOR_SETUP_1(Diffusion, Float, D); - /** - Decorates the particle as a core::XYZ particle with - coordinates v and as a Diffusion particle with a - diffusion coefficient D. - */ + //! Setup the particle with the specified coordinates and diffusion coefficient IMP_DECORATOR_SETUP_2(Diffusion, algebra::Vector3D, v, Float, D); + //! Setup the particle with a diffusion coefficient automatically + //! inferred from its radius using the Stokes-Einstein equation. /** - Decorates the particle as a Diffusion particle with the - diffusion coefficient of a particle with a stokes radius - of core::XYZR(m, pi).get_radius() at the default IMP - temperature (297.15K). - - \Note: It assumed particle is already a core::XYZR particle. + The diffusion coefficient is computed implicitly using the + Stokes-Einstein equation by calling + IMP::atom::get_einstein_diffusion_coefficient(R), where the + Stokes radius R is core::XYZR::get_radius() and the temperature + is the default IMP temperature of 297.15K. + + \note If the simulation temperature or particle radius change, + the diffusion coefficient must be changed explicity e.g., using + set_diffusion_coefficient() + \note This constructor can be used only on particles that have + a radius field, e.g. decorated as IMP::core::XYZR. */ IMP_DECORATOR_SETUP_0(Diffusion); //! Return true if the particle is an instance of Diffusion static bool get_is_setup(Model *m, ParticleIndex p) { - return m->get_has_attribute(get_diffusion_coefficient_key(), p); + return m->get_has_attribute(get_diffusion_coefficient_key(), p) && + XYZ::get_is_setup(m, p); } //! set diffusion coefficient in \f$A^2/fs\f$ void set_diffusion_coefficient(double d) { @@ -98,24 +116,44 @@ IMPATOMEXPORT double get_diffusion_coefficient_from_cm2_per_second(double din); IMP_DECORATORS(Diffusion, Diffusions, core::XYZs); -/** A rigid body that is diffusing, so it also has a rotation diffusion - coefficient. The units on the rotational coefficient are - \f$radians^2/fs\f$. +/** A rigid body that is diffusing, so it also has coordinates and a + rotational diffusion coefficient. The units on the rotational + coefficient are \f$radians^2/fs\f$. - The translational and rotational diffusion coefficients are set automatically - using IMP::atom::get_einstein_diffusion_coefficient(radius) and - IMP::atom::get_einstein_rotational_diffusion_coefficient(radius) for radius - IMP::core::XYZR(m, pi).get_radius(). + The translational and rotational diffusion coefficients are computed + automatically using + IMP::atom::get_einstein_diffusion_coefficient(radius) and + IMP::atom::get_einstein_rotational_diffusion_coefficient(radius) + for radius IMP::core::XYZR(m, pi).get_radius() and default IMP + temperature of 297.15, but they can be overridden explicitly. Note that different translational and rotational coefficients should probably be set manually if the temperature is not the default IMP temperature. + + \see Diffusion + \see BrownianDynamics */ class IMPATOMEXPORT RigidBodyDiffusion : public Diffusion { static void do_setup_particle(Model *m, ParticleIndex pi); public: IMP_DECORATOR_METHODS(RigidBodyDiffusion, Diffusion); - //! All diffusion coefficients are determined from the radius + //! Setup this particle with automatically inferred translation and + //! rotational diffusion coefficients + /** + The diffusion coefficients are computed using + core::XYZR::get_radius() for the Stokes radius and the + default IMP temperature of 297.15K. + + \note If the simulation temperature or particle radius change, + the diffusion coefficient must be changed explicity e.g., using + set_diffusion_coefficient() + \note The particle must have been decorated with core::XYZR + for this constructor to be used + The diffusion coefficients are inferred automatically from the particle's radius + using IMP::atom::get_einstein_diffusion_coefficient(radius) and + IMP::atom::get_einstein_rotational_diffusion_coefficient(radius). + */ IMP_DECORATOR_SETUP_0(RigidBodyDiffusion); //! returns the rotational diffusion coefficient in \f$radians^2/fs\f$ @@ -132,9 +170,10 @@ class IMPATOMEXPORT RigidBodyDiffusion : public Diffusion { d); } - //! Return true if the particle is an instance of an Diffusion + //! Return true if the particle is an instance of an RigidBodyDiffusion static bool get_is_setup(Model *m, ParticleIndex p) { - return m->get_has_attribute(get_rotational_diffusion_coefficient_key(), p); + return m->get_has_attribute(get_rotational_diffusion_coefficient_key(), p) && + Diffusion::get_is_setup(m, p); } //! Get the D key diff --git a/modules/atom/include/DihedralSingletonScore.h b/modules/atom/include/DihedralSingletonScore.h index 87a5927fad..b9122b1b1b 100644 --- a/modules/atom/include/DihedralSingletonScore.h +++ b/modules/atom/include/DihedralSingletonScore.h @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include IMPATOM_BEGIN_NAMESPACE @@ -36,7 +39,14 @@ class IMPATOMEXPORT DihedralSingletonScore : public SingletonScore { Model *m, const ParticleIndexes &pis) const override; IMP_SINGLETON_SCORE_METHODS(DihedralSingletonScore); IMP_OBJECT_METHODS(DihedralSingletonScore); - ; + + private: + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(DihedralSingletonScore); }; IMP_OBJECTS(DihedralSingletonScore, DihedralSingletonScores); diff --git a/modules/atom/include/Hierarchy.h b/modules/atom/include/Hierarchy.h index f4f406e1cd..062159b7b4 100644 --- a/modules/atom/include/Hierarchy.h +++ b/modules/atom/include/Hierarchy.h @@ -472,6 +472,10 @@ IMPATOMEXPORT Hierarchy create_clone_one(Hierarchy d); removed from the Model. If this particle has a parent, it is removed from the parent. Any provenance information for this Hierarchy is also removed. + + If any particle in the Hierarchy is a rigid body member, it is + removed from the rigid body. (This is currently slow; if possible, + destroy the rigid bodies first.) \relates Hierarchy */ IMPATOMEXPORT void destroy(Hierarchy d); diff --git a/modules/atom/include/MolecularDynamics.h b/modules/atom/include/MolecularDynamics.h index 71fc82e731..1effb6c56c 100644 --- a/modules/atom/include/MolecularDynamics.h +++ b/modules/atom/include/MolecularDynamics.h @@ -90,8 +90,9 @@ class IMPATOMEXPORT AngularVelocity : public Decorator { } }; -//! Simple molecular dynamics optimizer. -/** The particles to be optimized must have optimizable x,y,z attributes +//! Simple molecular dynamics simulator. +/** + The particles to be optimized must have optimizable x,y,z attributes and a non-optimizable mass attribute; this optimizer assumes the score to be energy in kcal/mol, the xyz coordinates to be in angstroms, and the mass to be in AMU (g/mol). diff --git a/modules/atom/include/Simulator.h b/modules/atom/include/Simulator.h index 0d97cff2d3..10d49b4048 100644 --- a/modules/atom/include/Simulator.h +++ b/modules/atom/include/Simulator.h @@ -115,7 +115,7 @@ class IMPATOMEXPORT Simulator : public Optimizer { void set_time_step(double ts) { set_maximum_time_step(ts); } #endif - // returns kt in units of kCal/mol for temperature get_temperature() [K] + // returns kt in units of kcal/mol for temperature get_temperature() [K] double get_kt() const; /** diff --git a/modules/atom/include/charmm_topology.h b/modules/atom/include/charmm_topology.h index cc3d5de38c..0ba29868c3 100644 --- a/modules/atom/include/charmm_topology.h +++ b/modules/atom/include/charmm_topology.h @@ -13,7 +13,7 @@ #include "Hierarchy.h" #include "Atom.h" #include -#include +#include #include #include @@ -31,10 +31,10 @@ class CHARMMAtomTopology { std::string charmm_type_; double charge_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & name_ & charmm_type_ & charge_; + template void serialize(Archive &ar) { + ar(name_, charmm_type_, charge_); } public: diff --git a/modules/atom/include/pdb.h b/modules/atom/include/pdb.h index f7225ba1fe..2cd9e333f3 100644 --- a/modules/atom/include/pdb.h +++ b/modules/atom/include/pdb.h @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include IMPATOM_BEGIN_NAMESPACE @@ -594,11 +597,19 @@ class IMPATOMEXPORT WritePDBOptimizerState : public OptimizerState { std::string filename_; ParticleIndexes pis_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), filename_, pis_); + } + IMP_OBJECT_SERIALIZE_DECL(WritePDBOptimizerState); + public: WritePDBOptimizerState(Model *m, const ParticleIndexesAdaptor &pis, std::string filename); WritePDBOptimizerState(const atom::Hierarchies mh, std::string filename); + WritePDBOptimizerState() {} protected: virtual void do_update(unsigned int call) override; diff --git a/modules/atom/pyext/swig.i-in b/modules/atom/pyext/swig.i-in index 79512f7092..f652e31238 100644 --- a/modules/atom/pyext/swig.i-in +++ b/modules/atom/pyext/swig.i-in @@ -1,8 +1,3 @@ -%{ -#include -#include -%} - namespace IMP { namespace atom { %warnfilter(403) ForceFieldParameters; @@ -66,7 +61,7 @@ IMP_SWIG_OBJECT(IMP::atom, CPDBSelector, CPDBSelectors); IMP_SWIG_OBJECT(IMP::atom, ChainPDBSelector, ChainPDBSelectors); IMP_SWIG_OBJECT(IMP::atom, CoulombPairScore, CoulombPairScores); IMP_SWIG_OBJECT(IMP::atom, CoverBond, CoverBonds); -IMP_SWIG_OBJECT(IMP::atom, DihedralSingletonScore, DihedralSingletonScores); +IMP_SWIG_OBJECT_SERIALIZE(IMP::atom, DihedralSingletonScore, DihedralSingletonScores); IMP_SWIG_OBJECT(IMP::atom, DopePairScore, DopePairScores); IMP_SWIG_OBJECT(IMP::atom, LoopStatisticalPairScore, LoopStatisticalPairScores); IMP_SWIG_OBJECT(IMP::atom, OrientedSoapPairScore, OrientedSoapPairScores); @@ -95,7 +90,7 @@ IMP_SWIG_OBJECT(IMP::atom, SmoothingFunction, SmoothingFunctions); IMP_SWIG_OBJECT(IMP::atom, StereochemistryPairFilter, StereochemistryPairFilters); IMP_SWIG_OBJECT(IMP::atom, VelocityScalingOptimizerState, VelocityScalingOptimizerStates); IMP_SWIG_OBJECT(IMP::atom, WaterPDBSelector,WaterPDBSelectors); -IMP_SWIG_OBJECT(IMP::atom, WritePDBOptimizerState, WritePDBOptimizerStates); +IMP_SWIG_OBJECT_SERIALIZE(IMP::atom, WritePDBOptimizerState, WritePDBOptimizerStates); IMP_SWIG_VALUE_INSTANCE(IMP::atom, AtomType, AtomType, AtomTypes); IMP_SWIG_VALUE_SERIALIZE(IMP::atom, CHARMMAtomTopology, CHARMMAtomTopologies); IMP_SWIG_VALUE(IMP::atom, CHARMMBondEndpoint, CHARMMBondEndpoints); diff --git a/modules/atom/src/BrownianDynamics.cpp b/modules/atom/src/BrownianDynamics.cpp index 50fabb391c..a7dc331965 100644 --- a/modules/atom/src/BrownianDynamics.cpp +++ b/modules/atom/src/BrownianDynamics.cpp @@ -63,10 +63,11 @@ bool BrownianDynamics::get_is_simulation_particle(ParticleIndex pi) } namespace { -/** get the force displacement term in the Ermak-Mccammon equation - for coordinate i of particle pi in model m, with time step dt [fs] and ikT=1/kT [mol/kcal] +/** get the force translation term in the Ermak-Mccammon equation + for coordinate i of particle pi in model m, with time step dt [fs] + and ikT=1/kT [mol/kcal] */ -inline double get_force_displacement(Model *m, ParticleIndex pi, +inline double get_force_i(Model *m, ParticleIndex pi, unsigned int i, double dt, double ikT) { Diffusion d(m, pi); double nforce(-d.get_derivative(i)); // [kCal/mol/A] @@ -84,7 +85,7 @@ inline double get_force_displacement(Model *m, ParticleIndex pi, << std::endl;*/ return force_term; } -// returns i'th torque displacement in radians given model m, particle index p, +// returns i'th torque translation in radians given model m, particle index p, // torque component number i, time dt in fs, and ikT (1/kT) in mol/kcal inline double get_torque(Model *m, ParticleIndex p, unsigned int i, double dt, double ikT) { @@ -104,19 +105,20 @@ inline double get_torque(Model *m, ParticleIndex p, return -force_term; } - // returns the std-dev for the random displacement in the Ermak-Mccammon equation -inline double get_sigma_displacement(Model *m, ParticleIndex p, + // returns the std-dev for the random translation in the Ermak-Mccammon equation + // for a single translational degree of freedom (e.g. x-coordinate) +inline double get_translational_sigma_i(Model *m, ParticleIndex p, double dtfs) { - // 6.0 is 2.0 for the variance of each translation dof (Barak) - // 6.0 since we are picking radius rather than the coordinates (Daniel) double dd = Diffusion(m, p).get_diffusion_coefficient(); - return sqrt(6.0 * dd * dtfs); + return sqrt(2.0 * dd * dtfs); } - // returns the std-dev for the random rotation angle in the Ermak-Mccammon equation -inline double get_rotational_sigma(Model *m, ParticleIndex p, + // returns the std-dev for the random rotation angle in the Ermak-Mccammon equation + // for all three rotational degree of freedom of a single particle (a single rotation + // of variance $6 x D_{rot} x \DeltaT$ is used to approximate the variance of three + // indepnendent rotations of $2 x D_{rot} * \DeltaT$ +inline double get_rotational_sigma_total(Model *m, ParticleIndex p, double dtfs) { - // 6.0 is 2.0 for the variance of each rotational dof (Barak) double dr = RigidBodyDiffusion(m, p).get_rotational_diffusion_coefficient(); return sqrt(6.0 * dr * dtfs); } @@ -132,10 +134,10 @@ void BrownianDynamics::setup(const ParticleIndexes &ips) { Model* m = get_model(); get_scoring_function()->evaluate(true); for (unsigned int i = 0; i < ps.size(); ++i) { - double c = get_sigma_displacement(m, ips[i], dtfs); + double c = get_translational_sigma_i(m, ips[i], dtfs); ms = std::max(ms, c); for (unsigned int j = 0; j < 3; ++j) { - double f = get_force_displacement(m, ips[i], j, dtfs, ikT); + double f = get_force_i(m, ips[i], j, dtfs, ikT); mf = std::max(mf, f); } } @@ -164,9 +166,9 @@ void BrownianDynamics::advance_coordinates_1(ParticleIndex pi, double ikT) { Diffusion d(get_model(), pi); core::XYZ xd(get_model(), pi); - algebra::Vector3D force(get_force_displacement(get_model(), pi, 0, dt, ikT), - get_force_displacement(get_model(), pi, 1, dt, ikT), - get_force_displacement(get_model(), pi, 2, dt, ikT)); + algebra::Vector3D force(get_force_i(get_model(), pi, 0, dt, ikT), + get_force_i(get_model(), pi, 1, dt, ikT), + get_force_i(get_model(), pi, 2, dt, ikT)); algebra::Vector3D dX = (force - forces_[i]) / 2.0; check_dX(dX, max_step_in_A_); xd.set_coordinates(xd.get_coordinates() + dX); @@ -176,13 +178,13 @@ void BrownianDynamics::advance_coordinates_0(ParticleIndex pi, unsigned int i, double dtfs, double ikT) { core::XYZ xd(get_model(), pi); - double sigma = get_sigma_displacement(get_model(), pi, dtfs); - double r = get_sample(sigma); - algebra::Vector3D random_dX = r * algebra::get_random_vector_on_unit_sphere(); + double sigma_i = get_translational_sigma_i(get_model(), pi, dtfs); + algebra::Vector3D random_dX + (get_sample(sigma_i), get_sample(sigma_i), get_sample(sigma_i)); algebra::Vector3D force_dX - (get_force_displacement(get_model(), pi, 0, dtfs, ikT), - get_force_displacement(get_model(), pi, 1, dtfs, ikT), - get_force_displacement(get_model(), pi, 2, dtfs, ikT)); + (get_force_i(get_model(), pi, 0, dtfs, ikT), + get_force_i(get_model(), pi, 1, dtfs, ikT), + get_force_i(get_model(), pi, 2, dtfs, ikT)); if (srk_) { forces_[i] = force_dX; } @@ -210,7 +212,10 @@ void BrownianDynamics::advance_coordinates_0(ParticleIndex pi, void BrownianDynamics::advance_orientation_0(ParticleIndex pi, double dtfs, double ikT) { core::RigidBody rb(get_model(), pi); - double sigma = get_rotational_sigma(get_model(), pi, dtfs); + // Note - 6*dr*dtfs*N(0,1) for sigma is an approximation. the real angle should be 2*X where + // X is a random variable drawn from the Chi2 distribution with 3 dofs + // (corresponding to each of the 3 rotational dofs) + double sigma = get_rotational_sigma_total(get_model(), pi, dtfs); double angle = get_sample(sigma); algebra::Transformation3D nt = rb.get_reference_frame().get_transformation_to(); diff --git a/modules/atom/src/DihedralSingletonScore.cpp b/modules/atom/src/DihedralSingletonScore.cpp index 05e013dac4..8f9db30450 100644 --- a/modules/atom/src/DihedralSingletonScore.cpp +++ b/modules/atom/src/DihedralSingletonScore.cpp @@ -66,4 +66,6 @@ ModelObjectsTemp DihedralSingletonScore::do_get_inputs( return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::atom::DihedralSingletonScore); + IMPATOM_END_NAMESPACE diff --git a/modules/atom/src/Hierarchy.cpp b/modules/atom/src/Hierarchy.cpp index 839729f2c7..16d6c85882 100644 --- a/modules/atom/src/Hierarchy.cpp +++ b/modules/atom/src/Hierarchy.cpp @@ -550,6 +550,11 @@ void destroy(Hierarchy d) { prov = previous; } } + if (core::RigidMember::get_is_setup(all[i])) { + core::RigidBody rb = core::RigidMember(all[i]).get_rigid_body(); + rb.remove_member(all[i]); + } + Hierarchy hc(all[i]); while (hc.get_number_of_children() > 0) { hc.remove_child(hc.get_child(hc.get_number_of_children() - 1)); diff --git a/modules/atom/src/Simulator.cpp b/modules/atom/src/Simulator.cpp index dd3bc679cc..6da660c8a4 100644 --- a/modules/atom/src/Simulator.cpp +++ b/modules/atom/src/Simulator.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -48,9 +48,9 @@ double Simulator::do_simulate(double time) { setup(ps); double target = current_time_ + time; - boost::scoped_ptr pgs; + boost::scoped_ptr pgs; if (get_log_level() == PROGRESS) { - pgs.reset(new boost::progress_display(time / max_time_step_)); + pgs.reset(new IMP::internal::BoostProgressDisplay(time / max_time_step_)); } while (current_time_ < target) { last_time_step_ = do_step(ps, max_time_step_); diff --git a/modules/atom/src/pdb.cpp b/modules/atom/src/pdb.cpp index ce9a13f427..30b256f2bc 100644 --- a/modules/atom/src/pdb.cpp +++ b/modules/atom/src/pdb.cpp @@ -250,8 +250,8 @@ Hierarchies read_pdb(std::istream& in, std::string name, std::string filename, } if (!has_atom) { IMP_WARN( - "Sorry, unable to read atoms from PDB file." - " Thanks for the effort.\n"); + "No atoms were read from " << filename + << "; perhaps it is not a PDB file.\n"); return Hierarchies(); } if (!noradii) { @@ -531,4 +531,6 @@ ModelObjectsTemp WritePDBOptimizerState::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::atom::WritePDBOptimizerState); + IMPATOM_END_NAMESPACE diff --git a/modules/atom/test/expensive_test_bd.py b/modules/atom/test/expensive_test_bd.py index 0892fcfc8c..4420359b14 100644 --- a/modules/atom/test/expensive_test_bd.py +++ b/modules/atom/test/expensive_test_bd.py @@ -4,6 +4,7 @@ import IMP.core import IMP.atom import IMP.statistics +import math try: import sympy from sympy.physics.units import * @@ -11,29 +12,30 @@ except: use_sympy = False -import math -nreps = 1000 +NREPS = 10000 if IMP.get_check_level() == IMP.USAGE_AND_INTERNAL: - nreps = nreps / 100 -nsteps = 500 -timestep = 1000 + NREPS = NREPS // 1000 +NSTEPS = 50 +TIMESTEP = 10000 D = .0002 -k = .01 -f = .1 -temperature = 297.15 -kt_silly = IMP.atom.get_kt(temperature) # (273.) -print("KT", kt_silly) -t = timestep * nsteps +K_HARMONIC = .02 # harmonic force coefficient in kcal/mol/A^2 +F_LINEAR = .1 # constant linear force in kcal/mol/A +T = 297.15 +KT_SILLY = IMP.atom.get_kt(T) +print("KT=%f kcal/mol" % KT_SILLY) +t = TIMESTEP * NSTEPS +print("NREPS=%d NSTEPS=%d} dT=%d fs time-per-simulation=%d fs" + % (NREPS, NSTEPS, TIMESTEP, t)) if use_sympy: - timestep_u = timestep * femto * second - t_u = timestep_u * nsteps + timestep_u = TIMESTEP * femto * second + t_u = timestep_u * NSTEPS angstrom = sympy.Rational(1, 10) * nano * meter D_u = .0002 * angstrom * angstrom / (femto * second) k_u = IMP.atom.get_spring_constant_in_femto_newtons_per_angstrom( - k) * femto * newton / angstrom - f_u = IMP.atom.get_force_in_femto_newtons(f) * femto * newton - kT_u = IMP.atom.get_energy_in_femto_joules(kt_silly) * femto * joule + K_HARMONIC) * femto * newton / angstrom + f_u = IMP.atom.get_force_in_femto_newtons(F_LINEAR) * femto * newton + kT_u = IMP.atom.get_energy_in_femto_joules(KT_SILLY) * femto * joule else: angstrom = 1.0 @@ -41,6 +43,11 @@ class Tests(IMP.test.TestCase): def _setup(self): + ''' + Setup a model with a single particle with diffusion coefficient D + and BD at temperature T and timestep TIMESTEP + Return (model, particle as XYZR, particle as Diffusion, bd object) + ''' m = IMP.Model() IMP.set_log_level(IMP.SILENT) p = IMP.Particle(m) @@ -51,38 +58,50 @@ def _setup(self): d.set_diffusion_coefficient(D) IMP.set_check_level(IMP.NONE) bd = IMP.atom.BrownianDynamics(m) - bd.set_maximum_time_step(float(timestep)) - bd.set_temperature(temperature) + bd.set_maximum_time_step(float(TIMESTEP)) + bd.set_temperature(T) xyzr.set_coordinates_are_optimized(True) return (m, xyzr, d, bd) - def _measure(self, m, xyzr, bd): + def _measure_stats(self, m, xyzr, bd, default_coords=[0,0,0]): + ''' optimize NREPS times for NSTEPS using BD + return a tuple with: + 1. mean displacement 3D vector after NSTEPS + 2. std-dev displacement 3D vector after NSTEPS + 3. NREPS + ''' ub = IMP.algebra.Vector3D(100, 100, 100) # was .1 h = IMP.statistics.Histogram3D(.3, IMP.algebra.BoundingBox3D(-ub, ub)) # IMP.benchmark.set_is_profiling(True) - for i in range(0, nreps): - xyzr.set_coordinates(IMP.algebra.Vector3D(0, 0, 0)) - bd.optimize(nsteps) + print("Computing mean and std from %d simulations" % NREPS) + for i in range(0, NREPS): + xyzr.set_coordinates(IMP.algebra.Vector3D(default_coords)) + bd.optimize(NSTEPS) h.add(xyzr.get_coordinates()) - if i % 1000 == 0: + if (i % 1000 == 0) or (i == NREPS-1): print(i, xyzr.get_coordinates()) - print("computing") mn = h.get_mean() - print(mn) std = h.get_standard_deviation(mn) - print(mn, std) + print("mean=%s, std=%s" % (mn, std)) # IMP.benchmark.set_is_profiling(False) - return (mn, std, nreps) + return (mn, std, NREPS) - def _get_sigma_error(self, sigma, n): - return 2.0 * sigma ** 4 / n + def _get_sigma_stderr(self, sigma, n): + ''' get sample estimate for sigma estimated from n samples + see https://web.eecs.umich.edu/~fessler/papers/files/tr/stderr.pdf + The estimator of sigma is K_N * S where S is the estimator of variance + Eq. 3 gives the ratio between the std-dev of sigma and sigma, and for n>10 or so, + we can assume K_n is 1.0 for practical purposes. + ''' + return sigma / math.sqrt(2*(n-1)) # estimate for a large n that ignores the K_n distribution + # return 2.0 * sigma ** 4 / n # TODO: how so? # def _measure_x(self, m, xyzr, bd): # ub= IMP.algebra.Vector1D(50) # h = IMP.statistics.Histogram1D(.1, IMP.algebra.BoundingBox1D(-ub, ub)) - # for i in range(0,nreps): + # for i in range(0,NREPS): # xyzr.set_coordinates(IMP.algebra.Vector3D(0,0,0)) - # bd.optimize(nsteps) + # bd.optimize(NSTEPS) # h.add(IMP.algebra.Vector1D(xyzr.get_coordinates()[0])) # if i%1000==0: # print i, xyzr.get_coordinates() @@ -91,112 +110,104 @@ def _get_sigma_error(self, sigma, n): # print mn, std # return mn, std - def _get_sigma_free(self): - sigma = (6.0 * t_u * D_u) ** sympy.Rational(1, 2) - print("GET SIGMA FREE") - print(sigma) - print(math.sqrt(6 * t * D)) - return sigma - - def _get_sigma_1_free(self): + def _get_sigma_i_free(self): + ''' get sigma for a single d.o.f. ''' if use_sympy: sigma = (2.0 * t_u * D_u) ** sympy.Rational(1, 2) return sigma else: - print("Computed SIGMA 1 FREE", math.sqrt(2 * t * D)) - return 14 + sigma= math.sqrt(2 * t * D) + print("Theoretical sigma per d.o.f. for D=%d A^2/fs and t=%d fs " + "FREE sigma=%.2f A" % (D, t, sigma)) + return sigma def _get_sigma_harmonic(self): + # computes the expected sigma while taking into account the + # relaxation time for the harmonic spring due to diffuson limit if use_sympy: delta2 = (kT_u / k_u) delta = delta2 ** sympy.Rational(1, 2) print("delta", delta) - taut = 2 * delta2 / D_u + taut = 2.0 * delta2 / D_u print("taut", taut.evalf()) tau = t_u / taut print("tau", tau.evalf()) - scale = 2 * delta2 - print("scale", scale.evalf()) - sigma2 = scale * (1 - sympy.E ** (-4 * tau)) + scale = delta2 + sigma2 = delta2 * (1 - sympy.E ** (-4 * tau)) print("sigma2", sigma2.evalf()) sigma = sigma2 ** sympy.Rational(1, 2) print("sigma", sigma.evalf()) return sigma else: - delta2 = kt_silly / k + # the sigma for a harmonic spring with spring-constant k should be when the spring energy + # k * dX^2/2 equals 0.5*kB*T. So dX=sqrt(kB*T/k) + delta2 = KT_SILLY / K_HARMONIC # when the spring energy is 0.5*kB*T delta = math.sqrt(delta2) - taut = 2 * delta2 / D - tau = t / taut - scale = 2 * delta2 - sigma2 = scale * (1 - math.exp(-4 * tau)) + taut = 2 * delta2 / D # spring relaxation time - time to diffuse delta2 randomly + tau = t / taut # number of times relaxed + sigma2 = delta2 * (1 - math.exp(-4 * tau)) sigma = math.sqrt(sigma2) - print("CALCULATED SIGMA", sigma) -# return 10 - return ( - # TODO: this should be evaluted - set it just to make the test - # work - a github feature was opened for this - 7.56 - ) + print("CALCULATED SIGMA %.2f A TAU=%.3f TAUT=%.1f RELAXATION=%.3f" + % (sigma, tau, taut, 1-math.exp(-4*tau))) + return sigma def _get_sigma_limit_harmonic(self): if use_sympy: - sigmass = 2 * kT_u / k_u + sigmass = kT_u / k_u print("sigma steady state 2", sigmass.evalf()) return sigmass ** sympy.Rational(1, 2) else: - sigmass = math.sqrt(2 * kt_silly / k) - print("CALCULATED SIGMA STEADY STATE", sigmass) - return ( - # TODO: this should be evaluated. was 0, now it's something - # else just to make the test work - and actually the results - # are consistently different. a github feature was opened - sigmass - ) - - def _check(self, mn, std, calc_mn, calc_std, n): + sigmass = math.sqrt(KT_SILLY / K_HARMONIC) # when the spring energy is 0.5*kB*T + print("CALCULATED SIGMA STEADY STATE %.2f A" % sigmass) + return sigmass + + def _check(self, simulated_mn, simulated_std, theoretical_mn, theoretical_std, n): if use_sympy: - print([(x.evalf() / angstrom).evalf() for x in calc_std]) - print("mean", mn, [float((x / angstrom).evalf()) for x in calc_mn]) - print("std", std, [float((x / angstrom).evalf()) for x in calc_std]) + print([(x.evalf() / angstrom).evalf() for x in theoretical_std]) + print("mean", simulated_mn, [float((x / angstrom).evalf()) for x in theoretical_mn]) + print("std", simulated_std, [float((x / angstrom).evalf()) for x in theoretical_std]) for i in range(0, 3): + mn_max_error = 2.0 * simulated_std[i] * 2 / n ** .5 # 2 x s.e.m. estimator from empricial std TODO: x2 for 95% interval, but why multiply by 2 twice? + sigma_max_error = 2.0 * 2.0 * self._get_sigma_stderr(simulated_std[i], n) # I am multiplying by 4 instead of 2 just to make it work - should see why it's practically large + print("Max allowed error mean=%.2f A, sigma=%.2f A" + % (mn_max_error, sigma_max_error)) + if use_sympy: self.assertAlmostEqual( - mn[i], - float((calc_mn[i] / angstrom).evalf()), - delta=2.0 * std[i] * 2 / n ** .5) + simulated_mn[i], + float((theoretical_mn[i] / angstrom).evalf()), + delta=mn_max_error) self.assertAlmostEqual( - std[i], - float((calc_std[i] / angstrom).evalf()), - delta=2.0 * self._get_sigma_error(std[i], - n)) + simulated_std[i], + float((theoretical_std[i] / angstrom).evalf()), + delta=sigma_max_error) else: self.assertAlmostEqual( - mn[i], - float(calc_mn[i] / angstrom), - delta=2.0 * std[i] * 2 / n ** .5) + simulated_mn[i], + float(theoretical_mn[i] / angstrom), + delta=mn_max_error) self.assertAlmostEqual( - std[i], - float(calc_std[i] / angstrom), - delta=2.0 * self._get_sigma_error(std[i], - n)) + simulated_std[i], + float(theoretical_std[i] / angstrom), + delta=sigma_max_error) def test_free(self): - """Test brownian free diffusion""" - print("\ntest_free") + """Test brownian free diffusion for an unrestrained particle""" + print("\n\ntest_free") #self.skipTest("too expensive") (m, xyzr, d, bd) = self._setup() - sigma = self._get_sigma_1_free() - print("free sigma is", sigma) + sigma = self._get_sigma_i_free() + print("theoretical free sigma per d.o.f. is %.2f A^2/fs" % sigma) r = IMP.RestraintSet(m) # "Empty" restraint bd.set_scoring_function([r]) - (mn, std, nreps) = self._measure(m, xyzr, bd) - print(mn, std) + (mn, std, NREPS) = self._measure_stats(m, xyzr, bd) self._check(mn, std, [0 * angstrom, 0 * angstrom, 0 * angstrom], - [sigma, sigma, sigma], nreps) + [sigma, sigma, sigma], NREPS) + print("FINISHED FREE\n\n") def test_linear(self): - """Test brownian linear diffusion""" - print("\ntest_linear") + """Test brownian linear diffusion for a linearly-restrained particle""" + print("\n\ntest_linear") #self.skipTest("too expensive") # from of course notes http://www.ks.uiuc.edu/~kosztin/ (m, xyzr, d, bd) = self._setup() @@ -207,45 +218,49 @@ def test_linear(self): mean = -D_u * f_u * t_u / kT_u else: # mean=-18 # -18 is wrong - was made for the wrong simulation temperature - mean = -D * f * t / kt_silly - print("Calculated mean linear D", mean) - print("mean", mean) - h = IMP.core.Linear(0, f) + mean = -D * F_LINEAR * t / KT_SILLY + print("Theoretical mean x-coordinate: %.2f A" % mean) + h = IMP.core.Linear(0, F_LINEAR) dss = IMP.core.AttributeSingletonScore( h, IMP.core.XYZ.get_xyz_keys()[0]) r = IMP.core.SingletonRestraint(m, dss, xyzr) bd.set_scoring_function([r]) - sigma = self._get_sigma_1_free() - mn, std, nreps = self._measure(m, xyzr, bd) + sigma = self._get_sigma_i_free() + mn, std, NREPS = self._measure_stats(m, xyzr, bd) self._check(mn, std, [mean, 0 * angstrom, 0 * angstrom], - [sigma, sigma, sigma], nreps) + [sigma, sigma, sigma], NREPS) + print("FINISHED LINEAR\n") def test_harmonic(self): - """Test a brownian harmonic""" - print("\ntest_harmonic") + """Test a brownian dynamics for a harmonically-restrained particle + applied only on the x-coordinate (thus limiting its diffusion)""" + print("\n\ntest_harmonic") #self.skipTest("too expensive") # taken from chapter 13 of course notes # http://www.ks.uiuc.edu/~kosztin/ + print() (m, xyzr, d, bd) = self._setup() - sigma = self._get_sigma_harmonic() - print("harmonic sigma", sigma) - sigmaf = self._get_sigma_1_free() + sigmah = self._get_sigma_harmonic() + print("harmonic sigma=%.2f A" % sigmah) + sigmaf = self._get_sigma_i_free() sigmass = self._get_sigma_limit_harmonic() - - h = IMP.core.Harmonic(0, k) + X_EQUILIBRIUM_A = 20 + h = IMP.core.Harmonic(X_EQUILIBRIUM_A, K_HARMONIC) dss = IMP.core.AttributeSingletonScore( h, IMP.core.XYZ.get_xyz_keys()[0]) r = IMP.core.SingletonRestraint(m, dss, xyzr) bd.set_scoring_function([r]) - mn, std, nreps = self._measure(m, xyzr, bd) - print("Mean / std / sigma / sigmaf / sigmass") + mn, std, NREPS = self._measure_stats(m, xyzr, bd, + default_coords=[X_EQUILIBRIUM_A,0,0]) + print("Mean / std / sigmah / sigmaf / sigmass") print(mn) print(std) - print(sigma) + print(sigmah) print(sigmaf) print(sigmass) - self._check(mn, std, [0 * angstrom, 0 * angstrom, 0 * angstrom], - [sigma, sigmaf, sigmaf], nreps) + self._check(mn, std, [X_EQUILIBRIUM_A, 0 * angstrom, 0 * angstrom], + [sigmah, sigmaf, sigmaf], NREPS) + print("FINISHED HARMONIC\n") if __name__ == '__main__': IMP.test.main() diff --git a/modules/atom/test/test_charmm_topology.py b/modules/atom/test/test_charmm_topology.py index d25b83b700..f1eabf88cd 100644 --- a/modules/atom/test/test_charmm_topology.py +++ b/modules/atom/test/test_charmm_topology.py @@ -97,6 +97,7 @@ def test_segments_python_list(self): self.assertNotIn(st_not_in, t.segments) self.assertEqual(t.segments.index(st), 5) self.assertRaises(ValueError, t.segments.index, st, start=6) + self.assertRaises(ValueError, t.segments.index, st, start=0, stop=0) self.assertRaises(ValueError, t.segments.index, st_not_in) t.segments.remove(st) self.assertRaises(ValueError, t.segments.index, st) diff --git a/modules/atom/test/test_clone.py b/modules/atom/test/test_clone.py index 5d64b19719..9dca065958 100644 --- a/modules/atom/test/test_clone.py +++ b/modules/atom/test/test_clone.py @@ -44,5 +44,19 @@ def test_destroy_child(self): atoms = IMP.atom.get_by_type(mh, IMP.atom.ATOM_TYPE) self.assertEqual(len(atoms), 67) + def test_destroy_rigid_body_member(self): + """Destroy of a member should update the rigid body""" + m = IMP.Model() + mh = IMP.atom.read_pdb(self.get_input_file_name("mini.pdb"), m) + residues = IMP.atom.get_by_type(mh, IMP.atom.RESIDUE_TYPE) + atoms = IMP.atom.get_by_type(residues[0], IMP.atom.ATOM_TYPE) + rb = IMP.atom.create_rigid_body(residues[0]) + self.assertEqual(len(rb.get_member_particle_indexes()), 6) + IMP.atom.destroy(atoms[0]) + self.assertEqual(len(rb.get_member_particle_indexes()), 5) + # Used to fail with "Invalid particle requested" + m.update() + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/atom/test/test_dihedral_singleton_score.py b/modules/atom/test/test_dihedral_singleton_score.py new file mode 100644 index 0000000000..6335e7fc4e --- /dev/null +++ b/modules/atom/test/test_dihedral_singleton_score.py @@ -0,0 +1,55 @@ +import IMP +import IMP.test +import IMP.atom +import pickle + + +def make_dihedral(): + m = IMP.Model() + p1 = IMP.Particle(m) + xyz1 = IMP.core.XYZ.setup_particle(p1, IMP.algebra.Vector3D(0,0,0)) + p2 = IMP.Particle(m) + xyz2 = IMP.core.XYZ.setup_particle(p2, IMP.algebra.Vector3D(1,0,0)) + p3 = IMP.Particle(m) + xyz3 = IMP.core.XYZ.setup_particle(p3, IMP.algebra.Vector3D(0,1,0)) + p4 = IMP.Particle(m) + xyz4 = IMP.core.XYZ.setup_particle(p4, IMP.algebra.Vector3D(0,0,1)) + d = IMP.Particle(m) + dih = IMP.atom.Dihedral.setup_particle(d, xyz1, xyz2, xyz3, xyz4) + dih.set_ideal(0.) + dih.set_multiplicity(1) + dih.set_stiffness(5.) + return m, d, dih + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of DihedralSingletonScore""" + m, p, dih = make_dihedral() + ss = IMP.atom.DihedralSingletonScore() + ss.set_name('foo') + self.assertAlmostEqual(ss.evaluate_index(m, p, None), 19.717, + delta=0.01) + + dump = pickle.dumps(ss) + newss = pickle.loads(dump) + self.assertEqual(newss.get_name(), 'foo') + self.assertAlmostEqual(newss.evaluate_index(m, p, None), 19.717, + delta=0.01) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of DihedralSingletonScore via polymorphic pointer""" + m, p, dih = make_dihedral() + ss = IMP.atom.DihedralSingletonScore() + ss.set_name('foo') + r = IMP.core.SingletonRestraint(m, ss, p) + self.assertAlmostEqual(r.evaluate(False), 19.717, delta=0.01) + + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(r.evaluate(False), 19.717, delta=0.01) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/atom/test/test_hierarchy.py b/modules/atom/test/test_hierarchy.py index 977bf5eef0..242dbbbdc9 100644 --- a/modules/atom/test/test_hierarchy.py +++ b/modules/atom/test/test_hierarchy.py @@ -2,6 +2,8 @@ import IMP.test import IMP.atom import io +import pickle + def _make_hierarchy_decorators(m, *types): decorators = [] @@ -135,5 +137,28 @@ def test_xyz_show(self): h.show(sio, "-foo-") self.assertIn(b"-foo-(1, 2, 3)", sio.getvalue()) + def test_pickle(self): + """Check that hierarchy decorators can be (un-)pickled""" + m = IMP.Model() + decs = _make_hierarchy_decorators( + m, (IMP.atom.State, 1), (IMP.atom.State, 2), + (IMP.atom.Residue, IMP.atom.VAL), (IMP.atom.Residue, IMP.atom.VAL), + (IMP.atom.Atom, IMP.atom.AT_C), (IMP.atom.Atom, IMP.atom.AT_C)) + dump = pickle.dumps(decs) + newdecs = pickle.loads(dump) + + def test_pickle_model_hierarchy(self): + """Check pickle of model containing atom.Hierarchy""" + m = IMP.Model() + s = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m, "System")) + state = IMP.atom.State.setup_particle(IMP.Particle(m, "State_0"), 0) + s.add_child(state) + self.assertEqual(s.get_number_of_children(), 1) + + dump = pickle.dumps((m, s)) + m, s = pickle.loads(dump) + self.assertEqual(s.get_number_of_children(), 1) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/atom/test/test_write_pdb_optimizer_state.py b/modules/atom/test/test_write_pdb_optimizer_state.py new file mode 100644 index 0000000000..02db46bfc0 --- /dev/null +++ b/modules/atom/test/test_write_pdb_optimizer_state.py @@ -0,0 +1,40 @@ +from __future__ import print_function +import IMP +import IMP.atom +import IMP.test +import pickle + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test that WritePDBOptimizerState can be (un-)pickled""" + m = IMP.Model() + p1 = IMP.Particle(m) + s = IMP.atom.WritePDBOptimizerState([p1], "test.pdb") + s.set_period(11) + s.set_name("foo") + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(news.get_name(), "foo") + self.assertEqual(news.get_period(), 11) + + def test_pickle_polymorphic(self): + """Test that WritePDBOptimizerState can be (un-)pickled + via polymorphic pointer""" + m = IMP.Model() + p1 = IMP.Particle(m) + s = IMP.atom.WritePDBOptimizerState([p1], "test.pdb") + s.set_period(11) + s.set_name("foo") + opt = IMP._ConstOptimizer(m) + opt.optimizer_states.append(s) + + dump = pickle.dumps(opt) + newopt = pickle.loads(dump) + news, = newopt.optimizer_states + self.assertEqual(news.get_name(), "foo") + self.assertEqual(news.get_period(), 11) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/bayesianem b/modules/bayesianem index aeb6c4e01b..e544cc3cff 160000 --- a/modules/bayesianem +++ b/modules/bayesianem @@ -1 +1 @@ -Subproject commit aeb6c4e01b68431cf2fb763c807c68b763eba5c4 +Subproject commit e544cc3cff61ae8c1e1d6127692ea1a83b9032dc diff --git a/modules/benchmark/include/benchmark_macros.h b/modules/benchmark/include/benchmark_macros.h index fcd6283874..97149a710a 100644 --- a/modules/benchmark/include/benchmark_macros.h +++ b/modules/benchmark/include/benchmark_macros.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include "internal/control.h" #include "internal/flags.h" @@ -95,7 +95,7 @@ /** The units for the time are in seconds. \see IMP_TIME_N */ #define IMP_TIME(block, timev) \ IMP_BENCHMARK_RUN { \ - boost::timer imp_timer; \ + IMP::internal::SimpleTimer imp_timer; \ unsigned int imp_reps = 0; \ IMP_BENCHMARK_PROFILING_BEGIN; \ try { \ @@ -145,7 +145,7 @@ exactly N times. \see IMP_TIME */ #define IMP_TIME_N(block, timev, N) \ IMP_BENCHMARK_RUN { \ - boost::timer imp_timer; \ + IMP::internal::SimpleTimer imp_timer; \ IMP_BENCHMARK_PROFILING_BEGIN; \ for (unsigned int i = 0; i < (N); ++i) { \ try { \ diff --git a/modules/cnmultifit/src/symmetric_multifit.cpp b/modules/cnmultifit/src/symmetric_multifit.cpp index 9b6b8cc869..0fa0f7552c 100644 --- a/modules/cnmultifit/src/symmetric_multifit.cpp +++ b/modules/cnmultifit/src/symmetric_multifit.cpp @@ -13,11 +13,11 @@ #include #include #include +#include #include #include #include #include -#include #include @@ -156,7 +156,7 @@ multifit::FittingSolutionRecords fit_models_to_density( int recs_size = recs.size(); multifit::FittingSolutionRecords return_sols; float max_allowed_diff = params.get_pca_matching_threshold(); - boost::progress_display show_progress(num_sols_to_fit + 1); + IMP::internal::BoostProgressDisplay show_progress(num_sols_to_fit + 1); for (int i = 0; i < recs_size && j < num_sols_to_fit; ++i) { if (!(is_valid_transformation(recs[i].get_dock_transformation()) && is_valid_transformation(recs[i].get_fit_transformation()))) diff --git a/modules/cnmultifit/src/symmetry_utils.cpp b/modules/cnmultifit/src/symmetry_utils.cpp index 1b6d97e769..0b54ffc499 100644 --- a/modules/cnmultifit/src/symmetry_utils.cpp +++ b/modules/cnmultifit/src/symmetry_utils.cpp @@ -18,7 +18,6 @@ #include #include #include -#include IMPCNMULTIFIT_BEGIN_NAMESPACE diff --git a/modules/container/benchmark/benchmark_connectivity.cpp b/modules/container/benchmark/benchmark_connectivity.cpp index 65fee03229..728bbaed60 100644 --- a/modules/container/benchmark/benchmark_connectivity.cpp +++ b/modules/container/benchmark/benchmark_connectivity.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/container/benchmark/benchmark_evaluate.cpp b/modules/container/benchmark/benchmark_evaluate.cpp index 20409887f9..efcec1645e 100644 --- a/modules/container/benchmark/benchmark_evaluate.cpp +++ b/modules/container/benchmark/benchmark_evaluate.cpp @@ -3,7 +3,6 @@ */ #include #include -#include #include #include #include diff --git a/modules/container/benchmark/benchmark_random_collisions.cpp b/modules/container/benchmark/benchmark_random_collisions.cpp index 9ad8648ea1..e263444109 100644 --- a/modules/container/benchmark/benchmark_random_collisions.cpp +++ b/modules/container/benchmark/benchmark_random_collisions.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/container/benchmark/benchmark_rigid_collisions.cpp b/modules/container/benchmark/benchmark_rigid_collisions.cpp index d7d1c8869f..e8f459f4c5 100644 --- a/modules/container/benchmark/benchmark_rigid_collisions.cpp +++ b/modules/container/benchmark/benchmark_rigid_collisions.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/container/include/ClosePairContainer.h b/modules/container/include/ClosePairContainer.h index d59afb61e0..4b3ca0e64c 100644 --- a/modules/container/include/ClosePairContainer.h +++ b/modules/container/include/ClosePairContainer.h @@ -2,7 +2,7 @@ * \file IMP/container/ClosePairContainer.h * \brief Return all pairs from a SingletonContainer * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCONTAINER_CLOSE_PAIR_CONTAINER_H @@ -11,6 +11,8 @@ #include #include "internal/ClosePairContainer.h" #include +#include +#include IMPCONTAINER_BEGIN_NAMESPACE @@ -70,6 +72,14 @@ class IMPCONTAINEREXPORT ClosePairContainer : { typedef internal::ClosePairContainer P; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); + } + + IMP_OBJECT_SERIALIZE_DECL(ClosePairContainer); + public: //! Get the individual particles from the passed SingletonContainer /** @@ -90,6 +100,8 @@ class IMPCONTAINEREXPORT ClosePairContainer : core::ClosePairsFinder *cpf, double slack = 1, std::string name = "ClosePairContainer%1%"); + ClosePairContainer() {} + #if defined(SWIG) || defined(IMP_DOXYGEN) /** @name Methods to control the set of filters @@ -143,12 +155,6 @@ IMPCONTAINEREXPORT double get_slack_estimate( const RestraintsTemp &restraints, bool derivatives, Optimizer *opt, ClosePairContainer *cpc); -IMPCONTAINER_DEPRECATED_METHOD_DECL(2.16) -IMPCONTAINEREXPORT double get_slack_estimate( - const ParticlesTemp &ps, double upper_bound, double step, - const RestraintsTemp &restraints, bool derivatives, Optimizer *opt, - ClosePairContainer *cpc); - IMPCONTAINER_END_NAMESPACE #endif /* IMPCONTAINER_CLOSE_PAIR_CONTAINER_H */ diff --git a/modules/container/include/internal/ClosePairContainer.h b/modules/container/include/internal/ClosePairContainer.h index 1412e2c507..34477e97ef 100644 --- a/modules/container/include/internal/ClosePairContainer.h +++ b/modules/container/include/internal/ClosePairContainer.h @@ -2,7 +2,7 @@ * \file container/internal/ClosePairContainer.h * \brief Internal class of close pair container * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCONTAINER_INTERNAL_CONTAINER_CLOSE_PAIR_CONTAINER_H @@ -19,6 +19,8 @@ #include #include #include +#include +#include IMPCONTAINER_BEGIN_INTERNAL_NAMESPACE @@ -34,6 +36,20 @@ class IMPCONTAINEREXPORT ClosePairContainer typedef IMP::internal::ContainerScoreState SS; PointerMember score_state_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class< + IMP::internal::ListLikeContainer >(this), + c_, cpf_, moved_count_, first_call_, distance_, slack_, updates_, + rebuilds_, partial_rebuilds_, mutable_access_pair_filters()); + if (std::is_base_of::value) { + // Reset moved particles list and score state + moved_ = cpf_->get_moved_singleton_container(c_, slack_); + score_state_ = new SS(this); + } + } + void initialize(SingletonContainer *c, double distance, double slack, core::ClosePairsFinder *cpf); @@ -55,6 +71,8 @@ class IMPCONTAINEREXPORT ClosePairContainer core::ClosePairsFinder *cpf, double slack = 1, std::string name = "ClosePairContainer%1%"); + ClosePairContainer() {} + IMP_LIST_ACTION(public, PairFilter, PairFilters, pair_filter, pair_filters, PairPredicate *, PairPredicates, { diff --git a/modules/container/include/internal/robin_map_cereal.h b/modules/container/include/internal/robin_map_cereal.h new file mode 100644 index 0000000000..7674bed6a2 --- /dev/null +++ b/modules/container/include/internal/robin_map_cereal.h @@ -0,0 +1,49 @@ +/** + * \file container/internal/robin_map_cereal.h + * \brief Serialization support for robin_map + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + */ + +#ifndef IMPCONTAINER_INTERNAL_ROBIN_MAP_CEREAL_H +#define IMPCONTAINER_INTERNAL_ROBIN_MAP_CEREAL_H + +#include + +#if IMP_CONTAINER_HAS_ROBIN_MAP==1 +#include + +// Allow serialization of robin_map +namespace cereal { + template + inline void save(Archive &ar, tsl::robin_map const &t) { + size_t count = t.size(); + ar(count); + for (const auto &i : t) { + ar(i.first, i.second); + } + } + + template + inline void load(Archive &ar, tsl::robin_map &t) { + size_t count; + ar(count); + t.clear(); + auto hint = t.begin(); + for (size_t i = 0; i < count; ++i) { + Key key; + T value; + ar(key, value); + hint = t.insert(hint, std::make_pair(key, value)); + } + } + + // Recent versions of robin_map have their own serialize method; + // make sure cereal uses our functions and not that method. + template + struct specialize, + cereal::specialization::non_member_load_save> {}; +} +#endif + +#endif /* IMPCONTAINER_INTERNAL_ROBIN_MAP_CEREAL_H */ diff --git a/modules/container/pyext/swig.i-in b/modules/container/pyext/swig.i-in index a239a0f797..3d01207ad7 100644 --- a/modules/container/pyext/swig.i-in +++ b/modules/container/pyext/swig.i-in @@ -1,16 +1,16 @@ IMP_SWIG_OBJECT(IMP::container, AllBipartitePairContainer, AllBipartitePairContainers); IMP_SWIG_OBJECT(IMP::container, AllPairContainer, AllPairContainers); IMP_SWIG_OBJECT(IMP::container, CloseBipartitePairContainer, CloseBipartitePairContainers); -IMP_SWIG_OBJECT(IMP::container, ClosePairContainer, ClosePairContainers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, ClosePairContainer, ClosePairContainers); IMP_SWIG_OBJECT(IMP::container, ConnectingPairContainer, ConnectingPairContainers); IMP_SWIG_OBJECT(IMP::container, ConsecutivePairContainer, ConsecutivePairContainers); IMP_SWIG_OBJECT(IMP::container, ExclusiveConsecutivePairContainer, ExclusiveConsecutivePairContainers); IMP_SWIG_OBJECT(IMP::container, ExclusiveConsecutivePairFilter, ExclusiveConsecutivePairFilters); IMP_SWIG_OBJECT(IMP::container, ConsecutivePairFilter, ConsecutivePairFilters); -IMP_SWIG_OBJECT(IMP::container, ListPairContainer, ListPairContainers); -IMP_SWIG_OBJECT(IMP::container, ListQuadContainer, ListQuadContainers); -IMP_SWIG_OBJECT(IMP::container, ListSingletonContainer, ListSingletonContainers); -IMP_SWIG_OBJECT(IMP::container, ListTripletContainer, ListTripletContainers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, ListPairContainer, ListPairContainers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, ListQuadContainer, ListQuadContainers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, ListSingletonContainer, ListSingletonContainers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, ListTripletContainer, ListTripletContainers); IMP_SWIG_OBJECT(IMP::container, DynamicListPairContainer, DynamicListPairContainers); IMP_SWIG_OBJECT(IMP::container, DynamicListQuadContainer, DynamicListQuadContainers); IMP_SWIG_OBJECT(IMP::container, DynamicListSingletonContainer, DynamicListSingletonContainers); @@ -24,21 +24,21 @@ IMP_SWIG_OBJECT(IMP::container, MinimumSingletonScore, MinimumSingletonScores); IMP_SWIG_OBJECT(IMP::container, MinimumTripletRestraint, MinimumTripletRestraints); IMP_SWIG_OBJECT(IMP::container, MinimumTripletScore, MinimumTripletScores); IMP_SWIG_OBJECT(IMP::container, PairContainerSet, PairContainerSets); -IMP_SWIG_OBJECT(IMP::container, PairsConstraint, PairsConstraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, PairsConstraint, PairsConstraints); IMP_SWIG_OBJECT(IMP::container, PairsOptimizerState, PairsOptimizerStates); -IMP_SWIG_OBJECT(IMP::container, PairsRestraint, PairsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, PairsRestraint, PairsRestraints); IMP_SWIG_OBJECT(IMP::container, QuadContainerSet, QuadContainerSets); -IMP_SWIG_OBJECT(IMP::container, QuadsConstraint, QuadsConstraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, QuadsConstraint, QuadsConstraints); IMP_SWIG_OBJECT(IMP::container, QuadsOptimizerState, QuadsOptimizerStates); -IMP_SWIG_OBJECT(IMP::container, QuadsRestraint, QuadsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, QuadsRestraint, QuadsRestraints); IMP_SWIG_OBJECT(IMP::container, SingletonContainerSet, SingletonContainerSets); -IMP_SWIG_OBJECT(IMP::container, SingletonsConstraint, SingletonsConstraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, SingletonsConstraint, SingletonsConstraints); IMP_SWIG_OBJECT(IMP::container, SingletonsOptimizerState, SingletonsOptimizerStates); -IMP_SWIG_OBJECT(IMP::container, SingletonsRestraint, SingletonsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, SingletonsRestraint, SingletonsRestraints); IMP_SWIG_OBJECT(IMP::container, TripletContainerSet, TripletContainerSets); -IMP_SWIG_OBJECT(IMP::container, TripletsConstraint, TripletsConstraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, TripletsConstraint, TripletsConstraints); IMP_SWIG_OBJECT(IMP::container, TripletsOptimizerState, TripletsOptimizerStates); -IMP_SWIG_OBJECT(IMP::container, TripletsRestraint, TripletsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, TripletsRestraint, TripletsRestraints); IMP_SWIG_OBJECT(IMP::container, InContainerSingletonFilter, InContainerSingletonFilters); IMP_SWIG_OBJECT(IMP::container, InContainerPairFilter, InContainerPairFilters); IMP_SWIG_OBJECT(IMP::container, InContainerTripletFilter, InContainerTripletFilters); @@ -51,10 +51,10 @@ IMP_SWIG_OBJECT(IMP::container, EventSingletonsOptimizerState, EventSingletonsOp IMP_SWIG_OBJECT(IMP::container, EventPairsOptimizerState, EventPairsOptimizerStateList); IMP_SWIG_OBJECT(IMP::container, EventTripletsOptimizerState, EventTripletsOptimizerStateList); IMP_SWIG_OBJECT(IMP::container, EventQuadsOptimizerState, EventQuadsOptimizerStateList); -IMP_SWIG_OBJECT(IMP::container, PredicateSingletonsRestraint, PredicateSingletonsRestraints); -IMP_SWIG_OBJECT(IMP::container, PredicatePairsRestraint, PredicatePairRestraints); -IMP_SWIG_OBJECT(IMP::container, PredicateTripletsRestraint, PredicateTripletsRestraints); -IMP_SWIG_OBJECT(IMP::container, PredicateQuadsRestraint, PredicateQuadsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, PredicateSingletonsRestraint, PredicateSingletonsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, PredicatePairsRestraint, PredicatePairRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, PredicateTripletsRestraint, PredicateTripletsRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::container, PredicateQuadsRestraint, PredicateQuadsRestraints); IMP_SWIG_OBJECT(IMP::container, DistributeSingletonsScoreState, DistributeSingletonsScoreStates); IMP_SWIG_OBJECT(IMP::container, DistributePairsScoreState, DistributePairScoreStates); IMP_SWIG_OBJECT(IMP::container, DistributeTripletsScoreState, DistributeTripletsScoreStates); @@ -125,4 +125,4 @@ IMP_SWIG_OBJECT(IMP::container, DistributeQuadsScoreState, DistributeQuadsScoreS IMP::Restraint *create_restraint(IMP::PairScore *ps, IMP::PairContainer* pp) { return IMP::container::create_restraint(ps, pp); } -%} \ No newline at end of file +%} diff --git a/modules/container/src/ClosePairContainer.cpp b/modules/container/src/ClosePairContainer.cpp index 3ee827056a..76bb656785 100644 --- a/modules/container/src/ClosePairContainer.cpp +++ b/modules/container/src/ClosePairContainer.cpp @@ -9,7 +9,7 @@ #include "IMP/core/internal/close_pairs_helpers.h" #include #include -#include +#include #include IMPCONTAINER_BEGIN_NAMESPACE @@ -49,7 +49,7 @@ double get_slack_estimate(Model *m, ParticleIndexes ps, double upper_bound, datas.push_back(Data()); datas.back().slack = slack; { - boost::timer imp_timer; + IMP::internal::SimpleTimer imp_timer; int count = 0; SetLogState sl(opt->get_model(), SILENT); do { @@ -62,7 +62,7 @@ double get_slack_estimate(Model *m, ParticleIndexes ps, double upper_bound, << std::endl); } { - boost::timer imp_timer; + IMP::internal::SimpleTimer imp_timer; double score = 0; int count = 0; int iters = 1; @@ -185,16 +185,6 @@ double get_slack_estimate(Model *m, ParticleIndexes ps, double upper_bound, return datas[opt_i].slack; } -double get_slack_estimate(const ParticlesTemp &ps, double upper_bound, - double step, const RestraintsTemp &restraints, - bool derivatives, Optimizer *opt, - ClosePairContainer *cpc) { - IMPCONTAINER_DEPRECATED_FUNCTION_DEF( - 2.16, "Use the index-based function instead"); - Model *m = ps[0]->get_model(); - return get_slack_estimate(m, IMP::internal::get_index(ps), - upper_bound, step, restraints, derivatives, - opt, cpc); -} +IMP_OBJECT_SERIALIZE_IMPL(IMP::container::ClosePairContainer); IMPCONTAINER_END_NAMESPACE diff --git a/modules/container/test/test_close_pair_container.py b/modules/container/test/test_close_pair_container.py new file mode 100644 index 0000000000..989b432cd7 --- /dev/null +++ b/modules/container/test/test_close_pair_container.py @@ -0,0 +1,35 @@ +from __future__ import print_function +import IMP +import IMP.test +import IMP.core +import IMP.container +import pickle + + +class Tests(IMP.test.TestCase): + + def make_system(self): + m = IMP.Model() + ps = IMP.get_indexes(self.create_particles_in_box(m, 4)) + for p in ps: + IMP.core.XYZR.setup_particle(m, p, 0) + pc = IMP.container.ListSingletonContainer(m, ps) + cpss = IMP.container.ClosePairContainer( + pc, 1, IMP.core.GridClosePairsFinder(), 100.) + return m, cpss + + def test_pickle(self): + """Test (un-)pickle of ClosePairContainer""" + m, cpss = self.make_system() + cpss.set_name("foo") + dump = pickle.dumps(cpss) + + newcpss = pickle.loads(dump) + self.assertEqual(newcpss.get_name(), "foo") + m.update() + # should contain all interactions for 4 particles, since slack is large + self.assertEqual(len(newcpss.get_contents()), 6) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/container/test/test_connectivity_container.py b/modules/container/test/test_connectivity_container.py index 3cc9cabbae..505677762f 100644 --- a/modules/container/test/test_connectivity_container.py +++ b/modules/container/test/test_connectivity_container.py @@ -75,7 +75,7 @@ def test_score(self): sd = IMP.core.DistancePairScore(ub) pr = IMP.container.PairsRestraint(sd, cpc) sf = IMP.core.RestraintsScoringFunction([pr]) - cg.set_threshold(.0001) + cg.set_gradient_threshold(.0001) cg.set_scoring_function(sf) for i in range(10): try: diff --git a/modules/container/test/test_list_singleton_container.py b/modules/container/test/test_list_singleton_container.py index bfadf9a4f4..e064a7a1a1 100644 --- a/modules/container/test/test_list_singleton_container.py +++ b/modules/container/test/test_list_singleton_container.py @@ -1,6 +1,7 @@ import IMP import IMP.test import IMP.container +import pickle class TestMovedScore(IMP.SingletonScore): @@ -51,6 +52,16 @@ def test_scoring_moved(self): self.assertAlmostEqual(r1.evaluate_moved(False, [p2], []), 168., delta=1e-6) + def test_pickle(self): + """Test (un-)serialize of ListSingletonContainer""" + m = IMP.Model() + p1 = m.add_particle("p1") + lpc = IMP.container.ListSingletonContainer(m, [p1]) + self.assertEqual(lpc.get_contents(), [p1]) + dump = pickle.dumps(lpc) + newlpc = pickle.loads(dump) + self.assertEqual(newlpc.get_contents(), [p1]) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/container/test/test_pred_restraint.py b/modules/container/test/test_pred_restraint.py index 1430b1a550..73ea8ecda6 100644 --- a/modules/container/test/test_pred_restraint.py +++ b/modules/container/test/test_pred_restraint.py @@ -5,6 +5,7 @@ import IMP.algebra import IMP.container import random +import pickle tk = IMP.IntKey("type") @@ -73,5 +74,59 @@ def test_it(self): d.set_coordinates(d.get_coordinates() + IMP.algebra.get_random_vector_in(IMP.algebra.Sphere3D(IMP.algebra.Vector3D(0, 0, 0), 5))) self.assertEqual(r.evaluate(False), 0) + + def make_system(self): + m = IMP.Model() + ps = self.create_particles_in_box(m, 20) + lsc = IMP.container.ListSingletonContainer(m, ps) + pred = IMP.core.ConstantSingletonPredicate(42) + r = IMP.container.PredicateSingletonsRestraint(pred, lsc) + return m, r + + def test_unknown_score(self): + """Test PredicateSingletonsRestraint handling of unknown score""" + m, r = self.make_system() + # By default, an error if a particle doesn't have a score set + self.assertRaisesUsageException(r.evaluate, False) + r.set_is_complete(False) + self.assertAlmostEqual(r.evaluate(False), 0.0, delta=0.1) + # 20 particles * 10 = 200 + r.set_unknown_score(IMP._ConstSingletonScore(10)) + self.assertAlmostEqual(r.evaluate(False), 200.0, delta=0.1) + + def test_set_score(self): + """Test PredicateSingletonsRestraint handling of set score""" + m, r = self.make_system() + r.set_score(42, IMP._ConstSingletonScore(10)) + # 20 particles * 10 = 200 + self.assertAlmostEqual(r.evaluate(False), 200.0, delta=0.1) + + def test_pickle(self): + """Test (un-pickle) of PredicateSingletonsRestraint""" + m, r = self.make_system() + r.set_score(42, IMP._ConstSingletonScore(10)) + r.set_name("foo") + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + # 20 particles * 10 = 200 + self.assertAlmostEqual(newr.evaluate(False), 200.0, delta=0.1) + + def test_pickle_polymorphic(self): + """Test (un-pickle) of PredicateSingletonsRestraint via poly ptr""" + m, r = self.make_system() + r.set_score(42, IMP._ConstSingletonScore(10)) + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + dump = pickle.dumps(sf) + + newsf = pickle.loads(dump) + newr, = newsf.restraints + + self.assertEqual(newr.get_name(), "foo") + # 20 particles * 10 = 200 + self.assertAlmostEqual(newr.evaluate(False), 200.0, delta=0.1) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/container/test/test_singletons_constraint.py b/modules/container/test/test_singletons_constraint.py new file mode 100644 index 0000000000..4f3939c96b --- /dev/null +++ b/modules/container/test/test_singletons_constraint.py @@ -0,0 +1,20 @@ +import IMP +import IMP.test +import IMP.container +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)serialize of SingletonsConstraint""" + m = IMP.Model() + p1 = m.add_particle("p1") + lpc = IMP.container.ListSingletonContainer(m, [p1]) + ss = IMP.container.SingletonsConstraint(None, None, lpc) + dump = pickle.dumps(ss) + newss = pickle.loads(dump) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/container/test/test_singletons_restraint.py b/modules/container/test/test_singletons_restraint.py new file mode 100644 index 0000000000..e5718504b6 --- /dev/null +++ b/modules/container/test/test_singletons_restraint.py @@ -0,0 +1,46 @@ +import IMP +import IMP.test +import IMP.core +import IMP.container +import pickle + + +class Tests(IMP.test.TestCase): + + def make_system(self): + m = IMP.Model() + p1 = m.add_particle("p1") + IMP.core.XYZ.setup_particle(m, p1, IMP.algebra.Vector3D(1., 2., 3.)) + p2 = m.add_particle("p2") + IMP.core.XYZ.setup_particle(m, p2, IMP.algebra.Vector3D(4., 5., 6.)) + ss = IMP.core.DistanceToSingletonScore( + IMP.core.Harmonic(0, 1), IMP.algebra.Vector3D(0., 0., 0.)) + lsc = IMP.container.ListSingletonContainer(m, [p1, p2]) + r = IMP.container.SingletonsRestraint(ss, lsc) + return m, p1, p2, r + + def test_pickle(self): + """Test (un-)pickle of SingletonsRestraint""" + m, p1, p2, r = self.make_system() + r.set_name("foo") + self.assertAlmostEqual(r.evaluate(False), 45.5, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 45.5, delta=1e-4) + self.assertEqual(newr.get_name(), "foo") + + def test_pickle_polymorphic(self): + """Test (un-)pickle of SingletonsRestraint via polymorphic pointer""" + m, p1, p2, r = self.make_system() + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + self.assertAlmostEqual(sf.evaluate(False), 45.5, delta=1e-4) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + self.assertAlmostEqual(newsf.evaluate(False), 45.5, delta=1e-4) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/benchmark/benchmark_omp_evaluate.cpp b/modules/core/benchmark/benchmark_omp_evaluate.cpp index 57308d66f3..f00cb095a9 100644 --- a/modules/core/benchmark/benchmark_omp_evaluate.cpp +++ b/modules/core/benchmark/benchmark_omp_evaluate.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/core/benchmark/benchmark_xyz_access.cpp b/modules/core/benchmark/benchmark_xyz_access.cpp index 46900ddcdf..7fe92c8d75 100644 --- a/modules/core/benchmark/benchmark_xyz_access.cpp +++ b/modules/core/benchmark/benchmark_xyz_access.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/core/dependency/python-ihm/.github/workflows/testpy.yml b/modules/core/dependency/python-ihm/.github/workflows/testpy.yml index f1551fd316..7ffd447d59 100644 --- a/modules/core/dependency/python-ihm/.github/workflows/testpy.yml +++ b/modules/core/dependency/python-ihm/.github/workflows/testpy.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04] - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] include: - os: ubuntu-20.04 python-version: '2.7' @@ -34,7 +34,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install coverage pytest-cov flake8 + if [ "${{ env.PY2 }}" == "on" ]; then + pip install coverage pytest-cov flake8 + else + pip install coverage pytest-cov flake8 pep8-naming + fi - name: Test run: | # Test with Python tokenizer @@ -45,6 +49,6 @@ jobs: if [ "${{ env.PY2 }}" == "on" ]; then flake8 --ignore E402,W503,W504 --exclude util/make-mmcif.py else - flake8 --ignore E402,W503,W504 + flake8 --ignore E402,W503,W504,N816 fi - uses: codecov/codecov-action@v1 diff --git a/modules/core/dependency/python-ihm/ChangeLog.rst b/modules/core/dependency/python-ihm/ChangeLog.rst index 7449b210a0..12e8990877 100644 --- a/modules/core/dependency/python-ihm/ChangeLog.rst +++ b/modules/core/dependency/python-ihm/ChangeLog.rst @@ -1,3 +1,40 @@ +0.38 - 2023-05-26 +================= + - Convenience classes are added to describe datasets stored in + the Model Archive, iProX, and AlphaFoldDB repositories + (:class:`ihm.location.ModelArchiveLocation`, + :class:`ihm.location.IProXLocation`, and + :class:`ihm.location.AlphaFoldDBLocation` respectively). + - The new class :class:`ihm.metadata.CIFParser` can be used to extract + metadata from starting models in mmCIF format. It is currently in + development and only supports model metadata from PDB or Model Archive + at this time. + - Line wrapping of output mmCIF files can now be turned if desired using + :func:`ihm.dumper.set_line_wrap` (by default files are wrapped to 80 + characters if possible). + - The make-mmcif.py utility script now allows for the name of the output + mmCIF file to be overridden (#115). + + +0.37 - 2023-02-03 +================= + - Convenience classes are added to describe ensemble FRET datasets + (:class:`ihm.dataset.EnsembleFRETDataset`) and datasets stored in + the jPOSTrepo repository (:class:`ihm.location.JPOSTLocation`). + - Related depositions can now be grouped using the :class:`ihm.Collection` + class (#108). + - The :class:`ihm.model.Ensemble` class has a new ``superimposed`` attribute + to indicate whether the grouped models are structurally aligned. + +0.36 - 2023-01-25 +================= + - When reading a file that references external files, preserve any + information on the size of those files (#104). + - When reading a file containing models not in a model group, preserve + any information on the number of models deposited (#105). + - Bugfix: :func:`ihm.dictionary.read` now correctly handles dictionaries + that define a category after data items in that category (#107). + 0.35 - 2022-09-16 ================= - Author names now use PDB style ("Lastname, A.B.") by default rather diff --git a/modules/core/dependency/python-ihm/LICENSE b/modules/core/dependency/python-ihm/LICENSE index 88777eae03..7a52608174 100644 --- a/modules/core/dependency/python-ihm/LICENSE +++ b/modules/core/dependency/python-ihm/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2022 IHM Working Group +Copyright (c) 2018-2023 IHM Working Group Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/modules/core/dependency/python-ihm/MANIFEST.in b/modules/core/dependency/python-ihm/MANIFEST.in index 7ac1362f50..b0692c7c2e 100644 --- a/modules/core/dependency/python-ihm/MANIFEST.in +++ b/modules/core/dependency/python-ihm/MANIFEST.in @@ -4,4 +4,4 @@ include examples/* include util/make-mmcif.py include src/ihm_format.h include src/ihm_format.i -include src/ihm_format_wrap_0.35.c +include src/ihm_format_wrap_0.38.c diff --git a/modules/core/dependency/python-ihm/docs/conf.py b/modules/core/dependency/python-ihm/docs/conf.py index d707deb374..866dd4f104 100644 --- a/modules/core/dependency/python-ihm/docs/conf.py +++ b/modules/core/dependency/python-ihm/docs/conf.py @@ -47,7 +47,7 @@ # General information about the project. project = u'Python-IHM' -copyright = u'2018-2022, Benjamin Webb' +copyright = u'2018-2023, Benjamin Webb' author = u'Benjamin Webb' # The version info for the project you're documenting, acts as replacement for diff --git a/modules/core/dependency/python-ihm/docs/dataset.rst b/modules/core/dependency/python-ihm/docs/dataset.rst index f8d2dfcbde..05056f3312 100644 --- a/modules/core/dependency/python-ihm/docs/dataset.rst +++ b/modules/core/dependency/python-ihm/docs/dataset.rst @@ -58,6 +58,9 @@ The :mod:`ihm.dataset` Python module .. autoclass:: FRETDataset :members: +.. autoclass:: EnsembleFRETDataset + :members: + .. autoclass:: YeastTwoHybridDataset :members: diff --git a/modules/core/dependency/python-ihm/docs/dumper.rst b/modules/core/dependency/python-ihm/docs/dumper.rst index 883af5a427..7b4f6376a0 100644 --- a/modules/core/dependency/python-ihm/docs/dumper.rst +++ b/modules/core/dependency/python-ihm/docs/dumper.rst @@ -17,4 +17,6 @@ The :mod:`ihm.dumper` Python module .. autoclass:: IgnoreVariant +.. autofunction:: set_line_wrap + .. autofunction:: write diff --git a/modules/core/dependency/python-ihm/docs/location.rst b/modules/core/dependency/python-ihm/docs/location.rst index bfcb089fef..c1f552510e 100644 --- a/modules/core/dependency/python-ihm/docs/location.rst +++ b/modules/core/dependency/python-ihm/docs/location.rst @@ -22,6 +22,9 @@ The :mod:`ihm.location` Python module .. autoclass:: PDBDevLocation :members: +.. autoclass:: ModelArchiveLocation + :members: + .. autoclass:: BMRBLocation :members: @@ -37,12 +40,21 @@ The :mod:`ihm.location` Python module .. autoclass:: PRIDELocation :members: +.. autoclass:: JPOSTLocation + :members: + .. autoclass:: BioGRIDLocation :members: .. autoclass:: ProXLLocation :members: +.. autoclass:: IProXLocation + :members: + +.. autoclass:: AlphaFoldDBLocation + :members: + .. autoclass:: FileLocation :members: diff --git a/modules/core/dependency/python-ihm/docs/main.rst b/modules/core/dependency/python-ihm/docs/main.rst index 38a3d442fa..14fd8b12d3 100644 --- a/modules/core/dependency/python-ihm/docs/main.rst +++ b/modules/core/dependency/python-ihm/docs/main.rst @@ -86,3 +86,6 @@ The :mod:`ihm` Python module .. autoclass:: ChemDescriptor :members: + +.. autoclass:: Collection + :members: diff --git a/modules/core/dependency/python-ihm/docs/metadata.rst b/modules/core/dependency/python-ihm/docs/metadata.rst index b1dc64ebf1..1b188e78f8 100644 --- a/modules/core/dependency/python-ihm/docs/metadata.rst +++ b/modules/core/dependency/python-ihm/docs/metadata.rst @@ -15,3 +15,6 @@ The :mod:`ihm.metadata` Python module .. autoclass:: PDBParser :members: + +.. autoclass:: CIFParser + :members: diff --git a/modules/core/dependency/python-ihm/docs/restraint.rst b/modules/core/dependency/python-ihm/docs/restraint.rst index a597a75986..6e574f26ef 100644 --- a/modules/core/dependency/python-ihm/docs/restraint.rst +++ b/modules/core/dependency/python-ihm/docs/restraint.rst @@ -22,6 +22,12 @@ The :mod:`ihm.restraint` Python module .. autoclass:: EM3DRestraintFit :members: +.. autoclass:: EM2DRestraint + :members: + +.. autoclass:: EM2DRestraintFit + :members: + .. autoclass:: SASRestraint :members: diff --git a/modules/core/dependency/python-ihm/ihm/__init__.py b/modules/core/dependency/python-ihm/ihm/__init__.py index 084844929d..cf3deb6dfc 100644 --- a/modules/core/dependency/python-ihm/ihm/__init__.py +++ b/modules/core/dependency/python-ihm/ihm/__init__.py @@ -20,7 +20,7 @@ import json from . import util -__version__ = '0.35' +__version__ = '0.38' class __UnknownValue(object): @@ -108,6 +108,11 @@ def __init__(self, title=None, id='model', model_details=None): #: All asymmetric units used in the system. See :class:`AsymUnit`. self.asym_units = [] + #: Collections (if any) to which this entry belongs. + #: These are used to group depositions of related entries. + #: See :class:`Collection`. + self.collections = [] + #: All orphaned chemical descriptors in the system. #: See :class:`ChemDescriptor`. This can be used to track descriptors #: that are not otherwise used - normally one is assigned to a @@ -1100,6 +1105,12 @@ def _get_ins_code(self): doc="Insertion code; only makes sense " "for asymmetric units") + def _get_comp(self): + entity = self.entity or self.asym.entity + return entity.sequence[self.seq_id - 1] + comp = property(_get_comp, + doc="Chemical component (residue type)") + # Allow passing residues where a range is requested # (e.g. to ResidueFeature) seq_id_range = property(lambda self: (self.seq_id, self.seq_id)) @@ -1466,3 +1477,20 @@ def __init__(self, auth_name, chem_comp_id=None, chemical_name=None, self.chemical_name, self.common_name = chemical_name, common_name self.smiles, self.smiles_canonical = smiles, smiles_canonical self.inchi, self.inchi_key = inchi, inchi_key + + +class Collection(object): + """A collection of entries belonging to single deposition or group. + These are used by the archive to group multiple related entries, + e.g. all entries deposited as part of a given study, or all + models for a genome. An entry (:class:`System`) can belong to + multiple collections. + + :param str id: Unique identifier (assigned by the archive). + :param str name: Short name for the collection. + :param str details: Longer description of the collection. + + See also :attr:`System.collections`. + """ + def __init__(self, id, name=None, details=None): + self.id, self.name, self.details = id, name, details diff --git a/modules/core/dependency/python-ihm/ihm/analysis.py b/modules/core/dependency/python-ihm/ihm/analysis.py index 97b3669bbe..332dd413bb 100644 --- a/modules/core/dependency/python-ihm/ihm/analysis.py +++ b/modules/core/dependency/python-ihm/ihm/analysis.py @@ -2,6 +2,9 @@ """ +from ihm.util import _text_choice_property + + class Step(object): """A single step in an :class:`Analysis`. @@ -38,6 +41,10 @@ def __init__(self, feature, num_models_begin, num_models_end, self.script_file = script_file self.details = details + feature = _text_choice_property( + "feature", ["energy/score", "RMSD", "dRMSD", "other", "none"], + doc="The feature used in the analysis, if applicable") + class FilterStep(Step): """A single filtering step in an :class:`Analysis`. diff --git a/modules/core/dependency/python-ihm/ihm/dataset.py b/modules/core/dependency/python-ihm/ihm/dataset.py index dad7247a7d..c1504b47ea 100644 --- a/modules/core/dependency/python-ihm/ihm/dataset.py +++ b/modules/core/dependency/python-ihm/ihm/dataset.py @@ -115,7 +115,7 @@ class HDXDataset(Dataset): class PDBDataset(Dataset): """An experimentally-determined 3D structure as a set of a coordinates, - usually in a PDB file""" + usually in a PDB or mmCIF file""" data_type = 'Experimental model' @@ -165,10 +165,17 @@ class SASDataset(Dataset): class FRETDataset(Dataset): - """Data from a Förster resonance energy transfer (FRET) experiment""" + """Single molecule data from a Förster resonance energy transfer + (FRET) experiment""" data_type = 'Single molecule FRET data' +class EnsembleFRETDataset(Dataset): + """Ensemble data from a Förster resonance energy transfer + (FRET) experiment""" + data_type = 'Ensemble FRET data' + + class YeastTwoHybridDataset(Dataset): """Yeast two-hybrid data""" data_type = 'Yeast two-hybrid screening data' diff --git a/modules/core/dependency/python-ihm/ihm/dictionary.py b/modules/core/dependency/python-ihm/ihm/dictionary.py index 1265eaeb4d..071b764d66 100644 --- a/modules/core/dependency/python-ihm/ihm/dictionary.py +++ b/modules/core/dependency/python-ihm/ihm/dictionary.py @@ -350,7 +350,11 @@ def end_save_frame(self): self._reset_keyword() if self.category_good: c = self.category - self.dictionary.categories[c.name] = c + if c.name in self.dictionary.categories: + # Handle case where keywords were defined before category + self.dictionary.categories[c.name]._update(c) + else: + self.dictionary.categories[c.name] = c self._reset_category() diff --git a/modules/core/dependency/python-ihm/ihm/dumper.py b/modules/core/dependency/python-ihm/ihm/dumper.py index 42223526a0..55a182eb75 100644 --- a/modules/core/dependency/python-ihm/ihm/dumper.py +++ b/modules/core/dependency/python-ihm/ihm/dumper.py @@ -77,6 +77,14 @@ def dump(self, system, writer): lp.write(id=system.id) +class _CollectionDumper(Dumper): + def dump(self, system, writer): + with writer.loop("_ihm_entry_collection", + ["id", "name", "details"]) as lp: + for c in system.collections: + lp.write(id=c.id, name=c.name, details=c.details) + + class _AuditConformDumper(Dumper): URL = ("https://raw.githubusercontent.com/" + "ihmwg/IHM-dictionary/%s/ihm-extension.dic") @@ -84,8 +92,8 @@ class _AuditConformDumper(Dumper): def dump(self, system, writer): with writer.category("_audit_conform") as lp: # Update to match the version of the IHM dictionary we support: - lp.write(dict_name="ihm-extension.dic", dict_version="1.17", - dict_location=self.URL % "f15a6bb") + lp.write(dict_name="ihm-extension.dic", dict_version="1.22", + dict_location=self.URL % "ac49042") class _StructDumper(Dumper): @@ -181,7 +189,7 @@ def _get_citation_authors(self, system): # If system.authors is empty, get the set of all citation authors # instead seen_authors = set() - # Only look at explictly-added citations (since these are likely to + # Only look at explicitly-added citations (since these are likely to # describe the modeling) not that describe a method or a piece of # software we used (system._all_citations()) for c in system.citations: @@ -1610,6 +1618,7 @@ def dump_info(self, system, writer): "num_ensemble_models_deposited", "ensemble_precision_value", "ensemble_file_id", "details", + "model_group_superimposed_flag", "sub_sample_flag", "sub_sampling_type"]) as lp: for e in system.ensembles: if e.subsamples: @@ -1627,6 +1636,7 @@ def dump_info(self, system, writer): ensemble_precision_value=e.precision, ensemble_file_id=e.file._id if e.file else None, details=e.details, + model_group_superimposed_flag=e.superimposed, sub_sample_flag=len(e.subsamples) > 0, sub_sampling_type=sstype) @@ -2454,7 +2464,7 @@ def dump(self, system, writer): lp.write(id=x._id, details=x.details) -class _FLR_ExpConditionDumper(Dumper): +class _FLRExpConditionDumper(Dumper): def finalize(self, system): def all_exp_conditions(): return itertools.chain.from_iterable(f._all_exp_conditions() @@ -3149,7 +3159,7 @@ def dump_mpp_modeling(self, system, writer): _flr_dumpers = [_FLRExperimentDumper, _FLRInstSettingDumper, - _FLR_ExpConditionDumper, _FLRInstrumentDumper, + _FLRExpConditionDumper, _FLRInstrumentDumper, _FLREntityAssemblyDumper, _FLRSampleConditionDumper, _FLRSampleDumper, _FLRProbeDumper, _FLRSampleProbeDetailsDumper, _FLRPolyProbePositionDumper, @@ -3230,6 +3240,7 @@ class IHMVariant(Variant): """Used to select typical PDBx/IHM file output. See :func:`write`.""" _dumpers = [ _EntryDumper, # must be first + _CollectionDumper, _StructDumper, _CommentDumper, _AuditConformDumper, _CitationDumper, _SoftwareDumper, _AuditAuthorDumper, _GrantDumper, _ChemCompDumper, _ChemDescriptorDumper, _EntityDumper, _EntitySrcGenDumper, @@ -3270,6 +3281,20 @@ def get_system_writer(self, system, writer_class, writer): return _IgnoreWriter(writer, self._ignores) +def set_line_wrap(line_wrap): + """Set whether output lines are wrapped at 80 characters. + By default the mmCIF writer tries to avoid writing lines longer than + 80 characters, for compatibility with traditional PDB. When + disabled, each row in a "loop" construct will be written on a + single line. + + This setting has no effect on binary formats (BinaryCIF). + + :param bool line_wrap: whether to wrap lines at 80 characters. + """ + ihm.format.CifWriter._set_line_wrap(line_wrap) + + def write(fh, systems, format='mmCIF', dumpers=[], variant=IHMVariant): """Write out all `systems` to the file handle `fh`. Files can be written in either the text-based mmCIF format or the diff --git a/modules/core/dependency/python-ihm/ihm/format.py b/modules/core/dependency/python-ihm/ihm/format.py index 6b2ec74bdd..705729d5b0 100644 --- a/modules/core/dependency/python-ihm/ihm/format.py +++ b/modules/core/dependency/python-ihm/ihm/format.py @@ -52,7 +52,7 @@ def write(self, val): return val = '.' if val is None else self.writer._repr(val) if self.column > 0: - if self.column + len(val) + 1 > self.line_len: + if self.line_len and self.column + len(val) + 1 > self.line_len: self.writer.fh.write("\n") self.column = 0 else: @@ -78,7 +78,8 @@ def __exit__(self, exc_type, exc_value, traceback): class _CifLoopWriter(object): - def __init__(self, writer, category, keys): + def __init__(self, writer, category, keys, line_wrap=True): + self._line_wrap = line_wrap self.writer = writer self.category = category self.keys = keys @@ -93,7 +94,7 @@ def write(self, **kwargs): for k in self.keys: f.write("%s.%s\n" % (self.category, k)) self._empty_loop = False - lw = _LineWriter(self.writer) + lw = _LineWriter(self.writer, line_len=80 if self._line_wrap else 0) for k in self.python_keys: lw.write(kwargs.get(k, None)) self.writer.fh.write("\n") @@ -129,6 +130,12 @@ class CifWriter(_Writer): than 1e-3); if a different amount of precision is desired, convert the float to a string first.""" + _line_wrap = True + + @classmethod + def _set_line_wrap(cls, line_wrap): + cls._line_wrap = line_wrap + def flush(self): # noop - data is written as it is encountered pass @@ -177,13 +184,17 @@ def loop(self, category, keys): for i in range(5): l.write(id='HELX_P1%d' % i, conf_type_id='HELX_P') """ - return _CifLoopWriter(self, category, keys) + return _CifLoopWriter(self, category, keys, line_wrap=self._line_wrap) def write_comment(self, comment): """Write a simple comment to the CIF file. - The comment will be wrapped if necessary for readability.""" - for line in textwrap.wrap(comment, 78): - self.fh.write('# ' + line + '\n') + The comment will be wrapped if necessary for readability. + See :meth:`set_line_wrap`.""" + if self._line_wrap: + for line in textwrap.wrap(comment, 78): + self.fh.write('# ' + line + '\n') + else: + self.fh.write('# ' + comment + '\n') def _write(self, category, kwargs): for key, val in sorted(kwargs.items(), key=operator.itemgetter(0)): diff --git a/modules/core/dependency/python-ihm/ihm/location.py b/modules/core/dependency/python-ihm/ihm/location.py index 4f9a0a813a..153f90a877 100644 --- a/modules/core/dependency/python-ihm/ihm/location.py +++ b/modules/core/dependency/python-ihm/ihm/location.py @@ -110,6 +110,17 @@ def __init__(self, db_code, version=None, details=None): version, details) +class ModelArchiveLocation(DatabaseLocation): + """Something stored in Model Archive. + See :class:`DatabaseLocation` for a description of the parameters + and :class:`Location` for discussion of the usage of these objects.""" + _db_name = 'MODEL ARCHIVE' + + def __init__(self, db_code, version=None, details=None): + super(ModelArchiveLocation, self).__init__(self._db_name, db_code, + version, details) + + class BMRBLocation(DatabaseLocation): """Something stored in the BMRB database. See :class:`DatabaseLocation` for a description of the parameters @@ -165,6 +176,17 @@ def __init__(self, db_code, version=None, details=None): details) +class JPOSTLocation(DatabaseLocation): + """Something stored in the JPOST database. + See :class:`DatabaseLocation` for a description of the parameters + and :class:`Location` for discussion of the usage of these objects.""" + _db_name = 'jPOSTrepo' + + def __init__(self, db_code, version=None, details=None): + super(JPOSTLocation, self).__init__(self._db_name, db_code, version, + details) + + class BioGRIDLocation(DatabaseLocation): """Something stored in the BioGRID database. See :class:`DatabaseLocation` for a description of the parameters @@ -187,6 +209,28 @@ def __init__(self, db_code, version=None, details=None): details) +class IProXLocation(DatabaseLocation): + """Something stored in the iProX database. + See :class:`DatabaseLocation` for a description of the parameters + and :class:`Location` for discussion of the usage of these objects.""" + _db_name = 'iProX' + + def __init__(self, db_code, version=None, details=None): + super(IProXLocation, self).__init__(self._db_name, db_code, version, + details) + + +class AlphaFoldDBLocation(DatabaseLocation): + """Something stored in the AlphaFoldDB database. + See :class:`DatabaseLocation` for a description of the parameters + and :class:`Location` for discussion of the usage of these objects.""" + _db_name = 'AlphaFoldDB' + + def __init__(self, db_code, version=None, details=None): + super(AlphaFoldDBLocation, self).__init__( + self._db_name, db_code, version, details) + + class FileLocation(Location): """Base class for an individual file or directory stored externally. diff --git a/modules/core/dependency/python-ihm/ihm/metadata.py b/modules/core/dependency/python-ihm/ihm/metadata.py index 9382615bbb..e7e93ab3c5 100644 --- a/modules/core/dependency/python-ihm/ihm/metadata.py +++ b/modules/core/dependency/python-ihm/ihm/metadata.py @@ -15,6 +15,8 @@ from .startmodel import SequenceIdentityDenominator import ihm.source import ihm.citations +import ihm.reader +import ihm.format import operator import struct @@ -209,7 +211,10 @@ class PDBParser(Parser): PDB file. This handles PDB headers added by the PDB database itself, comparative modeling packages such as MODELLER and Phyre2, and also some custom headers that can be used to indicate that a file has been - locally modified in some way.""" + locally modified in some way. + + See also :class:`CIFParser` for coordinate files in mmCIF format. + """ def parse_file(self, filename): """Extract metadata. See :meth:`Parser.parse_file` for details. @@ -607,3 +612,74 @@ def _parse_details(self, fh): elif line.startswith('ATOM'): break return details + + +class _Database2Handler(ihm.reader.Handler): + def __init__(self, m): + self.m = m + + def __call__(self, database_id, database_code): + self.m['db'][database_id.upper()] = database_code + + +class _StructHandler(ihm.reader.Handler): + def __init__(self, m): + self.m = m + + def __call__(self, title): + self.m['title'] = title + + +class _AuditRevHistHandler(ihm.reader.Handler): + def __init__(self, m): + self.m = m + + def __call__(self, revision_date): + self.m['version'] = revision_date + + +class CIFParser(Parser): + """Extract metadata from an mmCIF file. Currently, this does not handle + information from comparative modeling packages such as MODELLER + (see :class:`PDBParser`). + + See also :class:`PDBParser` for coordinate files in legacy PDB format. + """ + dbmap = {'PDB': (location.PDBLocation, dataset.PDBDataset), + 'MODELARCHIVE': (location.ModelArchiveLocation, + dataset.DeNovoModelDataset)} + + def parse_file(self, filename): + """Extract metadata. See :meth:`Parser.parse_file` for details. + + :param str filename: the file to extract metadata from. + :return: a dict with key `dataset` pointing to the coordinate file, + as an entry in the PDB or Model Archive databases if the + file contains appropriate headers, otherwise to the + file itself. + """ + dset = self._get_dataset(filename) + return {'dataset': dset} + + def _get_dataset(self, filename): + m = {'db': {}, 'title': 'Starting model structure'} + with open(filename) as fh: + dbh = _Database2Handler(m) + structh = _StructHandler(m) + arevhisth = _AuditRevHistHandler(m) + r = ihm.format.CifReader( + fh, {'_database_2': dbh, '_struct': structh, + '_pdbx_audit_revision_history': arevhisth}) + r.read_file() + # Check for known databases. Note that if a file is in multiple + # databases, we currently return one "at random" + for dbid, dbcode in m['db'].items(): + if dbid in self.dbmap: + loccls, dsetcls = self.dbmap[dbid] + loc = loccls(db_code=dbcode, version=m.get('version'), + details=m['title']) + return dsetcls(location=loc, details=loc.details) + # Fall back to a local file + loc = location.InputFileLocation(filename, details=m['title']) + return dataset.ComparativeModelDataset( + location=loc, details=loc.details) diff --git a/modules/core/dependency/python-ihm/ihm/model.py b/modules/core/dependency/python-ihm/ihm/model.py index ca10dd825d..91a60bdf89 100644 --- a/modules/core/dependency/python-ihm/ihm/model.py +++ b/modules/core/dependency/python-ihm/ihm/model.py @@ -4,7 +4,7 @@ import struct import itertools -import ihm +from ihm.util import _text_choice_property class Sphere(object): @@ -179,23 +179,6 @@ def __init__(self, elements=()): super(StateGroup, self).__init__(elements) -def _text_choice_property(attr, choices, doc=None): - schoices = frozenset(choices) - - def getfunc(obj): - return getattr(obj, "_" + attr) - - def setfunc(obj, val): - if val is not None and val is not ihm.unknown and val not in schoices: - raise ValueError( - "Invalid choice %s for %s; valid values are %s, " - "None, ihm.unknown" - % (repr(val), attr, ", ".join(repr(x) for x in choices))) - setattr(obj, "_" + attr, val) - - return property(getfunc, setfunc, doc=doc) - - class Ensemble(object): """Details about a model cluster or ensemble. See :attr:`ihm.System.ensembles`. @@ -220,19 +203,22 @@ class Ensemble(object): (see :class:`DCDWriter`). See also :attr:`subsamples`. :type file: :class:`ihm.location.OutputFileLocation` :param str details: Additional text describing this ensemble + :param bool superimposed: True if the models in the group are + structurally aligned. """ _num_deposited = None def __init__(self, model_group, num_models, post_process=None, clustering_method=None, clustering_feature=None, name=None, - precision=None, file=None, details=None): + precision=None, file=None, details=None, superimposed=None): self.model_group, self.num_models = model_group, num_models self.post_process = post_process self.clustering_method = clustering_method self.clustering_feature = clustering_feature self.name, self.precision, self.file = name, precision, file self.details = details + self.superimposed = superimposed #: All localization densities for this ensemble, as #: :class:`LocalizationDensity` objects @@ -257,7 +243,8 @@ def _get_num_deposited(self): clustering_method = _text_choice_property( "clustering_method", - ["Hierarchical", "Other", "Partitioning (k-means)"], + ["Hierarchical", "Other", "Partitioning (k-means)", + "Density based threshold-clustering"], doc="The clustering method used to obtain the ensemble, if applicable") clustering_feature = _text_choice_property( diff --git a/modules/core/dependency/python-ihm/ihm/reader.py b/modules/core/dependency/python-ihm/ihm/reader.py index a21f63701a..ecd7e72ce9 100644 --- a/modules/core/dependency/python-ihm/ihm/reader.py +++ b/modules/core/dependency/python-ihm/ihm/reader.py @@ -883,6 +883,14 @@ def copy_if_present(self, obj, data, keys=[], mapkeys={}): doc="The :class:`ihm.System` object to read into") +class _CollectionHandler(Handler): + category = '_ihm_entry_collection' + + def __call__(self, id, name, details): + c = ihm.Collection(id=id, name=name, details=details) + self.system.collections.append(c) + + class _StructHandler(Handler): category = '_struct' @@ -1425,6 +1433,9 @@ def __call__(self, dataset_list_id, db_name, id, version, details, typ = None if db_name is None else db_name.lower() dbloc = self.sysr.db_locations.get_by_id(id, self.type_map.get(typ, None)) + # Preserve user-provided name for unknown databases + if dbloc.db_name is None and db_name is not None: + dbloc.db_name = db_name ds.location = dbloc self.copy_if_present( dbloc, locals(), keys=['version', 'details'], @@ -1688,7 +1699,11 @@ def __call__(self, protocol_id, analysis_id, type, id, num_models_begin, step.software = self.sysr.software.get_by_id_or_none(software_id) step.script_file = self.sysr.external_files.get_by_id_or_none( script_file_id) - self.copy_if_present(step, locals(), keys=['feature']) + # Default to "other" if invalid method/feature read + try: + self.copy_if_present(step, locals(), keys=['feature']) + except ValueError: + step.feature = "other" class _ModelListHandler(Handler): @@ -1786,7 +1801,8 @@ def __call__(self, ensemble_id, model_group_id, post_process_id, ensemble_file_id, num_ensemble_models, ensemble_precision_value, ensemble_name, ensemble_clustering_method, ensemble_clustering_feature, - details, sub_sampling_type, num_ensemble_models_deposited): + details, sub_sampling_type, num_ensemble_models_deposited, + model_group_superimposed_flag): ensemble = self.sysr.ensembles.get_by_id(ensemble_id) mg = self.sysr.model_groups.get_by_id_or_none(model_group_id) pp = self.sysr.analysis_steps.get_by_id_or_none(post_process_id) @@ -1803,6 +1819,7 @@ def __call__(self, ensemble_id, model_group_id, post_process_id, ensemble.post_process = pp ensemble.file = f ensemble.details = details + ensemble.superimposed = self.get_bool(model_group_superimposed_flag) # Default to "other" if invalid method/feature read try: ensemble.clustering_method = ensemble_clustering_method @@ -3285,7 +3302,7 @@ class IHMVariant(Variant): system_reader = SystemReader _handlers = [ - _StructHandler, _SoftwareHandler, _CitationHandler, + _CollectionHandler, _StructHandler, _SoftwareHandler, _CitationHandler, _AuditAuthorHandler, _GrantHandler, _CitationAuthorHandler, _ChemCompHandler, _ChemDescriptorHandler, _EntityHandler, _EntitySrcNatHandler, _EntitySrcGenHandler, _EntitySrcSynHandler, diff --git a/modules/core/dependency/python-ihm/ihm/restraint.py b/modules/core/dependency/python-ihm/ihm/restraint.py index 40368a4d3b..ab5bf58917 100644 --- a/modules/core/dependency/python-ihm/ihm/restraint.py +++ b/modules/core/dependency/python-ihm/ihm/restraint.py @@ -237,6 +237,9 @@ def __init__(self, dataset, linker): class ExperimentalCrossLink(object): """A cross-link identified in the experiment. + These objects, once created, should be added to + the :attr:`CrossLinkRestraint.experimental_cross_links` list. + :param residue1: The first residue linked by the cross-link. :type residue1: :class:`ihm.Residue` :param residue2: The second residue linked by the cross-link. @@ -373,6 +376,9 @@ class ResidueCrossLink(CrossLink): """A cross-link used in the modeling, applied to residue alpha carbon atoms. + These objects, once created, should be added to + the :attr:`CrossLinkRestraint.cross_links` list. + :param experimental_cross_link: The corresponding cross-link identified by experiment. Multiple cross-links can map to a single experimental identification. @@ -408,16 +414,33 @@ def __init__(self, experimental_cross_link, asym1, asym2, distance, self.distance, self.restrain_all = distance, restrain_all self.pseudo1, self.pseudo2 = pseudo1, pseudo2 - #: Information about the fit of each model to this cross-link + #: Information about the fit of each model to this cross-link. #: This is a Python dict where keys are :class:`~ihm.model.Model` #: objects and values are :class:`CrossLinkFit` objects. self.fits = {} + def _get_residue1(self): + seq_id = self.experimental_cross_link.residue1.seq_id + return self.asym1.residue(seq_id) + residue1 = property(_get_residue1, + doc="Residue object representing one end " + "of the cross-link") + + def _get_residue2(self): + seq_id = self.experimental_cross_link.residue2.seq_id + return self.asym2.residue(seq_id) + residue2 = property(_get_residue2, + doc="Residue object representing one end " + "of the cross-link") + class FeatureCrossLink(CrossLink): """A cross-link used in the modeling, applied to the closest primitive object with the highest resolution. + These objects, once created, should be added to + the :attr:`CrossLinkRestraint.cross_links` list. + :param experimental_cross_link: The corresponding cross-link identified by experiment. Multiple cross-links can map to a single experimental identification. @@ -453,7 +476,7 @@ def __init__(self, experimental_cross_link, asym1, asym2, distance, self.distance, self.restrain_all = distance, restrain_all self.pseudo1, self.pseudo2 = pseudo1, pseudo2 - #: Information about the fit of each model to this cross-link + #: Information about the fit of each model to this cross-link. #: This is a Python dict where keys are :class:`~ihm.model.Model` #: objects and values are :class:`CrossLinkFit` objects. self.fits = {} @@ -462,6 +485,9 @@ def __init__(self, experimental_cross_link, asym1, asym2, distance, class AtomCrossLink(CrossLink): """A cross-link used in the modeling, applied to the specified atoms. + These objects, once created, should be added to + the :attr:`CrossLinkRestraint.cross_links` list. + :param experimental_cross_link: The corresponding cross-link identified by experiment. Multiple cross-links can map to a single experimental identification. @@ -499,7 +525,7 @@ def __init__(self, experimental_cross_link, asym1, asym2, atom1, atom2, self.distance, self.restrain_all = distance, restrain_all self.pseudo1, self.pseudo2 = pseudo1, pseudo2 - #: Information about the fit of each model to this cross-link + #: Information about the fit of each model to this cross-link. #: This is a Python dict where keys are :class:`~ihm.model.Model` #: objects and values are :class:`CrossLinkFit` objects. self.fits = {} diff --git a/modules/core/dependency/python-ihm/ihm/util.py b/modules/core/dependency/python-ihm/ihm/util.py index 75e13f5be7..98516d247d 100644 --- a/modules/core/dependency/python-ihm/ihm/util.py +++ b/modules/core/dependency/python-ihm/ihm/util.py @@ -2,6 +2,7 @@ import string import os +import ihm class _AsymIDs(object): @@ -45,3 +46,21 @@ def _get_relative_path(reference, path): return path else: return os.path.join(os.path.dirname(reference), path) + + +def _text_choice_property(attr, choices, doc=None): + """Like `property` but requires that the value be one of the set choices""" + schoices = frozenset(choices) + + def getfunc(obj): + return getattr(obj, "_" + attr) + + def setfunc(obj, val): + if val is not None and val is not ihm.unknown and val not in schoices: + raise ValueError( + "Invalid choice %s for %s; valid values are %s, " + "None, ihm.unknown" + % (repr(val), attr, ", ".join(repr(x) for x in choices))) + setattr(obj, "_" + attr, val) + + return property(getfunc, setfunc, doc=doc) diff --git a/modules/core/dependency/python-ihm/make-release.sh b/modules/core/dependency/python-ihm/make-release.sh index fa4f192532..d3e6912401 100755 --- a/modules/core/dependency/python-ihm/make-release.sh +++ b/modules/core/dependency/python-ihm/make-release.sh @@ -21,4 +21,5 @@ mv src/ihm_format_wrap.c "src/ihm_format_wrap_${VERSION}.c" python3 setup.py sdist rm -f "src/ihm_format_wrap_${VERSION}.c" -echo "Now use 'twine upload dist/ihm-${VERSION}.tar.gz' to publish the release on PyPi" +echo "Now use 'twine upload dist/ihm-${VERSION}.tar.gz' to publish the release on PyPi." +echo "Then, update the conda-forge and Homebrew packages to match." diff --git a/modules/core/dependency/python-ihm/setup.py b/modules/core/dependency/python-ihm/setup.py index 18b5bc6322..9013098346 100755 --- a/modules/core/dependency/python-ihm/setup.py +++ b/modules/core/dependency/python-ihm/setup.py @@ -7,7 +7,7 @@ import sys import os -VERSION = "0.35" +VERSION = "0.38" copy_args = sys.argv[1:] diff --git a/modules/core/dependency/python-ihm/test/input/modarchive.cif b/modules/core/dependency/python-ihm/test/input/modarchive.cif new file mode 100644 index 0000000000..b12b1d033d --- /dev/null +++ b/modules/core/dependency/python-ihm/test/input/modarchive.cif @@ -0,0 +1,19 @@ +data_ma-bak-cepc-0250 +_entry.id ma-bak-cepc-0250 +_entry.ma_collection_id ma-bak-cepc + +_struct.entry_id ma-bak-cepc-0250 +_struct.title 'Predicted interaction between CWP1 and IKI1' + +_database_2.database_id ModelArchive +_database_2.database_code ma-bak-cepc-0250 +_database_2.pdbx_DOI 10.5452/ma-bak-cepc-0250 + +loop_ +_pdbx_audit_revision_history.ordinal +_pdbx_audit_revision_history.data_content_type +_pdbx_audit_revision_history.major_revision +_pdbx_audit_revision_history.minor_revision +_pdbx_audit_revision_history.revision_date +1 'Structure model' 1 0 2021-11-11 +2 'Structure model' 1 1 2022-11-30 diff --git a/modules/core/dependency/python-ihm/test/input/official.cif b/modules/core/dependency/python-ihm/test/input/official.cif new file mode 100644 index 0000000000..a83a1cee92 --- /dev/null +++ b/modules/core/dependency/python-ihm/test/input/official.cif @@ -0,0 +1,29 @@ +data_2HBJ +# +_entry.id 2HBJ +# +loop_ +_database_2.database_id +_database_2.database_code +_database_2.pdbx_database_accession +_database_2.pdbx_DOI +PDB 2HBJ pdb_00002hbj 10.2210/pdb2hbj/pdb +RCSB RCSB038162 ? ? +WWPDB D_1000038162 ? ? +# +_struct.entry_id 2HBJ +_struct.title +'Structure of the yeast nuclear exosome component, Rrp6p, reveals an interplay between the active site and the HRDC domain' +# +# +loop_ +_pdbx_audit_revision_history.ordinal +_pdbx_audit_revision_history.data_content_type +_pdbx_audit_revision_history.major_revision +_pdbx_audit_revision_history.minor_revision +_pdbx_audit_revision_history.revision_date +1 'Structure model' 1 0 2006-07-25 +2 'Structure model' 1 1 2008-05-01 +3 'Structure model' 1 2 2011-07-13 +4 'Structure model' 1 3 2017-10-18 +5 'Structure model' 1 4 2021-11-10 diff --git a/modules/core/dependency/python-ihm/test/input/unknown_model.cif b/modules/core/dependency/python-ihm/test/input/unknown_model.cif new file mode 100644 index 0000000000..1d67ef500c --- /dev/null +++ b/modules/core/dependency/python-ihm/test/input/unknown_model.cif @@ -0,0 +1,2 @@ +data_foo +_entry.id foo diff --git a/modules/core/dependency/python-ihm/test/test_analysis.py b/modules/core/dependency/python-ihm/test/test_analysis.py index 49b558515a..4e3e18be3f 100644 --- a/modules/core/dependency/python-ihm/test/test_analysis.py +++ b/modules/core/dependency/python-ihm/test/test_analysis.py @@ -17,6 +17,10 @@ def test_filter_step(self): self.assertEqual(s.feature, 'RMSD') self.assertEqual(s.num_models_begin, 42) self.assertEqual(s.num_models_end, 5) + # test with invalid feature + self.assertRaises(ValueError, ihm.analysis.FilterStep, + feature='invalid', num_models_begin=42, + num_models_end=5) def test_cluster_step(self): """Test analysis ClusterStep class""" diff --git a/modules/core/dependency/python-ihm/test/test_dataset.py b/modules/core/dependency/python-ihm/test/test_dataset.py index ad0cf74491..43bd489c17 100644 --- a/modules/core/dependency/python-ihm/test/test_dataset.py +++ b/modules/core/dependency/python-ihm/test/test_dataset.py @@ -170,6 +170,12 @@ def test_fret_dataset(self): d = ihm.dataset.FRETDataset(loc) self.assertEqual(d.data_type, 'Single molecule FRET data') + def test_ensemble_fret_dataset(self): + """Test EnsembleFRETDataset""" + loc = ihm.location.FileLocation(repo='mydoi', path='a') + d = ihm.dataset.EnsembleFRETDataset(loc) + self.assertEqual(d.data_type, 'Ensemble FRET data') + def test_y2h_dataset(self): """Test YeastTwoHybridDataset""" loc = ihm.location.FileLocation(repo='mydoi', path='a') diff --git a/modules/core/dependency/python-ihm/test/test_dictionary.py b/modules/core/dependency/python-ihm/test/test_dictionary.py index e052b943a0..f824470dfe 100644 --- a/modules/core/dependency/python-ihm/test/test_dictionary.py +++ b/modules/core/dependency/python-ihm/test/test_dictionary.py @@ -111,6 +111,7 @@ def test_read(self): _item.mandatory_code '_test_category1.bar' test_category1 no '_test_category3.bar' test_category3 yes + '_test_category4.foo' test_category4 yes _item_type.code code save_ @@ -146,11 +147,23 @@ def test_read(self): "enum 1" "enum 2" save_ + +save_foo + _category.id test_category4 + _category.description 'my desc4' + _category.mandatory_code yes +save_ + +save_bar + _item.name '_test_category4.bar' + _item.mandatory_code no + _item_type.code ucode +save_ """ d = ihm.dictionary.read(StringIO(cif)) self.assertEqual(sorted(d.categories.keys()), ['test_category1', 'test_category2', - 'test_category3']) + 'test_category3', 'test_category4']) c1 = d.categories['test_category1'] self.assertTrue(c1.mandatory) self.assertEqual( @@ -179,6 +192,12 @@ def test_read(self): self.assertEqual(sorted(c3.keywords.keys()), ["bar"]) self.assertTrue(c3.keywords['bar'].mandatory) + # Test category that is defined after some keywords + c4 = d.categories['test_category4'] + self.assertEqual(c4.description, 'my desc4') + self.assertTrue(c4.mandatory) + self.assertEqual(sorted(c4.keywords.keys()), ["bar", "foo"]) + self.assertEqual(d.linked_items, {'_test_category2.baz': '_test_category1.bar'}) @@ -187,7 +206,7 @@ def test_read(self): d = ihm.dictionary.read(BytesIO(cif.encode('latin-1'))) self.assertEqual(sorted(d.categories.keys()), ['test_category1', 'test_category2', - 'test_category3']) + 'test_category3', 'test_category4']) def test_add(self): """Test adding two Dictionaries""" @@ -212,7 +231,7 @@ def test_add_update(self): self.assertEqual(sorted(d.categories.keys()), ['test_mandatory_category', 'test_optional_category']) ks = sorted(d.categories['test_mandatory_category'].keywords.keys()) - # Category should now contain keywords from from dictionaries + # Category should now contain keywords from both dictionaries self.assertEqual(ks, ['bar', 'baz', 'foo']) def test_category_update(self): diff --git a/modules/core/dependency/python-ihm/test/test_dumper.py b/modules/core/dependency/python-ihm/test/test_dumper.py index cda807913c..9c2da4d362 100644 --- a/modules/core/dependency/python-ihm/test/test_dumper.py +++ b/modules/core/dependency/python-ihm/test/test_dumper.py @@ -930,6 +930,22 @@ def test_nonpoly_scheme_dumper(self): B 2 HEM 1 1 1 HEM Q . C 3 ZN 1 6 6 ZN C . # +""") + + def test_collection_dumper(self): + """Test CollectionDumper""" + system = ihm.System() + c = ihm.Collection('foo', name='bar', details='more text') + system.collections.append(c) + dumper = ihm.dumper._CollectionDumper() + out = _get_dumper_output(dumper, system) + self.assertEqual(out, """# +loop_ +_ihm_entry_collection.id +_ihm_entry_collection.name +_ihm_entry_collection.details +foo bar 'more text' +# """) def test_struct_asym_dumper(self): @@ -2399,7 +2415,7 @@ class MockObject(object): post_process=pp, name='cluster1', clustering_method='Hierarchical', clustering_feature='RMSD', - precision=4.2) + precision=4.2, superimposed=True) loc = ihm.location.OutputFileLocation(repo='foo', path='bar') loc._id = 3 e2 = ihm.model.Ensemble(model_group=group, num_models=10, @@ -2433,10 +2449,11 @@ class MockObject(object): _ihm_ensemble_info.ensemble_precision_value _ihm_ensemble_info.ensemble_file_id _ihm_ensemble_info.details +_ihm_ensemble_info.model_group_superimposed_flag _ihm_ensemble_info.sub_sample_flag _ihm_ensemble_info.sub_sampling_type -1 cluster1 99 42 Hierarchical RMSD 10 2 4.200 . . NO . -2 . . 42 . . 10 2 . 3 'test details' YES independent +1 cluster1 99 42 Hierarchical RMSD 10 2 4.200 . . YES NO . +2 . . 42 . . 10 2 . 3 'test details' . YES independent # # loop_ @@ -3448,7 +3465,7 @@ class MockObject(object): # """) - def test_FLRDumper(self): + def test_flr_dumper(self): """Test FLR dumpers""" class MockObject(object): @@ -3775,7 +3792,7 @@ class MockObject(object): cur_fret_model_distance_2_1, cur_fret_model_distance_2_2)) # FPS modeling - cur_FPS_global_parameters = ihm.flr.FPSGlobalParameters( + cur_fps_global_parameters = ihm.flr.FPSGlobalParameters( forster_radius=52, conversion_function_polynom_order=3, repetition=1000, av_grid_rel=0.2, av_min_grid_a=0.4, av_allowed_sphere=0.5, av_search_nodes=3, av_e_samples_k=200, @@ -3785,31 +3802,31 @@ class MockObject(object): convergence_e=100, convergence_k=0.001, convergence_f=0.001, convergence_t=0.002) - cur_FPS_modeling_1 = ihm.flr.FPSModeling( + cur_fps_modeling_1 = ihm.flr.FPSModeling( protocol=cur_ihm_modeling_protocol, restraint_group=cur_fret_dist_restraint_group, - global_parameter=cur_FPS_global_parameters, + global_parameter=cur_fps_global_parameters, probe_modeling_method="AV3") - cur_FPS_modeling_2 = ihm.flr.FPSModeling( + cur_fps_modeling_2 = ihm.flr.FPSModeling( protocol=cur_ihm_modeling_protocol, restraint_group=cur_fret_dist_restraint_group, - global_parameter=cur_FPS_global_parameters, + global_parameter=cur_fps_global_parameters, probe_modeling_method="MPP") # Modeling by AV - cur_FPS_AV_parameters_1 = ihm.flr.FPSAVParameter( + cur_fps_av_parameters_1 = ihm.flr.FPSAVParameter( num_linker_atoms=15, linker_length=20.0, linker_width=3.5, probe_radius_1=10.0, probe_radius_2=5.0, probe_radius_3=3.5) - cur_FPS_AV_modeling_1 = ihm.flr.FPSAVModeling( - fps_modeling=cur_FPS_modeling_1, + cur_fps_av_modeling_1 = ihm.flr.FPSAVModeling( + fps_modeling=cur_fps_modeling_1, sample_probe=cur_sample_probe_details_1, - parameter=cur_FPS_AV_parameters_1) - cur_FPS_AV_modeling_3 = ihm.flr.FPSAVModeling( - fps_modeling=cur_FPS_modeling_1, + parameter=cur_fps_av_parameters_1) + cur_fps_av_modeling_3 = ihm.flr.FPSAVModeling( + fps_modeling=cur_fps_modeling_1, sample_probe=cur_sample_probe_details_3, - parameter=cur_FPS_AV_parameters_1) - cur_flr_data.fps_modeling.append(cur_FPS_AV_modeling_1) - cur_flr_data.fps_modeling.append(cur_FPS_AV_modeling_3) + parameter=cur_fps_av_parameters_1) + cur_flr_data.fps_modeling.append(cur_fps_av_modeling_1) + cur_flr_data.fps_modeling.append(cur_fps_av_modeling_3) # Modeling by mean probe position cur_mpp_atom_position_1 = ihm.flr.FPSMPPAtomPosition( @@ -3823,14 +3840,14 @@ class MockObject(object): sample_probe=cur_sample_probe_details_2, x=1.0, y=2.0, z=3.0) cur_mean_probe_position_4 = ihm.flr.FPSMeanProbePosition( sample_probe=cur_sample_probe_details_4, x=1.0, y=2.0, z=3.0) - cur_FPS_MPP_modeling_2 = ihm.flr.FPSMPPModeling( - fps_modeling=cur_FPS_modeling_2, mpp=cur_mean_probe_position_2, + cur_fps_mpp_modeling_2 = ihm.flr.FPSMPPModeling( + fps_modeling=cur_fps_modeling_2, mpp=cur_mean_probe_position_2, mpp_atom_position_group=cur_mpp_atom_position_group) - cur_FPS_MPP_modeling_4 = ihm.flr.FPSMPPModeling( - fps_modeling=cur_FPS_modeling_2, mpp=cur_mean_probe_position_4, + cur_fps_mpp_modeling_4 = ihm.flr.FPSMPPModeling( + fps_modeling=cur_fps_modeling_2, mpp=cur_mean_probe_position_4, mpp_atom_position_group=cur_mpp_atom_position_group) - cur_flr_data.fps_modeling.append(cur_FPS_MPP_modeling_2) - cur_flr_data.fps_modeling.append(cur_FPS_MPP_modeling_4) + cur_flr_data.fps_modeling.append(cur_fps_mpp_modeling_2) + cur_flr_data.fps_modeling.append(cur_fps_mpp_modeling_4) system.flr_data = [cur_flr_data] @@ -3845,7 +3862,7 @@ class MockObject(object): inst_setting_dumper = ihm.dumper._FLRInstSettingDumper() inst_setting_dumper.finalize(system) - exp_condition_dumper = ihm.dumper._FLR_ExpConditionDumper() + exp_condition_dumper = ihm.dumper._FLRExpConditionDumper() exp_condition_dumper.finalize(system) instrument_dumper = ihm.dumper._FLRInstrumentDumper() @@ -4406,6 +4423,34 @@ def test_write_ignore_variant(self): 'AUDIT_CONFORM'])) self.assertNotIn('_ihm_struct_assembly', fh.getvalue()) + def test_dumper_unwrapped(self): + """Test dumper output with line wrapping disabled""" + system = ihm.System() + system.software.append(ihm.Software( + name='long-software-name', classification='test code', + description='Some test program', + version=1, location='http://some-long-url.org')) + dumper = ihm.dumper._SoftwareDumper() + dumper.finalize(system) + try: + ihm.dumper.set_line_wrap(False) + out = _get_dumper_output(dumper, system) + finally: + ihm.dumper.set_line_wrap(True) + self.assertEqual(out, """# +loop_ +_software.pdbx_ordinal +_software.name +_software.classification +_software.description +_software.version +_software.type +_software.location +_software.citation_id +1 long-software-name 'test code' 'Some test program' 1 program http://some-long-url.org . +# +""") # noqa: E501 + if __name__ == '__main__': unittest.main() diff --git a/modules/core/dependency/python-ihm/test/test_flr.py b/modules/core/dependency/python-ihm/test/test_flr.py index 6e765245d7..492c964edf 100644 --- a/modules/core/dependency/python-ihm/test/test_flr.py +++ b/modules/core/dependency/python-ihm/test/test_flr.py @@ -9,13 +9,13 @@ class Tests(unittest.TestCase): - def test_Probe_Init(self): + def test_probe_init(self): """Test initialization of probe_list_entry and probe_descriptor.""" p = ihm.flr.Probe(probe_list_entry='foo', probe_descriptor='bar') self.assertEqual(p.probe_list_entry, 'foo') self.assertEqual(p.probe_descriptor, 'bar') - def test_Probe_Eq(self): + def test_probe_eq(self): """Test equality and inequality of Probe objects""" p_ref = ihm.flr.Probe(probe_list_entry='foo', probe_descriptor='bar') p_equal = ihm.flr.Probe(probe_list_entry='foo', probe_descriptor='bar') @@ -240,7 +240,7 @@ def test_sample_condition_eq(self): self.assertFalse(s_ref == s_unequal) self.assertTrue(s_ref != s_unequal) - def test_Experiment_Init(self): + def test_experiment_init(self): """Test initialization of Experiment.""" # Initialization with only one parameter given should not add an entry e1 = ihm.flr.Experiment(instrument='foo') @@ -271,7 +271,7 @@ def test_Experiment_Init(self): self.assertEqual(len(e3.details_list), 1) self.assertIsNone(e3.details_list[0]) - def test_Experiment_Add_entry(self): + def test_experiment_add_entry(self): """ Test addition of an entry to the experiment. """ # Adding to an empty Experiment e1 = ihm.flr.Experiment() @@ -303,7 +303,7 @@ def test_Experiment_Add_entry(self): self.assertEqual(e2.sample_list, ['foo4', 'bar4']) self.assertEqual(e2.details_list, ['foo5', 'bar5']) - def test_Experiment_Get_entry_by_index(self): + def test_experiment_get_entry_by_index(self): """ Test access to entries by index. """ e = ihm.flr.Experiment() e.add_entry(instrument='foo', inst_setting='foo2', @@ -324,7 +324,7 @@ def test_Experiment_Get_entry_by_index(self): ('foobar', 'foobar2', 'foobar3', 'foobar4', 'foobar5')) - def test_Experiment_Contains(self): + def test_experiment_contains(self): """Test whether experiment contains a combination of instrument, exp_setting, and sample.""" # An empty experiment should not contain anything @@ -341,7 +341,7 @@ def test_Experiment_Contains(self): self.assertFalse(e1.contains('foobar', 'foobar2', 'foobar3', 'foobar4')) - def test_Experiment_Eq(self): + def test_experiment_eq(self): """ Test equality and inequality of Experiment objects. """ e_ref = ihm.flr.Experiment() e_ref.add_entry(instrument='foo', inst_setting='foo2', @@ -356,12 +356,12 @@ def test_Experiment_Eq(self): self.assertFalse(e_ref == e_unequal) self.assertTrue(e_ref != e_unequal) - def test_Instrument_Init(self): + def test_instrument_init(self): """ Test initialization of Instrument. """ i = ihm.flr.Instrument(details='foo') self.assertEqual(i.details, 'foo') - def test_Instrument_Eq(self): + def test_instrument_eq(self): """Test equality and inequality of Instrument objects.""" i_ref = ihm.flr.Instrument(details='foo') i_equal = ihm.flr.Instrument(details='foo') @@ -837,10 +837,10 @@ def test_fret_model_distance_init(self): self.assertEqual(f1.distance_deviation, 4.0) # Initialization with calculation of distance deviation - class Dummy_Restraint(): + class DummyRestraint(): def __init__(self, distance): self.distance = distance - f2 = ihm.flr.FRETModelDistance(restraint=Dummy_Restraint(40), + f2 = ihm.flr.FRETModelDistance(restraint=DummyRestraint(40), model='bar2', distance=30) self.assertEqual(f2.model, 'bar2') self.assertEqual(f2.distance, 30) @@ -848,10 +848,10 @@ def __init__(self, distance): def test_fret_model_distance_calculate_deviation(self): """Test FRETModelDistance.calculate_deviation()""" - class Dummy_Restraint(): + class DummyRestraint(): def __init__(self, distance): self.distance = distance - f1 = ihm.flr.FRETModelDistance(restraint=Dummy_Restraint(40), + f1 = ihm.flr.FRETModelDistance(restraint=DummyRestraint(40), model='foo', distance=30) self.assertEqual(f1.distance_deviation, 10.0) # Directly changing the distance should not change the deviation diff --git a/modules/core/dependency/python-ihm/test/test_format.py b/modules/core/dependency/python-ihm/test/test_format.py index 214c3d7847..94a2783b99 100644 --- a/modules/core/dependency/python-ihm/test/test_format.py +++ b/modules/core/dependency/python-ihm/test/test_format.py @@ -182,6 +182,17 @@ def test_write_comment(self): self.assertEqual(fh.getvalue(), "# " + "X" * 78 + '\n# ' + "X" * 7 + '\n') + def test_write_comment_unwrapped(self): + """Test CifWriter.write_comment() with line wrapping disabled""" + fh = StringIO() + try: + ihm.format.CifWriter._set_line_wrap(False) + writer = ihm.format.CifWriter(fh) + writer.write_comment('X' * 85) + finally: + ihm.format.CifWriter._set_line_wrap(True) + self.assertEqual(fh.getvalue(), "# " + "X" * 85 + '\n') + def test_repr(self): """Test CifWriter._repr()""" w = ihm.format.CifWriter(None) diff --git a/modules/core/dependency/python-ihm/test/test_location.py b/modules/core/dependency/python-ihm/test/test_location.py index 208674a4ea..45b0ba382e 100644 --- a/modules/core/dependency/python-ihm/test/test_location.py +++ b/modules/core/dependency/python-ihm/test/test_location.py @@ -47,6 +47,15 @@ def test_pdb_dev_location(self): self.assertEqual(loc.version, 'foo') self.assertEqual(loc.details, 'bar') + def test_model_archive_location(self): + """Test ModelArchiveLocation""" + loc = ihm.location.ModelArchiveLocation( + 'ma-bak-cepc-0250', version='foo', details='bar') + self.assertEqual(loc.db_name, 'MODEL ARCHIVE') + self.assertEqual(loc.access_code, 'ma-bak-cepc-0250') + self.assertEqual(loc.version, 'foo') + self.assertEqual(loc.details, 'bar') + def test_bmrb_location(self): """Test BMRBLocation""" loc = ihm.location.BMRBLocation('27600', version='foo', details='bar') @@ -80,6 +89,30 @@ def test_proxl_location(self): self.assertEqual(d.version, 1) self.assertEqual(d.details, 'foo') + def test_jpost_location(self): + """Test JPOSTLocation class""" + d = ihm.location.JPOSTLocation('abc', version=1, details='foo') + self.assertEqual(d.db_name, 'jPOSTrepo') + self.assertEqual(d.access_code, 'abc') + self.assertEqual(d.version, 1) + self.assertEqual(d.details, 'foo') + + def test_iprox_location(self): + """Test IProXLocation class""" + d = ihm.location.IProXLocation('abc', version=1, details='foo') + self.assertEqual(d.db_name, 'iProX') + self.assertEqual(d.access_code, 'abc') + self.assertEqual(d.version, 1) + self.assertEqual(d.details, 'foo') + + def test_alpha_fold_db_location(self): + """Test AlphaFoldDBLocation class""" + d = ihm.location.AlphaFoldDBLocation('abc', version=1, details='foo') + self.assertEqual(d.db_name, 'AlphaFoldDB') + self.assertEqual(d.access_code, 'abc') + self.assertEqual(d.version, 1) + self.assertEqual(d.details, 'foo') + def test_empiar_location(self): """Test EMPIARLocation class""" d = ihm.location.EMPIARLocation('abc', version=1, details='foo') diff --git a/modules/core/dependency/python-ihm/test/test_main.py b/modules/core/dependency/python-ihm/test/test_main.py index 65923b2d9c..640c277137 100644 --- a/modules/core/dependency/python-ihm/test/test_main.py +++ b/modules/core/dependency/python-ihm/test/test_main.py @@ -351,6 +351,7 @@ def test_entity_residue(self): self.assertEqual(r.entity, e) self.assertIsNone(r.asym) self.assertEqual(r.seq_id, 3) + self.assertEqual(r.comp.id, 'CYS') def test_water_asym(self): """Test WaterAsymUnit class""" @@ -379,6 +380,7 @@ def test_asym_unit_residue(self): self.assertEqual(r.seq_id, 3) self.assertEqual(r.auth_seq_id, 8) self.assertIsNone(r.ins_code) + self.assertEqual(r.comp.id, 'CYS') def test_atom_entity(self): """Test Atom class built from an Entity""" diff --git a/modules/core/dependency/python-ihm/test/test_make_mmcif.py b/modules/core/dependency/python-ihm/test/test_make_mmcif.py index 15e08084e1..86c10b8b5a 100644 --- a/modules/core/dependency/python-ihm/test/test_make_mmcif.py +++ b/modules/core/dependency/python-ihm/test/test_make_mmcif.py @@ -25,6 +25,19 @@ def test_simple(self): 'of transcription regulation by Gdown1') os.unlink('output.cif') + @unittest.skipIf(sys.version_info[0] < 3, "make-mmcif.py needs Python 3") + def test_non_default_output(self): + """Simple test of make-mmcif with non-default output name""" + incif = utils.get_input_file_name(TOPDIR, 'struct_only.cif') + subprocess.check_call([sys.executable, MAKE_MMCIF, incif, + 'non-default-output.cif']) + with open('non-default-output.cif') as fh: + s, = ihm.reader.read(fh) + self.assertEqual(s.title, + 'Architecture of Pol II(G) and molecular mechanism ' + 'of transcription regulation by Gdown1') + os.unlink('non-default-output.cif') + @unittest.skipIf(sys.version_info[0] < 3, "make-mmcif.py needs Python 3") def test_no_title(self): """Check that make-mmcif adds missing title""" @@ -55,8 +68,8 @@ def test_mini(self): m = s.state_groups[0][0][0][0] self.assertEqual(m.protocol.name, 'modeling') self.assertEqual(m.assembly.name, 'Complete assembly') - chainA, chainB, = m.representation - for chain in chainA, chainB: + chain_a, chain_b, = m.representation + for chain in chain_a, chain_b: self.assertIsInstance(chain, ihm.representation.AtomicSegment) self.assertFalse(chain.rigid) self.assertEqual(s.title, 'Auto-generated system') @@ -76,11 +89,11 @@ def test_pass_through(self): m = s.state_groups[0][0][0][0] self.assertEqual(m.protocol.name, 'Modeling') self.assertEqual(m.assembly.name, 'Our complete assembly') - chainA, chainB, = m.representation - self.assertIsInstance(chainA, ihm.representation.AtomicSegment) - self.assertTrue(chainA.rigid) - self.assertIsInstance(chainB, ihm.representation.FeatureSegment) - self.assertFalse(chainB.rigid) + chain_a, chain_b, = m.representation + self.assertIsInstance(chain_a, ihm.representation.AtomicSegment) + self.assertTrue(chain_a.rigid) + self.assertIsInstance(chain_b, ihm.representation.FeatureSegment) + self.assertFalse(chain_b.rigid) self.assertEqual(s.title, 'Output from simple-docking example') os.unlink('output.cif') diff --git a/modules/core/dependency/python-ihm/test/test_metadata.py b/modules/core/dependency/python-ihm/test/test_metadata.py index 42e57a194c..6ec247827e 100644 --- a/modules/core/dependency/python-ihm/test/test_metadata.py +++ b/modules/core/dependency/python-ihm/test/test_metadata.py @@ -416,6 +416,45 @@ def test_get_aligned_region_empty(self): self.assertRaises(ValueError, ihm.metadata._get_aligned_region, 'AAAA', '----') + def _parse_cif(self, fname): + p = ihm.metadata.CIFParser() + return p.parse_file(fname) + + def test_cif_official_pdb(self): + """Test CIFParser when given an mmCIF in the official PDB database""" + p = self._parse_cif(utils.get_input_file_name(TOPDIR, 'official.cif')) + dataset = p['dataset'] + self.assertEqual(dataset.data_type, 'Experimental model') + self.assertEqual(dataset.location.db_name, 'PDB') + self.assertEqual(dataset.location.access_code, '2HBJ') + self.assertEqual(dataset.location.version, '2021-11-10') + self.assertEqual(dataset.location.details, + 'Structure of the yeast nuclear exosome component, ' + 'Rrp6p, reveals an interplay between the active ' + 'site and the HRDC domain') + + def test_cif_model_archive(self): + """Test CIFParser when given an mmCIF in Model Archive""" + p = self._parse_cif(utils.get_input_file_name(TOPDIR, + 'modarchive.cif')) + dataset = p['dataset'] + self.assertEqual(dataset.data_type, 'De Novo model') + self.assertEqual(dataset.location.db_name, 'MODEL ARCHIVE') + self.assertEqual(dataset.location.access_code, 'ma-bak-cepc-0250') + self.assertEqual(dataset.location.version, '2022-11-30') + self.assertEqual(dataset.location.details, + 'Predicted interaction between CWP1 and IKI1') + + def test_cif_unknown(self): + """Test CIFParser when given an mmCIF not in a database""" + fname = utils.get_input_file_name(TOPDIR, 'unknown_model.cif') + p = self._parse_cif(fname) + dataset = p['dataset'] + self.assertEqual(dataset.data_type, 'Comparative model') + self.assertIsInstance(dataset.location, ihm.location.FileLocation) + self.assertEqual(dataset.location.path, fname) + self.assertEqual(dataset.location.details, 'Starting model structure') + if __name__ == '__main__': unittest.main() diff --git a/modules/core/dependency/python-ihm/test/test_reader.py b/modules/core/dependency/python-ihm/test/test_reader.py index 56a929275e..3b9bb03c81 100644 --- a/modules/core/dependency/python-ihm/test/test_reader.py +++ b/modules/core/dependency/python-ihm/test/test_reader.py @@ -209,6 +209,22 @@ def test_multiple_systems(self): # and the system ID should match entry_id self.assertEqual(s4.id, 'id4') + def test_collection_handler(self): + """Test CollectionHandler""" + cif = """ +loop_ +_ihm_entry_collection.id +_ihm_entry_collection.name +_ihm_entry_collection.details +foo bar 'more text' +""" + for fh in cif_file_handles(cif): + s, = ihm.reader.read(fh) + c, = s.collections + self.assertEqual(c.id, 'foo') + self.assertEqual(c.name, 'bar') + self.assertEqual(c.details, 'more text') + def test_software_handler(self): """Test SoftwareHandler""" cif = """ @@ -1030,10 +1046,11 @@ def test_dataset_dbref_handler(self): 2 3 PDB 3F3F 30-OCT-08 'CRYSTAL STRUCTURE' 3 5 emdb EMD-123 . . 4 6 . . . . +5 7 testDB testcode testver testdetails """ for fh in cif_file_handles(cif): s, = ihm.reader.read(fh) - d1, d2, d3, d4 = s.orphan_datasets + d1, d2, d3, d4, d5 = s.orphan_datasets self.assertEqual(d1.location.db_name, 'PDB') self.assertEqual(d1.location.__class__, ihm.location.PDBLocation) self.assertEqual(d1.location.access_code, '3JRO') @@ -1051,6 +1068,12 @@ def test_dataset_dbref_handler(self): self.assertEqual(d4.location.__class__, ihm.location.DatabaseLocation) self.assertIsNone(d4.location.access_code) + self.assertEqual(d5.location.__class__, + ihm.location.DatabaseLocation) + self.assertEqual(d5.location.db_name, "testDB") + self.assertEqual(d5.location.access_code, "testcode") + self.assertEqual(d5.location.version, "testver") + self.assertEqual(d5.location.details, "testdetails") def test_related_datasets_handler(self): """Test RelatedDatasetsHandler""" @@ -1358,7 +1381,7 @@ def test_post_process_handler(self): _ihm_modeling_post_process.script_file_id _ihm_modeling_post_process.details 1 1 1 1 'filter' 'energy/score' 15000 6520 . . 401 501 . -2 1 1 2 'cluster' 'dRMSD' 6520 6520 . . . . . +2 1 1 2 'cluster' 'invalid' 6520 6520 . . . . . 3 1 2 1 'filter' 'energy/score' 16000 7520 . . . . . 4 1 2 2 'filter' 'composition' 7520 5520 . . . . . 5 1 2 3 'cluster' 'dRMSD' 5520 6520 . . . . . @@ -1384,7 +1407,8 @@ def test_post_process_handler(self): self.assertEqual(a1.steps[0].software._id, '401') self.assertEqual(a1.steps[0].script_file._id, '501') self.assertEqual(a1.steps[1].__class__, ihm.analysis.ClusterStep) - self.assertEqual(a1.steps[1].feature, 'dRMSD') + # invalid feature should be mapped to default + self.assertEqual(a1.steps[1].feature, 'other') self.assertEqual(a1.steps[1].num_models_begin, 6520) self.assertIsNone(a1.steps[1].software) self.assertIsNone(a1.steps[1].script_file) @@ -1555,11 +1579,12 @@ def test_ensemble_handler(self): _ihm_ensemble_info.ensemble_precision_value _ihm_ensemble_info.ensemble_file_id _ihm_ensemble_info.details +_ihm_ensemble_info.model_group_superimposed_flag _ihm_ensemble_info.sub_sample_flag _ihm_ensemble_info.sub_sampling_type -1 'Cluster 1' 2 3 . dRMSD 1257 10 15.400 9 . . . -2 'Cluster 2' 2 . . dRMSD 1257 10 15.400 9 'cluster details' YES independent -3 'Cluster 3' . . invalid_cluster invalid_feature 1 1 15.400 9 . . . +1 'Cluster 1' 2 3 . dRMSD 1257 10 15.400 9 . . . . +2 'Cluster 2' 2 . . dRMSD 1257 10 15.400 9 'cluster details' NO YES independent +3 'Cluster 3' . . invalid_cluster invalid_feature 1 1 15.400 9 . YES . . # # loop_ @@ -1588,6 +1613,7 @@ def test_ensemble_handler(self): self.assertIsNone(e.details) self.assertAlmostEqual(e.precision, 15.4, delta=0.1) self.assertEqual(e.file._id, '9') + self.assertIsNone(e.superimposed) self.assertIsNone(e2.model_group) self.assertEqual(e2.num_models_deposited, 10) self.assertEqual(e2.details, 'cluster details') @@ -1602,9 +1628,11 @@ def test_ensemble_handler(self): self.assertEqual(s2.model_group._id, '42') self.assertEqual(s2.file._id, '3') self.assertIsInstance(s2, ihm.model.IndependentSubsample) + self.assertFalse(e2.superimposed) # invalid cluster/feature should be mapped to default self.assertEqual(e3.clustering_method, 'Other') self.assertEqual(e3.clustering_feature, 'other') + self.assertTrue(e3.superimposed) def test_density_handler(self): """Test DensityHandler""" diff --git a/modules/core/dependency/python-ihm/test/test_restraint.py b/modules/core/dependency/python-ihm/test/test_restraint.py index 3b53718274..ccc062f9b5 100644 --- a/modules/core/dependency/python-ihm/test/test_restraint.py +++ b/modules/core/dependency/python-ihm/test/test_restraint.py @@ -106,14 +106,22 @@ def test_cross_link(self): def test_residue_cross_link(self): """Test ResidueCrossLink class""" + e = ihm.Entity('AHCDAH') + asym1 = ihm.AsymUnit(e) + asym2 = ihm.AsymUnit(e) + ex_xl = ihm.restraint.ExperimentalCrossLink(e.residue(1), e.residue(2)) f = ihm.restraint.ResidueCrossLink( - experimental_cross_link='ex', asym1='asym1', asym2='asym2', + experimental_cross_link=ex_xl, asym1=asym1, asym2=asym2, distance='dist') self.assertEqual(f.granularity, 'by-residue') self.assertIsNone(f.atom1) self.assertIsNone(f.atom2) - self.assertEqual(f.asym1, 'asym1') - self.assertEqual(f.asym2, 'asym2') + self.assertEqual(f.asym1, asym1) + self.assertEqual(f.asym2, asym2) + self.assertEqual(f.residue1.seq_id, 1) + self.assertEqual(f.residue1.asym, asym1) + self.assertEqual(f.residue2.seq_id, 2) + self.assertEqual(f.residue2.asym, asym2) def test_feature_cross_link(self): """Test FeatureCrossLink class""" diff --git a/modules/core/dependency/python-ihm/util/make-mmcif.py b/modules/core/dependency/python-ihm/util/make-mmcif.py index 73c9ea0868..2f0ac1683c 100644 --- a/modules/core/dependency/python-ihm/util/make-mmcif.py +++ b/modules/core/dependency/python-ihm/util/make-mmcif.py @@ -52,13 +52,18 @@ def add_ihm_info(s): return s -if len(sys.argv) != 2: - print("Usage: %s input.cif" % sys.argv[0], file=sys.stderr) +if len(sys.argv) != 2 and len(sys.argv) != 3: + print("Usage: %s input.cif [output.cif]" % sys.argv[0], file=sys.stderr) sys.exit(1) + fname = sys.argv[1] +if len(sys.argv) > 2: + out_fname = sys.argv[2] +else: + out_fname = 'output.cif' with open(fname) as fh: - with open('output.cif', 'w') as fhout: + with open(out_fname, 'w') as fhout: ihm.dumper.write( fhout, [add_ihm_info(s) for s in ihm.reader.read(fh)], variant=ihm.dumper.IgnoreVariant(['_audit_conform'])) diff --git a/modules/core/examples/excluded_volume.py b/modules/core/examples/excluded_volume.py index eb2cbc34fc..291ecece48 100644 --- a/modules/core/examples/excluded_volume.py +++ b/modules/core/examples/excluded_volume.py @@ -2,22 +2,31 @@ # Setup an excluded volume restraint between a bunch of particles with radius. # -import IMP.example +import IMP.container import sys IMP.setup_from_argv(sys.argv, "excluded volume") -(m, c) = IMP.example.create_model_and_particles() +# Make 100 particles randomly distributed in a cubic box +m = IMP.Model() +lsc = IMP.container.ListSingletonContainer(m) +b = IMP.algebra.BoundingBox3D(IMP.algebra.Vector3D(0,0,0), + IMP.algebra.Vector3D(10,10,10)) +for i in range(100): + p = m.add_particle("p") + lsc.add(p) + d = IMP.core.XYZR.setup_particle(m, p, + IMP.algebra.Sphere3D(IMP.algebra.get_random_vector_in(b), 1)) # this container lists all pairs that are close at the time of evaluation -nbl = IMP.container.ClosePairContainer(c, 0, 2) +nbl = IMP.container.ClosePairContainer(lsc, 0, 2) h = IMP.core.HarmonicLowerBound(0, 1) sd = IMP.core.SphereDistancePairScore(h) # use the lower bound on the inter-sphere distance to push the spheres apart nbr = IMP.container.PairsRestraint(sd, nbl) # alternatively, one could just do -r = IMP.core.ExcludedVolumeRestraint(c) +r = IMP.core.ExcludedVolumeRestraint(lsc) # get the current score sf = IMP.core.RestraintsScoringFunction([nbr, r]) diff --git a/modules/core/examples/linear_and_harmonic_scores.py b/modules/core/examples/linear_and_harmonic_scores.py new file mode 100644 index 0000000000..e417ebafcc --- /dev/null +++ b/modules/core/examples/linear_and_harmonic_scores.py @@ -0,0 +1,106 @@ +## \example core/linear_and_harmonic_scores.py +# An example for setting a linear or harmonic score between two particles +# using either a point distance (between particle centers) or a sphere +# distance (between particle surfaces). +# +# Note: this example relies on matplotlib for plotting the scores, +# but it can be easily modified to just print the scores. +# +# Author: Barak Raveh, 2022/12/13 + +import IMP +import IMP.algebra +import IMP.core +try: + import matplotlib.pyplot +except ImportError: + matplotlib = None +import numpy +import sys + + +IMP.setup_from_argv(sys.argv, "linear or harmonic score example") + + +DEFAULT_RADIUS = 2.0 # radius of particles +LINEAR_OFFSET = 4.0 # distance at which the function is zero (note this is not the Y-axis intercept!) +LINEAR_SLOPE = 3.0 # slope of linear score (= force in kcal/mol/A) +HARMONIC_MEAN = 3 # distance at which the function is minimal/maximal +HARMONIC_K = 2.0 # quadratic coefficient + +def create_particle(m, radius = DEFAULT_RADIUS): + p = IMP.Particle(m) + s = IMP.algebra.Sphere3D([0,0,0], radius) + IMP.core.XYZR.setup_particle(p, s) + return p + +def create_linear_point_pair_score(): + ''' slope*x + intercept for point distance ''' + linear_functor = IMP.core.Linear(LINEAR_OFFSET, LINEAR_SLOPE) + return IMP.core.DistancePairScore(linear_functor) + +def create_harmonic_point_pair_score(): + ''' 0.5*k*(x-mean)^2 for point distance ''' + harmonic_functor = IMP.core.Harmonic(HARMONIC_MEAN, HARMONIC_K) + return IMP.core.DistancePairScore(harmonic_functor) + +def create_linear_sphere_pair_score(): + ''' slope*x + intercept for sphere distance ''' + linear_functor = IMP.core.Linear(LINEAR_OFFSET, LINEAR_SLOPE) + return IMP.core.SphereDistancePairScore(linear_functor) + +def create_harmonic_sphere_pair_score(): + ''' 0.5*k*(x-mean)^2 for sphere distance ''' + harmonic_functor = IMP.core.Harmonic(HARMONIC_MEAN, HARMONIC_K) + return IMP.core.SphereDistancePairScore(harmonic_functor) + +def create_model(pair_score): + m = IMP.Model() + particles = [create_particle(m) for x in range(2)] + restraint = IMP.core.PairRestraint(m, pair_score, particles) + xyzrs = [IMP.core.XYZR(p) for p in particles] + return m, xyzrs, restraint + +def plot_score(pair_score, caption, + xmin = -15.0, xmax = 15.0, xstep = 0.01): + ''' + Plots a pair_score between two particles, one particle + being at [0,0,0] and the other particle being at [x,0,0] + for x in the closed interval [xmin:xstep:xmax] + ''' + m, xyzrs, restraint = create_model(pair_score) + xyzrs[0].set_coordinates([0,0,0]) + X = numpy.arange(xmin, xmax+0.1*xstep, xstep) + Y = 0.0*X + for i,x in enumerate(X): + xyzrs[0].set_coordinates([x,0,0]) + Y[i] = restraint.get_score() + if not matplotlib: + print("Not showing plot; matplotlib is not installed " + "or could not be imported") + elif IMP.get_is_quick_test(): + print("Not showing plot, as we are running test cases") + else: + matplotlib.pyplot.plot(X,Y,'-') + matplotlib.pyplot.title(caption) + matplotlib.pyplot.xlabel(r"$X_2$ [$\AA$]") + matplotlib.pyplot.ylabel("Energy [$kcal \cdot mol^{-1}$]") + matplotlib.pyplot.gca().spines['bottom'].set_position(('data', 0)) + matplotlib.pyplot.show() + +if __name__ == "__main__": + # NOTE: sphere distance is not distance! + linear_str = "{:.1f}*(dist-{:.1f})".format(LINEAR_SLOPE, LINEAR_OFFSET) + harmonic_str = "{:.1f}*(dist-{:.1f})^2".format(HARMONIC_K, HARMONIC_MEAN) + plot_score(create_linear_point_pair_score(), + caption="Linear point distance\n{}" + .format(linear_str)) + plot_score(create_linear_sphere_pair_score(), + caption="Linear sphere distance (R={:.1f} A)\n{}" + .format(DEFAULT_RADIUS, linear_str)) + plot_score(create_harmonic_point_pair_score(), + caption="Harmonic point distance\n{}" + .format(harmonic_str)) + plot_score(create_harmonic_sphere_pair_score(), + caption="Harmonic sphere distance (R={:.1f} A)\n{}" + .format(DEFAULT_RADIUS, harmonic_str)) diff --git a/modules/core/examples/model_numpy.py b/modules/core/examples/model_numpy.py index 2a87645e44..6eed6e6e28 100644 --- a/modules/core/examples/model_numpy.py +++ b/modules/core/examples/model_numpy.py @@ -2,19 +2,29 @@ # Demonstration using NumPy to manipulate IMP data. # -import IMP.example +import IMP.container import sys IMP.setup_from_argv(sys.argv, "model numpy") -(m, c) = IMP.example.create_model_and_particles() - if not IMP.IMP_KERNEL_HAS_NUMPY: print("IMP was not built with NumPy support.") sys.exit(0) +# Make 100 xyz particles randomly distributed in a cubic box +m = IMP.Model() +sc = IMP.container.ListSingletonContainer(m) +b = IMP.algebra.BoundingBox3D(IMP.algebra.Vector3D(0,0,0), + IMP.algebra.Vector3D(10,10,10)) +for i in range(100): + p = m.add_particle("p") + sc.add(p) + d = IMP.core.XYZR.setup_particle(m, p, + IMP.algebra.Sphere3D(IMP.algebra.get_random_vector_in(b), 1)) + d.set_coordinates_are_optimized(True) + # Get all pairs of particles that are close to each other -nbl = IMP.container.ClosePairContainer(c, 0, 2) +nbl = IMP.container.ClosePairContainer(sc, 0, 2) m.update() # contents is a NumPy 2xN array of the indices of each close particle pair diff --git a/modules/core/examples/pair_restraint.py b/modules/core/examples/pair_restraint.py index c9a19dbefd..af3b1e373e 100644 --- a/modules/core/examples/pair_restraint.py +++ b/modules/core/examples/pair_restraint.py @@ -2,15 +2,27 @@ # Restrain the distance between a pair of particles. # -import IMP.example +import IMP.algebra +import IMP.core import sys IMP.setup_from_argv(sys.argv, "pair restraint") -(m, c) = IMP.example.create_model_and_particles() +# Make two xyz particles randomly distributed in space +m = IMP.Model() +b = IMP.algebra.BoundingBox3D(IMP.algebra.Vector3D(0,0,0), + IMP.algebra.Vector3D(10,10,10)) +inds = [] +for i in range(2): + p = m.add_particle("p") + d = IMP.core.XYZR.setup_particle(m, p, + IMP.algebra.Sphere3D(IMP.algebra.get_random_vector_in(b), 1)) + inds.append(p) +# Score the distance between the two particles with a harmonic function uf = IMP.core.Harmonic(0, 1) df = IMP.core.DistancePairScore(uf) -inds = c.get_indexes() r = IMP.core.PairRestraint(m, df, (inds[0], inds[1])) + +# Print the current score of the restraint, without first derivatives print(r.evaluate(False)) diff --git a/modules/core/include/AngleRestraint.h b/modules/core/include/AngleRestraint.h index 5f18a75c5a..3ef810cd7f 100644 --- a/modules/core/include/AngleRestraint.h +++ b/modules/core/include/AngleRestraint.h @@ -15,6 +15,9 @@ #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -22,6 +25,14 @@ IMPCORE_BEGIN_NAMESPACE /** \see AngleTripletScore */ class IMPCOREEXPORT AngleRestraint : public TripletRestraint { + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + + IMP_OBJECT_SERIALIZE_DECL(AngleRestraint); + public: //! Create the angle restraint. /** \param[in] m Model. @@ -32,6 +43,7 @@ class IMPCOREEXPORT AngleRestraint : public TripletRestraint { */ AngleRestraint(Model *m, UnaryFunction* score_func, ParticleIndexAdaptor p1, ParticleIndexAdaptor p2, ParticleIndexAdaptor p3); + AngleRestraint() {} IMP_OBJECT_METHODS(AngleRestraint); }; diff --git a/modules/core/include/AngleTripletScore.h b/modules/core/include/AngleTripletScore.h index d25054dd43..e79541a884 100644 --- a/modules/core/include/AngleTripletScore.h +++ b/modules/core/include/AngleTripletScore.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -22,9 +24,17 @@ IMPCORE_BEGIN_NAMESPACE class IMPCOREEXPORT AngleTripletScore : public TripletScore { IMP::PointerMember f_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), f_); + } + IMP_OBJECT_SERIALIZE_DECL(AngleTripletScore); + public: //! Score the angle (in radians) using f AngleTripletScore(UnaryFunction *f); + AngleTripletScore() {} virtual double evaluate_index(Model *m, const ParticleIndexTriplet &pi, DerivativeAccumulator *da) const override; diff --git a/modules/core/include/BallMover.h b/modules/core/include/BallMover.h index fcb7c1b136..ca784ef6b7 100644 --- a/modules/core/include/BallMover.h +++ b/modules/core/include/BallMover.h @@ -2,7 +2,7 @@ * \file IMP/core/BallMover.h * \brief A modifier which variables within a ball. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -13,6 +13,9 @@ #include #include #include "MonteCarloMover.h" +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -26,6 +29,14 @@ class IMPCOREEXPORT BallMover : public MonteCarloMover { double radius_; algebra::VectorKDs originals_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + pis_, keys_, radius_, originals_); + } + IMP_OBJECT_SERIALIZE_DECL(BallMover); + void initialize(ParticleIndexes pis, FloatKeys keys, double radius); public: @@ -56,6 +67,8 @@ class IMPCOREEXPORT BallMover : public MonteCarloMover { */ BallMover(Model *m, const ParticleIndexes &pis, Float radius); + BallMover() {} + void set_radius(Float radius) { IMP_ALWAYS_CHECK(radius > 0, "The radius must be positive", IMP::ValueException); diff --git a/modules/core/include/ChecksScoreState.h b/modules/core/include/ChecksScoreState.h index 14d1fa3d41..de2189146a 100644 --- a/modules/core/include/ChecksScoreState.h +++ b/modules/core/include/ChecksScoreState.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -20,8 +22,15 @@ class IMPCOREEXPORT ChecksScoreState : public ScoreState { double probability_; unsigned int num_checked_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), probability_, num_checked_); + } + IMP_OBJECT_SERIALIZE_DECL(ChecksScoreState); + public: ChecksScoreState(Model *m, double probability); + ChecksScoreState() {} unsigned int get_number_of_checked() const { return num_checked_; } diff --git a/modules/core/include/ClosePairsFinder.h b/modules/core/include/ClosePairsFinder.h index b97c8e8ffd..0b05528ca0 100644 --- a/modules/core/include/ClosePairsFinder.h +++ b/modules/core/include/ClosePairsFinder.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE #ifndef IMP_DOXYGEN @@ -36,8 +38,15 @@ class IMPCOREEXPORT ClosePairsFinder : public ParticleInputs, public IMP::Object { double distance_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), distance_, + mutable_access_pair_filters()); + } + public: ClosePairsFinder(std::string name); + ClosePairsFinder() : IMP::Object("") {} ~ClosePairsFinder(); //! return all close pairs among pc in model m diff --git a/modules/core/include/ConjugateGradients.h b/modules/core/include/ConjugateGradients.h index 9492f4a829..ec0847155f 100644 --- a/modules/core/include/ConjugateGradients.h +++ b/modules/core/include/ConjugateGradients.h @@ -12,6 +12,8 @@ #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -35,12 +37,17 @@ class IMPCOREEXPORT ConjugateGradients : public AttributeOptimizer { public: ConjugateGradients(Model *m, std::string name = "ConjugateGradients%1%"); + ConjugateGradients() {} //! Set the threshold for the minimum gradient void set_gradient_threshold(Float t) { threshold_ = t; } #ifndef IMP_DOXYGEN - void set_threshold(Float t) { set_gradient_threshold(t); } + IMPCORE_DEPRECATED_METHOD_DECL(2.19) + void set_threshold(Float t) { + IMPCORE_DEPRECATED_METHOD_DEF(2.19, "Use set_gradient_threshold()."); + set_gradient_threshold(t); + } #endif //! Limit how far anything can change each time step @@ -64,6 +71,12 @@ class IMPCOREEXPORT ConjugateGradients : public AttributeOptimizer { const Vector &estimate); Float threshold_; Float max_change_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), threshold_, max_change_); + } }; IMPCORE_END_NAMESPACE diff --git a/modules/core/include/ConstantRestraint.h b/modules/core/include/ConstantRestraint.h index fc94de1039..04edd48421 100644 --- a/modules/core/include/ConstantRestraint.h +++ b/modules/core/include/ConstantRestraint.h @@ -14,6 +14,9 @@ #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -24,9 +27,17 @@ IMPCORE_BEGIN_NAMESPACE class IMPCOREEXPORT ConstantRestraint : public Restraint { Float v_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), v_); + } + IMP_OBJECT_SERIALIZE_DECL(ConstantRestraint); + public: //! Add v to the total score. ConstantRestraint(Model *m, Float v); + ConstantRestraint() {} virtual double unprotected_evaluate(IMP::DerivativeAccumulator *accum) const override; diff --git a/modules/core/include/Cosine.h b/modules/core/include/Cosine.h index 79c9aa30dc..f93420414e 100644 --- a/modules/core/include/Cosine.h +++ b/modules/core/include/Cosine.h @@ -9,6 +9,9 @@ #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -31,6 +34,8 @@ class IMPCOREEXPORT Cosine : public UnaryFunction { periodicity_(periodicity), phase_(phase) {} + Cosine() {} + virtual DerivativePair evaluate_with_derivative( double feature) const override; @@ -44,6 +49,14 @@ class IMPCOREEXPORT Cosine : public UnaryFunction { Float force_constant_; int periodicity_; Float phase_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + force_constant_, periodicity_, phase_); + } + IMP_OBJECT_SERIALIZE_DECL(Cosine); }; IMPCORE_END_NAMESPACE diff --git a/modules/core/include/DistanceRestraint.h b/modules/core/include/DistanceRestraint.h index a310899ec2..20e751a017 100644 --- a/modules/core/include/DistanceRestraint.h +++ b/modules/core/include/DistanceRestraint.h @@ -17,6 +17,9 @@ #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -36,6 +39,14 @@ class IMPCOREEXPORT DistanceRestraint : public IMP::internal::TupleRestraint #endif { + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class< + IMP::internal::TupleRestraint >(this)); + } + IMP_OBJECT_SERIALIZE_DECL(DistanceRestraint); + public: //! Create the distance restraint. /** \param[in] m Model. @@ -48,6 +59,7 @@ class IMPCOREEXPORT DistanceRestraint : ParticleIndexAdaptor a, ParticleIndexAdaptor b, std::string name = "DistanceRestraint %1%"); + DistanceRestraint() {} #ifdef SWIG protected: diff --git a/modules/core/include/DistanceToSingletonScore.h b/modules/core/include/DistanceToSingletonScore.h index c6e985dd55..e23d08552e 100644 --- a/modules/core/include/DistanceToSingletonScore.h +++ b/modules/core/include/DistanceToSingletonScore.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -44,8 +46,16 @@ class GenericDistanceToSingletonScore : public SingletonScore { } }; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), f_, pt_); + } + IMP_OBJECT_SERIALIZE_DECL(GenericDistanceToSingletonScore); + public: GenericDistanceToSingletonScore(UF *f, const algebra::Vector3D &pt); + GenericDistanceToSingletonScore() {} virtual double evaluate_index(Model *m, ParticleIndex p, DerivativeAccumulator *da) const override; virtual ModelObjectsTemp do_get_inputs( diff --git a/modules/core/include/Gaussian.h b/modules/core/include/Gaussian.h index a6acc39fe7..03a0f9ee42 100644 --- a/modules/core/include/Gaussian.h +++ b/modules/core/include/Gaussian.h @@ -2,7 +2,7 @@ * \file IMP/core/Gaussian.h * \brief Decorator to hold Gaussian3D * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -20,6 +20,8 @@ #include #include "internal/rigid_bodies.h" #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -28,9 +30,24 @@ IMPCORE_BEGIN_NAMESPACE /** little class to store an Eigen::Matrix3d */ class IMPCOREEXPORT Matrix3D : public IMP::Object{ Eigen::Matrix3d mat_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + for (unsigned i = 0; i < 3; ++i) { + for (unsigned j = 0; j < 3; ++j) { + ar(mat_(i, j)); + } + } + } + IMP_OBJECT_SERIALIZE_DECL(Matrix3D); + public: - Matrix3D(Eigen::Matrix3d mat, - std::string name="Matrix3DDensityMap%1%"):Object(name),mat_(mat){ } + Matrix3D(Eigen::Matrix3d mat, + std::string name="Matrix3DDensityMap%1%"):Object(name),mat_(mat){ } + + Matrix3D() : IMP::Object("") {} + Eigen::Matrix3d get_mat() const {return mat_;} }; diff --git a/modules/core/include/GridClosePairsFinder.h b/modules/core/include/GridClosePairsFinder.h index 7fc7c82f98..2b2e7de4f9 100644 --- a/modules/core/include/GridClosePairsFinder.h +++ b/modules/core/include/GridClosePairsFinder.h @@ -11,6 +11,8 @@ #include "ClosePairsFinder.h" #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -19,6 +21,11 @@ IMPCORE_BEGIN_NAMESPACE \see ClosePairsScoreState */ class IMPCOREEXPORT GridClosePairsFinder : public ClosePairsFinder { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(GridClosePairsFinder); public: GridClosePairsFinder(); virtual IntPairs get_close_pairs(const algebra::BoundingBox3Ds &bbs) const diff --git a/modules/core/include/Harmonic.h b/modules/core/include/Harmonic.h index 958bc39800..75c12fd711 100644 --- a/modules/core/include/Harmonic.h +++ b/modules/core/include/Harmonic.h @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -25,6 +28,7 @@ class Harmonic : public UnaryFunction { public: /** Create with the given mean and the spring constant k */ Harmonic(Float mean, Float k) : mean_(mean), k_(k) {} + Harmonic() {} virtual DerivativePair evaluate_with_derivative( double feature) const override { @@ -69,6 +73,13 @@ class Harmonic : public UnaryFunction { private: Float mean_; Float k_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), mean_, k_); + } + IMP_OBJECT_SERIALIZE_DECL(Harmonic); }; IMPCORE_END_NAMESPACE diff --git a/modules/core/include/HarmonicLowerBound.h b/modules/core/include/HarmonicLowerBound.h index bffd52790c..92b4b6750b 100644 --- a/modules/core/include/HarmonicLowerBound.h +++ b/modules/core/include/HarmonicLowerBound.h @@ -1,7 +1,7 @@ /** * \file IMP/core/HarmonicLowerBound.h \brief Harmonic lower bound function. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCORE_HARMONIC_LOWER_BOUND_H @@ -9,6 +9,8 @@ #include #include "Harmonic.h" +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -18,9 +20,15 @@ IMPCORE_BEGIN_NAMESPACE \see TruncatedHarmonicLowerBound */ class HarmonicLowerBound : public Harmonic { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(HarmonicLowerBound); public: /** Create with the given mean and the spring constant k */ HarmonicLowerBound(Float mean, Float k) : Harmonic(mean, k) {} + HarmonicLowerBound() {} virtual double evaluate(double feature) const override { return feature >= Harmonic::get_mean() ? 0.0 : Harmonic::evaluate(feature); } diff --git a/modules/core/include/HarmonicUpperBound.h b/modules/core/include/HarmonicUpperBound.h index 644f763d27..c595deda89 100644 --- a/modules/core/include/HarmonicUpperBound.h +++ b/modules/core/include/HarmonicUpperBound.h @@ -1,7 +1,7 @@ /** * \file IMP/core/HarmonicUpperBound.h \brief Harmonic upper bound function. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCORE_HARMONIC_UPPER_BOUND_H @@ -9,6 +9,8 @@ #include #include "Harmonic.h" +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -18,9 +20,15 @@ IMPCORE_BEGIN_NAMESPACE \see TruncatedHarmonicUpperBound */ class HarmonicUpperBound : public Harmonic { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(HarmonicUpperBound); public: /** Create with the given mean and the spring constant k */ HarmonicUpperBound(Float mean, Float k) : Harmonic(mean, k) {} + HarmonicUpperBound() {} virtual double evaluate(double feature) const override { return feature <= Harmonic::get_mean() ? 0.0 : Harmonic::evaluate(feature); } diff --git a/modules/core/include/Hierarchy.h b/modules/core/include/Hierarchy.h index fe8c56a023..75e68fe451 100644 --- a/modules/core/include/Hierarchy.h +++ b/modules/core/include/Hierarchy.h @@ -21,11 +21,13 @@ #include #include -#include +#include #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -49,6 +51,11 @@ class IMPCOREEXPORT HierarchyTraits { ParticleIndexesKey children_; ParticleIndexKey parent_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(children_, parent_); + } + public: HierarchyTraits() {} //! Create a HierarchyTraits with the given name @@ -77,6 +84,11 @@ typedef IMP::Vector GenericHierarchies; \see HierarchyTraits */ class IMPCOREEXPORT Hierarchy : public Decorator { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), traits_); + } + static void do_setup_particle(Model *, ParticleIndex, HierarchyTraits) {} static void do_setup_particle(Model *m, ParticleIndex pi, @@ -433,10 +445,10 @@ struct HierarchyCounter : public HierarchyVisitor { private: unsigned int ct_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & ct_; + template void serialize(Archive &ar) { + ar(ct_); } }; diff --git a/modules/core/include/Linear.h b/modules/core/include/Linear.h index bbc5589d53..e02aef1397 100644 --- a/modules/core/include/Linear.h +++ b/modules/core/include/Linear.h @@ -9,6 +9,9 @@ #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -20,6 +23,7 @@ class Linear : public UnaryFunction { public: //! Create with the given offset and slope. Linear(double offset, double slope) : slope_(slope), offset_(offset) {} + Linear() {} void set_slope(double f) { slope_ = f; } @@ -38,6 +42,14 @@ class Linear : public UnaryFunction { private: double slope_, offset_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + slope_, offset_); + } + IMP_OBJECT_SERIALIZE_DECL(Linear); }; IMPCORE_END_NAMESPACE diff --git a/modules/core/include/MonteCarloMover.h b/modules/core/include/MonteCarloMover.h index 6924ef33b0..8ae0fb1196 100644 --- a/modules/core/include/MonteCarloMover.h +++ b/modules/core/include/MonteCarloMover.h @@ -2,7 +2,7 @@ * \file IMP/core/MonteCarloMover.h * \brief The base class for movers for Monte Carlo optimization. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -15,6 +15,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -44,8 +46,16 @@ class IMPCOREEXPORT MonteCarloMover : public ModelObject { unsigned int num_rejected_; bool has_move_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + num_proposed_, num_rejected_, has_move_); + } + public: MonteCarloMover(Model *m, std::string name); + MonteCarloMover(); //! Propose a modification /** The method should return the list of all particles that were diff --git a/modules/core/include/MultipleBinormalRestraint.h b/modules/core/include/MultipleBinormalRestraint.h index a01ed6a83c..122f46adde 100644 --- a/modules/core/include/MultipleBinormalRestraint.h +++ b/modules/core/include/MultipleBinormalRestraint.h @@ -13,7 +13,7 @@ #include #include -#include +#include IMPCORE_BEGIN_NAMESPACE @@ -57,11 +57,11 @@ class BinormalTerm { double correlation_, weight_; std::pair means_, stdevs_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & correlation_ & weight_ & means_.first & means_.second - & stdevs_.first & stdevs_.second; + template void serialize(Archive &ar) { + ar(correlation_, weight_, means_.first, means_.second, stdevs_.first, + stdevs_.second); } double evaluate(const double dihedral[2], double &sin1, double &sin2, diff --git a/modules/core/include/RestraintsScoringFunction.h b/modules/core/include/RestraintsScoringFunction.h index 97004b8cdf..a9e150af1a 100644 --- a/modules/core/include/RestraintsScoringFunction.h +++ b/modules/core/include/RestraintsScoringFunction.h @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -23,7 +26,14 @@ class RestraintsScoringFunction : #else public IMP::internal::RestraintsScoringFunction #endif - { +{ + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(RestraintsScoringFunction); + public: RestraintsScoringFunction(const RestraintsAdaptor &rs, double weight = 1.0, double max = NO_MAX, @@ -32,6 +42,8 @@ class RestraintsScoringFunction : RestraintsScoringFunction(const RestraintsAdaptor &rs, std::string name) : IMP::internal::RestraintsScoringFunction(rs, 1.0, NO_MAX, name) {} + + RestraintsScoringFunction() {} #if defined(SWIG) void do_add_score_and_derivatives( ScoreAccumulator sa, const ScoreStatesTemp &ss) override; @@ -43,7 +55,22 @@ class RestraintsScoringFunction : virtual Restraints create_restraints() const override; virtual ModelObjectsTemp do_get_inputs() const override; + + // Expose methods to access the list of restraints from Python + Restraints get_restraints() const; + void set_restraints(const Restraints& d); + unsigned int get_number_of_restraints() const; + void clear_restraints(); + Restraint *get_restraint(unsigned int i) const; + void erase_restraint(unsigned int i); + unsigned int add_restraint(Restraint *d); + void add_restraints(const Restraints& d); + unsigned int _python_index_restraint(Restraint *r, unsigned int start, + unsigned int stop); + IMP_LIST_PYTHON_IMPL(restraint, restraints, Restraints, Restraints) + IMP_OBJECT_METHODS(RestraintsScoringFunction); + #endif }; diff --git a/modules/core/include/RigidBodyMover.h b/modules/core/include/RigidBodyMover.h index d04a428b42..d53114724c 100644 --- a/modules/core/include/RigidBodyMover.h +++ b/modules/core/include/RigidBodyMover.h @@ -16,6 +16,9 @@ #include #include #include +#include +#include + IMPCORE_BEGIN_NAMESPACE //! Modify the transformation of a rigid body @@ -31,6 +34,13 @@ class IMPCOREEXPORT RigidBodyMover : public MonteCarloMover { Float max_angle_; ParticleIndex pi_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + last_transformation_, max_translation_, max_angle_, pi_); + } + IMP_OBJECT_SERIALIZE_DECL(RigidBodyMover); + public: //! Constructor. The given rigid body is rotated and translated. /** \param[in] m the Model @@ -41,6 +51,8 @@ class IMPCOREEXPORT RigidBodyMover : public MonteCarloMover { RigidBodyMover(Model *m, ParticleIndex pi, Float max_translation, Float max_rotation); + RigidBodyMover() {} + void set_maximum_translation(Float mt) { IMP_USAGE_CHECK(mt > 0, "Max translation must be positive"); max_translation_ = mt; diff --git a/modules/core/include/RigidClosePairsFinder.h b/modules/core/include/RigidClosePairsFinder.h index 538522bacb..9962dda981 100644 --- a/modules/core/include/RigidClosePairsFinder.h +++ b/modules/core/include/RigidClosePairsFinder.h @@ -2,7 +2,7 @@ * \file IMP/core/RigidClosePairsFinder.h * \brief Handle rigid bodies by looking at their members * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCORE_RIGID_CLOSE_PAIRS_FINDER_H @@ -11,6 +11,8 @@ #include "ClosePairsFinder.h" #include "rigid_bodies.h" #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -60,6 +62,18 @@ class IMPCOREEXPORT RigidClosePairsFinder : public ClosePairsFinder { mutable IMP::PointerMember cpf_; ObjectKey k_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), cpf_); + if (std::is_base_of::value) { + k_ = get_hierarchy_key(); + } + } + IMP_OBJECT_SERIALIZE_DECL(RigidClosePairsFinder); + + ObjectKey get_hierarchy_key() const; + public: RigidClosePairsFinder(ClosePairsFinder *cpf = nullptr); diff --git a/modules/core/include/SerialMover.h b/modules/core/include/SerialMover.h index 75d5f8647b..ae3353825c 100644 --- a/modules/core/include/SerialMover.h +++ b/modules/core/include/SerialMover.h @@ -2,7 +2,7 @@ * \file IMP/core/SerialMover.h * \brief A mover that applies other movers one at a time * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,6 +12,10 @@ #include #include "MonteCarlo.h" #include "MonteCarloMover.h" +#include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -24,12 +28,22 @@ class IMPCOREEXPORT SerialMover : public MonteCarloMover { int imov_; MonteCarloMovers movers_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + imov_, movers_); + } + IMP_OBJECT_SERIALIZE_DECL(SerialMover); + public: /** Constructor. \param[in] mvs list of movers to apply one after another */ SerialMover(const MonteCarloMoversTemp& mvs); + SerialMover() {} + const MonteCarloMovers& get_movers() const { return movers_; } protected: diff --git a/modules/core/include/SubsetMover.h b/modules/core/include/SubsetMover.h index 6805d86099..66e582f1c4 100644 --- a/modules/core/include/SubsetMover.h +++ b/modules/core/include/SubsetMover.h @@ -2,7 +2,7 @@ * \file IMP/core/SubsetMover.h * \brief A mover that applies a random subset of movers * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,6 +12,10 @@ #include #include "MonteCarlo.h" #include "MonteCarloMover.h" +#include +#include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -25,6 +29,14 @@ class IMPCOREEXPORT SubsetMover : public MonteCarloMover { unsigned int n_; std::vector subset_inds_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + movers_, n_, subset_inds_); + } + IMP_OBJECT_SERIALIZE_DECL(SubsetMover); + public: /** Constructor. \param[in] mvs list of movers @@ -33,6 +45,8 @@ class IMPCOREEXPORT SubsetMover : public MonteCarloMover { */ SubsetMover(const MonteCarloMoversTemp& mvs, unsigned int n); + SubsetMover() {} + const MonteCarloMovers& get_movers() const { return movers_; } unsigned int get_subset_size() const { return n_; } diff --git a/modules/core/include/Transform.h b/modules/core/include/Transform.h index bc9685497e..a869ea23ec 100644 --- a/modules/core/include/Transform.h +++ b/modules/core/include/Transform.h @@ -11,6 +11,9 @@ #include #include #include +#include +#include + IMPCORE_BEGIN_NAMESPACE //! Apply a transformation to a passed particle @@ -27,6 +30,8 @@ class IMPCOREEXPORT Transform : public SingletonModifier { */ Transform(const algebra::Transformation3D &t, bool ignore_non_xyz = false); + Transform() {} + virtual void apply_index(Model *m, ParticleIndex p) const override; virtual ModelObjectsTemp do_get_inputs( @@ -40,6 +45,13 @@ class IMPCOREEXPORT Transform : public SingletonModifier { private: algebra::Transformation3D t_; bool ignore_non_xyz_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), t_, ignore_non_xyz_); + } + IMP_OBJECT_SERIALIZE_DECL(Transform); + }; IMPCORE_END_NAMESPACE diff --git a/modules/core/include/internal/rigid_body_tree.h b/modules/core/include/internal/rigid_body_tree.h index fc292690e1..b0e381ab90 100644 --- a/modules/core/include/internal/rigid_body_tree.h +++ b/modules/core/include/internal/rigid_body_tree.h @@ -2,7 +2,7 @@ * \file rigid_pair_score.h * \brief utilities for rigid pair scores. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCORE_INTERNAL_RIGID_BODY_TREE_H @@ -13,6 +13,8 @@ #include "../rigid_bodies.h" #include #include +#include +#include IMPCORE_BEGIN_INTERNAL_NAMESPACE @@ -21,10 +23,17 @@ class IMPCOREEXPORT RigidBodyHierarchy : public IMP::Object { struct Data { Ints children_; algebra::Sphere3D s_; + template void serialize(Archive &ar) { ar(children_, s_); } }; Vector tree_; ParticleIndexes constituents_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), rb_, tree_, constituents_); + } + IMP_OBJECT_SERIALIZE_DECL(RigidBodyHierarchy); + typedef Vector SphereIndexes; typedef Vector SpheresSplit; SpheresSplit divide_spheres(const algebra::Sphere3Ds &ss, @@ -86,7 +95,11 @@ class IMPCOREEXPORT RigidBodyHierarchy : public IMP::Object { return index; } algebra::Sphere3Ds get_all_spheres() const; + RigidBodyHierarchy(RigidBody rb, const ParticleIndexes &constituents); + + RigidBodyHierarchy() : Object("") {} + algebra::Sphere3Ds get_tree() const; bool get_constituents_match(const ParticleIndexes &ps) const { if (ps.size() != constituents_.size()) return false; diff --git a/modules/core/include/rigid_bodies.h b/modules/core/include/rigid_bodies.h index fd1cfea79d..fff010c6e5 100644 --- a/modules/core/include/rigid_bodies.h +++ b/modules/core/include/rigid_bodies.h @@ -120,6 +120,12 @@ class IMPCOREEXPORT RigidBody : public XYZ { // add a member associated with a reference frame void add_rigid_body_member(ParticleIndex pi); + // remove a member associated with xyz coords + void remove_point_member(ParticleIndex pi); + + // remove a member associated with a reference frame + void remove_rigid_body_member(ParticleIndex pi); + public: RigidMembers get_rigid_members() const; @@ -180,6 +186,8 @@ class IMPCOREEXPORT RigidBody : public XYZ { IMP_DECORATOR_SETUP_1(RigidBody, algebra::ReferenceFrame3D, rf); //! Make the rigid body no longer rigid. + /** If this rigid body has been added as a member of another rigid body, + it must be removed first. */ static void teardown_particle(RigidBody rb); IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(RigidBody); @@ -581,6 +589,16 @@ class IMPCOREEXPORT RigidBody : public XYZ { The radius of the rigid body is updated to reflect this change. */ void set_is_rigid_member(ParticleIndex pi, bool tf); + + //! Remove the member from this rigid body. + /** The member can be either a rigid body member or a point + member, either rigid ot non-rigid. + + The radius of the rigid body is updated to reflect the removed member. + + \throw UsageException if the given particle is not a member of this body. + */ + void remove_member(ParticleIndexAdaptor p); }; #ifndef IMP_DOXYGEN diff --git a/modules/core/pyext/swig.i-in b/modules/core/pyext/swig.i-in index 8ba207baee..4ab2fe1c5f 100644 --- a/modules/core/pyext/swig.i-in +++ b/modules/core/pyext/swig.i-in @@ -1,8 +1,3 @@ -%{ -#include -#include -%} - %template(_OpenCubicSplineBase) IMP::score_functor::ScoreUnaryFunction; IMP_SWIG_BASE_OBJECT(IMP::core, MonteCarloMover, MonteCarloMovers); @@ -11,12 +6,12 @@ IMP_SWIG_CONTAINER(IMP::core, IMP::core, MonteCarlo, Mover, mover); IMP_SWIG_CONTAINER(IMP::core, IMP::core, SerialMover, Mover, mover); IMP_SWIG_CONTAINER(IMP::core, IMP::core, SubsetMover, Mover, mover); -IMP_SWIG_OBJECT( IMP::core, AngleRestraint, AngleRestraints); -IMP_SWIG_OBJECT( IMP::core, AngleTripletScore, AngleTripletScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, AngleRestraint, AngleRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, AngleTripletScore, AngleTripletScores); IMP_SWIG_OBJECT_INSTANCE( IMP::core, AttributeSingletonScore, AttributeSingletonScore, AttributeSingletonScores); -IMP_SWIG_OBJECT( IMP::core, BallMover, BallMovers); -IMP_SWIG_OBJECT( IMP::core, SerialMover, SerialMovers); -IMP_SWIG_OBJECT( IMP::core, SubsetMover, SubsetMovers); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, BallMover, BallMovers); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, SerialMover, SerialMovers); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, SubsetMover, SubsetMovers); IMP_SWIG_OBJECT( IMP::core, DirectionMover, DirectionMovers); IMP_SWIG_OBJECT( IMP::core, SurfaceMover, SurfaceMovers); IMP_SWIG_OBJECT_INSTANCE( IMP::core, BoundingBox3DSingletonScore, BoundingBox3DSingletonScore, BoundingBox3DSingletonScores); @@ -26,32 +21,32 @@ IMP_SWIG_OBJECT( IMP::core, BoxSweepClosePairsFinder, BoxSweepClosePairsFinders) #endif IMP_SWIG_OBJECT( IMP::core, NearestNeighborsClosePairsFinder, NearestNeighborsClosePairsFinders); IMP_SWIG_OBJECT( IMP::core, CentroidOfRefined, CentroidOfRefineds); -IMP_SWIG_OBJECT( IMP::core, ChecksScoreState, ChecksScoreStates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ChecksScoreState, ChecksScoreStates); IMP_SWIG_OBJECT( IMP::core, ChildrenRefiner, ChildrenRefiners); IMP_SWIG_OBJECT( IMP::core, ClosePairsFinder, ClosePairsFinders); IMP_SWIG_OBJECT( IMP::core, ClosePairsPairScore, ClosePairsPairScores); IMP_SWIG_OBJECT( IMP::core, ClosedCubicSpline, ClosedCubicSplines); -IMP_SWIG_OBJECT( IMP::core, ConjugateGradients, ConjugateGradientsList); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ConjugateGradients, ConjugateGradientsList); IMP_SWIG_OBJECT( IMP::core, ConnectivityRestraint, ConnectivityRestraints); -IMP_SWIG_OBJECT( IMP::core, ConstantRestraint, ConstantRestraints); -IMP_SWIG_OBJECT( IMP::core, Cosine, Cosines); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ConstantRestraint, ConstantRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, Cosine, Cosines); IMP_SWIG_OBJECT( IMP::core, CoverRefined, CoverRefineds); IMP_SWIG_OBJECT( IMP::core, DerivativesFromRefined, DerivativesFromRefineds); IMP_SWIG_OBJECT( IMP::core, DerivativesToRefined, DerivativesToRefineds); IMP_SWIG_OBJECT( IMP::core, WeightedDerivativesToRefined, WeightedDerivativesToRefineds); IMP_SWIG_OBJECT( IMP::core, DiameterRestraint, DiameterRestraints); IMP_SWIG_OBJECT( IMP::core, DihedralRestraint, DihedralRestraints); -IMP_SWIG_OBJECT( IMP::core, DistanceRestraint, DistanceRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, DistanceRestraint, DistanceRestraints); IMP_SWIG_OBJECT_INSTANCE( IMP::core, DistanceToSingletonScore, DistanceToSingletonScore, DistanceToSingletonScores); IMP_SWIG_OBJECT( IMP::core, ExcludedVolumeRestraint, ExcludedVolumeRestraints); IMP_SWIG_OBJECT( IMP::core, FixedRefiner, FixedRefiners); -IMP_SWIG_OBJECT( IMP::core, GridClosePairsFinder, GridClosePairsFinders); -IMP_SWIG_OBJECT( IMP::core, Harmonic, Harmonics); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, GridClosePairsFinder, GridClosePairsFinders); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, Harmonic, Harmonics); IMP_SWIG_OBJECT( IMP::core, HarmonicWell, HarmonicWells); -IMP_SWIG_OBJECT( IMP::core, HarmonicLowerBound, HarmonicLowerBounds); -IMP_SWIG_OBJECT( IMP::core, HarmonicUpperBound, HarmonicUpperBounds); -IMP_SWIG_OBJECT( IMP::core, HarmonicSphereDistancePairScore, HarmonicSphereDistancePairScores); -IMP_SWIG_OBJECT( IMP::core, HarmonicUpperBoundSphereDistancePairScore, HarmonicUpperBoundSphereDistancePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, HarmonicLowerBound, HarmonicLowerBounds); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, HarmonicUpperBound, HarmonicUpperBounds); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, HarmonicSphereDistancePairScore, HarmonicSphereDistancePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, HarmonicUpperBoundSphereDistancePairScore, HarmonicUpperBoundSphereDistancePairScores); IMP_SWIG_OBJECT( IMP::core, HarmonicUpperBoundSphereDiameterPairScore, HarmonicUpperBoundSphereDiameterPairScores); IMP_SWIG_OBJECT( IMP::core, HarmonicSurfaceDistancePairScore, HarmonicSurfaceDistancePairScores); IMP_SWIG_OBJECT( IMP::core, HarmonicSurfaceHeightPairScore, HarmonicSurfaceHeightPairScores); @@ -61,7 +56,7 @@ IMP_SWIG_OBJECT( IMP::core, WeightedSumOfExponential, WeightedSumOfExponentials) IMP_SWIG_OBJECT( IMP::core, IncrementalScoringFunction, IncrementalScoringFunctions); IMP_SWIG_OBJECT( IMP::core, KClosePairsPairScore, KClosePairsPairScores); IMP_SWIG_OBJECT( IMP::core, LeavesRefiner, LeavesRefiners); -IMP_SWIG_OBJECT( IMP::core, Linear, Linears); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, Linear, Linears); IMP_SWIG_OBJECT( IMP::core, LogNormalMover, LogNormalMovers); IMP_SWIG_OBJECT( IMP::core, MCCGSampler, MCCGSamplers); IMP_SWIG_OBJECT( IMP::core, MonteCarlo, MonteCarlos); @@ -72,25 +67,25 @@ IMP_SWIG_OBJECT( IMP::core, NeighborsTable, NeighborsTables); IMP_SWIG_OBJECT( IMP::core, NormalMover, NormalMovers); IMP_SWIG_OBJECT( IMP::core, NormalizedSphereDistancePairScore, NormalizedSphereDistancePairScores); IMP_SWIG_OBJECT( IMP::core, OpenCubicSpline, OpenCubicSplines); -IMP_SWIG_OBJECT( IMP::core, PairConstraint, PairConstraints); -IMP_SWIG_OBJECT( IMP::core, PairRestraint, PairRestraints); -IMP_SWIG_OBJECT( IMP::core, QuadConstraint, QuadConstraints); -IMP_SWIG_OBJECT( IMP::core, QuadRestraint, QuadRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, PairConstraint, PairConstraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, PairRestraint, PairRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, QuadConstraint, QuadConstraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, QuadRestraint, QuadRestraints); IMP_SWIG_OBJECT( IMP::core, QuadraticClosePairsFinder, QuadraticClosePairsFinders); IMP_SWIG_OBJECT( IMP::core, RefinedPairsPairScore, RefinedPairsPairScores); -IMP_SWIG_OBJECT(IMP::core, RestraintsScoringFunction, RestraintsScoringFunctions); +IMP_SWIG_OBJECT_SERIALIZE(IMP::core, RestraintsScoringFunction, RestraintsScoringFunctions); IMP_SWIG_OBJECT( IMP::core, RigidBodyDistancePairScore, RigidBodyDistancePairScores); IMP_SWIG_OBJECT( IMP::core, RigidBodyAnglePairScore, RigidBodyAnglePairScores); -IMP_SWIG_OBJECT( IMP::core, RigidBodyMover, RigidBodyMovers); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, RigidBodyMover, RigidBodyMovers); IMP_SWIG_OBJECT( IMP::core, RigidBodyTunneler, RigidBodyTunnelers); IMP_SWIG_OBJECT( IMP::core, RigidBodyUmbrella, RigidBodyUmbrellas); -IMP_SWIG_OBJECT( IMP::core, RigidClosePairsFinder, RigidClosePairsFinders); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, RigidClosePairsFinder, RigidClosePairsFinders); IMP_SWIG_OBJECT( IMP::core, RigidMembersRefiner, RigidMembersRefiners); -IMP_SWIG_OBJECT( IMP::core, SingletonConstraint, SingletonConstraints); -IMP_SWIG_OBJECT( IMP::core, SingletonRestraint, SingletonRestraints); -IMP_SWIG_OBJECT( IMP::core, SoftSpherePairScore, SoftSpherePairScores); -IMP_SWIG_OBJECT( IMP::core, SphereDistancePairScore, SphereDistancePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, SingletonConstraint, SingletonConstraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, SingletonRestraint, SingletonRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, SoftSpherePairScore, SoftSpherePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, SphereDistancePairScore, SphereDistancePairScores); IMP_SWIG_OBJECT( IMP::core, SphereDistanceToSingletonScore, SphereDistanceToSingletonScores); IMP_SWIG_OBJECT( IMP::core, SoftSubSurfacePairScore, SoftSubSurfacePairScores); IMP_SWIG_OBJECT( IMP::core, SoftSuperSurfacePairScore, SoftSuperSurfacePairScores); @@ -101,13 +96,13 @@ IMP_SWIG_OBJECT( IMP::core, SurfaceTetheredChain, SurfaceTetheredChains); IMP_SWIG_OBJECT( IMP::core, SurfaceSymmetryConstraint, SurfaceSymmetryConstraints); IMP_SWIG_OBJECT( IMP::core, SteepestDescent, SteepestDescents); IMP_SWIG_OBJECT( IMP::core, TableRefiner, TableRefiners); -IMP_SWIG_OBJECT( IMP::core, Transform, Transforms); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, Transform, Transforms); IMP_SWIG_OBJECT( IMP::core, TransformationAndReflectionSymmetry, TransformationAndReflectionSymmetries); IMP_SWIG_OBJECT( IMP::core, TransformationSymmetry, TransformationSymmetries); IMP_SWIG_OBJECT( IMP::core, TransformationSymmetryMover, TransformationSymmetryMovers); IMP_SWIG_OBJECT( IMP::core, TransformedDistancePairScore, TransformedDistancePairScores); -IMP_SWIG_OBJECT( IMP::core, TripletConstraint, TripletConstraints); -IMP_SWIG_OBJECT( IMP::core, TripletRestraint, TripletRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, TripletConstraint, TripletConstraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, TripletRestraint, TripletRestraints); IMP_SWIG_OBJECT( IMP::core, TypedPairScore, TypedPairScores); #ifdef IMP_CORE_USE_IMP_CGAL IMP_SWIG_OBJECT( IMP::core, VolumeRestraint, VolumeRestraints); @@ -118,30 +113,30 @@ IMP_SWIG_OBJECT( IMP::core, MinimumRestraint, MinimumRestraints); IMP_SWIG_OBJECT( IMP::core, WriteRestraintScoresOptimizerState, WriteRestraintScoresOptimizerStates); IMP_SWIG_OBJECT( IMP::core, LateralSurfaceConstraint, LateralSurfaceConstraints); -IMP_SWIG_OBJECT( IMP::core, ConstantSingletonPredicate, ConstantSingletonPredicates); -IMP_SWIG_OBJECT( IMP::core, ConstantPairPredicate, ConstantPairPredicates); -IMP_SWIG_OBJECT( IMP::core, ConstantTripletPredicate, ConstantTripletPredicates); -IMP_SWIG_OBJECT( IMP::core, ConstantQuadPredicate, ConstantQuadPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ConstantSingletonPredicate, ConstantSingletonPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ConstantPairPredicate, ConstantPairPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ConstantTripletPredicate, ConstantTripletPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, ConstantQuadPredicate, ConstantQuadPredicates); IMP_SWIG_OBJECT( IMP::core, CoinFlipSingletonPredicate, CoinFlipSingletonPredicates); IMP_SWIG_OBJECT( IMP::core, CoinFlipPairPredicate, CoinFlipPairPredicates); IMP_SWIG_OBJECT( IMP::core, CoinFlipTripletPredicate, CoinFlipTripletPredicates); IMP_SWIG_OBJECT( IMP::core, CoinFlipQuadPredicate, CoinFlipQuadPredicates); -IMP_SWIG_OBJECT( IMP::core, UnorderedTypeSingletonPredicate, UnorderedTypeSingletonPredicates); -IMP_SWIG_OBJECT( IMP::core, UnorderedTypePairPredicate, UnorderedTypePairPredicates); -IMP_SWIG_OBJECT( IMP::core, UnorderedTypeTripletPredicate, UnorderedTypeTripletPredicates); -IMP_SWIG_OBJECT( IMP::core, UnorderedTypeQuadPredicate, UnorderedTypeQuadPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, UnorderedTypeSingletonPredicate, UnorderedTypeSingletonPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, UnorderedTypePairPredicate, UnorderedTypePairPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, UnorderedTypeTripletPredicate, UnorderedTypeTripletPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, UnorderedTypeQuadPredicate, UnorderedTypeQuadPredicates); IMP_SWIG_OBJECT( IMP::core, OrderedTypeSingletonPredicate, OrderedTypeSingletonPredicates); IMP_SWIG_OBJECT( IMP::core, OrderedTypePairPredicate, OrderedTypePairPredicates); IMP_SWIG_OBJECT( IMP::core, OrderedTypeTripletPredicate, OrderedTypeTripletPredicates); IMP_SWIG_OBJECT( IMP::core, OrderedTypeQuadPredicate, OrderedTypeQuadPredicates); -IMP_SWIG_OBJECT( IMP::core, AllSameSingletonPredicate, AllSameSingletonPredicates); -IMP_SWIG_OBJECT( IMP::core, AllSamePairPredicate, AllSamePairPredicates); -IMP_SWIG_OBJECT( IMP::core, AllSameTripletPredicate, AllSameTripletPredicates); -IMP_SWIG_OBJECT( IMP::core, AllSameQuadPredicate, AllSameQuadPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, AllSameSingletonPredicate, AllSameSingletonPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, AllSamePairPredicate, AllSamePairPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, AllSameTripletPredicate, AllSameTripletPredicates); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, AllSameQuadPredicate, AllSameQuadPredicates); IMP_SWIG_DECORATOR( IMP::core, XYZ, XYZs); IMP_SWIG_DECORATOR( IMP::core, XYZR, XYZRs); @@ -177,8 +172,8 @@ IMP_SWIG_OBJECT_INSTANCE( IMP::core, TruncatedHarmonicBound, TruncatedHarmonic, IMP_SWIG_OBJECT_INSTANCE( IMP::core, TruncatedHarmonicLowerBound, TruncatedHarmonic, TruncatedHarmonicLowerBounds); IMP_SWIG_OBJECT_INSTANCE( IMP::core, TruncatedHarmonicUpperBound, TruncatedHarmonic, TruncatedHarmonicUpperBounds); IMP_SWIG_OBJECT_TEMPLATE( IMP::core, TruncatedHarmonic); -IMP_SWIG_OBJECT( IMP::core, HarmonicDistancePairScore, HarmonicDistancePairScores); -IMP_SWIG_OBJECT( IMP::core, DistancePairScore, DistancePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, HarmonicDistancePairScore, HarmonicDistancePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::core, DistancePairScore, DistancePairScores); IMP_SWIG_OBJECT(IMP::core, XYZRGeometry, XYZRGeometries); @@ -402,6 +397,8 @@ IMP_SWIG_GENERIC_OBJECT_TEMPLATE(IMP::core, AttributeSingletonScore, generic_att IMP_SWIG_GENERIC_OBJECT_TEMPLATE(IMP::core, BoundingBox3DSingletonScore, bounding_box_3d_singleton_score, UnaryFunction); IMP_SWIG_GENERIC_OBJECT_TEMPLATE(IMP::core, BoundingSphere3DSingletonScore, bounding_sphere_3d_singleton_score, UnaryFunction); IMP_SWIG_GENERIC_OBJECT_TEMPLATE(IMP::core, DistanceToSingletonScore, distance_to_singleton_score, UnaryFunction); +IMP_SWIG_OBJECT_SERIALIZE_IMPL(IMP::core, GenericDistanceToSingletonScore); +IMP_SWIG_OBJECT_SERIALIZE_PICKLE(IMP::core, GenericDistanceToSingletonScore); %pythoncode %{ diff --git a/modules/core/src/AngleRestraint.cpp b/modules/core/src/AngleRestraint.cpp index 3919f09fd7..cd6c2f120f 100644 --- a/modules/core/src/AngleRestraint.cpp +++ b/modules/core/src/AngleRestraint.cpp @@ -16,4 +16,6 @@ AngleRestraint::AngleRestraint(Model *m, UnaryFunction* score_func, : TripletRestraint(m, new AngleTripletScore(score_func), ParticleIndexTriplet(p1, p2, p3)) {} +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::AngleRestraint); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/AngleTripletScore.cpp b/modules/core/src/AngleTripletScore.cpp index 10d533339c..0f850d7ec9 100644 --- a/modules/core/src/AngleTripletScore.cpp +++ b/modules/core/src/AngleTripletScore.cpp @@ -49,4 +49,6 @@ ModelObjectsTemp AngleTripletScore::do_get_inputs( return IMP::get_particles(m, pis); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::AngleTripletScore); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/BallMover.cpp b/modules/core/src/BallMover.cpp index d38640c9a1..abebb065ca 100644 --- a/modules/core/src/BallMover.cpp +++ b/modules/core/src/BallMover.cpp @@ -88,4 +88,6 @@ ModelObjectsTemp BallMover::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::BallMover); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/ChecksScoreState.cpp b/modules/core/src/ChecksScoreState.cpp index abd3afb6dd..3e7614fe54 100644 --- a/modules/core/src/ChecksScoreState.cpp +++ b/modules/core/src/ChecksScoreState.cpp @@ -40,4 +40,6 @@ ModelObjectsTemp ChecksScoreState::do_get_outputs() const { return ModelObjectsTemp(); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::ChecksScoreState); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/ConstantRestraint.cpp b/modules/core/src/ConstantRestraint.cpp index 606225b40e..2fb117d02d 100644 --- a/modules/core/src/ConstantRestraint.cpp +++ b/modules/core/src/ConstantRestraint.cpp @@ -20,4 +20,6 @@ ModelObjectsTemp ConstantRestraint::do_get_inputs() const { return ModelObjectsTemp(); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::ConstantRestraint); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/Cosine.cpp b/modules/core/src/Cosine.cpp index 0d12e9ce78..69a878652d 100644 --- a/modules/core/src/Cosine.cpp +++ b/modules/core/src/Cosine.cpp @@ -27,4 +27,6 @@ void Cosine::do_show(std::ostream &out) const { << "\nphase " << phase_ << std::endl; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::Cosine); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/DistancePairScore.cpp b/modules/core/src/DistancePairScore.cpp new file mode 100644 index 0000000000..f062ca93f1 --- /dev/null +++ b/modules/core/src/DistancePairScore.cpp @@ -0,0 +1,15 @@ +/** + * \file DistancePairScore.cpp + * \brief A Score on the distance between a pair of particles. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + */ + +#include + +IMPCORE_BEGIN_NAMESPACE + +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::DistancePairScore); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::HarmonicDistancePairScore); + +IMPCORE_END_NAMESPACE diff --git a/modules/core/src/DistanceRestraint.cpp b/modules/core/src/DistanceRestraint.cpp index a2e637121c..8b2da8fde1 100644 --- a/modules/core/src/DistanceRestraint.cpp +++ b/modules/core/src/DistanceRestraint.cpp @@ -23,4 +23,6 @@ DistanceRestraint::DistanceRestraint(Model *m, UnaryFunction* score_func, new DistancePairScore(score_func), m, ParticleIndexPair(p1, p2), name) {} +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::DistanceRestraint); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/DistanceToSingletonScore.cpp b/modules/core/src/DistanceToSingletonScore.cpp index 51644807d3..8c5d588173 100644 --- a/modules/core/src/DistanceToSingletonScore.cpp +++ b/modules/core/src/DistanceToSingletonScore.cpp @@ -28,4 +28,8 @@ Float SphereDistanceToSingletonScore::evaluate_index( return v; } +template <> +IMP_OBJECT_SERIALIZE_IMPL( + IMP::core::GenericDistanceToSingletonScore); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/Gaussian.cpp b/modules/core/src/Gaussian.cpp index 42843e310a..b68b66ba4b 100644 --- a/modules/core/src/Gaussian.cpp +++ b/modules/core/src/Gaussian.cpp @@ -79,4 +79,6 @@ void Gaussian::show(std::ostream &out) const { out << get_gaussian(); } return prob; }*/ +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::Matrix3D); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/GridClosePairsFinder.cpp b/modules/core/src/GridClosePairsFinder.cpp index 325ce4ca2f..707b81c9a4 100644 --- a/modules/core/src/GridClosePairsFinder.cpp +++ b/modules/core/src/GridClosePairsFinder.cpp @@ -77,4 +77,6 @@ ModelObjectsTemp GridClosePairsFinder::do_get_inputs( return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::GridClosePairsFinder); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/Harmonic.cpp b/modules/core/src/Harmonic.cpp new file mode 100644 index 0000000000..26ccccfb7c --- /dev/null +++ b/modules/core/src/Harmonic.cpp @@ -0,0 +1,18 @@ +/** + * \file Harmonic.cpp \brief Harmonic function. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#include +#include +#include + +IMPCORE_BEGIN_NAMESPACE + +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::Harmonic); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::HarmonicLowerBound); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::HarmonicUpperBound); + +IMPCORE_END_NAMESPACE diff --git a/modules/core/src/Linear.cpp b/modules/core/src/Linear.cpp new file mode 100644 index 0000000000..ee9e2d5c22 --- /dev/null +++ b/modules/core/src/Linear.cpp @@ -0,0 +1,14 @@ +/** + * \file Linear.cpp \brief A linear function. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#include + +IMPCORE_BEGIN_NAMESPACE + +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::Linear); + +IMPCORE_END_NAMESPACE diff --git a/modules/core/src/MCCGSampler.cpp b/modules/core/src/MCCGSampler.cpp index b7251261d1..a32f7c8c14 100644 --- a/modules/core/src/MCCGSampler.cpp +++ b/modules/core/src/MCCGSampler.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -361,9 +361,9 @@ ConfigurationSet *MCCGSampler::do_sample() const { } IMP_CHECK_OBJECT(sc); int failures = 0; - boost::scoped_ptr progress; + boost::scoped_ptr progress; if (IMP::get_log_level() == PROGRESS) { - progress.reset(new boost::progress_display(pms.attempts_)); + progress.reset(new IMP::internal::BoostProgressDisplay(pms.attempts_)); } for (unsigned int i = 0; i < pms.attempts_; ++i) { ret->load_configuration(-1); diff --git a/modules/core/src/MonteCarloMover.cpp b/modules/core/src/MonteCarloMover.cpp index 7affca75d2..9278f916cc 100644 --- a/modules/core/src/MonteCarloMover.cpp +++ b/modules/core/src/MonteCarloMover.cpp @@ -14,4 +14,9 @@ MonteCarloMover::MonteCarloMover(Model *m, std::string name) reset_statistics(); } +MonteCarloMover::MonteCarloMover() + : has_move_(false) { + reset_statistics(); +} + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/RestraintsScoringFunction.cpp b/modules/core/src/RestraintsScoringFunction.cpp new file mode 100644 index 0000000000..dcd1044f11 --- /dev/null +++ b/modules/core/src/RestraintsScoringFunction.cpp @@ -0,0 +1,15 @@ +/** + * \file RestraintsScoringFunction.cpp + * \brief A scoring function on a list of restraints + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#include + +IMPCORE_BEGIN_NAMESPACE + +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::RestraintsScoringFunction); + +IMPCORE_END_NAMESPACE diff --git a/modules/core/src/RigidBodyMover.cpp b/modules/core/src/RigidBodyMover.cpp index 68f1f521bb..7e24686696 100644 --- a/modules/core/src/RigidBodyMover.cpp +++ b/modules/core/src/RigidBodyMover.cpp @@ -69,4 +69,6 @@ ModelObjectsTemp RigidBodyMover::do_get_inputs() const { return ModelObjectsTemp(1, get_model()->get_particle(pi_)); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::RigidBodyMover); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/RigidClosePairsFinder.cpp b/modules/core/src/RigidClosePairsFinder.cpp index dfb02a6948..124f9923ea 100644 --- a/modules/core/src/RigidClosePairsFinder.cpp +++ b/modules/core/src/RigidClosePairsFinder.cpp @@ -24,9 +24,7 @@ IMPCORE_BEGIN_NAMESPACE RigidClosePairsFinder::RigidClosePairsFinder(ClosePairsFinder *cpf) : ClosePairsFinder("RigidCPF") { - std::ostringstream oss; - oss << "RigidClosePairsFinderHiearchy " << this; - k_ = ObjectKey(oss.str()); + k_ = get_hierarchy_key(); if (cpf) { cpf_ = cpf; } else { @@ -34,6 +32,12 @@ RigidClosePairsFinder::RigidClosePairsFinder(ClosePairsFinder *cpf) } } +ObjectKey RigidClosePairsFinder::get_hierarchy_key() const { + std::ostringstream oss; + oss << "RigidClosePairsFinderHierarchy " << this; + return ObjectKey(oss.str()); +} + namespace { ParticlesTemp get_rigid_bodies(Model *m, const ParticleIndexes &pis) { @@ -270,4 +274,6 @@ RigidClosePairsFinder::get_moved_singleton_container(SingletonContainer *in, return new internal::RigidMovedSingletonContainer(in, threshold); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::RigidClosePairsFinder); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/SerialMover.cpp b/modules/core/src/SerialMover.cpp index 00644a1d91..fdb7391e97 100644 --- a/modules/core/src/SerialMover.cpp +++ b/modules/core/src/SerialMover.cpp @@ -36,4 +36,6 @@ ModelObjectsTemp SerialMover::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::SerialMover); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/SphereDistancePairScore.cpp b/modules/core/src/SphereDistancePairScore.cpp index cdc223c71c..731b2e39f1 100644 --- a/modules/core/src/SphereDistancePairScore.cpp +++ b/modules/core/src/SphereDistancePairScore.cpp @@ -69,4 +69,9 @@ ModelObjectsTemp WeightedSphereDistancePairScore::do_get_inputs( return IMP::get_particles(m, pis); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::SphereDistancePairScore); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::HarmonicUpperBoundSphereDistancePairScore); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::HarmonicSphereDistancePairScore); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::SoftSpherePairScore); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/SubsetMover.cpp b/modules/core/src/SubsetMover.cpp index 3dc00f4f3c..6fedcdca14 100644 --- a/modules/core/src/SubsetMover.cpp +++ b/modules/core/src/SubsetMover.cpp @@ -65,4 +65,6 @@ ModelObjectsTemp SubsetMover::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::SubsetMover); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/Transform.cpp b/modules/core/src/Transform.cpp index 66ee08350b..60407664d1 100644 --- a/modules/core/src/Transform.cpp +++ b/modules/core/src/Transform.cpp @@ -35,4 +35,6 @@ ModelObjectsTemp Transform::do_get_outputs( return IMP::get_particles(m, pis); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::Transform); + IMPCORE_END_NAMESPACE diff --git a/modules/core/src/internal/rigid_body_tree.cpp b/modules/core/src/internal/rigid_body_tree.cpp index caeba85c97..6edbad3e36 100644 --- a/modules/core/src/internal/rigid_body_tree.cpp +++ b/modules/core/src/internal/rigid_body_tree.cpp @@ -554,4 +554,6 @@ ParticlesTemp close_particles(Model *m, const RigidBodyHierarchy *da, return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::internal::RigidBodyHierarchy); + IMPCORE_END_INTERNAL_NAMESPACE diff --git a/modules/core/src/rigid_bodies.cpp b/modules/core/src/rigid_bodies.cpp index 12650371ba..0c74be2ed3 100644 --- a/modules/core/src/rigid_bodies.cpp +++ b/modules/core/src/rigid_bodies.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_INTERNAL_NAMESPACE @@ -382,8 +384,61 @@ ModelKey get_rb_list_key() { static ModelKey key("rigid body list"); return key; } + } +/* Make a simple subclass rather than using + IMP::internal::create_tuple_constraint(), so that we can serialize it */ +class RigidBodyPositionConstraint + : public IMP::internal::TupleConstraint { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class< + IMP::internal::TupleConstraint >(this)); + } + IMP_OBJECT_SERIALIZE_DECL(RigidBodyPositionConstraint); + +public: + RigidBodyPositionConstraint(UpdateRigidBodyMembers *before, + AccumulateRigidBodyDerivatives *after, + Model *m, const ParticleIndex &vt, + std::string name, bool can_skip) + : IMP::internal::TupleConstraint< + UpdateRigidBodyMembers, AccumulateRigidBodyDerivatives>( + before, after, m, vt, name, can_skip) {} + + RigidBodyPositionConstraint() {} +}; +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::RigidBodyPositionConstraint); + +/* Make a simple subclass rather than using + IMP::internal::create_container_constraint(), so that we can serialize it */ +class RigidBodyNormalizeConstraint + : public IMP::internal::ContainerConstraint< + NormalizeRotation, NullSDM, + IMP::internal::StaticListContainer > { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class< + IMP::internal::ContainerConstraint > >(this)); + } + IMP_OBJECT_SERIALIZE_DECL(RigidBodyNormalizeConstraint); +public: + RigidBodyNormalizeConstraint( + NormalizeRotation *before, NullSDM *after, + IMP::internal::StaticListContainer *c, + std::string name, bool can_skip=false) + : IMP::internal::ContainerConstraint >( + before, after, c, name, can_skip) {} + + RigidBodyNormalizeConstraint() {} +}; +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::RigidBodyNormalizeConstraint); + namespace { // compute inertia tensor for particles ds with origin center Eigen::Matrix3d compute_I(Model *model, @@ -533,8 +588,8 @@ void RigidBody::do_setup_particle(Model *m, ParticleIndex pi, list->set(ParticleIndexes(1, p->get_index())); IMP_NEW(NormalizeRotation, nr, ()); IMP_NEW(NullSDM, null, ()); - Pointer c1 = IMP::internal::create_container_constraint( - nr.get(), null.get(), list.get(), "normalize rigid bodies"); + IMP_NEW(RigidBodyNormalizeConstraint, c1, + (nr, null, list, "normalize rigid bodies")); d.get_model()->add_score_state(c1); d.get_model()->add_data(mk, list); } @@ -542,6 +597,10 @@ void RigidBody::do_setup_particle(Model *m, ParticleIndex pi, void RigidBody::teardown_particle(RigidBody rb) { IMP_FUNCTION_LOG; + IMP_USAGE_CHECK(!RigidMember::get_is_setup(rb), + "This body is a member of another rigid body. " + "Remove it first."); + // clear caches rb.on_change(); { @@ -766,9 +825,9 @@ void RigidBody::setup_score_states() { get_particle_index())) { IMP_NEW(UpdateRigidBodyMembers, urbm, ()); IMP_NEW(AccumulateRigidBodyDerivatives, arbd, ()); - Pointer c0 = IMP::internal::create_tuple_constraint( - urbm.get(), arbd.get(), get_particle(), - get_particle()->get_name() + " rigid body positions", true); + IMP_NEW(RigidBodyPositionConstraint, c0, + (urbm, arbd, get_model(), get_particle_index(), + get_particle()->get_name() + " rigid body positions", true)); get_model()->add_score_state(c0); get_model()->add_attribute(get_rb_score_state_0_key(), get_particle_index(), c0); @@ -845,6 +904,65 @@ void RigidBody::add_non_rigid_member(ParticleIndexAdaptor pi) { set_is_rigid_member(pi, false); } +void RigidBody::remove_member(ParticleIndexAdaptor pi) { + IMP_FUNCTION_LOG; + if (RigidBody::get_is_setup(get_model(), pi)) { + remove_rigid_body_member(pi); + } else { + remove_point_member(pi); + } + setup_score_states(); + on_change(); +} + +void RigidBody::remove_point_member(ParticleIndex pi) { + ParticleIndexes members; + if (get_model()->get_has_attribute(internal::rigid_body_data().members_, + get_particle_index())) { + members = get_model()->get_attribute( + internal::rigid_body_data().members_, get_particle_index()); + } + + auto r = std::remove(members.begin(), members.end(), pi); + IMP_CHECK_VARIABLE(r); + IMP_USAGE_CHECK(r != members.end(), + "Particle is not a member of this rigid body"); + members.erase(r, members.end()); + + if (members.empty()) { + get_model()->remove_attribute(internal::rigid_body_data().members_, + get_particle_index()); + } else { + get_model()->set_attribute(internal::rigid_body_data().members_, + get_particle_index(), members); + } + internal::remove_required_attributes_for_member(get_model(), pi); +} + +void RigidBody::remove_rigid_body_member(ParticleIndex pi) { + ParticleIndexes members; + if (get_model()->get_has_attribute(internal::rigid_body_data().body_members_, + get_particle_index())) { + members = get_model()->get_attribute( + internal::rigid_body_data().body_members_, get_particle_index()); + } + + auto r = std::remove(members.begin(), members.end(), pi); + IMP_CHECK_VARIABLE(r); + IMP_USAGE_CHECK(r != members.end(), + "Particle is not a member of this rigid body"); + members.erase(r, members.end()); + + if (members.empty()) { + get_model()->remove_attribute(internal::rigid_body_data().body_members_, + get_particle_index()); + } else { + get_model()->set_attribute(internal::rigid_body_data().body_members_, + get_particle_index(), members); + } + internal::remove_required_attributes_for_body_member(get_model(), pi); +} + algebra::VectorD<4> RigidBody::get_rotational_derivatives() const { algebra::VectorD<4> v(get_particle()->get_derivative( internal::rigid_body_data().quaternion_[0]), diff --git a/modules/core/test/test_all_same_predicate.py b/modules/core/test/test_all_same_predicate.py new file mode 100644 index 0000000000..4c85385865 --- /dev/null +++ b/modules/core/test/test_all_same_predicate.py @@ -0,0 +1,43 @@ +from __future__ import print_function +import IMP +import IMP.container +import IMP.core +import IMP.test +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of AllSamePairPredicate""" + m = IMP.Model() + p1 = IMP.Particle(m) + p2 = IMP.Particle(m) + pred = IMP.core.AllSamePairPredicate("foo") + self.assertEqual(pred.get_value_index(m, [p1, p2]), 0) + self.assertEqual(pred.get_value_index(m, [p1, p1]), 1) + dump = pickle.dumps(pred) + + newpred = pickle.loads(dump) + self.assertEqual(newpred.get_name(), "foo") + self.assertEqual(newpred.get_value_index(m, [p1, p2]), 0) + self.assertEqual(newpred.get_value_index(m, [p1, p1]), 1) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of AllSamePairPredicate via polymorphic ptr""" + m = IMP.Model() + p1 = IMP.Particle(m) + p2 = IMP.Particle(m) + pred = IMP.core.AllSamePairPredicate("foo") + lpc = IMP.container.ListPairContainer(m, [(p1, p1), (p1, p2)]) + cont = IMP.container.PredicatePairsRestraint(pred, lpc) + cont.set_score(1, IMP._ConstPairScore(10.0)) + cont.set_score(0, IMP._ConstPairScore(40.0)) + + dump = pickle.dumps(cont) + newcont = pickle.loads(dump) + self.assertAlmostEqual(newcont.evaluate(False), 50.0, delta=0.1) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_angle.py b/modules/core/test/test_angle.py index 661a2b79ce..b6501ced09 100644 --- a/modules/core/test/test_angle.py +++ b/modules/core/test/test_angle.py @@ -3,6 +3,7 @@ import IMP.core import io import math +import pickle class Tests(IMP.test.TestCase): @@ -74,5 +75,39 @@ def test_show(self): # no reason to check the show value #self.assertEqual(s.getvalue().split('\n')[0], "angle restraint:") + def test_pickle(self): + """Test (un-)pickle of AngleRestraint""" + model, rsr, sf, ps = self._setup_particles(0., math.pi / 2.0) + rsr.set_name("foo") + self.assertAlmostEqual(rsr.evaluate(False), 72.801, delta=1e-3) + dump = pickle.dumps(rsr) + newrsr = pickle.loads(dump) + self.assertEqual(newrsr.get_name(), "foo") + self.assertAlmostEqual(newrsr.evaluate(False), 72.801, delta=1e-3) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of AngleRestraint via polymorphic pointer""" + model, rsr, sf, ps = self._setup_particles(0., math.pi / 2.0) + rsr.set_name("foo") + self.assertAlmostEqual(rsr.evaluate(False), 72.801, delta=1e-3) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newrsr = newsf.restraints[-1] + self.assertEqual(newrsr.get_name(), "foo") + self.assertAlmostEqual(newrsr.evaluate(False), 72.801, delta=1e-3) + + def test_pickle_polymorphic_diff_module(self): + """Test pickle via polymorphic ptr with parent class in other module""" + model, rsr, sf, ps = self._setup_particles(0., math.pi / 2.0) + rsr.set_name("foo") + self.assertAlmostEqual(rsr.evaluate(False), 72.801, delta=1e-3) + opt = IMP._ConstOptimizer(model) + opt.set_scoring_function(sf) + dump = pickle.dumps(opt) + newopt = pickle.loads(dump) + newsf = newopt.get_scoring_function() + self.assertAlmostEqual(newsf.evaluate(False), 72.801, delta=1e-3) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_angle_triplet_score.py b/modules/core/test/test_angle_triplet_score.py new file mode 100644 index 0000000000..fdd66bc4e5 --- /dev/null +++ b/modules/core/test/test_angle_triplet_score.py @@ -0,0 +1,80 @@ +import IMP +import IMP.test +import IMP.core +import pickle + + +def _make_model(): + m = IMP.Model() + p1 = IMP.Particle(m) + p2 = IMP.Particle(m) + p3 = IMP.Particle(m) + d1 = IMP.core.XYZ.setup_particle(p1, IMP.algebra.Vector3D(0,0,0)) + d2 = IMP.core.XYZ.setup_particle(p2, IMP.algebra.Vector3D(0,1,0)) + d3 = IMP.core.XYZ.setup_particle(p3, IMP.algebra.Vector3D(1,0,0)) + return m, p1, p2, p3, d1, d2, d3 + + +class Tests(IMP.test.TestCase): + + def test_pickle_cosine(self): + """Test (un-)pickle of AngleTripletScore with Cosine""" + m, p1, p2, p3, d1, d2, d3 = _make_model() + + uf = IMP.core.Cosine(10.0, 2, 0.0) + ats = IMP.core.AngleTripletScore(uf) + ats.set_name('foo') + self.assertAlmostEqual(ats.evaluate_index(m, [p1, p2, p3], None), + 10.0, delta=1e-2) + + dump = pickle.dumps(ats) + newats = pickle.loads(dump) + self.assertEqual(ats.get_name(), 'foo') + self.assertAlmostEqual(newats.evaluate_index(m, [p1, p2, p3], None), + 10.0, delta=1e-2) + + def test_pickle_linear(self): + """Test (un-)pickle of AngleTripletScore with Linear""" + m, p1, p2, p3, d1, d2, d3 = _make_model() + + uf = IMP.core.Linear(-1.0, 2.0) + ats = IMP.core.AngleTripletScore(uf) + ats.set_name('foo') + self.assertAlmostEqual(ats.evaluate_index(m, [p1, p2, p3], None), + 3.5708, delta=1e-2) + + dump = pickle.dumps(ats) + newats = pickle.loads(dump) + self.assertEqual(ats.get_name(), 'foo') + self.assertAlmostEqual(newats.evaluate_index(m, [p1, p2, p3], None), + 3.5708, delta=1e-2) + + def test_pickle_harmonic(self): + """Test (un-)pickle of AngleTripletScore with Harmonic""" + m, p1, p2, p3, d1, d2, d3 = _make_model() + + uf = IMP.core.Harmonic(1.0, 10.0) + ats = IMP.core.AngleTripletScore(uf) + ats.set_name('foo') + self.assertAlmostEqual(ats.evaluate_index(m, [p1, p2, p3], None), + 0.2303, delta=1e-2) + + dump = pickle.dumps(ats) + newats = pickle.loads(dump) + self.assertEqual(ats.get_name(), 'foo') + self.assertAlmostEqual(newats.evaluate_index(m, [p1, p2, p3], None), + 0.2303, delta=1e-2) + + def test_pickle_unregistered(self): + """Test (un-)pickle of AngleTripletScore with unregistered class""" + m, p1, p2, p3, d1, d2, d3 = _make_model() + + uf = IMP.core.OpenCubicSpline([1.,2.,3.], 0., 1.) + ats = IMP.core.AngleTripletScore(uf) + # OpenCubicSpline is (currently) unregistered, so this should fail + # with a "trying to save an unregistered polymorphic type" error + self.assertRaises(TypeError, pickle.dumps, ats) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_cg_optimizer.py b/modules/core/test/test_cg_optimizer.py index 6317d9e1df..5b18f52971 100644 --- a/modules/core/test/test_cg_optimizer.py +++ b/modules/core/test/test_cg_optimizer.py @@ -70,7 +70,7 @@ def _test_starting_conditions(self, starting_values): rsr = WoodsFunc(model, particles) opt = IMP.core.ConjugateGradients(model) opt.set_scoring_function([rsr]) - opt.set_threshold(1e-5) + opt.set_gradient_threshold(1e-5) e = opt.optimize(100) for p in particles: val = model.get_attribute(xkey, p) diff --git a/modules/core/test/test_checks_score_state.py b/modules/core/test/test_checks_score_state.py new file mode 100644 index 0000000000..6316d4287d --- /dev/null +++ b/modules/core/test/test_checks_score_state.py @@ -0,0 +1,29 @@ +from __future__ import print_function +import sys +import IMP +import IMP.core +import IMP.test +import pickle + + +class Tests(IMP.test.TestCase): + + def test_simple(self): + """Test simple usage of ChecksScoreState""" + m = IMP.Model() + ss = IMP.core.ChecksScoreState(m, 0.0) + m.update() + # probability is zero, so checked should not get updated + self.assertEqual(ss.get_number_of_checked(), 0) + + def test_pickle(self): + """Test (un-)pickle of ChecksScoreState""" + m = IMP.Model() + ss = IMP.core.ChecksScoreState(m, 0.0) + dump = pickle.dumps(ss) + newss = pickle.loads(dump) + self.assertEqual(newss.get_number_of_checked(), 0) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_close_pairs_finder.py b/modules/core/test/test_close_pairs_finder.py new file mode 100644 index 0000000000..76f54dcb49 --- /dev/null +++ b/modules/core/test/test_close_pairs_finder.py @@ -0,0 +1,70 @@ +import IMP +import IMP.test +import IMP.core +import IMP.container +import pickle + + +def _make_system(): + m = IMP.Model() + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + m, p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(0., 0., 0.), 1.)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + m, p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 0., 0.), 1.)) + p3 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + m, p3, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(20., 0., 0.), 1.)) + return m, p1, p2, p3 + + +class Tests(IMP.test.TestCase): + + def test_grid_pickle(self): + """Test (un-)pickle of GridClosePairsFinder""" + m, p1, p2, p3 = _make_system() + lpc = IMP.container.ListPairContainer(m, []) + gpf = IMP.core.GridClosePairsFinder() + gpf.set_name("foo") + gpf.set_distance(6.0) + # todo: add a PairFilter too + + dump = pickle.dumps(gpf) + newgpf = pickle.loads(dump) + self.assertEqual(newgpf.get_name(), "foo") + self.assertAlmostEqual(newgpf.get_distance(), 6.0, delta=1e-5) + self.assertEqual(len(newgpf.pair_filters), 0) + # Coerce from numpy.array to plain Python array + cps = newgpf.get_close_pairs(m, ([p1, p2, p3])) + if IMP.IMP_KERNEL_HAS_NUMPY: + cps = [tuple(p) for p in cps] + self.assertEqual(cps, [(p2.get_index(), p1.get_index())]) + + def test_rigid_pickle(self): + """Test (un-)pickle of RigidClosePairsFinder""" + m, p1, p2, p3 = _make_system() + lpc = IMP.container.ListPairContainer(m, []) + gpf = IMP.core.GridClosePairsFinder() + gpf.set_name("foo") + gpf.set_distance(6.0) + + rpf = IMP.core.RigidClosePairsFinder(gpf) + rpf.set_name("bar") + rpf.set_distance(4.0) + # todo: add a PairFilter too + + dump = pickle.dumps(rpf) + newrpf = pickle.loads(dump) + self.assertEqual(newrpf.get_name(), "bar") + self.assertAlmostEqual(newrpf.get_distance(), 4.0, delta=1e-5) + self.assertEqual(len(newrpf.pair_filters), 0) + # Coerce from numpy.array to plain Python array + cps = newrpf.get_close_pairs(m, ([p1, p2, p3])) + if IMP.IMP_KERNEL_HAS_NUMPY: + cps = [tuple(p) for p in cps] + self.assertEqual(cps, [(p2.get_index(), p1.get_index())]) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_conjugate_gradients.py b/modules/core/test/test_conjugate_gradients.py new file mode 100644 index 0000000000..8a66a7e94a --- /dev/null +++ b/modules/core/test/test_conjugate_gradients.py @@ -0,0 +1,33 @@ +import IMP +import IMP.test +import IMP.core +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of ConjugateGradients""" + m = IMP.Model() + p1 = IMP.Particle(m) + p2 = IMP.Particle(m) + d1 = IMP.core.XYZ.setup_particle(p1, IMP.algebra.Vector3D(0,0,0)) + d2 = IMP.core.XYZ.setup_particle(p2, IMP.algebra.Vector3D(1,1,1)) + d2.set_coordinates_are_optimized(True) + dr = IMP.core.DistanceRestraint(m, IMP.core.Harmonic(0, 1), p1, p2) + cg = IMP.core.ConjugateGradients(m) + sf = IMP.core.RestraintsScoringFunction([dr]) + cg.set_scoring_function(sf) + cg.set_name("foo") + dump = pickle.dumps(cg) + newcg = pickle.loads(dump) + self.assertEqual(newcg.get_name(), "foo") + # CG should pull particles together + newcg.optimize(20) + dist = IMP.algebra.get_distance( + d1.get_coordinates(), d2.get_coordinates()) + self.assertLess(dist, 0.1) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_connectivity.py b/modules/core/test/test_connectivity.py index fc1f157d92..1c1e14eb97 100644 --- a/modules/core/test/test_connectivity.py +++ b/modules/core/test/test_connectivity.py @@ -21,7 +21,7 @@ def test_connectivity(self): ps = self.create_particles_in_box(m, 4) ds = [IMP.core.XYZ(p) for p in ps] o = IMP.core.ConjugateGradients(m) - o.set_threshold(1e-4) + o.set_gradient_threshold(1e-4) self.randomize_particles(ps, 50.0) # add connectivity restraints diff --git a/modules/core/test/test_constant_predicate.py b/modules/core/test/test_constant_predicate.py new file mode 100644 index 0000000000..c0b9d9d8e4 --- /dev/null +++ b/modules/core/test/test_constant_predicate.py @@ -0,0 +1,38 @@ +from __future__ import print_function +import IMP +import IMP.container +import IMP.core +import IMP.test +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of ConstantSingletonPredicate""" + m = IMP.Model() + p = IMP.Particle(m) + pred = IMP.core.ConstantSingletonPredicate(42, "foo") + self.assertEqual(pred.get_value_index(m, p), 42) + dump = pickle.dumps(pred) + + newpred = pickle.loads(dump) + self.assertEqual(newpred.get_name(), "foo") + self.assertEqual(newpred.get_value_index(m, p), 42) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of ConstantSingletonPredicate via polymorphic ptr""" + m = IMP.Model() + p = IMP.Particle(m) + pred = IMP.core.ConstantSingletonPredicate(42, "foo") + lsc = IMP.container.ListSingletonContainer(m, [p]) + cont = IMP.container.PredicateSingletonsRestraint(pred, lsc) + cont.set_score(42, IMP._ConstSingletonScore(10.0)) + + dump = pickle.dumps(cont) + newcont = pickle.loads(dump) + self.assertAlmostEqual(newcont.evaluate(False), 10.0, delta=0.1) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_constant_restraint.py b/modules/core/test/test_constant_restraint.py new file mode 100644 index 0000000000..2da22bb0d4 --- /dev/null +++ b/modules/core/test/test_constant_restraint.py @@ -0,0 +1,37 @@ +from __future__ import print_function +import IMP +import IMP.core +import IMP.test +import pickle + + +class Tests(IMP.test.TestCase): + """Test ConstantRestraint""" + + def test_pickle(self): + """Test (un-)pickle of ConstantRestraint""" + m = IMP.Model() + r = IMP.core.ConstantRestraint(m, 42.0) + r.set_name("foo") + dump = pickle.dumps(r) + + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(False), 42.0, delta=1e-3) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of ConstantRestraint via polymorphic pointer""" + m = IMP.Model() + r = IMP.core.ConstantRestraint(m, 42.0) + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + dump = pickle.dumps(sf) + + newsf = pickle.loads(dump) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(False), 42.0, delta=1e-3) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_cosine.py b/modules/core/test/test_cosine.py index cd9bb37528..1693b3598a 100644 --- a/modules/core/test/test_cosine.py +++ b/modules/core/test/test_cosine.py @@ -3,6 +3,7 @@ import IMP.core import math import io +import pickle def _cosfunc(val, force_constant, periodicity, phase): @@ -34,5 +35,17 @@ def test_values(self): self.assertAlmostEqual(expscore, score, delta=0.1) self.assertAlmostEqual(expderiv, deriv, delta=0.1) + def test_pickle(self): + """Test (un-)pickle of Cosine""" + func = IMP.core.Cosine(10.0, 2, 0.0) + func.set_name('foo') + self.assertAlmostEqual(func.evaluate(4.0), 11.455, delta=0.01) + dump = pickle.dumps(func) + del func + f = pickle.loads(dump) + self.assertEqual(f.get_name(), 'foo') + self.assertAlmostEqual(f.evaluate(4.0), 11.455, delta=0.01) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_distance.py b/modules/core/test/test_distance.py index d6f59144c1..062423e47b 100644 --- a/modules/core/test/test_distance.py +++ b/modules/core/test/test_distance.py @@ -2,6 +2,7 @@ import IMP.core import IMP.test import io +import pickle class Tests(IMP.test.TestCase): @@ -130,5 +131,33 @@ def test_distance(self): 2].evaluate(False) == 0.0, "unexpected distance score") + def test_pickle(self): + """Test (un-)pickle of DistanceRestraint""" + uf = IMP.core.Harmonic(1.0, 0.1) + rsr = IMP.core.DistanceRestraint(self.imp_model, uf, + self.particles[0], self.particles[1]) + rsr.set_name("foo") + self.assertAlmostEqual(rsr.evaluate(False), 0.2, delta=1e-3) + dump = pickle.dumps(rsr) + newrsr = pickle.loads(dump) + self.assertEqual(newrsr.get_name(), "foo") + self.assertAlmostEqual(rsr.evaluate(False), 0.2, delta=1e-3) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of DistanceRestraint via polymorphic pointer""" + uf = IMP.core.Harmonic(1.0, 0.1) + rsr = IMP.core.DistanceRestraint(self.imp_model, uf, + self.particles[0], self.particles[1]) + rsr.set_name("foo") + rsr.set_name("foo") + self.assertAlmostEqual(rsr.evaluate(False), 0.2, delta=1e-3) + sf = IMP.core.RestraintsScoringFunction([rsr]) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newrsr = newsf.restraints[-1] + self.assertEqual(newrsr.get_name(), "foo") + self.assertAlmostEqual(newrsr.evaluate(False), 0.2, delta=1e-3) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_distance_pair_score.py b/modules/core/test/test_distance_pair_score.py new file mode 100644 index 0000000000..9d7cea0dd5 --- /dev/null +++ b/modules/core/test/test_distance_pair_score.py @@ -0,0 +1,43 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + s = IMP.core.DistancePairScore(IMP.core.Linear(0, 1)) + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4., 0., 0.), 1.0)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 6., 7.), 2.0)) + return m, p1, p2, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of DistancePairScore""" + m, p1, p2, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, (p1, p2), None), + 9.2736, delta=1e-4) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p1, p2), None), + 9.2736, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of DistancePairScore via polymorphic ptr""" + m, p1, p2, s = make_score() + r = IMP.core.PairRestraint(m, s, (p1, p2)) + self.assertAlmostEqual(r.evaluate(False), 9.2736, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 9.2736, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_distance_to.py b/modules/core/test/test_distance_to.py new file mode 100644 index 0000000000..8276eb7654 --- /dev/null +++ b/modules/core/test/test_distance_to.py @@ -0,0 +1,39 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + func = IMP.core.Harmonic(1.0, 4.0) + s = IMP.core.DistanceToSingletonScore(func, IMP.algebra.Vector3D(0,0,0)) + p = IMP.Particle(m) + IMP.core.XYZ.setup_particle(p, IMP.algebra.Vector3D(4,0,0)) + return m, p, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of DistanceToSingletonScore""" + m, p, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, p, None), 18.0, delta=0.01) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, p, None), + 18.0, delta=0.01) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of DistanceToSingletonScore via polymorphic ptr""" + m, p, s = make_score() + r = IMP.core.SingletonRestraint(m, s, p) + self.assertAlmostEqual(r.evaluate(False), 18.0, delta=0.01) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 18.0, delta=0.01) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_harmonic.py b/modules/core/test/test_harmonic.py index 91b3b0efc5..bafa4a19c8 100644 --- a/modules/core/test/test_harmonic.py +++ b/modules/core/test/test_harmonic.py @@ -1,6 +1,7 @@ import IMP import IMP.test import IMP.core +import pickle def _harmonicfunc(val, mean, force_constant): @@ -49,5 +50,30 @@ def test_show(self): func.set_was_used(True) func.show() + def test_pickle(self): + """Test (un-)pickle of Harmonic""" + func = IMP.core.Harmonic(1.0, 4.0) + func.set_name('foo') + self.assertAlmostEqual(func.evaluate(4.0), 18.0, delta=0.01) + dump = pickle.dumps(func) + del func + f = pickle.loads(dump) + self.assertEqual(f.get_name(), 'foo') + self.assertAlmostEqual(f.evaluate(4.0), 18.0, delta=0.01) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of Harmonic via polymorphic pointer""" + m = IMP.Model() + func = IMP.core.Harmonic(1.0, 4.0) + s = IMP.core.DistanceToSingletonScore(func, IMP.algebra.Vector3D(0,0,0)) + p = IMP.Particle(m) + IMP.core.XYZ.setup_particle(p, IMP.algebra.Vector3D(4,0,0)) + self.assertAlmostEqual(s.evaluate_index(m, p, None), 18.0, delta=0.01) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertAlmostEqual(news.evaluate_index(m, p, None), + 18.0, delta=0.01) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_harmonic_distance_ps.py b/modules/core/test/test_harmonic_distance_ps.py new file mode 100644 index 0000000000..cbc3753fe6 --- /dev/null +++ b/modules/core/test/test_harmonic_distance_ps.py @@ -0,0 +1,43 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + s = IMP.core.HarmonicDistancePairScore(0, 1) + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4., 0., 0.), 1.0)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 6., 7.), 2.0)) + return m, p1, p2, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of HarmonicDistancePairScore""" + m, p1, p2, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, (p1, p2), None), + 43.0, delta=1e-4) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p1, p2), None), + 43.0, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of HarmonicDistancePairScore via poly ptr""" + m, p1, p2, s = make_score() + r = IMP.core.PairRestraint(m, s, (p1, p2)) + self.assertAlmostEqual(r.evaluate(False), 43.0, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 43.0, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_harmonic_lower_bound.py b/modules/core/test/test_harmonic_lower_bound.py new file mode 100644 index 0000000000..d071e523ec --- /dev/null +++ b/modules/core/test/test_harmonic_lower_bound.py @@ -0,0 +1,35 @@ +import IMP +import IMP.test +import IMP.core +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of HarmonicLowerBound""" + func = IMP.core.HarmonicLowerBound(10.0, 4.0) + func.set_name('foo') + self.assertAlmostEqual(func.evaluate(4.0), 72.0, delta=0.01) + dump = pickle.dumps(func) + del func + f = pickle.loads(dump) + self.assertEqual(f.get_name(), 'foo') + self.assertAlmostEqual(f.evaluate(4.0), 72.0, delta=0.01) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of HarmonicLowerBound via polymorphic pointer""" + m = IMP.Model() + func = IMP.core.HarmonicLowerBound(10.0, 4.0) + s = IMP.core.DistanceToSingletonScore(func, IMP.algebra.Vector3D(0,0,0)) + p = IMP.Particle(m) + IMP.core.XYZ.setup_particle(p, IMP.algebra.Vector3D(4,0,0)) + self.assertAlmostEqual(s.evaluate_index(m, p, None), 72.0, delta=0.01) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertAlmostEqual(news.evaluate_index(m, p, None), + 72.0, delta=0.01) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_harmonic_sdps.py b/modules/core/test/test_harmonic_sdps.py new file mode 100644 index 0000000000..98c3fff7f4 --- /dev/null +++ b/modules/core/test/test_harmonic_sdps.py @@ -0,0 +1,43 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + s = IMP.core.HarmonicSphereDistancePairScore(0, 1) + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4., 0., 0.), 1.0)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 6., 7.), 2.0)) + return m, p1, p2, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of HarmonicSphereDistancePairScore""" + m, p1, p2, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, (p1, p2), None), + 19.6791, delta=1e-4) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p1, p2), None), + 19.6791, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of HarmonicSphereDistancePairScore via poly ptr""" + m, p1, p2, s = make_score() + r = IMP.core.PairRestraint(m, s, (p1, p2)) + self.assertAlmostEqual(r.evaluate(False), 19.6791, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 19.6791, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_harmonic_upper_bound.py b/modules/core/test/test_harmonic_upper_bound.py new file mode 100644 index 0000000000..7bce6b86e8 --- /dev/null +++ b/modules/core/test/test_harmonic_upper_bound.py @@ -0,0 +1,35 @@ +import IMP +import IMP.test +import IMP.core +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of HarmonicUpperBound""" + func = IMP.core.HarmonicUpperBound(1.0, 4.0) + func.set_name('foo') + self.assertAlmostEqual(func.evaluate(4.0), 18.0, delta=0.01) + dump = pickle.dumps(func) + del func + f = pickle.loads(dump) + self.assertEqual(f.get_name(), 'foo') + self.assertAlmostEqual(f.evaluate(4.0), 18.0, delta=0.01) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of HarmonicUpperBound via polymorphic pointer""" + m = IMP.Model() + func = IMP.core.HarmonicUpperBound(1.0, 4.0) + s = IMP.core.DistanceToSingletonScore(func, IMP.algebra.Vector3D(0,0,0)) + p = IMP.Particle(m) + IMP.core.XYZ.setup_particle(p, IMP.algebra.Vector3D(4,0,0)) + self.assertAlmostEqual(s.evaluate_index(m, p, None), 18.0, delta=0.01) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertAlmostEqual(news.evaluate_index(m, p, None), + 18.0, delta=0.01) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_harmonic_upper_sdps.py b/modules/core/test/test_harmonic_upper_sdps.py new file mode 100644 index 0000000000..3eecbab4e5 --- /dev/null +++ b/modules/core/test/test_harmonic_upper_sdps.py @@ -0,0 +1,44 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + s = IMP.core.HarmonicUpperBoundSphereDistancePairScore(0, 1) + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4., 0., 0.), 1.0)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 6., 7.), 2.0)) + return m, p1, p2, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of HarmonicUpperBoundSphereDistancePairScore""" + m, p1, p2, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, (p1, p2), None), + 19.6791, delta=1e-4) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p1, p2), None), + 19.6791, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of HarmonicUpperBoundSphereDistancePairScore + via poly ptr""" + m, p1, p2, s = make_score() + r = IMP.core.PairRestraint(m, s, (p1, p2)) + self.assertAlmostEqual(r.evaluate(False), 19.6791, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 19.6791, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_linear.py b/modules/core/test/test_linear.py index 83d45a19f5..8814585b7b 100644 --- a/modules/core/test/test_linear.py +++ b/modules/core/test/test_linear.py @@ -1,6 +1,7 @@ import IMP import IMP.test import IMP.core +import pickle class Tests(IMP.test.TestCase): @@ -38,5 +39,17 @@ def test_show(self): func.set_was_used(True) func.show() + def test_pickle(self): + """Test (un-)pickle of Linear""" + func = IMP.core.Linear(2.0, 4.0) + func.set_name('foo') + self.assertAlmostEqual(func.evaluate(4.0), 8.0, delta=0.01) + dump = pickle.dumps(func) + del func + f = pickle.loads(dump) + self.assertEqual(f.get_name(), 'foo') + self.assertAlmostEqual(f.evaluate(4.0), 8.0, delta=0.01) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_ms_connectivity.py b/modules/core/test/test_ms_connectivity.py index 6fd203ce75..f3cfb4408f 100644 --- a/modules/core/test/test_ms_connectivity.py +++ b/modules/core/test/test_ms_connectivity.py @@ -138,7 +138,7 @@ def test_ms_connectivity(self): o = IMP.core.ConjugateGradients(self.m) o.set_scoring_function(self.sf) - o.set_threshold(1e-4) + o.set_gradient_threshold(1e-4) o.optimize(100) # print 'AFTER optimization' diff --git a/modules/core/test/test_restraints_scoring_function.py b/modules/core/test/test_restraints_scoring_function.py index 9c68c9fa62..6f416a6025 100644 --- a/modules/core/test/test_restraints_scoring_function.py +++ b/modules/core/test/test_restraints_scoring_function.py @@ -1,6 +1,7 @@ import IMP import IMP.test import IMP.core +import pickle class TestMovedRestraint(IMP.Restraint): @@ -53,7 +54,7 @@ def test_weights(self): """Test that restraints decompose ok""" m = IMP.Model() p = IMP.Particle(m) - r = IMP._ConstRestraint(1, [p]) + r = IMP._ConstRestraint(m, [p], 1) rd = r.create_decomposition() self.assertEqual(r.evaluate(False), rd.evaluate(False)) ra = IMP.get_restraints([r]) @@ -90,6 +91,70 @@ def test_scoring_moved(self): self.assertEqual(r1.moved_pis, IMP.get_indexes([p])) self.assertEqual(len(r1.reset_pis), 0) + def test_python_list(self): + """Test Python list-like access to restraints""" + m = IMP.Model() + p = IMP.Particle(m) + r1 = TestMovedRestraint(m, [p], value=42.) + r2 = TestMovedRestraint(m, [p], value=99.) + sf = IMP.core.RestraintsScoringFunction([r1]) + self.assertAlmostEqual(sf.evaluate(False), 42., delta=1e-6) + + self.assertEqual(len(sf.restraints), 1) + self.assertIn(r1, sf.restraints) + self.assertNotIn(r2, sf.restraints) + + del sf.restraints + self.assertEqual(len(sf.restraints), 0) + self.assertAlmostEqual(sf.evaluate(False), 0., delta=1e-6) + + sf.restraints = [r1, r2] + self.assertEqual(sf.restraints, [r1, r2]) + self.assertNotEqual(sf.restraints, (r1, r2)) + self.assertNotEqual(sf.restraints, [r1]) + othersf = IMP.core.RestraintsScoringFunction([r1, r2]) + self.assertEqual(sf.restraints, othersf.restraints) + self.assertAlmostEqual(sf.evaluate(False), 141., delta=1e-6) + sf.restraints.pop() + self.assertAlmostEqual(sf.evaluate(False), 42., delta=1e-6) + sf.restraints.pop() + self.assertAlmostEqual(sf.evaluate(False), 0., delta=1e-6) + self.assertRaises(IndexError, sf.restraints.pop) + + sf.restraints.append(r1) + sf.restraints.extend([r2]) + self.assertAlmostEqual(sf.evaluate(False), 141., delta=1e-6) + self.assertEqual(sf.restraints.index(r1), 0) + self.assertEqual(sf.restraints.index(r2), 1) + self.assertRaises(ValueError, sf.restraints.index, r1, start=6) + self.assertRaises(ValueError, sf.restraints.index, r1, start=0, stop=0) + self.assertEqual(sf.restraints[0], r1) + self.assertEqual(sf.restraints[1], r2) + self.assertRaises(IndexError, lambda: sf.restraints[42]) + self.assertRaises(IndexError, lambda: sf.restraints[-42]) + del sf.restraints[1] + def _delfunc(): + del sf.restraints[42] + self.assertRaises(IndexError, _delfunc) + self.assertRaises(ValueError, sf.restraints.index, r2) + + def test_pickle(self): + """Test (un-)pickle of RestraintsScoringFunction""" + m = IMP.Model() + p = IMP.Particle(m) + r = IMP._ConstRestraint(m, [p], 42) + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + sf.set_name("bar") + self.assertEqual(sf.evaluate(False), 42) + + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + self.assertEqual(newsf.get_name(), "bar") + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertEqual(newsf.evaluate(False), 42) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_rigid_bodies.py b/modules/core/test/test_rigid_bodies.py index 6250a7a807..eee5575948 100644 --- a/modules/core/test/test_rigid_bodies.py +++ b/modules/core/test/test_rigid_bodies.py @@ -90,6 +90,30 @@ def test_create_one(self): success = success + 1 self.assertGreater(success, count / 2.0) + def test_remove_member(self): + """Test RigidBody.remove_member()""" + m = IMP.Model() + member = IMP.core.RigidMember.setup_particle(IMP.Particle(m)) + body = IMP.core.RigidBody.setup_particle( + IMP.core.RigidMember.setup_particle( + IMP.Particle(m)), IMP.algebra.ReferenceFrame3D()) + + rb = IMP.core.RigidBody.setup_particle(IMP.Particle(m), [member, body]) + self.assertTrue(IMP.core.RigidMember.get_is_setup(member)) + self.assertTrue(IMP.core.RigidMember.get_is_setup(body)) + self.assertEqual(len(rb.get_body_member_particle_indexes()), 1) + self.assertEqual(len(rb.get_member_particle_indexes()), 1) + rb.remove_member(member) + self.assertEqual(len(rb.get_body_member_particle_indexes()), 1) + self.assertEqual(len(rb.get_member_particle_indexes()), 0) + rb.remove_member(body) + self.assertEqual(len(rb.get_body_member_particle_indexes()), 0) + self.assertEqual(len(rb.get_member_particle_indexes()), 0) + self.assertFalse(IMP.core.RigidMember.get_is_setup(member)) + self.assertFalse(IMP.core.RigidMember.get_is_setup(body)) + self.assertRaisesUsageException(rb.remove_member, member) + self.assertRaisesUsageException(rb.remove_member, body) + def test_get_members(self): """Test rigid body get_member* functions""" m = IMP.Model() @@ -173,9 +197,17 @@ def test_teardown(self): rb0 = IMP.core.RigidBody.setup_particle(rbp0, ps) rb1 = IMP.core.RigidBody.setup_particle(rbp1, [rb0]) IMP.core.RigidBody.teardown_particle(rb1) + IMP.core.RigidBody.teardown_particle(rb0) print("setting up again") + rb0 = IMP.core.RigidBody.setup_particle(rbp0, ps) rb1 = IMP.core.RigidBody.setup_particle(rbp1, [rb0]) print("tearing down") + # Cannot teardown body that is a member of another body; + # must remove it first + if IMP.get_check_level() >= IMP.USAGE_AND_INTERNAL: + self.assertRaises(IMP.UsageException, + IMP.core.RigidBody.teardown_particle, rb0) + rb1.remove_member(rb0) IMP.core.RigidBody.teardown_particle(rb0) print("again") IMP.core.RigidBody.teardown_particle(rb1) diff --git a/modules/core/test/test_rigid_body_mover.py b/modules/core/test/test_rigid_body_mover.py index 7e2ce48bed..4f5b09b4b5 100644 --- a/modules/core/test/test_rigid_body_mover.py +++ b/modules/core/test/test_rigid_body_mover.py @@ -3,9 +3,10 @@ import IMP.core import IMP.atom import IMP.algebra - +import pickle from math import * + def get_axis_and_angle(q): angle = 2 * acos(q[0]) if angle != 0: @@ -16,6 +17,24 @@ def get_axis_and_angle(q): else: return (0,None) + +def make_system(): + m = IMP.Model() + mol = IMP.atom.Hierarchy(IMP.Particle(m)) + for c in [(100, 100, 100), (5, 100, 100), (10, 5, 100)]: + p = IMP.Particle(m) + dr = IMP.core.XYZR.setup_particle(p) + dr.set_coordinates(c) + dr.set_radius(1.0) + IMP.atom.Mass.setup_particle(p, 1.0) + h = IMP.atom.Hierarchy(p) + mol.add_child(h) + rb = IMP.atom.create_rigid_body(IMP.atom.get_leaves(mol)) + rb_mover = IMP.core.RigidBodyMover(m, rb, 1.0, 2.0) + rb_mover.set_name("foo") + return m, rb_mover + + class NormalMoverTest(IMP.test.TestCase): def test_zeros(self): @@ -108,6 +127,25 @@ def test_mc_mover_rotate_transalte(self): self.assertLessEqual(abs(get_axis_and_angle(q)[0]),1.0) self.assertLessEqual(transm,1.0) + def test_pickle(self): + """Test (un-)pickle of RigidBodyMover""" + m, rb_mover = make_system() + dump = pickle.dumps(rb_mover) + + newmvr = pickle.loads(dump) + self.assertEqual(newmvr.get_name(), "foo") + self.assertAlmostEqual(newmvr.get_maximum_translation(), + 1.0, delta=1e-5) + self.assertAlmostEqual(newmvr.get_maximum_rotation(), 2.0, delta=1e-5) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of RigidBodyMover via polymorphic pointer""" + m, rb_mover = make_system() + sm = IMP.core.SerialMover([rb_mover]) + dump = pickle.dumps(sm) + newsm = pickle.loads(dump) + newmvr, = newsm.get_movers() + self.assertEqual(newmvr.get_name(), "foo") if __name__ == '__main__': diff --git a/modules/core/test/test_serial_mover.py b/modules/core/test/test_serial_mover.py new file mode 100644 index 0000000000..881574d0de --- /dev/null +++ b/modules/core/test/test_serial_mover.py @@ -0,0 +1,35 @@ +import IMP +import IMP.test +import IMP.core +import IMP.algebra +import pickle + + +class Test(IMP.test.TestCase): + + def make_system(self): + self.m = IMP.Model() + self.ps = [] + self.mvs = [] + for i in range(10): + p = IMP.Particle(self.m) + self.ps.append(p) + IMP.core.XYZ.setup_particle(p, IMP.algebra.Vector3D(0, 0, 0)) + IMP.core.XYZ(p).set_coordinates_are_optimized(True) + self.mvs.append(IMP.core.BallMover(self.m, p, 1.)) + self.mvs[-1].set_was_used(True) + + def test_pickle(self): + """Test (un-)pickle of SerialMover""" + self.make_system() + mvr = IMP.core.SerialMover(self.mvs) + mvr.set_name("foo") + dump = pickle.dumps(mvr) + + newmvr = pickle.loads(dump) + self.assertEqual(newmvr.get_name(), "foo") + self.assertEqual(len(newmvr.get_movers()), 10) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_serialize.cpp b/modules/core/test/test_serialize.cpp new file mode 100644 index 0000000000..5a2e362aef --- /dev/null +++ b/modules/core/test/test_serialize.cpp @@ -0,0 +1,117 @@ +/** + * \file test_serialize.cpp + * \brief Test of serialize/deserialize functionality + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +void test_triplet_score() { + IMP_NEW(IMP::core::Cosine, uf, (0., 1, 0.)); + IMP_NEW(IMP::core::AngleTripletScore, ats, (uf)); + + std::ostringstream oss; + cereal::BinaryOutputArchive ba(oss); + ba(*ats); + std::string s = oss.str(); + std::cerr << "serialize done, written " << s.size() << " bytes" << std::endl; + + std::istringstream iss(s); + cereal::BinaryInputArchive iba(iss); + IMP_NEW(IMP::core::AngleTripletScore, newats, ()); + iba(*newats); + std::cerr << "deserialize done, read in " << *newats << std::endl; +} + +void test_scoring_function() { + IMP_NEW(IMP::Model, m, ()); + IMP_NEW(IMP::Particle, p, (m)); + IMP::ParticleIndexes pis; + pis.push_back(p->get_index()); + IMP_NEW(IMP::internal::_ConstRestraint, cr, (m, pis, 1.0)); + IMP::RestraintsTemp rt; + rt.push_back(cr); + IMP_NEW(IMP::core::RestraintsScoringFunction, sf, (rt)); + + std::ostringstream oss; + cereal::BinaryOutputArchive ba(oss); + ba(*sf); + std::string s = oss.str(); + std::cerr << "serialize done, written " << s.size() << " bytes" << std::endl; + + std::istringstream iss(s); + cereal::BinaryInputArchive iba(iss); + IMP_NEW(IMP::core::RestraintsScoringFunction, newsf, ()); + iba(*newsf); + std::cerr << "deserialize done, read in " << *newsf << std::endl; +} + +void test_optimizer() { + IMP_NEW(IMP::Model, m, ()); + IMP_NEW(IMP::Particle, p, (m)); + IMP::ParticleIndexes pis; + pis.push_back(p->get_index()); + IMP_NEW(IMP::internal::_ConstRestraint, cr, (m, pis, 1.0)); + IMP::RestraintsTemp rt; + rt.push_back(cr); + IMP_NEW(IMP::core::RestraintsScoringFunction, sf, (rt)); + IMP_NEW(IMP::internal::_ConstOptimizer, opt, (m)); + opt->set_scoring_function(sf); + + std::ostringstream oss; + cereal::BinaryOutputArchive ba(oss); + ba(*opt); + std::string s = oss.str(); + std::cerr << "serialize done, written " << s.size() << " bytes" << std::endl; + + std::istringstream iss(s); + cereal::BinaryInputArchive iba(iss); + IMP_NEW(IMP::internal::_ConstOptimizer, newopt, ()); + iba(*newopt); + std::cerr << "deserialize done, read in " << *newopt << std::endl; +} + +void test_matrix3d() { + Eigen::Matrix3d mat; + mat(0, 1) = 1; + mat(0, 2) = 2; + IMP_NEW(IMP::core::Matrix3D, m, (mat)); + + std::ostringstream oss; + cereal::BinaryOutputArchive ba(oss); + ba(*m); + std::string s = oss.str(); + std::cerr << "serialize done, written " << s.size() << " bytes" << std::endl; + + std::istringstream iss(s); + cereal::BinaryInputArchive iba(iss); + IMP_NEW(IMP::core::Matrix3D, newm, ()); + iba(*newm); + std::cerr << "deserialize done, read in " << *newm << std::endl; + + assert(int(newm->get_mat()(0, 1)) == 1); + assert(int(newm->get_mat()(0, 2)) == 2); +} + +} // namespace + +int main(int argc, char* argv[]) { + IMP::setup_from_argv(argc, argv, "Test serialize"); + test_triplet_score(); + test_scoring_function(); + test_optimizer(); + test_matrix3d(); + return 0; +} diff --git a/modules/core/test/test_singleton_constraint.py b/modules/core/test/test_singleton_constraint.py new file mode 100644 index 0000000000..3c95c2a4bb --- /dev/null +++ b/modules/core/test/test_singleton_constraint.py @@ -0,0 +1,57 @@ +import IMP +import IMP.test +import IMP.core +import pickle + + +class Tests(IMP.test.TestCase): + + def make_system(self): + m = IMP.Model() + p1 = m.add_particle("p1") + xyz = IMP.core.XYZ.setup_particle( + m, p1, IMP.algebra.Vector3D(1., 2., 3.)) + trans = IMP.algebra.Transformation3D( + IMP.algebra.get_identity_rotation_3d(), + IMP.algebra.Vector3D(10., 0., 0.)) + before = IMP.core.Transform(trans) + r = IMP.core.SingletonConstraint(before, None, m, p1) + return m, xyz, r + + def test_pickle(self): + """Test (un-)pickle of SingletonConstraint""" + m, xyz, r = self.make_system() + r.before_evaluate() + self.assertAlmostEqual(xyz.get_coordinates()[0], 11.0, delta=1e-5) + r.set_name("foo") + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + newr.before_evaluate() + self.assertAlmostEqual(xyz.get_coordinates()[0], 21.0, delta=1e-5) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of SingletonConstraint via polymorphic pointer""" + m, xyz, r = self.make_system() + r.before_evaluate() + self.assertAlmostEqual(xyz.get_coordinates()[0], 11.0, delta=1e-5) + r.set_name("foo") + m.score_states.append(r) + dump = pickle.dumps(m) + newm = pickle.loads(dump) + # Get copy of xyz particle in new model + self.assertTrue(IMP.core.XYZ.get_is_setup(newm, xyz)) + newxyz = IMP.core.XYZ(newm, xyz) + self.assertAlmostEqual(newxyz.get_coordinates()[0], 11.0, delta=1e-5) + self.assertAlmostEqual(xyz.get_coordinates()[0], 11.0, delta=1e-5) + newr, = newm.score_states + self.assertEqual(newr.get_name(), "foo") + # Updating the constraint in the new model should only update the + # particle in the new model, not the original + newr.before_evaluate() + self.assertAlmostEqual(newxyz.get_coordinates()[0], 21.0, delta=1e-5) + self.assertAlmostEqual(xyz.get_coordinates()[0], 11.0, delta=1e-5) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_singleton_restraint.py b/modules/core/test/test_singleton_restraint.py new file mode 100644 index 0000000000..8855e3906e --- /dev/null +++ b/modules/core/test/test_singleton_restraint.py @@ -0,0 +1,42 @@ +import IMP +import IMP.test +import IMP.core +import pickle + + +class Tests(IMP.test.TestCase): + + def make_system(self): + m = IMP.Model() + p1 = m.add_particle("p1") + IMP.core.XYZ.setup_particle(m, p1, IMP.algebra.Vector3D(1., 2., 3.)) + ss = IMP.core.DistanceToSingletonScore( + IMP.core.Harmonic(0, 1), IMP.algebra.Vector3D(0., 0., 0.)) + r = IMP.core.SingletonRestraint(m, ss, p1) + return m, p1, ss, r + + def test_pickle(self): + """Test (un-)pickle of SingletonRestraint""" + m, p1, ss, r = self.make_system() + r.set_name("foo") + self.assertAlmostEqual(r.evaluate(False), 7.0, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 7.0, delta=1e-4) + self.assertEqual(newr.get_name(), "foo") + + def test_pickle_polymorphic(self): + """Test (un-)pickle of SingletonRestraint via polymorphic pointer""" + m, p1, ss, r = self.make_system() + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + self.assertAlmostEqual(sf.evaluate(False), 7.0, delta=1e-4) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + self.assertAlmostEqual(newsf.evaluate(False), 7.0, delta=1e-4) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_soft_sphere_pair_score.py b/modules/core/test/test_soft_sphere_pair_score.py new file mode 100644 index 0000000000..33d3e8a70e --- /dev/null +++ b/modules/core/test/test_soft_sphere_pair_score.py @@ -0,0 +1,43 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + s = IMP.core.SoftSpherePairScore(1) + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4., 0., 0.), 1.0)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 1., 0.), 2.0)) + return m, p1, p2, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of SoftSpherePairScore""" + m, p1, p2, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, (p1, p2), None), + 1.2574, delta=1e-4) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p1, p2), None), + 1.2574, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of SoftSpherePairScore via poly ptr""" + m, p1, p2, s = make_score() + r = IMP.core.PairRestraint(m, s, (p1, p2)) + self.assertAlmostEqual(r.evaluate(False), 1.2574, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 1.2574, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_sphere_distance_ps.py b/modules/core/test/test_sphere_distance_ps.py new file mode 100644 index 0000000000..ebd7825970 --- /dev/null +++ b/modules/core/test/test_sphere_distance_ps.py @@ -0,0 +1,43 @@ +import IMP +import IMP.test +import IMP.core +import pickle + +def make_score(): + m = IMP.Model() + s = IMP.core.SphereDistancePairScore(IMP.core.Linear(0, 1)) + p1 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p1, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4., 0., 0.), 1.0)) + p2 = IMP.Particle(m) + IMP.core.XYZR.setup_particle( + p2, IMP.algebra.Sphere3D(IMP.algebra.Vector3D(5., 6., 7.), 2.0)) + return m, p1, p2, s + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of SphereDistancePairScore""" + m, p1, p2, s = make_score() + s.set_name('foo') + self.assertAlmostEqual(s.evaluate_index(m, (p1, p2), None), + 6.2736, delta=1e-4) + dump = pickle.dumps(s) + news = pickle.loads(dump) + self.assertEqual(s.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p1, p2), None), + 6.2736, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of SphereDistancePairScore via polymorphic ptr""" + m, p1, p2, s = make_score() + r = IMP.core.PairRestraint(m, s, (p1, p2)) + self.assertAlmostEqual(r.evaluate(False), 6.2736, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 6.2736, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/core/test/test_subset_mover.py b/modules/core/test/test_subset_mover.py index d88c9241b6..c271253145 100644 --- a/modules/core/test/test_subset_mover.py +++ b/modules/core/test/test_subset_mover.py @@ -2,6 +2,7 @@ import IMP.test import IMP.core import IMP.algebra +import pickle class Test(IMP.test.TestCase): @@ -75,6 +76,30 @@ def test_reject(self): num_moved = self.count_moved(self.ps) self.assertEqual(num_moved, 0) + def test_pickle(self): + """Test (un-)pickle of SubsetMover""" + self.make_system() + mvr = IMP.core.SubsetMover(self.mvs, 5) + mvr.set_name("foo") + dump = pickle.dumps(mvr) + + newmvr = pickle.loads(dump) + self.assertEqual(newmvr.get_name(), "foo") + self.assertEqual(len(newmvr.get_movers()), 10) + self.assertEqual(newmvr.get_subset_size(), 5) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of SubsetMover via polymorphic pointer""" + self.make_system() + mvr = IMP.core.SubsetMover(self.mvs, 5) + mvr.set_name("foo") + sm = IMP.core.SerialMover([mvr]) + dump = pickle.dumps(sm) + + newsm = pickle.loads(dump) + newmvr, = newsm.get_movers() + self.assertEqual(newmvr.get_name(), "foo") + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_transform_particles.py b/modules/core/test/test_transform_particles.py index bfd9b31599..fd7b61ffbf 100644 --- a/modules/core/test/test_transform_particles.py +++ b/modules/core/test/test_transform_particles.py @@ -3,6 +3,7 @@ import IMP.core import IMP.algebra import IMP.test +import pickle class Tests(IMP.test.TestCase): @@ -31,5 +32,40 @@ def test_transformation(self): 0, delta=0.01) + def make_system(self): + m = IMP.Model() + p1 = m.add_particle("p1") + xyz = IMP.core.XYZ.setup_particle( + m, p1, IMP.algebra.Vector3D(1., 2., 3.)) + trans = IMP.algebra.Transformation3D( + IMP.algebra.get_identity_rotation_3d(), + IMP.algebra.Vector3D(10., 0., 0.)) + t = IMP.core.Transform(trans) + return m, xyz, t + + def test_pickle(self): + """Test (un-)pickle of Transform""" + m, xyz, t = self.make_system() + t.apply_index(m, xyz) + self.assertAlmostEqual(xyz.get_coordinates()[0], 11.0, delta=1e-5) + t.set_name("foo") + dump = pickle.dumps(t) + newt = pickle.loads(dump) + self.assertEqual(newt.get_name(), "foo") + newt.apply_index(m, xyz) + self.assertAlmostEqual(xyz.get_coordinates()[0], 21.0, delta=1e-5) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of Transform via polymorphic pointer""" + m, xyz, t = self.make_system() + r = IMP.core.SingletonConstraint(t, None, m, xyz) + r.before_evaluate() + self.assertAlmostEqual(xyz.get_coordinates()[0], 11.0, delta=1e-5) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + newr.before_evaluate() + self.assertAlmostEqual(xyz.get_coordinates()[0], 21.0, delta=1e-5) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/core/test/test_unordered_type_predicate.py b/modules/core/test/test_unordered_type_predicate.py new file mode 100644 index 0000000000..c64ab494b7 --- /dev/null +++ b/modules/core/test/test_unordered_type_predicate.py @@ -0,0 +1,49 @@ +from __future__ import print_function +import IMP +import IMP.container +import IMP.core +import IMP.test +import pickle + +t1 = IMP.core.ParticleType("type1") +t2 = IMP.core.ParticleType("type2") + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of UnorderedTypeSingletonPredicate""" + m = IMP.Model() + p1 = IMP.Particle(m) + IMP.core.Typed.setup_particle(p1, t1) + p2 = IMP.Particle(m) + IMP.core.Typed.setup_particle(p2, t2) + pred = IMP.core.UnorderedTypeSingletonPredicate("foo") + self.assertEqual(pred.get_value_index(m, p1), t1.get_index()) + self.assertEqual(pred.get_value_index(m, p2), t2.get_index()) + dump = pickle.dumps(pred) + + newpred = pickle.loads(dump) + self.assertEqual(newpred.get_name(), "foo") + self.assertEqual(newpred.get_value_index(m, p1), t1.get_index()) + self.assertEqual(newpred.get_value_index(m, p2), t2.get_index()) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of UnorderedTypeSingletonPredicate via poly ptr""" + m = IMP.Model() + p1 = IMP.Particle(m) + IMP.core.Typed.setup_particle(p1, t1) + p2 = IMP.Particle(m) + IMP.core.Typed.setup_particle(p2, t2) + pred = IMP.core.UnorderedTypeSingletonPredicate("foo") + lsc = IMP.container.ListSingletonContainer(m, [p1, p2]) + cont = IMP.container.PredicateSingletonsRestraint(pred, lsc) + cont.set_score(t1.get_index(), IMP._ConstSingletonScore(10.0)) + cont.set_score(t2.get_index(), IMP._ConstSingletonScore(40.0)) + + dump = pickle.dumps(cont) + newcont = pickle.loads(dump) + self.assertAlmostEqual(newcont.evaluate(False), 50.0, delta=0.1) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/display/include/Color.h b/modules/display/include/Color.h index 1a866b65ab..ffdeafab64 100644 --- a/modules/display/include/Color.h +++ b/modules/display/include/Color.h @@ -14,8 +14,8 @@ #include #include #include -#include -#include +#include +#include IMPDISPLAY_BEGIN_NAMESPACE @@ -23,12 +23,12 @@ IMPDISPLAY_BEGIN_NAMESPACE /** */ class IMPDISPLAYEXPORT Color : public Value { - boost::array c_; + std::array c_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & c_[0] & c_[1] & c_[2]; + template void serialize(Archive &ar) { + ar(c_[0], c_[1], c_[2]); } int compare(double a, double b) const { @@ -72,10 +72,10 @@ class IMPDISPLAYEXPORT Color : public Value { double get_green() const { return c_[1]; } double get_blue() const { return c_[2]; } #ifndef SWIG - typedef const double *ComponentIterator; + typedef std::array::const_iterator ComponentIterator; ComponentIterator components_begin() const { return c_.begin(); } ComponentIterator components_end() const { return c_.end(); } - const boost::array &get_rgb() const { return c_; } + const std::array &get_rgb() const { return c_; } #endif //!@} diff --git a/modules/display/include/internal/writers.h b/modules/display/include/internal/writers.h index 0fd80b59a8..7f80453dc3 100644 --- a/modules/display/include/internal/writers.h +++ b/modules/display/include/internal/writers.h @@ -10,7 +10,7 @@ #include #include -#include +#include IMPDISPLAY_BEGIN_NAMESPACE class Writer; IMPDISPLAY_END_NAMESPACE @@ -33,12 +33,12 @@ class WriterFactoryHelper : public WriterFactory { } }; -std::map > & +std::map > & get_writer_factory_table(); struct WriterFactoryRegistrar { WriterFactoryRegistrar(std::string suffix, - boost::shared_ptr wf) { + std::shared_ptr wf) { get_writer_factory_table()[suffix] = wf; } }; diff --git a/modules/display/include/writer_macros.h b/modules/display/include/writer_macros.h index 8fdaf9df01..50210a162c 100644 --- a/modules/display/include/writer_macros.h +++ b/modules/display/include/writer_macros.h @@ -8,8 +8,7 @@ #ifndef IMPDISPLAY_WRITER_MACROS_H #define IMPDISPLAY_WRITER_MACROS_H #include "Writer.h" -#include -#include +#include //! Define information for an TextWriter object /** This macro declares the methods do_open, do_close, add_geometry @@ -46,7 +45,7 @@ #define IMP_REGISTER_WRITER(Name, suffix) \ namespace { \ internal::WriterFactoryRegistrar Name##registrar( \ - suffix, boost::make_shared >()); \ + suffix, std::make_shared >()); \ } #endif diff --git a/modules/display/pyext/swig.i-in b/modules/display/pyext/swig.i-in index ec404715e9..7397675b96 100644 --- a/modules/display/pyext/swig.i-in +++ b/modules/display/pyext/swig.i-in @@ -1,9 +1,3 @@ -%{ -#include -#include -%} - - IMP_SWIG_BASE_OBJECT(IMP::display, Writer, Writers); IMP_SWIG_BASE_OBJECT(IMP::display, TextWriter, TextWriters); IMP_SWIG_BASE_OBJECT(IMP::display, Geometry, Geometries); diff --git a/modules/display/src/Writer.cpp b/modules/display/src/Writer.cpp index 8ac3a5a573..ec0c6942c0 100644 --- a/modules/display/src/Writer.cpp +++ b/modules/display/src/Writer.cpp @@ -56,7 +56,7 @@ void TextWriter::do_set_frame() { } Writer *create_writer(std::string name) { - typedef std::pair > + typedef std::pair > MP; for(MP mp : internal::get_writer_factory_table()) { if (boost::algorithm::ends_with(name, mp.first)) { diff --git a/modules/display/src/internal/writers.cpp b/modules/display/src/internal/writers.cpp index 3d5bcc62f3..220b6730cd 100644 --- a/modules/display/src/internal/writers.cpp +++ b/modules/display/src/internal/writers.cpp @@ -10,9 +10,9 @@ #include IMPDISPLAY_BEGIN_INTERNAL_NAMESPACE -std::map >& +std::map >& get_writer_factory_table() { - static std::map > table; + static std::map > table; return table; } diff --git a/modules/domino/include/Assignment.h b/modules/domino/include/Assignment.h index 38135aab69..cae47e0c9b 100644 --- a/modules/domino/include/Assignment.h +++ b/modules/domino/include/Assignment.h @@ -16,9 +16,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include IMPDOMINO_BEGIN_NAMESPACE @@ -35,10 +35,10 @@ IMPDOMINO_BEGIN_NAMESPACE class IMPDOMINOEXPORT Assignment : public ConstVector { typedef ConstVector P; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & boost::serialization::base_object

(*this); + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); } public: diff --git a/modules/domino/include/Order.h b/modules/domino/include/Order.h index b4f1f5473f..b22c8eaa52 100644 --- a/modules/domino/include/Order.h +++ b/modules/domino/include/Order.h @@ -17,9 +17,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include IMPDOMINO_BEGIN_NAMESPACE @@ -32,10 +32,10 @@ IMPDOMINO_BEGIN_NAMESPACE class IMPDOMINOEXPORT Order : public ConstVector { typedef ConstVector P; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & boost::serialization::base_object

(*this); + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); } public: diff --git a/modules/domino/include/Slice.h b/modules/domino/include/Slice.h index 1adb9e0fc2..10b02eaf10 100644 --- a/modules/domino/include/Slice.h +++ b/modules/domino/include/Slice.h @@ -17,9 +17,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include IMPDOMINO_BEGIN_NAMESPACE @@ -30,10 +30,10 @@ IMPDOMINO_BEGIN_NAMESPACE class IMPDOMINOEXPORT Slice : public ConstVector { typedef ConstVector P; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & boost::serialization::base_object

(*this); + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); } static Ints get_slice(Subset outer, Subset inner) { diff --git a/modules/domino/include/Subset.h b/modules/domino/include/Subset.h index edb924b85e..b813a71971 100644 --- a/modules/domino/include/Subset.h +++ b/modules/domino/include/Subset.h @@ -103,4 +103,12 @@ inline Subset get_difference(const Subset &a, const Subset &b) { IMPDOMINO_END_NAMESPACE +#if !defined(IMP_DOXYGEN) && !defined(SWIG) +namespace IMP { + inline std::size_t hash_value(const domino::Subset &t) { + return t.__hash__(); + } +} +#endif + #endif /* IMPDOMINO_SUBSET_H */ diff --git a/modules/domino/pyext/swig.i-in b/modules/domino/pyext/swig.i-in index 9a454fff86..2288477133 100644 --- a/modules/domino/pyext/swig.i-in +++ b/modules/domino/pyext/swig.i-in @@ -1,8 +1,3 @@ -%{ -#include -#include -%} - %include "IMP_domino.hdf5.i" %include "IMP/domino/domino_macros.h" namespace IMP { diff --git a/modules/domino/src/internal/tree_inference.cpp b/modules/domino/src/internal/tree_inference.cpp index 970bc2eb5a..034f9738ed 100644 --- a/modules/domino/src/internal/tree_inference.cpp +++ b/modules/domino/src/internal/tree_inference.cpp @@ -11,10 +11,10 @@ #include #include #include +#include #include #include #include -#include #include IMPDOMINO_BEGIN_INTERNAL_NAMESPACE @@ -53,7 +53,7 @@ void load_best_conformations_internal( const MergeTree &jt, unsigned int root, const Subset &all, const AssignmentsTable *states, const SubsetFilterTables &filters, ListSubsetFilterTable *lsft, InferenceStatistics *stats, unsigned int max, - boost::progress_display *progress, AssignmentContainer *out) { + IMP::internal::BoostProgressDisplay *progress, AssignmentContainer *out) { Pointer outp(out); typedef boost::property_map::const_type SubsetMap; @@ -96,9 +96,10 @@ void load_best_conformations(const MergeTree &mt, int root, InferenceStatistics *stats, unsigned int max, AssignmentContainer *out) { Pointer outp(out); - boost::scoped_ptr progress; + boost::scoped_ptr progress; if (get_log_level() == PROGRESS) { - progress.reset(new boost::progress_display(boost::num_vertices(mt))); + progress.reset( + new IMP::internal::BoostProgressDisplay(boost::num_vertices(mt))); } return load_best_conformations_internal(mt, root, all_particles, states, filters, lsft, stats, max, diff --git a/modules/domino/test/standards_exceptions b/modules/domino/test/standards_exceptions index cd603f9bb8..3bb9d20b77 100644 --- a/modules/domino/test/standards_exceptions +++ b/modules/domino/test/standards_exceptions @@ -1,5 +1,5 @@ -spelling_exceptions=[], +spelling_exceptions=[] function_name_exceptions=["AssignmentsTable.fill_assignments", "BranchAndBoundAssignmentsTable.fill_assignments", "DominoSampler.fill_vertex_assignments", - "ListAssignmentsTable.fill_assignments"] \ No newline at end of file + "ListAssignmentsTable.fill_assignments"] diff --git a/modules/domino/test/test_caching_sampling.py b/modules/domino/test/test_caching_sampling.py index 78915819bf..48b52e6e43 100644 --- a/modules/domino/test/test_caching_sampling.py +++ b/modules/domino/test/test_caching_sampling.py @@ -28,7 +28,7 @@ def test_global_min3(self): r = IMP.RestraintSet(m) for p in ps: pst.set_particle_states(p, particle_state) - r.add_restraint(IMP._ConstRestraint(1, [p])) + r.add_restraint(IMP._ConstRestraint(m, [p], 1)) sst = IMP.domino.BranchAndBoundAssignmentsTable(pst, []) r.add_restraint(IMP.core.DistanceRestraint(m, IMP.core.Harmonic(1, 1), ps[0], ps[1])) diff --git a/modules/domino/test/test_restraint_cache.py b/modules/domino/test/test_restraint_cache.py index 7a348c1ae7..863b5b805a 100644 --- a/modules/domino/test/test_restraint_cache.py +++ b/modules/domino/test/test_restraint_cache.py @@ -13,7 +13,7 @@ class Tests(IMP.test.TestCase): def _create_stuff(self): m = IMP.Model() ps = [IMP.Particle(m) for i in range(0, 10)] - r = IMP._ConstRestraint(1, ps) + r = IMP._ConstRestraint(m, ps, 1) r.set_name("const restraint") pst = IMP.domino.ParticleStatesTable() ik = IMP.IntKey("key") @@ -99,7 +99,7 @@ def test_decomposition_5(self): """Test cache with simple restraint""" (m, ps, r, pst, ik, cache) = self._create_stuff() rs = IMP.RestraintSet(m, 1.0, "outer") - r = IMP._ConstRestraint(1, [ps[0]]) + r = IMP._ConstRestraint(m, [ps[0]], 1) r.set_name("const 2") rs.add_restraint(r) r.set_maximum_score(.5) diff --git a/modules/domino/test/test_sampling.py b/modules/domino/test/test_sampling.py index 443e81dac5..3fefddf152 100644 --- a/modules/domino/test/test_sampling.py +++ b/modules/domino/test/test_sampling.py @@ -72,7 +72,7 @@ def test_global_min3(self): r = IMP.RestraintSet(m) for p in ps: pst.set_particle_states(p, particle_state) - r.add_restraint(IMP._ConstRestraint(1, [p])) + r.add_restraint(IMP._ConstRestraint(m, [p], 1)) r.add_restraint(IMP.core.DistanceRestraint(m, IMP.core.Harmonic(1, 1), ps[0], ps[1])) r.add_restraint(IMP.core.DistanceRestraint(m, diff --git a/modules/em/include/DensityHeader.h b/modules/em/include/DensityHeader.h index 1ba9af88b7..d3f99183a0 100644 --- a/modules/em/include/DensityHeader.h +++ b/modules/em/include/DensityHeader.h @@ -211,6 +211,22 @@ class IMPEMEXPORT DensityHeader { //! How many bits are used to store the density of a single voxel //! (used in MRC format) int data_type_; + +private: + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(nxstart, nystart, nzstart, mx, my, mz, xlen, ylen, zlen, + alpha, beta, gamma, mapc, mapr, maps, dmin, dmax, dmean, + ispg, nsymbt, user, map, machinestamp, rms, nlabl, comments, + magic, voltage, Cs, Aperture, Magnification, Postmagnification, + Exposuretime, Microscope, Pixelsize, CCDArea, Defocus, + Astigmatism, AstigmatismAngle, FocusIncrement, CountsPerElectron, + Intensity, EnergySlitwidth, EnergyOffset, Tiltangle, Tiltaxis, + MarkerX, MarkerY, lswap, Objectpixelsize_, xtop_, ytop_, ztop_, + xorigin_, yorigin_, zorigin_, top_calculated_, resolution_, + is_resolution_set_, nx_, ny_, nz_, data_type_); + } }; //! Create a header from a bounding box in 3D diff --git a/modules/em/include/DensityMap.h b/modules/em/include/DensityMap.h index 1e741ecab7..9783e141d3 100644 --- a/modules/em/include/DensityMap.h +++ b/modules/em/include/DensityMap.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -476,6 +478,28 @@ class IMPEMEXPORT DensityMap : public IMP::Object { bool normalized_; bool rms_calculated_; +private: + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + header_, data_allocated_, loc_calculated_, normalized_, + rms_calculated_); + long size = get_number_of_voxels(); + + if (std::is_base_of::value) { + data_.reset(new double[size]); + if (loc_calculated_) { + // force recalculation of loc arrays + loc_calculated_ = false; + calc_all_voxel2loc(); + } + } + + for (long i = 0; i < size; ++i) { + ar(data_[i]); + } + } }; inline algebra::BoundingBoxD<3> get_bounding_box(const DensityMap *m) { diff --git a/modules/em/include/KernelParameters.h b/modules/em/include/KernelParameters.h index bee8cc48a8..d6011c33b9 100644 --- a/modules/em/include/KernelParameters.h +++ b/modules/em/include/KernelParameters.h @@ -21,8 +21,7 @@ #include #include #include -#include -#include +#include IMPEM_BEGIN_NAMESPACE @@ -96,23 +95,19 @@ class IMPEMEXPORT KernelParameters { void init(float resolution); -#ifndef SWIG - friend class boost::serialization::access; + friend class cereal::access; - template void save(Archive &ar, const unsigned int) const { - ar << resolution_; + template void save(Archive &ar) const { + ar(resolution_); } - template void load(Archive &ar, const unsigned int) { + template void load(Archive &ar) { float resolution; - ar >> resolution; + ar(resolution); init(resolution); initialized_ = true; } - BOOST_SERIALIZATION_SPLIT_MEMBER() -#endif - }; IMP_VALUES(KernelParameters, KernelParametersList); diff --git a/modules/em/include/def.h b/modules/em/include/def.h index c37844b00a..619d911614 100644 --- a/modules/em/include/def.h +++ b/modules/em/include/def.h @@ -13,8 +13,6 @@ IMPEM_BEGIN_NAMESPACE -// Deprecated: just use 'double' instead -typedef double emreal; const double EPS = 1e-16; IMPEM_END_NAMESPACE diff --git a/modules/em/include/rigid_fitting.h b/modules/em/include/rigid_fitting.h index f44ecdca1c..aa14e6b6f8 100644 --- a/modules/em/include/rigid_fitting.h +++ b/modules/em/include/rigid_fitting.h @@ -21,16 +21,13 @@ #include #include #include -#include -#include +#include +#include -namespace boost { - namespace serialization { - template void serialize(Archive &ar, - std::pair &g, - const unsigned int) { - ar & g.first & g.second; - } +namespace cereal { + template void serialize(Archive &ar, + std::pair &g) { + ar(g.first, g.second); } } @@ -114,10 +111,10 @@ class IMPEMEXPORT FittingSolutions { std::vector fs_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & fs_; + template void serialize(Archive &ar) { + ar(fs_); } }; IMP_VALUES(FittingSolutions, FittingSolutionsList); diff --git a/modules/em/pyext/swig.i-in b/modules/em/pyext/swig.i-in index 4a4aca023b..ba73b3669f 100644 --- a/modules/em/pyext/swig.i-in +++ b/modules/em/pyext/swig.i-in @@ -1,8 +1,3 @@ -%{ -#include -#include -%} - /* Ignore things to prevent SWIG warning about them */ namespace IMP { namespace em { @@ -12,7 +7,7 @@ namespace IMP { %ignore operator<<(std::ostream&, const DensityHeader &); /* Make selected classes extensible in Python */ -IMP_SWIG_OBJECT(IMP::em, DensityMap, DensityMaps); +IMP_SWIG_OBJECT_SERIALIZE(IMP::em, DensityMap, DensityMaps); IMP_SWIG_OBJECT(IMP::em, SampledDensityMap, SampledDensityMaps); IMP_SWIG_OBJECT(IMP::em, SurfaceShellDensityMap, SurfaceShellDensityMaps); IMP_SWIG_OBJECT(IMP::em, FitRestraint, FitRestraints); @@ -52,7 +47,11 @@ PyObject *_get_float_view_numpy(PyObject *pyobj, unsigned sz, float *data) /* Ensure that the DensityMap is kept around as long as the numpy object is alive. */ Py_INCREF(pyobj); - PyArray_BASE(obj) = pyobj; + if (PyArray_SetBaseObject((PyArrayObject *)obj, pyobj) != 0) { + Py_DECREF(pyobj); + Py_DECREF(obj); + return NULL; + } return obj; #else @@ -92,7 +91,7 @@ PyObject *_get_float_view_numpy(PyObject *pyobj, unsigned sz, float *data) dims[2] = header->get_nx(); PyObject *obj = PyArray_New(&PyArray_Type, 3, dims, NPY_DOUBLE, NULL, - m->get_data(), 0, NPY_WRITEABLE, NULL); + m->get_data(), 0, NPY_ARRAY_WRITEABLE, NULL); if (!obj) { return NULL; } @@ -100,7 +99,11 @@ PyObject *_get_float_view_numpy(PyObject *pyobj, unsigned sz, float *data) /* Ensure that the DensityMap is kept around as long as the numpy object is alive. */ Py_INCREF(pyobj); - PyArray_BASE(obj) = pyobj; + if (PyArray_SetBaseObject((PyArrayObject *)obj, pyobj) != 0) { + Py_DECREF(pyobj); + Py_DECREF(obj); + return NULL; + } return obj; #else diff --git a/modules/em/src/ImageHeader.cpp b/modules/em/src/ImageHeader.cpp index 292df3795f..a25555f529 100644 --- a/modules/em/src/ImageHeader.cpp +++ b/modules/em/src/ImageHeader.cpp @@ -141,7 +141,7 @@ bool ImageHeader::read(std::ifstream& f, bool skip_type_check, f.seekg(current_position, std::ios::beg); // Check if it is an "aberrant" image - if (spider_header_.fIform == IMG_IMPEM) { + if ((int)spider_header_.fIform == IMG_IMPEM) { if ((usfNcol * usfNrow * sizeof(float)) == file_size) { usfNrow = (unsigned long)(--spider_header_.fNrow); --spider_header_.fNrec; diff --git a/modules/em/src/XplorReaderWriter.cpp b/modules/em/src/XplorReaderWriter.cpp index 4be7c746df..296f674802 100644 --- a/modules/em/src/XplorReaderWriter.cpp +++ b/modules/em/src/XplorReaderWriter.cpp @@ -116,7 +116,7 @@ int XplorReaderWriter::read_map(std::ifstream &XPLORstream, float *data, int counter, densNum; bool keep; - char dens[12]; + char dens[13]; float density; while (!XPLORstream.eof()) { @@ -132,7 +132,8 @@ int XplorReaderWriter::read_map(std::ifstream &XPLORstream, float *data, densNum = strlen(line) / 12; while ((counter < densNum) && keep) { - strncpy(dens, line + (counter * 12), 12); + memcpy(dens, line + (counter * 12), 12); + dens[12] = '\0'; counter++; density = atof(dens); data[x + y * header.extent[0] + diff --git a/modules/em/src/rigid_fitting.cpp b/modules/em/src/rigid_fitting.cpp index 1d124c89a5..f3270df916 100644 --- a/modules/em/src/rigid_fitting.cpp +++ b/modules/em/src/rigid_fitting.cpp @@ -76,7 +76,7 @@ core::MonteCarlo *set_optimizer(Model *model, opt->add_mover(rb_mover); opt->set_return_best(true); // return the lowest energy state visited - lopt->set_threshold(0.001); + lopt->set_gradient_threshold(0.001); // lopt->set_step_size(0.05); // opt->set_local_optimizer(lopt); // opt->set_local_steps(number_of_cg_steps); diff --git a/modules/em/test/test_density_map.py b/modules/em/test/test_density_map.py new file mode 100644 index 0000000000..253d24e426 --- /dev/null +++ b/modules/em/test/test_density_map.py @@ -0,0 +1,34 @@ +from __future__ import print_function +import IMP +import IMP.test +import IMP.em +import pickle + + +class Tests(IMP.test.TestCase): + def test_pickle(self): + """Test (un-)pickle of DensityMap""" + m = IMP.em.read_map(self.get_input_file_name("mini-4.0.mrc")) + origin = IMP.algebra.Vector3D(89.725, 44.746, -53.842) + m.set_name('foo') + self.assertEqual(m.get_number_of_voxels(), 19656) + self.assertLess(IMP.algebra.get_distance(m.get_origin(), origin), 1e-4) + self.assertAlmostEqual(m.get_spacing(), 1.3333, delta=1e-3) + + dump = pickle.dumps(m) + del m + m2 = pickle.loads(dump) + self.assertEqual(m2.get_name(), 'foo') + self.assertEqual(m2.get_number_of_voxels(), 19656) + self.assertLess(IMP.algebra.get_distance(m2.get_origin(), origin), + 1e-4) + self.assertAlmostEqual(m2.get_spacing(), 1.3333, delta=1e-3) + + if IMP.IMP_KERNEL_HAS_NUMPY: + data = m2.get_data() + self.assertEqual(data.shape, (27, 28, 26)) + self.assertAlmostEqual(data[17, 14, 10], 1.006, delta=1e-3) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/em2d/include/CenteredMat.h b/modules/em2d/include/CenteredMat.h index a75740bd5e..a2bb5b7ae4 100644 --- a/modules/em2d/include/CenteredMat.h +++ b/modules/em2d/include/CenteredMat.h @@ -1,134 +1,29 @@ /** * \file IMP/em2d/CenteredMat.h * \brief Decorator for OpenCV matrix to use relative coordinates - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPEM2D_CENTERED_MAT_H #define IMPEM2D_CENTERED_MAT_H #include -#include "IMP/em2d/opencv_interface.h" -#include "IMP/exception.h" -#include "IMP/macros.h" -#include "IMP/showable_macros.h" -#include +#include "internal/CenteredMat.h" IMPEM2D_BEGIN_NAMESPACE -//! Decorator for a cv::Mat to use coordinates respect to a point -//! Almost always that point is the center -class CenteredMat { - +class CenteredMat : public internal::CenteredMat { public: - /** - * Creates and CenteredMat for the matrix - * @param m The matrix - * @note The center pixel is not provided. It is assumed - * to be the center of the matrix - */ - CenteredMat(cv::Mat &m) { - // m is not copied, just a reference is added. - - IMP_USAGE_CHECK((m.rows != 0 && m.cols != 0), - "CenteredMat: Matrix passed is empty"); - centered_ = m; - center_row_ = static_cast(0.5 * m.rows); - center_col_ = static_cast(0.5 * m.cols); - set_starts_and_ends(); - } - - /** - * Creates a CenteredMat for the matrix - * @param m The matrix - * @param center_row - The row for the point used as center of CenteredMat - * @param center_col - The column for the point used as center of CenteredMat - * @return - */ - CenteredMat(cv::Mat &m, int center_row, int center_col) { - centered_ = m; - if (center_row >= 0 && center_row < m.rows && center_col >= 0 && - center_col < m.cols) { - center_row_ = center_row; - center_col_ = center_col; - } else { - IMP_THROW("CenteredMat: Center index out of range ", ValueException); - } - set_starts_and_ends(); - } - - /** - * get the starting value for a dimension. - //! For example, in a matrix of 5x5 centered at the origin (2,2), the - //! starting point will be (-2,2) - * @param i The dimension to use (0 - rows, 1 - columns) - * @return The starting point in the given dimension - */ - int get_start(int i) const { return start_[i]; } - - /** - * See get_start() function help. In the example of the 5x5 matrix, - * the end values would be (2,2) - * @param i The dimension to use (0 - rows, 1 - columns) - * @return The end point in the given dimension - */ - int get_end(int i) const { return end_[i]; } - - //! Returns true if the indices are in the matrix. - /** Remember that the indices - are those respect to the center of CenteredMat - @param i Row - @param j Column - @return whether all the indices are in the matrix. - */ - bool get_is_in_range(int i, int j) const { - if (i < get_start(0) || i > get_end(0)) return false; - if (j < get_start(1) || j > get_end(1)) return false; - return true; - } - - //! Returns the element (i,j) RELATIVE to the center. - /** Remember then that - * the indices can be negative. For performance the indices out of range - * are NOT checked - * @param i row - * @param j column - * @return the value of the matrix at row i and column j - */ - double &operator()(int i, int j) { - // if (!get_is_in_range(i,j)) { - // IMP_THROW("CenteredMat () : Index out of range",ValueException); - // } - return centered_.at(center_row_ + i, center_col_ + j); + IMPEM2D_DEPRECATED_VALUE_DECL(2.19) + CenteredMat(cv::Mat &m) : internal::CenteredMat(m) { + IMPEM2D_DEPRECATED_VALUE_DEF(2.19, "Use internal::CenteredMat instead"); } - //! Shows information about the class - /** @param out Stream used to show the information - */ - void do_show(std::ostream &out) const { - out << "Matrix of size: (" << centered_.rows << "," << centered_.cols - << ") centered mat at: (" << center_row_ << "," << center_col_ - << ") start (" << start_[0] << "," << start_[1] << ") end (" << end_[0] - << "," << end_[1] << ")" << std::endl; + IMPEM2D_DEPRECATED_VALUE_DECL(2.19) + CenteredMat(cv::Mat &m, int center_row, int center_col) + : internal::CenteredMat(m, center_row, center_col) { + IMPEM2D_DEPRECATED_VALUE_DEF(2.19, "Use internal::CenteredMat instead"); } - - IMP_SHOWABLE_INLINE(CenteredMat, do_show(out)); - - protected: - //! Sets the starting and ending points for the object. - /** See get_start() and get_end() for more help - */ - void set_starts_and_ends() { - start_[0] = -center_row_; - start_[1] = -center_col_; - end_[0] = centered_.rows - 1 - center_row_; - end_[1] = centered_.cols - 1 - center_col_; - } - - int center_row_, center_col_; // center pixel - cv::Mat centered_; - // starts and ends - int start_[2], end_[2]; }; IMPEM2D_END_NAMESPACE diff --git a/modules/em2d/include/Fine2DRegistrationRestraint.h b/modules/em2d/include/Fine2DRegistrationRestraint.h index 42ef7878c3..3e38be7361 100644 --- a/modules/em2d/include/Fine2DRegistrationRestraint.h +++ b/modules/em2d/include/Fine2DRegistrationRestraint.h @@ -1,94 +1,28 @@ /** * \file IMP/em2d/Fine2DRegistrationRestraint.h * \brief Alignment of 2D projections of a 3D volume - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPEM2D_FINE_2DREGISTRATION_RESTRAINT_H #define IMPEM2D_FINE_2DREGISTRATION_RESTRAINT_H #include -#include "IMP/em2d/project.h" -#include "IMP/em2d/ProjectionMask.h" -#include "IMP/em2d/RegistrationResult.h" -#include "IMP/em2d/ProjectionParameters.h" -#include "IMP/em2d/Image.h" -#include "IMP/em2d/scores2D.h" -#include "IMP/algebra/Vector2D.h" -#include "IMP/atom/Atom.h" -#include "IMP/Pointer.h" -#include "IMP/macros.h" +#include "internal/Fine2DRegistrationRestraint.h" IMPEM2D_BEGIN_NAMESPACE -//! Performs the fine search for the registration values in order to register -//! a model projection with an image -class IMPEM2DEXPORT Fine2DRegistrationRestraint : public Restraint { +class IMPEM2DEXPORT Fine2DRegistrationRestraint + : public internal::Fine2DRegistrationRestraint { public: - /** - * Constructs the restraint. Use the setup() function after construction - */ - Fine2DRegistrationRestraint(Model *m); - - /** - * Initialization function. To be called after setting the model for the - * restraint - * @param ps The particles used for the registration - * @param params The parameters used to project the images - * @param scoring_model The model that is projected. - * @param score_function The function that is used to score the similarity - * between a projection of the model and the EM image - * @param masks A manager containing the masks used for projecting. - */ - void setup(ParticlesTemp &ps, const ProjectingParameters ¶ms, - Model *scoring_model, ScoreFunction *score_function, - MasksManagerPtr masks = MasksManagerPtr()); - - /** - * Sets the image to use by the restraint to perform the fine search of - * the projection registration parameters - * @param subject The subject image - */ - void set_subject_image(em2d::Image *subject); - - /** - * Get the final values for the parameters after the optimization performed - * by this restraint - * @return The registration result - */ - RegistrationResult get_final_registration() const; - - virtual double unprotected_evaluate(IMP::DerivativeAccumulator *accum) - const override; - virtual IMP::ModelObjectsTemp do_get_inputs() const override; - IMP_OBJECT_METHODS(Fine2DRegistrationRestraint); - - /** - * Get the number of times that the function was called - * @return The number of calls - */ - unsigned int get_calls() const { return calls_; } - - private: - Pointer subject_; - mutable Pointer projection_; - // Subject particle (it is going to be the parameters for the subject) - mutable Pointer subj_params_particle_; - // Decorator for the subject particle - ProjectionParameters PP_; - // Access point for the particles - ParticlesTemp ps_; - // Projection masks for the particles - MasksManagerPtr masks_; - double resolution_, pixelsize_; - Pointer score_function_; - ProjectingParameters params_; - - mutable unsigned int calls_; + IMPEM2D_DEPRECATED_OBJECT_DECL(2.19) + Fine2DRegistrationRestraint(Model *m) + : internal::Fine2DRegistrationRestraint(m) { + IMPEM2D_DEPRECATED_OBJECT_DEF( + 2.19, "Use internal::Fine2DRegistrationRestraint instead"); + } }; -IMP_OBJECTS(Fine2DRegistrationRestraint, Fine2DRegistrationRestraints); - IMPEM2D_END_NAMESPACE #endif /* IMPEM2D_FINE_2DREGISTRATION_RESTRAINT_H */ diff --git a/modules/em2d/include/PCAFitRestraint.h b/modules/em2d/include/PCAFitRestraint.h index 08e450c69a..ff8bd6cce8 100644 --- a/modules/em2d/include/PCAFitRestraint.h +++ b/modules/em2d/include/PCAFitRestraint.h @@ -44,13 +44,17 @@ class IMPEM2DEXPORT PCAFitRestraint : public IMP::Restraint { recalculating projections \param[in] n_components Number of the largest components to be considered for the EM image + \param[in] micrographs_number Number of micrograph particles that were + used to generate the class averages (or zero, the default, + if unknown) */ PCAFitRestraint(Particles particles, const std::vector& image_files, double pixel_size, double resolution = 10.0, unsigned int projection_number = 100, bool reuse_direction = false, - unsigned int n_components = 1); + unsigned int n_components = 1, + unsigned int micrographs_number = 0); double unprotected_evaluate( IMP::DerivativeAccumulator *accum) const override; @@ -59,6 +63,10 @@ class IMPEM2DEXPORT PCAFitRestraint : public IMP::Restraint { void set_projection_number(unsigned int n) { projection_number_ = n; } + unsigned int get_micrographs_number() const { return micrographs_number_; } + + void set_micrographs_number(unsigned int n) { micrographs_number_ = n; } + //! Get transformation that best places the model on the image /** The transformation places the model such that if the image is placed on the xy plane with its lower left corner at the origin the model's @@ -125,6 +133,7 @@ class IMPEM2DEXPORT PCAFitRestraint : public IMP::Restraint { // Number of the largest components to be considered for the EM image unsigned int n_components_; + unsigned int micrographs_number_; mutable unsigned long counter_; }; diff --git a/modules/em2d/include/PolarResamplingParameters.h b/modules/em2d/include/PolarResamplingParameters.h index aae90deb08..edd969e737 100644 --- a/modules/em2d/include/PolarResamplingParameters.h +++ b/modules/em2d/include/PolarResamplingParameters.h @@ -13,7 +13,7 @@ #include "IMP/exception.h" #include "IMP/log.h" #include "IMP/log_macros.h" -#include +#include #include IMPEM2D_BEGIN_NAMESPACE @@ -185,12 +185,12 @@ class IMPEM2DEXPORT PolarResamplingParameters { double radius_step_, angle_step_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & polar_map_ & map_16SC2_ & map_16UC1_ & starting_radius_ - & ending_radius_ & n_rings_ & n_angles_ & matrix_rows_ & matrix_cols_ - & parameters_set_ & radius_step_ & angle_step_; + template void serialize(Archive &ar) { + ar(polar_map_, map_16SC2_, map_16UC1_, starting_radius_, + ending_radius_, n_rings_, n_angles_, matrix_rows_, matrix_cols_, + parameters_set_, radius_step_, angle_step_); } }; diff --git a/modules/em2d/include/ProjectionFinder.h b/modules/em2d/include/ProjectionFinder.h index 88fc46fc21..1973a37ce3 100644 --- a/modules/em2d/include/ProjectionFinder.h +++ b/modules/em2d/include/ProjectionFinder.h @@ -24,8 +24,8 @@ #include "IMP/Pointer.h" #include "IMP/Particle.h" #include -#include -#include +#include +#include IMPEM2D_BEGIN_NAMESPACE @@ -37,12 +37,12 @@ const unsigned int ALIGN2D_WITH_CENTERS = 2; //! Parameters used by Em2DRestraint and ProjectionFinder. class IMPEM2DEXPORT Em2DRestraintParameters : public ProjectingParameters { private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & boost::serialization::base_object(*this); - ar & n_projections & coarse_registration_method & save_match_images - & optimization_steps & simplex_initial_length & simplex_minimum_size; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + ar(n_projections, coarse_registration_method, save_match_images, + optimization_steps, simplex_initial_length, simplex_minimum_size); } void init_defaults() { diff --git a/modules/em2d/include/ProjectionMask.h b/modules/em2d/include/ProjectionMask.h index 877b20231e..5b49870fbc 100644 --- a/modules/em2d/include/ProjectionMask.h +++ b/modules/em2d/include/ProjectionMask.h @@ -1,7 +1,7 @@ /** * \file IMP/em2d/ProjectionMask.h * \brief projection masks - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPEM2D_PROJECTION_MASK_H @@ -9,7 +9,6 @@ #include #include "IMP/em2d/opencv_interface.h" -#include "IMP/em2d/CenteredMat.h" #include "IMP/atom/Mass.h" #include "IMP/em/exp.h" #include "IMP/algebra/Vector3D.h" @@ -21,17 +20,16 @@ #include "IMP/Particle.h" #include "IMP/exception.h" #include -#include -#include -#include +#include +#include IMPEM2D_BEGIN_NAMESPACE class ProjectionMask; class MasksManager; -typedef boost::shared_ptr ProjectionMaskPtr; -typedef boost::shared_ptr MasksManagerPtr; +typedef std::shared_ptr ProjectionMaskPtr; +typedef std::shared_ptr MasksManagerPtr; //! Mask that contains the projection of a given particles. This matrices //! speed up projecting because the only have to be computed once for a model @@ -67,10 +65,10 @@ class IMPEM2DEXPORT ProjectionMask { double sq_pixelsize_; // Used to save multiplications cv::Mat data_; // actual matrix with the mask private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & dim_ & sq_pixelsize_ & data_; + template void serialize(Archive &ar) { + ar(dim_, sq_pixelsize_, data_); } }; @@ -78,38 +76,29 @@ IMP_VALUES(ProjectionMask, ProjectionMasks); IMPEM2D_END_NAMESPACE -namespace boost { - namespace serialization { - template inline void save( - Archive &ar, const std::map &m, - const unsigned int) { - size_t sz = m.size(); - ar << sz; - for (const auto &p : m) { - ar << p.first; - ar << *(p.second); - } - } - - template inline void load( - Archive &ar, std::map &m, - const unsigned int) { - m.clear(); - size_t sz; - ar >> sz; - for (size_t i = 0; i < sz; ++i) { - double mass; - IMP::em2d::ProjectionMaskPtr ptr(new IMP::em2d::ProjectionMask()); - ar >> mass; - ar >> *ptr; - m[mass] = ptr; - } +namespace cereal { + template inline void save( + Archive &ar, const std::map &m) { + size_t sz = m.size(); + ar(sz); + for (const auto &p : m) { + ar(p.first); + ar(*(p.second)); } + } - template inline void serialize( - Archive &ar, std::map &m, - const unsigned int version) { - boost::serialization::split_free(ar, m, version); + template inline void load( + Archive &ar, std::map &m) { + m.clear(); + size_t sz; + ar(sz); + for (size_t i = 0; i < sz; ++i) { + double mass; + IMP::em2d::ProjectionMaskPtr ptr(new IMP::em2d::ProjectionMask()); + ar(mass); + ar(*ptr); + m[mass] = ptr; } } } @@ -221,10 +210,10 @@ class IMPEM2DEXPORT MasksManager { bool is_setup_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & mass2mask_ & kernel_params_ & pixelsize_ & is_setup_; + template void serialize(Archive &ar) { + ar(mass2mask_, kernel_params_, pixelsize_, is_setup_); } }; diff --git a/modules/em2d/include/RegistrationResult.h b/modules/em2d/include/RegistrationResult.h index 61910a1e9a..f4fefa4413 100644 --- a/modules/em2d/include/RegistrationResult.h +++ b/modules/em2d/include/RegistrationResult.h @@ -17,7 +17,7 @@ #include "IMP/algebra/Transformation2D.h" #include "IMP/Pointer.h" #include -#include +#include IMPEM2D_BEGIN_NAMESPACE @@ -154,11 +154,11 @@ class IMPEM2DEXPORT RegistrationResult { bool is_optimized_result_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & shift_ & ccc_ & Score_ & name_ & projection_index_ & image_index_ - & phi_ & theta_ & psi_ & R_ & is_optimized_result_; + template void serialize(Archive &ar) { + ar(shift_, ccc_, Score_, name_, projection_index_, image_index_, + phi_, theta_, psi_, R_, is_optimized_result_); } }; IMP_VALUES(RegistrationResult, RegistrationResults); diff --git a/modules/em2d/include/hierarchical_clustering.h b/modules/em2d/include/hierarchical_clustering.h index 853c5ce14b..e88a69cc52 100644 --- a/modules/em2d/include/hierarchical_clustering.h +++ b/modules/em2d/include/hierarchical_clustering.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include IMPEM2D_BEGIN_NAMESPACE @@ -109,11 +109,11 @@ class IMPEM2DEXPORT ClusterSet { IntsList clusters_elements_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & steps_ & n_elements_ & joined_ids1_ & joined_ids2_ - & cluster_distances_ & clusters_elements_; + template void serialize(Archive &ar) { + ar(steps_, n_elements_, joined_ids1_, joined_ids2_, + cluster_distances_, clusters_elements_); } }; IMP_VALUES(ClusterSet, ClusterSets); @@ -141,9 +141,9 @@ class IMPEM2DEXPORT SingleLinkage { out << "SingleLinkage"; }; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &, const unsigned int) {} + template void serialize(Archive &) {} }; IMP_VALUES(SingleLinkage, SingleLinkages); @@ -164,9 +164,9 @@ class IMPEM2DEXPORT CompleteLinkage { out << "CompleteLinkage"; }; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &, const unsigned int) {} + template void serialize(Archive &) {} }; IMP_VALUES(CompleteLinkage, CompleteLinkages); @@ -186,9 +186,9 @@ class IMPEM2DEXPORT AverageDistanceLinkage { out << "AverageDistanceLinkage"; }; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &, const unsigned int) {} + template void serialize(Archive &) {} }; IMP_VALUES(AverageDistanceLinkage, AverageDistanceLinkages); diff --git a/modules/em2d/include/image_processing.h b/modules/em2d/include/image_processing.h index 2d516e1600..090f7f462d 100644 --- a/modules/em2d/include/image_processing.h +++ b/modules/em2d/include/image_processing.h @@ -14,19 +14,19 @@ #include "IMP/base_types.h" #include #include -#include +#include IMPEM2D_BEGIN_NAMESPACE //! Class to provide all the parameters to the segmentation function class IMPEM2DEXPORT SegmentationParameters { private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & image_pixel_size & diffusion_beta & diffusion_timesteps - & fill_holes_stddevs & opening_kernel & remove_sizing_percentage - & binary_background & binary_foreground & threshold; + template void serialize(Archive &ar) { + ar(image_pixel_size, diffusion_beta, diffusion_timesteps, + fill_holes_stddevs, opening_kernel, remove_sizing_percentage, + binary_background, binary_foreground, threshold); } public: @@ -91,10 +91,10 @@ class IMPEM2DEXPORT MatchTemplateResult { << ") ccc = " << cross_correlation << std::endl; } private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & pair.first & pair.second & cross_correlation; + template void serialize(Archive &ar) { + ar(pair.first, pair.second, cross_correlation); } }; IMP_VALUES(MatchTemplateResult, MatchTemplateResults); diff --git a/modules/em2d/include/internal/CenteredMat.h b/modules/em2d/include/internal/CenteredMat.h new file mode 100644 index 0000000000..8167dd6429 --- /dev/null +++ b/modules/em2d/include/internal/CenteredMat.h @@ -0,0 +1,128 @@ +/** + * \file IMP/em2d/internal/CenteredMat.h + * \brief Decorator for OpenCV matrix to use relative coordinates + * Copyright 2007-2023 IMP Inventors. All rights reserved. +*/ + +#ifndef IMPEM2D_INTERNAL_CENTERED_MAT_H +#define IMPEM2D_INTERNAL_CENTERED_MAT_H + +#include +#include "IMP/em2d/opencv_interface.h" +#include "IMP/exception.h" +#include "IMP/macros.h" +#include "IMP/showable_macros.h" +#include + +IMPEM2D_BEGIN_INTERNAL_NAMESPACE + +//! Decorator for a cv::Mat to use coordinates with respect to a point +/** Almost always that point is the center */ +class CenteredMat { + + public: + //! Creates a CenteredMat for the matrix + /** @param m The matrix + @note The center pixel is not provided. It is assumed + to be the center of the matrix. */ + CenteredMat(cv::Mat &m) { + // m is not copied, just a reference is added. + + IMP_USAGE_CHECK((m.rows != 0 && m.cols != 0), + "CenteredMat: Matrix passed is empty"); + centered_ = m; + center_row_ = static_cast(0.5 * m.rows); + center_col_ = static_cast(0.5 * m.cols); + set_starts_and_ends(); + } + + //! Creates a CenteredMat for the matrix + /** @param m The matrix + @param center_row - The row for the point used as center of CenteredMat + @param center_col - The column for the point used as center of CenteredMat + */ + CenteredMat(cv::Mat &m, int center_row, int center_col) { + centered_ = m; + if (center_row >= 0 && center_row < m.rows && center_col >= 0 && + center_col < m.cols) { + center_row_ = center_row; + center_col_ = center_col; + } else { + IMP_THROW("CenteredMat: Center index out of range ", ValueException); + } + set_starts_and_ends(); + } + + //! get the starting value for a dimension. + /** For example, in a matrix of 5x5 centered at the origin (2,2), the + starting point will be (-2,2) + @param i The dimension to use (0 - rows, 1 - columns) + @return The starting point in the given dimension + */ + int get_start(int i) const { return start_[i]; } + + //! See get_start() function help. + /** In the example of the 5x5 matrix, the end values would be (2,2) + @param i The dimension to use (0 - rows, 1 - columns) + @return The end point in the given dimension + */ + int get_end(int i) const { return end_[i]; } + + //! Returns true if the indices are in the matrix. + /** Remember that the indices are those respect to the center of CenteredMat + @param i Row + @param j Column + @return whether all the indices are in the matrix. + */ + bool get_is_in_range(int i, int j) const { + if (i < get_start(0) || i > get_end(0)) return false; + if (j < get_start(1) || j > get_end(1)) return false; + return true; + } + + //! Returns the element (i,j) RELATIVE to the center. + /** Remember that the indices can be negative. For performance the + indices are NOT checked for out of range. + @param i row + @param j column + @return the value of the matrix at row i and column j + */ + double &operator()(int i, int j) { + // if (!get_is_in_range(i,j)) { + // IMP_THROW("CenteredMat () : Index out of range",ValueException); + // } + return centered_.at(center_row_ + i, center_col_ + j); + } + + //! Shows information about the class + /** @param out Stream used to show the information + */ + void do_show(std::ostream &out) const { + out << "Matrix of size: (" << centered_.rows << "," << centered_.cols + << ") centered mat at: (" << center_row_ << "," << center_col_ + << ") start (" << start_[0] << "," << start_[1] << ") end (" << end_[0] + << "," << end_[1] << ")" << std::endl; + } + + IMP_SHOWABLE_INLINE(CenteredMat, do_show(out)); + + protected: + //! Sets the starting and ending points for the object. + /** See get_start() and get_end() for more help + */ + void set_starts_and_ends() { + start_[0] = -center_row_; + start_[1] = -center_col_; + end_[0] = centered_.rows - 1 - center_row_; + end_[1] = centered_.cols - 1 - center_col_; + } + + int center_row_, center_col_; // center pixel + cv::Mat centered_; + // starts and ends + int start_[2], end_[2]; +}; + +IMPEM2D_END_INTERNAL_NAMESPACE + +#endif /* IMPEM2D_INTERNAL_CENTERED_MAT_H */ diff --git a/modules/em2d/include/internal/Fine2DRegistrationRestraint.h b/modules/em2d/include/internal/Fine2DRegistrationRestraint.h new file mode 100644 index 0000000000..72a1c73187 --- /dev/null +++ b/modules/em2d/include/internal/Fine2DRegistrationRestraint.h @@ -0,0 +1,94 @@ +/** + * \file IMP/em2d/internal/Fine2DRegistrationRestraint.h + * \brief Alignment of 2D projections of a 3D volume + * Copyright 2007-2023 IMP Inventors. All rights reserved. +*/ + +#ifndef IMPEM2D_INTERNAL_FINE_2DREGISTRATION_RESTRAINT_H +#define IMPEM2D_INTERNAL_FINE_2DREGISTRATION_RESTRAINT_H + +#include +#include "IMP/em2d/project.h" +#include "IMP/em2d/ProjectionMask.h" +#include "IMP/em2d/RegistrationResult.h" +#include "IMP/em2d/ProjectionParameters.h" +#include "IMP/em2d/Image.h" +#include "IMP/em2d/scores2D.h" +#include "IMP/algebra/Vector2D.h" +#include "IMP/atom/Atom.h" +#include "IMP/Pointer.h" +#include "IMP/macros.h" + +IMPEM2D_BEGIN_INTERNAL_NAMESPACE + +//! Performs the fine search for the registration values in order to register +//! a model projection with an image +class IMPEM2DEXPORT Fine2DRegistrationRestraint : public Restraint { + public: + /** + * Constructs the restraint. Use the setup() function after construction + */ + Fine2DRegistrationRestraint(Model *m); + + /** + * Initialization function. To be called after setting the model for the + * restraint + * @param ps The particles used for the registration + * @param params The parameters used to project the images + * @param scoring_model The model that is projected. + * @param score_function The function that is used to score the similarity + * between a projection of the model and the EM image + * @param masks A manager containing the masks used for projecting. + */ + void setup(ParticlesTemp &ps, const ProjectingParameters ¶ms, + Model *scoring_model, ScoreFunction *score_function, + MasksManagerPtr masks = MasksManagerPtr()); + + /** + * Sets the image to use by the restraint to perform the fine search of + * the projection registration parameters + * @param subject The subject image + */ + void set_subject_image(em2d::Image *subject); + + /** + * Get the final values for the parameters after the optimization performed + * by this restraint + * @return The registration result + */ + RegistrationResult get_final_registration() const; + + virtual double unprotected_evaluate(IMP::DerivativeAccumulator *accum) + const override; + virtual IMP::ModelObjectsTemp do_get_inputs() const override; + IMP_OBJECT_METHODS(Fine2DRegistrationRestraint); + + /** + * Get the number of times that the function was called + * @return The number of calls + */ + unsigned int get_calls() const { return calls_; } + + private: + Pointer subject_; + mutable Pointer projection_; + // Subject particle (it is going to be the parameters for the subject) + mutable Pointer subj_params_particle_; + // Decorator for the subject particle + ProjectionParameters PP_; + // Access point for the particles + ParticlesTemp ps_; + // Projection masks for the particles + MasksManagerPtr masks_; + double resolution_, pixelsize_; + Pointer score_function_; + ProjectingParameters params_; + + mutable unsigned int calls_; +}; + +IMP_OBJECTS(Fine2DRegistrationRestraint, Fine2DRegistrationRestraints); + +IMPEM2D_END_INTERNAL_NAMESPACE + +#endif /* IMPEM2D_INTERNAL_FINE_2DREGISTRATION_RESTRAINT_H */ diff --git a/modules/em2d/include/opencv_interface.h b/modules/em2d/include/opencv_interface.h index 7d1418e1cf..3fcee7da92 100644 --- a/modules/em2d/include/opencv_interface.h +++ b/modules/em2d/include/opencv_interface.h @@ -21,8 +21,8 @@ #endif #include -#include -#include +#include +#include IMPEM2D_BEGIN_NAMESPACE @@ -56,35 +56,33 @@ void show(const cv::Mat_ &m, std::ostream &out = std::cout) { IMPEM2D_END_NAMESPACE -namespace boost { - namespace serialization { - template - inline void serialize(Archive &ar, cv::Mat &m, const unsigned int) { - int rows, cols, type; - bool continuous; - - if (Archive::is_saving::value) { - rows = m.rows; - cols = m.cols; - type = m.type(); - continuous = m.isContinuous(); - } - ar & rows & cols & type & continuous; +namespace cereal { + template + inline void serialize(Archive &ar, cv::Mat &m) { + int rows, cols, type; + bool continuous; + + if (std::is_base_of::value) { + rows = m.rows; + cols = m.cols; + type = m.type(); + continuous = m.isContinuous(); + } + ar(rows, cols, type, continuous); - if (Archive::is_loading::value) { - m.create(rows, cols, type); - } + if (std::is_base_of::value) { + m.create(rows, cols, type); + } - if (continuous) { - size_t data_size = rows * cols * m.elemSize(); - boost::serialization::binary_object mat_data(m.data, data_size); - ar & mat_data; - } else { - size_t row_size = cols * m.elemSize(); - for (int i = 0; i < rows; ++i) { - boost::serialization::binary_object row_data(m.ptr(i), row_size); - ar & row_data; - } + if (continuous) { + size_t data_size = rows * cols * m.elemSize(); + auto mat_data = cereal::binary_data(m.data, data_size); + ar(mat_data); + } else { + size_t row_size = cols * m.elemSize(); + for (int i = 0; i < rows; ++i) { + auto row_data = cereal::binary_data(m.ptr(i), row_size); + ar(row_data); } } } diff --git a/modules/em2d/include/project.h b/modules/em2d/include/project.h index 0f29b845d8..034231bb44 100644 --- a/modules/em2d/include/project.h +++ b/modules/em2d/include/project.h @@ -23,17 +23,17 @@ #include #include #include -#include +#include IMPEM2D_BEGIN_NAMESPACE //! Parameters needed for the core projection routine class IMPEM2DEXPORT ProjectingParameters { private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & pixel_size & resolution; + template void serialize(Archive &ar) { + ar(pixel_size, resolution); } public: diff --git a/modules/em2d/pyext/swig.i-in b/modules/em2d/pyext/swig.i-in index ee9af25a59..56b9c0e61f 100644 --- a/modules/em2d/pyext/swig.i-in +++ b/modules/em2d/pyext/swig.i-in @@ -1,8 +1,6 @@ %import "RMF.i" %{ #include "RMF.h" -#include -#include #include %} @@ -33,9 +31,6 @@ IMP_SWIG_OBJECT(IMP::em2d, MeanAbsoluteDifference,MeanAbsoluteDifferences); IMP_SWIG_OBJECT(IMP::em2d, ProjectionParametersScoreState, ProjectionParametersScoreStates); IMP_SWIG_OBJECT(IMP::em2d, Em2DRestraint, Em2DRestraints); -/*header is not included -IMP_SWIG_OBJECT(IMP::em2d, Fine2DRegistrationRestraint, - Fine2DRegistrationRestraints);*/ IMP_SWIG_OBJECT(IMP::em2d, Image, Images); IMP_SWIG_OBJECT(IMP::em2d, ImageReaderWriter, ImageReaderWriters); IMP_SWIG_OBJECT(IMP::em2d, JPGImageReaderWriter, JPGImageReaderWriters); diff --git a/modules/em2d/src/PCAFitRestraint.cpp b/modules/em2d/src/PCAFitRestraint.cpp index 3181a009f5..7cbf5b9015 100644 --- a/modules/em2d/src/PCAFitRestraint.cpp +++ b/modules/em2d/src/PCAFitRestraint.cpp @@ -19,7 +19,8 @@ PCAFitRestraint::PCAFitRestraint(Particles particles, const std::vector& image_files, double pixel_size, double resolution, unsigned int projection_number, bool reuse_direction, - unsigned int n_components) + unsigned int n_components, + unsigned int micrographs_number) : Restraint(particles[0]->get_model(), "PCAFitRestraint%1%"), ps_(particles), pixel_size_(pixel_size), @@ -28,6 +29,7 @@ PCAFitRestraint::PCAFitRestraint(Particles particles, projector_(ps_, projection_number, pixel_size, resolution), reuse_direction_(reuse_direction), n_components_(n_components), + micrographs_number_(micrographs_number), counter_(0) { // read and process the images @@ -171,6 +173,7 @@ RestraintInfo *PCAFitRestraint::get_static_info() const { ri->add_float("pixel size", pixel_size_); ri->add_float("resolution", resolution_); ri->add_int("projection number", projection_number_); + ri->add_int("micrographs number", micrographs_number_); return ri.release(); } diff --git a/modules/em2d/src/ProjectionFinder.cpp b/modules/em2d/src/ProjectionFinder.cpp index 561ec4fdf3..67345d607d 100644 --- a/modules/em2d/src/ProjectionFinder.cpp +++ b/modules/em2d/src/ProjectionFinder.cpp @@ -2,7 +2,7 @@ * \file ProjectionFinder.cpp * \brief Coarse registration of 2D projections from a 3D volume * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #include "IMP/em2d/ProjectionFinder.h" @@ -11,7 +11,7 @@ #include "IMP/em2d/FFToperations.h" #include "IMP/em2d/scores2D.h" #include "IMP/em2d/project.h" -#include "IMP/em2d/Fine2DRegistrationRestraint.h" +#include "IMP/em2d/internal/Fine2DRegistrationRestraint.h" #include "IMP/em2d/SpiderImageReaderWriter.h" #include "IMP/em2d/TIFFImageReaderWriter.h" #include "IMP/em2d/opencv_interface.h" @@ -22,8 +22,7 @@ #include "IMP/log.h" #include "IMP/Pointer.h" #include "IMP/exception.h" -#include -#include +#include #include #include #include @@ -54,7 +53,7 @@ void ProjectionFinder::set_subjects(const em2d::Images &subjects) { subjects[0]->get_header().get_number_of_columns()); polar_params_.create_maps_for_resampling(); } - boost::timer preprocessing_timer; + IMP::internal::SimpleTimer preprocessing_timer; subjects_.resize(subjects.size()); unsigned int n_subjects = subjects_.size(); registration_results_.clear(); @@ -109,7 +108,7 @@ void ProjectionFinder::set_projections(const em2d::Images &projections) { PROJECTIONS_POLAR_AUTOC_.clear(); PROJECTIONS_POLAR_AUTOC_.resize(n_projections); projections_cog_.resize(n_projections); - boost::timer preprocessing_timer; + IMP::internal::SimpleTimer preprocessing_timer; for (unsigned int i = 0; i < n_projections; ++i) { projections_[i] = projections[i]; // does not copy std::ostringstream oss; @@ -302,7 +301,7 @@ void ProjectionFinder::get_coarse_registration() { // boost::progress_display show_progress(subjects_.size()); for (unsigned long i = 0; i < subjects_.size(); ++i) { RegistrationResults coarse_RRs(projections_.size()); - boost::timer timer_coarse_subject; + IMP::internal::SimpleTimer timer_coarse_subject; get_coarse_registrations_for_subject(i, coarse_RRs); coarse_registration_time_ += timer_coarse_subject.elapsed(); @@ -345,7 +344,7 @@ void ProjectionFinder::get_complete_registration() { // Set optimizer IMP_NEW(Model, scoring_model, ()); - IMP_NEW(Fine2DRegistrationRestraint, fine2d, (scoring_model)); + IMP_NEW(internal::Fine2DRegistrationRestraint, fine2d, (scoring_model)); IMP_NEW(IMP::gsl::Simplex, simplex_optimizer, (scoring_model)); IMP_LOG_TERSE("ProjectionFinder: Setting Fine2DRegistrationRestraint " @@ -368,7 +367,7 @@ void ProjectionFinder::get_complete_registration() { for (unsigned long i = 0; i < subjects_.size(); ++i) { RegistrationResults coarse_RRs(projections_.size()); - boost::timer timer_coarse_subject; + IMP::internal::SimpleTimer timer_coarse_subject; get_coarse_registrations_for_subject(i, coarse_RRs); coarse_registration_time_ += timer_coarse_subject.elapsed(); // The coarse registration scoring is done by cross-correlation @@ -391,7 +390,7 @@ void ProjectionFinder::get_complete_registration() { RegistrationResult best_fine_registration; best_fine_registration.set_score(std::numeric_limits::max()); - boost::timer timer_fine_subject; + IMP::internal::SimpleTimer timer_fine_subject; for (unsigned int k = 0; k < n_optimized; ++k) { // Fine registration of the subject using simplex sorted_coarse_RRs[k]->set_in_image(subjects_[i]->get_header()); diff --git a/modules/em2d/src/ProjectionMask.cpp b/modules/em2d/src/ProjectionMask.cpp index d234ba22f3..83d7e744ca 100644 --- a/modules/em2d/src/ProjectionMask.cpp +++ b/modules/em2d/src/ProjectionMask.cpp @@ -1,10 +1,11 @@ /** * \file ProjectionMask.cpp * \brief projection masks - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #include "IMP/em2d/ProjectionMask.h" +#include "IMP/em2d/internal/CenteredMat.h" #include "IMP/exception.h" IMPEM2D_BEGIN_NAMESPACE @@ -32,7 +33,7 @@ void ProjectionMask::create(const em::KernelParameters &kparams, double mass) { // Decorate the masks to use centered coordinates - CenteredMat centered_mask(data_); + internal::CenteredMat centered_mask(data_); IMP_LOG_VERBOSE(" Generating mask. " << centered_mask); diff --git a/modules/em2d/src/align2D.cpp b/modules/em2d/src/align2D.cpp index e365cbd1c7..2bb3f44ccf 100644 --- a/modules/em2d/src/align2D.cpp +++ b/modules/em2d/src/align2D.cpp @@ -15,8 +15,6 @@ #include "IMP/em/exp.h" #include "IMP/exception.h" #include "IMP/constants.h" -#include -#include #include #include diff --git a/modules/em2d/src/image_processing.cpp b/modules/em2d/src/image_processing.cpp index da13790f57..8e4f4d3782 100644 --- a/modules/em2d/src/image_processing.cpp +++ b/modules/em2d/src/image_processing.cpp @@ -1,11 +1,11 @@ /** * \file image_processing.cpp * \brief image processing for EM - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #include "IMP/em2d/image_processing.h" -#include "IMP/em2d/CenteredMat.h" +#include "IMP/em2d/internal/CenteredMat.h" #include "IMP/em2d/internal/image_processing_helper.h" #include "IMP/em2d/Image.h" #include "IMP/em2d/SpiderImageReaderWriter.h" @@ -574,8 +574,8 @@ void get_transformed(const cv::Mat &input, cv::Mat &transformed, void do_extend_borders(cv::Mat &orig, cv::Mat &dst, unsigned int pix) { dst.create(orig.rows + 2 * pix, orig.cols + 2 * pix, orig.type()); dst.setTo(0.0); - CenteredMat Orig(orig); - CenteredMat Dst(dst); + internal::CenteredMat Orig(orig); + internal::CenteredMat Dst(dst); for (int i = Orig.get_start(0); i <= Orig.get_end(0); ++i) { for (int j = Orig.get_start(1); j <= Orig.get_end(1); ++j) { Dst(i, j) = Orig(i, j); @@ -622,8 +622,8 @@ void get_morphologic_gradient(const cv::Mat &m, cv::Mat &result, double get_overlap_percentage(cv::Mat &m1, cv::Mat &m2, const IntPair ¢er) { - CenteredMat M1(m1, center.first, center.second); - CenteredMat M2(m2); + internal::CenteredMat M1(m1, center.first, center.second); + internal::CenteredMat M2(m2); IMP_USAGE_CHECK( (M2.get_start(0) < M1.get_start(0) || M2.get_start(1) < M1.get_start(1) || M2.get_end(0) > M1.get_end(0) || M2.get_end(1) > M1.get_end(1)), diff --git a/modules/em2d/src/Fine2DRegistrationRestraint.cpp b/modules/em2d/src/internal/Fine2DRegistrationRestraint.cpp similarity index 97% rename from modules/em2d/src/Fine2DRegistrationRestraint.cpp rename to modules/em2d/src/internal/Fine2DRegistrationRestraint.cpp index 9413e15cdd..cb096f6c0d 100644 --- a/modules/em2d/src/Fine2DRegistrationRestraint.cpp +++ b/modules/em2d/src/internal/Fine2DRegistrationRestraint.cpp @@ -1,5 +1,5 @@ /** - * \file Fine2DRegistrationRestraint.cpp + * \file internal/Fine2DRegistrationRestraint.cpp * \brief Finely refine the angles and translations of a set of subject images * Copyright 2007-2022 IMP Inventors. All rights reserved. */ @@ -12,7 +12,7 @@ #include "IMP/algebra/SphericalVector3D.h" #include "IMP/log.h" -IMPEM2D_BEGIN_NAMESPACE +IMPEM2D_BEGIN_INTERNAL_NAMESPACE Fine2DRegistrationRestraint::Fine2DRegistrationRestraint(Model *m) : Restraint(m, "File2DRegistrationRestraint%1%"), calls_(0) { @@ -134,4 +134,4 @@ RegistrationResult Fine2DRegistrationRestraint::get_final_registration() const { return rr; } -IMPEM2D_END_NAMESPACE +IMPEM2D_END_INTERNAL_NAMESPACE diff --git a/modules/em2d/src/project.cpp b/modules/em2d/src/project.cpp index 6b8d08cd92..0d16528a0e 100644 --- a/modules/em2d/src/project.cpp +++ b/modules/em2d/src/project.cpp @@ -13,8 +13,6 @@ #include "IMP/core/utility.h" #include "IMP/core/XYZ.h" #include "IMP/core/CoverRefined.h" -#include -#include IMPEM2D_BEGIN_NAMESPACE diff --git a/modules/em2d/test/medium_test_pca_fit_restraint.py b/modules/em2d/test/medium_test_pca_fit_restraint.py index 6f5f76c8d6..bf75b05529 100644 --- a/modules/em2d/test/medium_test_pca_fit_restraint.py +++ b/modules/em2d/test/medium_test_pca_fit_restraint.py @@ -67,6 +67,9 @@ def test_simple(self): pca_fit_restraint = IMP.em2d.PCAFitRestraint( particles, image_list, 2.2, 20, 100) + self.assertEqual(pca_fit_restraint.get_micrographs_number(), 0) + pca_fit_restraint.set_micrographs_number(22) + self.assertEqual(pca_fit_restraint.get_micrographs_number(), 22) self.check_standard_object_methods(pca_fit_restraint) score = pca_fit_restraint.evaluate(False) print('initial score = ' + str(score)) @@ -90,9 +93,11 @@ def _check_restraint_info(self, r): def _check_static_restraint_info(self, r): info = r.get_static_info() - self.assertEqual(info.get_number_of_int(), 1) + self.assertEqual(info.get_number_of_int(), 2) self.assertEqual(info.get_int_key(0), "projection number") self.assertEqual(info.get_int_value(0), 100) + self.assertEqual(info.get_int_key(1), "micrographs number") + self.assertEqual(info.get_int_value(1), 22) self.assertEqual(info.get_number_of_float(), 2) self.assertEqual(info.get_float_key(0), "pixel size") diff --git a/modules/em2d/utility/score_model.cpp b/modules/em2d/utility/score_model.cpp index 83f7359f73..146c647b3b 100644 --- a/modules/em2d/utility/score_model.cpp +++ b/modules/em2d/utility/score_model.cpp @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include @@ -214,7 +214,7 @@ int main(int argc, char **argv) { // Deal with the generation of projections digest_parameter("projs", vm, opt); - boost::timer project_timer; + IMP::internal::SimpleTimer project_timer; if (opt[0] == "model") { if (check_parameters(vm, "np") == false) { std::cerr << "Error: The --np parameter is missing" << std::endl; @@ -253,7 +253,7 @@ int main(int argc, char **argv) { // Prepare finder IMP::set_log_level(IMP::VERBOSE); - boost::timer registration_timer; + IMP::internal::SimpleTimer registration_timer; IMP_NEW(em2d::EM2DScore, score_function, ()); IMP_NEW(em2d::ProjectionFinder, finder, ()); diff --git a/modules/example/include/ExampleConstraint.h b/modules/example/include/ExampleConstraint.h index d442608e09..85b5a7ccb8 100644 --- a/modules/example/include/ExampleConstraint.h +++ b/modules/example/include/ExampleConstraint.h @@ -14,6 +14,7 @@ #include #include #include +#include IMPEXAMPLE_BEGIN_NAMESPACE @@ -21,11 +22,12 @@ IMPEXAMPLE_BEGIN_NAMESPACE /** */ class IMPEXAMPLEEXPORT ExampleConstraint : public Constraint { - Pointer p_; + ParticleIndex p_; IntKey k_; public: ExampleConstraint(Particle *p); + ExampleConstraint() {} virtual void do_update_attributes() override; virtual void do_update_derivatives(DerivativeAccumulator *da) override; @@ -34,6 +36,18 @@ class IMPEXAMPLEEXPORT ExampleConstraint : public Constraint { static IntKey get_key(); IMP_OBJECT_METHODS(ExampleConstraint); + + private: + // Serialization support + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), p_); + // There is no need to serialize the IntKey - just recreate it on load: + if (std::is_base_of::value) { + k_ = get_key(); + } + } + IMP_OBJECT_SERIALIZE_DECL(ExampleConstraint); }; IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/include/ExampleObject.h b/modules/example/include/ExampleObject.h index e37bccf405..a41fe8c338 100644 --- a/modules/example/include/ExampleObject.h +++ b/modules/example/include/ExampleObject.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include IMPEXAMPLE_BEGIN_NAMESPACE @@ -32,6 +34,9 @@ class IMPEXAMPLEEXPORT ExampleObject : public Object { public: ExampleObject(const Floats &data); + // Default constructor, needed for serialization or Python pickle support + ExampleObject() : Object("") {} + double get_data(unsigned int i) const { IMP_USAGE_CHECK(i < data_.size(), "Index " << i << " out of range."); return data_[i]; @@ -43,6 +48,15 @@ class IMPEXAMPLEEXPORT ExampleObject : public Object { to maintain. */ IMP_OBJECT_METHODS(ExampleObject); + + private: + // Serialization support + friend class cereal::access; + template void serialize(Archive &ar) { + // We must save/load everything in the Object base class + // (e.g. name) plus our own variables + ar(cereal::base_class(this), data_); + } }; typedef Vector > ExampleObjects; diff --git a/modules/example/include/ExamplePairScore.h b/modules/example/include/ExamplePairScore.h index fa74cea4da..923c48b153 100644 --- a/modules/example/include/ExamplePairScore.h +++ b/modules/example/include/ExamplePairScore.h @@ -14,6 +14,7 @@ #include #include #include +#include IMPEXAMPLE_BEGIN_NAMESPACE @@ -27,6 +28,7 @@ class IMPEXAMPLEEXPORT ExamplePairScore : public PairScore { public: ExamplePairScore(double x0, double k); + ExamplePairScore() {} virtual double evaluate_index(Model *m, const ParticleIndexPair &p, DerivativeAccumulator *da) const override; @@ -34,7 +36,15 @@ class IMPEXAMPLEEXPORT ExamplePairScore : public PairScore { Model *m, const ParticleIndexes &pis) const override; IMP_PAIR_SCORE_METHODS(ExamplePairScore); IMP_OBJECT_METHODS(ExamplePairScore); - ; + + // Serialization support + private: + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), x0_, k_); + } + IMP_OBJECT_SERIALIZE_DECL(ExamplePairScore); + }; IMP_OBJECTS(ExamplePairScore, ExamplePairScores); diff --git a/modules/example/include/ExampleRestraint.h b/modules/example/include/ExampleRestraint.h index 6c3d0b9418..e8646f82ca 100644 --- a/modules/example/include/ExampleRestraint.h +++ b/modules/example/include/ExampleRestraint.h @@ -11,6 +11,7 @@ #include #include +#include IMPEXAMPLE_BEGIN_NAMESPACE @@ -32,10 +33,28 @@ class IMPEXAMPLEEXPORT ExampleRestraint : public Restraint { preferably in a Singleton or PairContainer as appropriate. */ ExampleRestraint(Model *m, ParticleIndex p, double k); + + // Default constructor, needed for serialization or Python pickle support + ExampleRestraint() {} + void do_add_score_and_derivatives(ScoreAccumulator sa) const override; ModelObjectsTemp do_get_inputs() const override; IMP_OBJECT_METHODS(ExampleRestraint); + + private: + // Serialization support + friend class cereal::access; + template void serialize(Archive &ar) { + // We must save/load everything in the Restraint base class + // (e.g. restraint name, Model pointer) plus our own variables p_ and k_ + ar(cereal::base_class(this), p_, k_); + } + // ExampleRestraint is polymorphic (e.g. it is stored in + // IMP.core.RestraintsScoringFunction as a Restraint, not an + // ExampleRestraint) so tell the serialization subsystem how to handle this + IMP_OBJECT_SERIALIZE_DECL(ExampleRestraint); + }; IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/include/ExampleSingletonModifier.h b/modules/example/include/ExampleSingletonModifier.h index 862cf7312e..f3f05507f5 100644 --- a/modules/example/include/ExampleSingletonModifier.h +++ b/modules/example/include/ExampleSingletonModifier.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include IMPEXAMPLE_BEGIN_NAMESPACE @@ -33,8 +35,15 @@ IMPEXAMPLE_BEGIN_NAMESPACE class IMPEXAMPLEEXPORT ExampleSingletonModifier : public SingletonModifier { algebra::BoundingBoxD<3> bb_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), bb_); + } + IMP_OBJECT_SERIALIZE_DECL(ExampleSingletonModifier); + public: ExampleSingletonModifier(const algebra::BoundingBoxD<3> &bb); + ExampleSingletonModifier() {} // note, Doxygen wants a semicolon at the end of macro lines virtual void apply_index(Model *m, ParticleIndex p) const diff --git a/modules/example/include/ExampleUnaryFunction.h b/modules/example/include/ExampleUnaryFunction.h index a21abcce3e..9877397c76 100644 --- a/modules/example/include/ExampleUnaryFunction.h +++ b/modules/example/include/ExampleUnaryFunction.h @@ -2,7 +2,7 @@ * \file IMP/example/ExampleUnaryFunction.h * \brief A simple unary function. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,6 +12,10 @@ #include #include #include +#include +#include +#include +#include IMPEXAMPLE_BEGIN_NAMESPACE @@ -19,11 +23,8 @@ IMPEXAMPLE_BEGIN_NAMESPACE /** This one happens to be a harmonic. The source code is as follows: \include ExampleUnaryFunction.h - - \note The class does not have an IMPEXAMPLEEXPORT - since it is all defined in a header. */ -class ExampleUnaryFunction : public UnaryFunction { +class IMPEXAMPLEEXPORT ExampleUnaryFunction : public UnaryFunction { Float center_; Float k_; @@ -35,6 +36,8 @@ class ExampleUnaryFunction : public UnaryFunction { IMP_USAGE_CHECK(k > 0, "The spring constant must be positive."); } + ExampleUnaryFunction() {} + virtual DerivativePair evaluate_with_derivative(double feature) const override { return DerivativePair(evaluate(feature), k_ * (feature - center_)); @@ -43,6 +46,13 @@ class ExampleUnaryFunction : public UnaryFunction { return .5 * k_ * algebra::get_squared(feature - center_); } IMP_OBJECT_METHODS(ExampleUnaryFunction); + + private: + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), center_, k_); + } + IMP_OBJECT_SERIALIZE_DECL(ExampleUnaryFunction); }; IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/pyext/swig.i-in b/modules/example/pyext/swig.i-in index 3a2a53d9f1..31f9a0b8b6 100644 --- a/modules/example/pyext/swig.i-in +++ b/modules/example/pyext/swig.i-in @@ -10,14 +10,14 @@ %{ #include "RMF.h" %} -IMP_SWIG_OBJECT(IMP::example, ExampleRestraint, ExampleRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::example, ExampleRestraint, ExampleRestraints); IMP_SWIG_DECORATOR(IMP::example, ExampleDecorator, ExampleDecorators); -IMP_SWIG_OBJECT(IMP::example, ExampleUnaryFunction, ExampleUnaryFunctions); -IMP_SWIG_OBJECT(IMP::example, ExampleSingletonModifier, ExampleSingletonModifiers); -IMP_SWIG_OBJECT(IMP::example, ExamplePairScore, ExamplePairScores); +IMP_SWIG_OBJECT_SERIALIZE(IMP::example, ExampleUnaryFunction, ExampleUnaryFunctions); +IMP_SWIG_OBJECT_SERIALIZE(IMP::example, ExampleSingletonModifier, ExampleSingletonModifiers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::example, ExamplePairScore, ExamplePairScores); IMP_SWIG_OBJECT(IMP::example, ExampleSubsetFilterTable, ExampleSubsetFilterTables); -IMP_SWIG_OBJECT(IMP::example, ExampleConstraint, ExampleConstraints); -IMP_SWIG_OBJECT(IMP::example, ExampleObject, ExampleObjects); +IMP_SWIG_OBJECT_SERIALIZE(IMP::example, ExampleConstraint, ExampleConstraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::example, ExampleObject, ExampleObjects); IMP_SWIG_VALUE_INSTANCE(IMP::example, ExampleTemplateClass3D, ExampleTemplateClassD, ExampleTemplateClass3Ds); IMP_SWIG_VALUE_TEMPLATE(IMP::example, ExampleTemplateClassD); diff --git a/modules/example/src/ExampleConstraint.cpp b/modules/example/src/ExampleConstraint.cpp index fca0d99014..3f89f9fce5 100644 --- a/modules/example/src/ExampleConstraint.cpp +++ b/modules/example/src/ExampleConstraint.cpp @@ -13,25 +13,30 @@ IMPEXAMPLE_BEGIN_NAMESPACE ExampleConstraint::ExampleConstraint(Particle *p) : Constraint(p->get_model(), "ExampleConstraint%1%"), - p_(p), + p_(p->get_index()), k_(get_key()) { - if (!p_->has_attribute(k_)) { - p_->add_attribute(k_, 0); + if (!p->has_attribute(k_)) { + p->add_attribute(k_, 0); } } void ExampleConstraint::do_update_attributes() { IMP_OBJECT_LOG; + Particle *p = get_model()->get_particle(p_); IMP_LOG_TERSE("Updating example constraint with particle " - << p_->get_value(k_) << std::endl); - p_->set_value(k_, p_->get_value(k_) + 1); + << p->get_value(k_) << std::endl); + p->set_value(k_, p->get_value(k_) + 1); } + void ExampleConstraint::do_update_derivatives(DerivativeAccumulator *) {} + ModelObjectsTemp ExampleConstraint::do_get_inputs() const { - return ModelObjectsTemp(1, p_); + Particle *p = get_model()->get_particle(p_); + return ModelObjectsTemp(1, p); } ModelObjectsTemp ExampleConstraint::do_get_outputs() const { - return ModelObjectsTemp(1, p_); + Particle *p = get_model()->get_particle(p_); + return ModelObjectsTemp(1, p); } IntKey ExampleConstraint::get_key() { @@ -39,4 +44,6 @@ IntKey ExampleConstraint::get_key() { return k; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::example::ExampleConstraint); + IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/src/ExamplePairScore.cpp b/modules/example/src/ExamplePairScore.cpp index 1634281d2d..f3b68f1372 100644 --- a/modules/example/src/ExamplePairScore.cpp +++ b/modules/example/src/ExamplePairScore.cpp @@ -45,4 +45,6 @@ ModelObjectsTemp ExamplePairScore::do_get_inputs( return IMP::get_particles(m, pis); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::example::ExamplePairScore); + IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/src/ExampleRestraint.cpp b/modules/example/src/ExampleRestraint.cpp index e01133e12a..bb5ac60d9e 100644 --- a/modules/example/src/ExampleRestraint.cpp +++ b/modules/example/src/ExampleRestraint.cpp @@ -37,4 +37,8 @@ ModelObjectsTemp ExampleRestraint::do_get_inputs() const { return ModelObjectsTemp(1, get_model()->get_particle(p_)); } +// Complete the serialization support (see IMP_OBJECT_SERIALIZE_DECL in the +// header file) +IMP_OBJECT_SERIALIZE_IMPL(IMP::example::ExampleRestraint); + IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/src/ExampleSingletonModifier.cpp b/modules/example/src/ExampleSingletonModifier.cpp index 05d6bd441a..2ba7d10f5e 100644 --- a/modules/example/src/ExampleSingletonModifier.cpp +++ b/modules/example/src/ExampleSingletonModifier.cpp @@ -42,4 +42,6 @@ ModelObjectsTemp ExampleSingletonModifier::do_get_outputs( return do_get_inputs(m, pis); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::example::ExampleSingletonModifier); + IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/src/ExampleUnaryFunction.cpp b/modules/example/src/ExampleUnaryFunction.cpp new file mode 100644 index 0000000000..dd22aac805 --- /dev/null +++ b/modules/example/src/ExampleUnaryFunction.cpp @@ -0,0 +1,15 @@ +/** + * \file ExampleUnaryFunction.cpp + * \brief A simple unary function. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#include + +IMPEXAMPLE_BEGIN_NAMESPACE + +IMP_OBJECT_SERIALIZE_IMPL(IMP::example::ExampleUnaryFunction); + +IMPEXAMPLE_END_NAMESPACE diff --git a/modules/example/test/test_constraint.py b/modules/example/test/test_constraint.py index 94a7a05213..dbcce106ca 100644 --- a/modules/example/test/test_constraint.py +++ b/modules/example/test/test_constraint.py @@ -4,6 +4,8 @@ import IMP.algebra import IMP.core import IMP.example +import pickle + class Tests(IMP.test.TestCase): @@ -27,5 +29,24 @@ def test_constraint(self): self.assertEqual(len(c.get_inputs()), 1) self.assertEqual(len(c.get_outputs()), 1) + def test_pickle(self): + """Test (un-)pickle of example Constraint""" + k = IMP.IntKey("Constraint key") + m = IMP.Model() + p = IMP.Particle(m) + c = IMP.example.ExampleConstraint(p) + self.assertEqual(p.get_value(k), 0) + m.update() + self.assertEqual(p.get_value(k), 1) + dump = pickle.dumps(c) + del c + # Updating should not happen once the ScoreState goes away + m.update() + self.assertEqual(p.get_value(k), 1) + newc = pickle.loads(dump) + m.update() + self.assertEqual(p.get_value(k), 2) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/example/test/test_modifier.py b/modules/example/test/test_modifier.py index 3fdddaa211..2c1a094cf1 100644 --- a/modules/example/test/test_modifier.py +++ b/modules/example/test/test_modifier.py @@ -4,6 +4,18 @@ import IMP.algebra import IMP.core import IMP.example +import pickle + + +def make_modifier(): + m = IMP.Model() + bb = IMP.algebra.BoundingBox3D(IMP.algebra.Vector3D(0, 0, 0), + IMP.algebra.Vector3D(10, 10, 10)) + p = m.add_particle("p1") + d = IMP.core.XYZ.setup_particle(m, p, IMP.algebra.Vector3D(-4, 13, 28)) + s = IMP.example.ExampleSingletonModifier(bb) + return m, p, d, s + class Tests(IMP.test.TestCase): @@ -43,5 +55,25 @@ def test_combine(self): self.assertLess(IMP.algebra.get_distance(d.get_coordinates(), IMP.algebra.Vector3D(6,3,8)), 1e-4) + def test_pickle(self): + """Test (un-)pickle of ExampleSingletonModifier""" + m, p, d, s = make_modifier() + dump = pickle.dumps(s) + news = pickle.loads(dump) + news.apply_index(m, p) + self.assertLess(IMP.algebra.get_distance( + d.get_coordinates(), IMP.algebra.Vector3D(6,3,8)), 1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of ExampleSingletonModifier via polymorphic ptr""" + m, p, d, s = make_modifier() + c = IMP.core.SingletonConstraint(s, None, m, p) + dump = pickle.dumps(c) + newc = pickle.loads(dump) + newc.before_evaluate() + self.assertLess(IMP.algebra.get_distance( + d.get_coordinates(), IMP.algebra.Vector3D(6,3,8)), 1e-4) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/example/test/test_object.py b/modules/example/test/test_object.py new file mode 100644 index 0000000000..77c4e069a6 --- /dev/null +++ b/modules/example/test/test_object.py @@ -0,0 +1,25 @@ +from __future__ import print_function +import IMP +import IMP.test +import IMP.example +import pickle + + +class Tests(IMP.test.TestCase): + + def test_object(self): + """Test example object""" + e = IMP.example.ExampleObject([1.0, 2.0, 3.0]) + self.assertAlmostEqual(e.get_data(0), 1.0, delta=1e-3) + + def test_serialize(self): + """Test (un-)serialize of ExampleObject""" + e = IMP.example.ExampleObject([1.0, 2.0, 3.0]) + self.assertAlmostEqual(e.get_data(0), 1.0, delta=1e-3) + dump = pickle.dumps(e) + newe = pickle.loads(dump) + self.assertAlmostEqual(newe.get_data(0), 1.0, delta=1e-3) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/example/test/test_restraint.py b/modules/example/test/test_restraint.py index 0f629e6ed4..a41df12e30 100644 --- a/modules/example/test/test_restraint.py +++ b/modules/example/test/test_restraint.py @@ -4,6 +4,16 @@ import IMP.algebra import IMP.core import IMP.example +import pickle + + +def make_restraint(): + m = IMP.Model() + p = m.add_particle("p") + d = IMP.core.XYZ.setup_particle(m, p, IMP.algebra.Vector3D(1,2,3)) + r = IMP.example.ExampleRestraint(m, p, 10.) + return m, r + class Tests(IMP.test.TestCase): @@ -25,5 +35,23 @@ def test_restraint(self): self.assertIn("example", r.get_version_info().get_module()) self.assertEqual(len(r.get_inputs()), 1) + def test_serialize(self): + """Test (un-)serialize of ExampleRestraint""" + m, r = make_restraint() + self.assertAlmostEqual(r.evaluate(False), 45.0, delta=1e-3) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 45.0, delta=1e-3) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of ExampleRestraint via polymorphic pointer""" + m, r = make_restraint() + sf = IMP.core.RestraintsScoringFunction([r]) + self.assertAlmostEqual(sf.evaluate(False), 45.0, delta=1e-3) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + self.assertAlmostEqual(newsf.evaluate(False), 45.0, delta=1e-3) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/example/test/test_unary_function.py b/modules/example/test/test_unary_function.py index 8a9aae8509..d4ace32b6b 100644 --- a/modules/example/test/test_unary_function.py +++ b/modules/example/test/test_unary_function.py @@ -4,6 +4,8 @@ import IMP.algebra import IMP.core import IMP.example +import pickle + class Tests(IMP.test.TestCase): @@ -36,5 +38,30 @@ def test_combine(self): self.assertAlmostEqual(ps.evaluate_index(m, [p1, p2], da), 51.08, delta=0.01) + def test_pickle(self): + """Test (un-)pickle of ExampleUnaryFunction""" + u = IMP.example.ExampleUnaryFunction(2.0, 10.0) + self.assertAlmostEqual(u.evaluate(4.0), 20.0, delta=0.01) + dump = pickle.dumps(u) + newu = pickle.loads(dump) + self.assertAlmostEqual(newu.evaluate(4.0), 20.0, delta=0.01) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of ExampleUnaryFunction via polymorphic pointer""" + m = IMP.Model() + p1 = m.add_particle("p1") + p2 = m.add_particle("p2") + d1 = IMP.core.XYZ.setup_particle(m, p1, IMP.algebra.Vector3D(1,2,3)) + d2 = IMP.core.XYZ.setup_particle(m, p2, IMP.algebra.Vector3D(4,5,6)) + u = IMP.example.ExampleUnaryFunction(2.0, 10.0) + ps = IMP.core.DistancePairScore(u) + self.assertAlmostEqual(ps.evaluate_index(m, [p1, p2], None), + 51.08, delta=0.01) + dump = pickle.dumps(ps) + newps = pickle.loads(dump) + self.assertAlmostEqual(newps.evaluate_index(m, [p1, p2], None), + 51.08, delta=0.01) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/foxs/bin/foxs.cpp b/modules/foxs/bin/foxs.cpp index f7b5178633..9d34ac1fdd 100644 --- a/modules/foxs/bin/foxs.cpp +++ b/modules/foxs/bin/foxs.cpp @@ -44,13 +44,14 @@ int main(int argc, char** argv) { bool score_log = false; bool gnuplot_script = false; bool explicit_water = false; - po::options_description desc( + std::string desc_prefix( "Usage: ... ...\n" "\nAny number of input PDBs and profiles is supported.\n" "Each PDB will be fitted against each profile.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/integrative_docking/bin/cross_links_score.cpp b/modules/integrative_docking/bin/cross_links_score.cpp index 6da2e9452c..3a2ef7975e 100644 --- a/modules/integrative_docking/bin/cross_links_score.cpp +++ b/modules/integrative_docking/bin/cross_links_score.cpp @@ -28,14 +28,15 @@ using namespace IMP::integrative_docking::internal; int main(int argc, char **argv) { // input parsing std::string out_file_name; - po::options_description desc( + std::string desc_prefix( "Usage: \n" "\nScore each docked complex (generated by combining pdb1 with a\n" "transformed version of pdb2, using transformations from trans_file)\n" "against cross links in cross_links_file.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/integrative_docking/bin/cross_links_single_score.cpp b/modules/integrative_docking/bin/cross_links_single_score.cpp index 9d838ef36a..f89703fa2f 100644 --- a/modules/integrative_docking/bin/cross_links_single_score.cpp +++ b/modules/integrative_docking/bin/cross_links_single_score.cpp @@ -29,12 +29,13 @@ using namespace IMP::integrative_docking::internal; int main(int argc, char **argv) { // input parsing std::string out_file_name; - po::options_description desc( + std::string desc_prefix( "Usage: \n" "\nScore a PDB structure against the given cross links.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") diff --git a/modules/integrative_docking/bin/em2d_score.cpp b/modules/integrative_docking/bin/em2d_score.cpp index 992c76a81c..35e29e4c7c 100644 --- a/modules/integrative_docking/bin/em2d_score.cpp +++ b/modules/integrative_docking/bin/em2d_score.cpp @@ -37,11 +37,13 @@ int main(int argc, char** argv) { bool residue_level = false; std::vector image_files; std::string rpdb, lpdb, trans_file, out_file_name; - po::options_description desc( + std::string desc_prefix( "Usage: ...\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.")( diff --git a/modules/integrative_docking/bin/em2d_single_score.cpp b/modules/integrative_docking/bin/em2d_single_score.cpp index b8432c9ae4..be043d40ee 100644 --- a/modules/integrative_docking/bin/em2d_single_score.cpp +++ b/modules/integrative_docking/bin/em2d_single_score.cpp @@ -36,11 +36,13 @@ int main(int argc, char **argv) { unsigned int n_components = 1; std::vector image_files; std::string pdb; - po::options_description desc( + std::string desc_prefix( "Usage: ...\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.")( diff --git a/modules/integrative_docking/bin/em3d_score.cpp b/modules/integrative_docking/bin/em3d_score.cpp index 3453ff699c..7b2dec4360 100644 --- a/modules/integrative_docking/bin/em3d_score.cpp +++ b/modules/integrative_docking/bin/em3d_score.cpp @@ -28,12 +28,14 @@ int main(int argc, char **argv) { bool cc_score = false; std::string rec_file_name, lig_file_name, map_file_name, trans_file_name; std::string out_file_name = "em3d_score.res"; - po::options_description desc( + std::string desc_prefix( "Usage: \n" "\nProgram for scoring of docking models with EM density map\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.")( diff --git a/modules/integrative_docking/bin/em3d_single_score.cpp b/modules/integrative_docking/bin/em3d_single_score.cpp index b310eca05c..bf6f70f17e 100644 --- a/modules/integrative_docking/bin/em3d_single_score.cpp +++ b/modules/integrative_docking/bin/em3d_single_score.cpp @@ -51,12 +51,14 @@ int main(int argc, char **argv) { std::vector pdb_file_names; std::string map_file_name; std::string out_file_name = "em_fit"; - po::options_description desc( + std::string desc_prefix( "Usage: ... \n" "\nProgram for filtering of docking solutions with EM density maps.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.")( diff --git a/modules/integrative_docking/bin/interface_cross_links.cpp b/modules/integrative_docking/bin/interface_cross_links.cpp index ca21a76e4f..2210a276dc 100644 --- a/modules/integrative_docking/bin/interface_cross_links.cpp +++ b/modules/integrative_docking/bin/interface_cross_links.cpp @@ -59,13 +59,15 @@ int main(int argc, char** argv) { // input parsing std::string out_file_name; bool use_nter = true; - po::options_description desc( + std::string desc_prefix( "Usage: \n" "\nReturns Lys-Lys cross links for the two molecules below the\n" "given threshold.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/integrative_docking/bin/interface_rtc.cpp b/modules/integrative_docking/bin/interface_rtc.cpp index 1742a4a331..382abd116a 100644 --- a/modules/integrative_docking/bin/interface_rtc.cpp +++ b/modules/integrative_docking/bin/interface_rtc.cpp @@ -85,12 +85,15 @@ void select_ecoli_residue_content(const ResidueContent& interface_rc, int main(int argc, char** argv) { // input parsing std::string out_file_name; - po::options_description desc("Usage: \n" + std::string desc_prefix( + "Usage: \n" "\nReturns interface residue content for the interface\n" "defined by two molecules.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit."); diff --git a/modules/integrative_docking/bin/nmr_rtc_score.cpp b/modules/integrative_docking/bin/nmr_rtc_score.cpp index ddd94c5323..a7efbfbef1 100644 --- a/modules/integrative_docking/bin/nmr_rtc_score.cpp +++ b/modules/integrative_docking/bin/nmr_rtc_score.cpp @@ -28,7 +28,7 @@ using namespace IMP::integrative_docking::internal; int main(int argc, char **argv) { // input parsing std::string out_file_name; - po::options_description desc( + std::string desc_prefix( "Usage: " " \n" "\nScore each docked complex (generated by combining pdb1 with a\n" @@ -36,8 +36,10 @@ int main(int argc, char **argv) { "against residue content files. Use '-' if there is no file for one\n" "of the molecules.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.")( diff --git a/modules/integrative_docking/bin/saxs_score.cpp b/modules/integrative_docking/bin/saxs_score.cpp index fa001f88ca..4bca1d2de4 100644 --- a/modules/integrative_docking/bin/saxs_score.cpp +++ b/modules/integrative_docking/bin/saxs_score.cpp @@ -50,12 +50,14 @@ int main(int argc, char **argv) { int units = 1; // determine automatically bool vr_score = false; - po::options_description desc( + std::string desc_prefix( "Usage: \n" "\nProgram for scoring of docking models with SAXS profile.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.")( diff --git a/modules/integrative_docking/bin/soap_score.cpp b/modules/integrative_docking/bin/soap_score.cpp index fdaeb8b004..c8307f66eb 100644 --- a/modules/integrative_docking/bin/soap_score.cpp +++ b/modules/integrative_docking/bin/soap_score.cpp @@ -65,15 +65,17 @@ int main(int argc, char** argv) { bool oriented_potentials = false; bool normalize = false; std::string potentials_file, receptor_potentials_file, ligand_potentials_file; - po::options_description desc( + std::string desc_prefix( "Usage: [trans_file] OR \n" "\nOption 1: compute the SOAP score of the interface between pdb1\n" "and pdb2 for a set of transformations in the trans_file.\n\n" "Option 2: compute SOAP scores for each pair of PDB file names in\n" "the input file filenames.txt.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); + desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/integrative_docking/test/expensive_test_pcsk9_example.py b/modules/integrative_docking/test/expensive_test_pcsk9_example.py index 5c1e97b514..926363e9dd 100644 --- a/modules/integrative_docking/test/expensive_test_pcsk9_example.py +++ b/modules/integrative_docking/test/expensive_test_pcsk9_example.py @@ -15,29 +15,30 @@ def make_dummy_patch_dock(self, input_docking): os.chmod('buildParams.pl', 0o755) with open('patch_dock.Linux', 'w') as fh: - fh.write("""#!/usr/bin/python + fh.write("""#!%s import sys, shutil params, outfname = sys.argv[1:] shutil.copy('%s', outfname) -""" % input_docking) +""" % (sys.executable, input_docking)) os.chmod('patch_dock.Linux', 0o755) with open('interface_cluster.linux', 'w') as fh: - fh.write("""#!/usr/bin/python + fh.write("#!" + sys.executable + """ +from __future__ import print_function import sys receptor, ligand, trans_in, dummy, clustered_out = sys.argv[1:] fh = open(clustered_out, 'w') -print >> fh, "receptorPdb (str) " + receptor -print >> fh, "ligandPdb (str) " + ligand +print("receptorPdb (str) " + receptor, file=fh) +print("ligandPdb (str) " + ligand, file=fh) for n, line in enumerate(open(trans_in)): spl = line.rstrip('\\r\\n').split() spl[0] = int(spl[0]) for i in range(1, 8): spl[i] = float(spl[i]) - print >> fh, "%4d | %.4f | %5d | %4d |%.5f %.5f %.5f %.5f %.5f %.5f" \ - % tuple(spl[0:2] + [n+1, 1] + spl[2:]) + print("%4d | %.4f | %5d | %4d |%.5f %.5f %.5f %.5f %.5f %.5f" + % tuple(spl[0:2] + [n+1, 1] + spl[2:]), file=fh) """) os.chmod('interface_cluster.linux', 0o755) diff --git a/modules/isd/include/AmbiguousNOERestraint.h b/modules/isd/include/AmbiguousNOERestraint.h index 9e483d5ace..ab85fc6489 100644 --- a/modules/isd/include/AmbiguousNOERestraint.h +++ b/modules/isd/include/AmbiguousNOERestraint.h @@ -28,12 +28,23 @@ class IMPISDEXPORT AmbiguousNOERestraint : public Restraint { double chi_; void set_chi(double chi) { chi_ = chi; } + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + pc_, sigma_, gamma_, Vexp_, chi_); + } + + IMP_OBJECT_SERIALIZE_DECL(AmbiguousNOERestraint); + public: //! Create the restraint. AmbiguousNOERestraint(Model *m, PairContainer *pc, ParticleIndexAdaptor sigma, ParticleIndexAdaptor gamma, double Iexp); + AmbiguousNOERestraint() {} + /* call for probability */ double get_probability() const { return exp(-unprotected_evaluate(nullptr)); } diff --git a/modules/isd/include/AmbiguousRestraint.h b/modules/isd/include/AmbiguousRestraint.h index 8d92013f9d..4053321424 100644 --- a/modules/isd/include/AmbiguousRestraint.h +++ b/modules/isd/include/AmbiguousRestraint.h @@ -30,6 +30,14 @@ class IMPISDEXPORT AmbiguousRestraint : public Restraint { int d_; Restraints rs_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), d_, rs_); + } + + IMP_OBJECT_SERIALIZE_DECL(AmbiguousRestraint); + public: //! Create the restraint. /** Two ways to call it: pass it two restraints, or a list of restraints. @@ -37,6 +45,7 @@ class IMPISDEXPORT AmbiguousRestraint : public Restraint { AmbiguousRestraint(Model *m, int d, Restraint *r0, Restraint *r1); AmbiguousRestraint(Model *m, int d, Restraints rs); + AmbiguousRestraint() {} double get_probability() const { return exp(-unprotected_evaluate(nullptr)); } diff --git a/modules/isd/include/AtomicCrossLinkMSRestraint.h b/modules/isd/include/AtomicCrossLinkMSRestraint.h index 7db0717557..d1d91bef98 100644 --- a/modules/isd/include/AtomicCrossLinkMSRestraint.h +++ b/modules/isd/include/AtomicCrossLinkMSRestraint.h @@ -35,6 +35,7 @@ class IMPISDEXPORT AtomicCrossLinkMSRestraint : public Restraint { ParticleIndex psi, Float slope = 0.0, bool part_of_log_score=false, std::string name = "AtomicCrossLinkMSRestraint%1%"); + AtomicCrossLinkMSRestraint() {} //! Add a contribution to this xlink /** @@ -79,6 +80,15 @@ class IMPISDEXPORT AtomicCrossLinkMSRestraint : public Restraint { ParticleIndexPairs ppis_; ParticleIndexPairs sigmass_; Ints default_range_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), xlen_, psi_, slope_, + part_of_log_score_, ppis_, sigmass_, default_range_); + } + + IMP_OBJECT_SERIALIZE_DECL(AtomicCrossLinkMSRestraint); }; IMPISD_END_NAMESPACE diff --git a/modules/isd/include/CrossLinkData.h b/modules/isd/include/CrossLinkData.h index f9b05c9efe..3211dcbf7c 100644 --- a/modules/isd/include/CrossLinkData.h +++ b/modules/isd/include/CrossLinkData.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -29,6 +31,14 @@ class IMPISDEXPORT CrossLinkData : public Object { int prior_type_; bool bias_; std::vector grid_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), lexp_, dist_grid_, sigma_grid_, + omega_grid_, pot_x_grid_, pot_value_grid_, prior_type_, bias_, grid_); + } + double get_unbiased_element(double dist, double sigmai) const; double get_biased_element(double dist, double sigmai) const; @@ -42,6 +52,7 @@ class IMPISDEXPORT CrossLinkData : public Object { double don = std::numeric_limits::max(), double doff = std::numeric_limits::max(), int prior_type = 0); + CrossLinkData() : Object("") {} int get_closest(std::vector const& vec, double value) const; Floats get_omegas(double sigma, Floats dists) const; double get_omega_prior(double omega, double omega0) const; diff --git a/modules/isd/include/CrossLinkMSRestraint.h b/modules/isd/include/CrossLinkMSRestraint.h index 05fc64b81e..b5b4d429e5 100644 --- a/modules/isd/include/CrossLinkMSRestraint.h +++ b/modules/isd/include/CrossLinkMSRestraint.h @@ -9,10 +9,14 @@ #ifndef IMPISD_CROSS_LINK_MSRESTRAINT_H #define IMPISD_CROSS_LINK_MSRESTRAINT_H + #include #include #include #include +#include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -30,9 +34,21 @@ class IMPISDEXPORT CrossLinkMSRestraint : public Restraint { double slope_; int constr_; bool get_log_prob_; + std::string protein1_, protein2_; + int residue1_, residue2_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + ppis_, sigmass_, lengthi_, psis_, length_, slope_, + constr_, get_log_prob_, protein1_, protein2_, residue1_, residue2_); + } double sphere_cap(float r1, float r2, float d) const; + IMP_OBJECT_SERIALIZE_DECL(CrossLinkMSRestraint); + public: //! Create the restraint. CrossLinkMSRestraint(IMP::Model* m, double length, @@ -48,6 +64,41 @@ class IMPISDEXPORT CrossLinkMSRestraint : public Restraint { bool get_log_prob = false, std::string name = "CrossLinkMSRestraint%1%"); + CrossLinkMSRestraint() {} + + /** \name Source information + These methods get or set the protein name and residue index of + each end of the cross-link, as identified in the experiment + (typically these will correspond to the information in a CSV + file or similar). This information is not used in modeling, but + is written into output RMF files and is needed to generate mmCIF files. + %{ + */ + //! Set protein name for one end of the cross-link + void set_source_protein1(std::string protein1) { protein1_ = protein1; } + + //! Get protein name for one end of the cross-link + std::string get_source_protein1() const { return protein1_; } + + //! Set protein name for one end of the cross-link + void set_source_protein2(std::string protein2) { protein2_ = protein2; } + + //! Get protein name for one end of the cross-link + std::string get_source_protein2() const { return protein2_; } + + //! Set residue number for one end of the cross-link + void set_source_residue1(int residue1) { residue1_ = residue1; } + + //! Get residue number for one end of the cross-link + int get_source_residue1() const { return residue1_; } + + //! Set residue number for one end of the cross-link + void set_source_residue2(int residue2) { residue2_ = residue2; } + + //! Get residue number for one end of the cross-link + int get_source_residue2() const { return residue2_; } + /** @} */ + void add_contribution(const IMP::ParticleIndexPair& pps, const IMP::ParticleIndexPair& sigmas, IMP::ParticleIndex psi) { @@ -69,8 +120,20 @@ class IMPISDEXPORT CrossLinkMSRestraint : public Restraint { } } + //! Return true iff the length is variable (stored in a Scale) + bool get_is_length_variable() const { + return constr_ == 1; + } + + //! Return true iff the restraint has a slope + bool get_has_slope() const { + return constr_ == 2; + } + double get_slope() const { return slope_; } + bool get_log_prob() const { return get_log_prob_; } + //! Get the sigma particle indexes from a contribution ParticleIndexPair get_contribution_sigma_indexes(int i) const { return sigmass_[i]; @@ -91,6 +154,10 @@ class IMPISDEXPORT CrossLinkMSRestraint : public Restraint { virtual double unprotected_evaluate( IMP::DerivativeAccumulator* accum) const override; virtual IMP::ModelObjectsTemp do_get_inputs() const override; + + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(CrossLinkMSRestraint); }; diff --git a/modules/isd/include/CysteineCrossLinkData.h b/modules/isd/include/CysteineCrossLinkData.h index 755ae36a76..004189aaa3 100644 --- a/modules/isd/include/CysteineCrossLinkData.h +++ b/modules/isd/include/CysteineCrossLinkData.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -26,12 +28,21 @@ class IMPISDEXPORT CysteineCrossLinkData : public Object { int prior_type_; Floats omega_grid_; std::vector grid_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), omega0_grid_, fmod_grid_, fexp_, + prior_type_, omega_grid_, grid_); + } + double get_element(double fexp, double fmod, double omega) const; double get_omega_prior(double omega, double omega0) const; public: CysteineCrossLinkData(double fexp, Floats fmod_grid, Floats omega_grid, Floats omega0_grid, int prior_type = 3); + CysteineCrossLinkData() : Object("") {} int get_closest(std::vector const& vec, double value) const; Floats get_omegas(Floats fmods, double omega0) const; diff --git a/modules/isd/include/CysteineCrossLinkRestraint.h b/modules/isd/include/CysteineCrossLinkRestraint.h index 39af44655d..cb030c5a24 100644 --- a/modules/isd/include/CysteineCrossLinkRestraint.h +++ b/modules/isd/include/CysteineCrossLinkRestraint.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE //! A restraint for cysteine cross-linking data. @@ -56,6 +58,16 @@ class IMPISDEXPORT CysteineCrossLinkRestraint : public Restraint { double fexp_; bool use_CA_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), ps1_, ps2_, pslist1_, pslist2_, + beta_, sigma_, epsilon_, weight_, data_, ccldata_, constr_type_, + fexp_, use_CA_); + } + + IMP_OBJECT_SERIALIZE_DECL(CysteineCrossLinkRestraint); + public: //! Create the restraint. CysteineCrossLinkRestraint(Model *m, ParticleIndexAdaptor beta, @@ -70,6 +82,8 @@ class IMPISDEXPORT CysteineCrossLinkRestraint : public Restraint { ParticleIndexAdaptor weight, CrossLinkData *data, CysteineCrossLinkData *ccldata); + CysteineCrossLinkRestraint() {} + /* call for probability */ double get_probability() const; diff --git a/modules/isd/include/FretData.h b/modules/isd/include/FretData.h index 303a662169..a759339abf 100644 --- a/modules/isd/include/FretData.h +++ b/modules/isd/include/FretData.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -28,6 +30,13 @@ class IMPISDEXPORT FretData : public Object { Floats grid_; Floats norm_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), d_term_, d_center_, s_grid_, nbin_, + dimension_, grid_, norm_); + } + unsigned get_index(unsigned indices[3]) const; void init_grids(const Floats& d_grid_int, Float R0, Float Rmin, Float Rmax, bool do_limit); @@ -35,6 +44,7 @@ class IMPISDEXPORT FretData : public Object { public: FretData(Floats d_term, Floats d_center, Floats d_int, Floats s_grid, Float R0, Float Rmin, Float Rmax, bool do_limit = true); + FretData() : Object("") {} int get_closest(std::vector const& vec, double value) const; diff --git a/modules/isd/include/FretRestraint.h b/modules/isd/include/FretRestraint.h index 6d390cd58e..ff06ed3bb7 100644 --- a/modules/isd/include/FretRestraint.h +++ b/modules/isd/include/FretRestraint.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE /** A restraint for using in-vivo ensemble FRET data. @@ -21,20 +23,20 @@ IMPISD_BEGIN_NAMESPACE */ class IMPISDEXPORT FretRestraint : public Restraint { - Particles pd_; - Particles pa_; - Pointer prd_; + ParticleIndexes pd_; + ParticleIndexes pa_; + ParticleIndex prd_; algebra::Vector3D GMMterd_; algebra::Vector3Ds GMMctrd_; - Pointer pra_; + ParticleIndex pra_; algebra::Vector3D GMMtera_; algebra::Vector3Ds GMMctra_; - Pointer kda_; - Pointer Ida_; - Pointer R0_; - Pointer sumFi_; - Pointer sigma0_; - Pointer Pbl_; + ParticleIndex kda_; + ParticleIndex Ida_; + ParticleIndex R0_; + ParticleIndex sumFi_; + ParticleIndex sigma0_; + ParticleIndex Pbl_; PointerMember data_; double fexp_; double multi_d_; @@ -45,12 +47,23 @@ class IMPISDEXPORT FretRestraint : public Restraint { mutable Floats power6_; std::vector > states_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), pd_, pa_, prd_, GMMterd_, + GMMctrd_, pra_, GMMtera_, GMMctra_, kda_, Ida_, R0_, sumFi_, sigma0_, + Pbl_, data_, fexp_, multi_d_, constr_type_, GMMsig_, GMMw_, Na_, + power6_, states_); + } + + IMP_OBJECT_SERIALIZE_DECL(FretRestraint); + double get_sumFi(double Pbleach) const; std::vector get_indices(unsigned index, int dimension) const; public: //! Create the restraint. - FretRestraint(Particles pd, Particles pa, + FretRestraint(ParticlesTemp pd, ParticlesTemp pa, Particle *kda, Particle *Ida, Particle *R0, Particle *sigma0, Particle *Pbl, double fexp, double m_d = 1.0, @@ -68,6 +81,8 @@ class IMPISDEXPORT FretRestraint : public Restraint { Particle *sigma0, Particle *Pbl, FretData *data, double fexp); + FretRestraint() {} + // get sumFi double get_sumFi() const; @@ -99,10 +114,10 @@ class IMPISDEXPORT FretRestraint : public Restraint { private: double get_model_fretr_type_0() const; double get_model_fretr_type_1() const; - algebra::Vector3Ds get_current_centers(Particle *p, + algebra::Vector3Ds get_current_centers(ParticleIndex p, const algebra::Vector3Ds &ctrs) const; - algebra::Vector3D get_current_center(Particle *p, + algebra::Vector3D get_current_center(ParticleIndex p, const algebra::Vector3D &ctr) const; }; diff --git a/modules/isd/include/GaussianEMRestraint.h b/modules/isd/include/GaussianEMRestraint.h index 73cf4a96c6..e9c190cfba 100644 --- a/modules/isd/include/GaussianEMRestraint.h +++ b/modules/isd/include/GaussianEMRestraint.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -67,6 +69,7 @@ class IMPISDEXPORT GaussianEMRestraint : public Restraint bool update_model=true, bool backbone_slope=false, bool local=false, std::string name="GaussianEMRestraint%1%"); + GaussianEMRestraint() {} //! Returns exp(score) double get_probability() const { @@ -136,6 +139,25 @@ class IMPISDEXPORT GaussianEMRestraint : public Restraint double argmax_; mutable double cross_correlation_; + + //! Create containers of model and density particles + void create_containers(); + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), model_cutoff_dist_, + density_cutoff_dist_, model_ps_, density_ps_, slope_, update_model_, + local_, msize_,dsize_, normalization_, dd_score_, self_mm_score_, + slope_ps_, density_fn_, exp_grid_, + invdx_, argmax_, cross_correlation_); + // recreate md_container and mm_container on input + if (std::is_base_of::value) { + create_containers(); + } + } + + IMP_OBJECT_SERIALIZE_DECL(GaussianEMRestraint); }; IMPISD_END_NAMESPACE diff --git a/modules/isd/include/JeffreysRestraint.h b/modules/isd/include/JeffreysRestraint.h index de3203debe..c1d2d84ec3 100644 --- a/modules/isd/include/JeffreysRestraint.h +++ b/modules/isd/include/JeffreysRestraint.h @@ -2,7 +2,7 @@ * \file IMP/isd/JeffreysRestraint.h * \brief A restraint on a scale parameter. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -19,12 +21,20 @@ IMPISD_BEGIN_NAMESPACE //! the probability is 1/scale class IMPISDEXPORT JeffreysRestraint : public Restraint { - Pointer p_; + ParticleIndex pi_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), pi_); + } + IMP_OBJECT_SERIALIZE_DECL(JeffreysRestraint); public: //! Create the restraint. JeffreysRestraint(Model *m, Particle *p); + JeffreysRestraint() {} + virtual double unprotected_evaluate(IMP::DerivativeAccumulator *accum) const override; virtual IMP::ModelObjectsTemp do_get_inputs() const override; diff --git a/modules/isd/include/LogWrapper.h b/modules/isd/include/LogWrapper.h index 8ba3d19a7c..1a195c27be 100644 --- a/modules/isd/include/LogWrapper.h +++ b/modules/isd/include/LogWrapper.h @@ -2,7 +2,7 @@ * \file IMP/isd/LogWrapper.h * \brief Calculate the -Log of a list of restraints. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,6 +12,9 @@ #include #include #include +#include +#include + IMPISD_BEGIN_NAMESPACE @@ -21,6 +24,13 @@ IMPISD_BEGIN_NAMESPACE \note Any weights of the wrapped restraints are ignored. */ class IMPISDEXPORT LogWrapper : public RestraintSet { + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(LogWrapper); + void show_it(std::ostream &out) const; public: @@ -31,6 +41,7 @@ class IMPISDEXPORT LogWrapper : public RestraintSet { //! Create a set that is registered with the model LogWrapper(const RestraintsTemp &rs, double weight, const std::string &name = "LogWrapper %1%"); + LogWrapper() {} virtual double unprotected_evaluate( IMP::DerivativeAccumulator* accum) const override; diff --git a/modules/isd/include/Nuisance.h b/modules/isd/include/Nuisance.h index 9855ab25c5..aef5f7de9c 100644 --- a/modules/isd/include/Nuisance.h +++ b/modules/isd/include/Nuisance.h @@ -2,7 +2,7 @@ * \file IMP/isd/Nuisance.h * \brief A decorator for nuisance parameters particles * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPISD_NUISANCE_H @@ -12,6 +12,8 @@ #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -37,7 +39,7 @@ class IMPISDEXPORT Nuisance : public Decorator { static FloatKey get_nuisance_key(); Float get_nuisance() const { - return get_particle()->get_value(get_nuisance_key()); + return get_model()->get_attribute(get_nuisance_key(), get_particle_index()); } void set_nuisance(Float d); @@ -92,12 +94,20 @@ IMP_DECORATORS(Nuisance, Nuisances, ParticlesTemp); #if !defined(IMP_DOXYGEN) && !defined(SWIG) class IMPISDEXPORT NuisanceScoreState : public ScoreState { - private: - IMP::WeakPointer p_; + ParticleIndex pi_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), pi_); + } + IMP_OBJECT_SERIALIZE_DECL(NuisanceScoreState); private: NuisanceScoreState(Particle *p) - : ScoreState(p->get_model(), "NuisanceScoreState%1%"), p_(p) {} + : ScoreState(p->get_model(), "NuisanceScoreState%1%"), + pi_(p->get_index()) {} + + NuisanceScoreState() {} public: friend class Nuisance; diff --git a/modules/isd/include/Scale.h b/modules/isd/include/Scale.h index 8aba6300d8..63accef0e4 100644 --- a/modules/isd/include/Scale.h +++ b/modules/isd/include/Scale.h @@ -34,7 +34,7 @@ class IMPISDEXPORT Scale : public Nuisance { return Nuisance::get_is_setup(m, pi) && Nuisance(m, pi).get_lower() >= 0; } - Float get_scale() const { return Nuisance(get_particle()).get_nuisance(); } + Float get_scale() const { return get_nuisance(); } void set_scale(Float d) { set_nuisance(d); } diff --git a/modules/isd/include/UniformPrior.h b/modules/isd/include/UniformPrior.h index 85ff1b5c7d..160a5fd928 100644 --- a/modules/isd/include/UniformPrior.h +++ b/modules/isd/include/UniformPrior.h @@ -2,7 +2,7 @@ * \file IMP/isd/UniformPrior.h * \brief A restraint on a scale parameter. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPISD_BEGIN_NAMESPACE @@ -19,15 +21,23 @@ IMPISD_BEGIN_NAMESPACE class IMPISDEXPORT UniformPrior : public Restraint { - Pointer p_; - Float upperb_; - Float lowerb_; - Float k_; + ParticleIndex pi_; + double upperb_; + double lowerb_; + double k_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), pi_, upperb_, lowerb_, k_); + } + IMP_OBJECT_SERIALIZE_DECL(UniformPrior); public: //! Create the restraint. - UniformPrior(IMP::Model* m, Particle *p, Float k, - Float upperb, Float lowerb, std::string name="UniformPrior%1%"); + UniformPrior(IMP::Model* m, Particle *p, double k, double upperb, + double lowerb, std::string name="UniformPrior%1%"); + + UniformPrior() {} virtual double unprotected_evaluate(IMP::DerivativeAccumulator *accum) diff --git a/modules/isd/include/Weight.h b/modules/isd/include/Weight.h index 27ac39fd0c..b1e9e261eb 100755 --- a/modules/isd/include/Weight.h +++ b/modules/isd/include/Weight.h @@ -54,9 +54,6 @@ class IMPISDEXPORT Weight : public Decorator { //! Set up Weight from the provided weight vector. IMP_DECORATOR_SETUP_1(Weight, const algebra::VectorKD&, w); - IMPISD_DEPRECATED_METHOD_DECL(2.12) - static IntKey get_nstates_key(); - //! Get number of weights key static IntKey get_number_of_weights_key(); diff --git a/modules/isd/pyext/swig.i-in b/modules/isd/pyext/swig.i-in index 2417166227..5a6588328a 100644 --- a/modules/isd/pyext/swig.i-in +++ b/modules/isd/pyext/swig.i-in @@ -7,10 +7,10 @@ the types in question). */ IMP_SWIG_BASE_OBJECT(IMP::isd, ISDRestraint, ISDRestraints); -IMP_SWIG_OBJECT(IMP::isd, CrossLinkMSRestraint, CrossLinkMSRestraints); -IMP_SWIG_OBJECT(IMP::isd, LogWrapper, LogWrappers); -IMP_SWIG_OBJECT(IMP::isd, UniformPrior, UniformPriors); -IMP_SWIG_OBJECT(IMP::isd, JeffreysRestraint, JeffreysRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, CrossLinkMSRestraint, CrossLinkMSRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, LogWrapper, LogWrappers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, UniformPrior, UniformPriors); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, JeffreysRestraint, JeffreysRestraints); IMP_SWIG_OBJECT(IMP::isd, NormalSigmaPCRestraint, NormalSigmaPCRestraints); IMP_SWIG_OBJECT(IMP::isd, vonMisesKappaJeffreysRestraint, vonMisesKappaJeffreysRestraints); IMP_SWIG_OBJECT(IMP::isd, vonMisesKappaConjugateRestraint, vonMisesKappaConjugateRestraints); @@ -31,12 +31,12 @@ IMP_SWIG_OBJECT(IMP::isd, GaussianRestraint, GaussianRestraints); IMP_SWIG_OBJECT(IMP::isd, StudentTRestraint, StudentTRestraints); IMP_SWIG_OBJECT(IMP::isd, LognormalRestraint, LognormalRestraints); IMP_SWIG_OBJECT(IMP::isd, LognormalAmbiguousRestraint, LognormalAmbiguousRestraints); -IMP_SWIG_OBJECT(IMP::isd, AmbiguousNOERestraint, AmbigousNOERestraints); -IMP_SWIG_OBJECT(IMP::isd, MarginalNOERestraint, AmbigousNOERestraints); -IMP_SWIG_OBJECT(IMP::isd, MarginalHBondRestraint, AmbigousHBondRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, AmbiguousNOERestraint, AmbiguousNOERestraints); +IMP_SWIG_OBJECT(IMP::isd, MarginalNOERestraint, MarginalNOERestraints); +IMP_SWIG_OBJECT(IMP::isd, MarginalHBondRestraint, MarginalHBondRestraints); IMP_SWIG_OBJECT(IMP::isd, TALOSRestraint, TALOSRestraints); IMP_SWIG_OBJECT(IMP::isd, RepulsiveDistancePairScore, RepulsiveDistancePairScores); -IMP_SWIG_OBJECT(IMP::isd, AmbiguousRestraint, AmbiguousRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, AmbiguousRestraint, AmbiguousRestraints); IMP_SWIG_OBJECT(IMP::isd, UnivariateFunction, UnivariateFunctions); IMP_SWIG_OBJECT(IMP::isd, Linear1DFunction, Linear1DFunctions); IMP_SWIG_OBJECT(IMP::isd, GeneralizedGuinierPorodFunction, GeneralizedGuinierPorodFunctions); @@ -47,19 +47,126 @@ IMP_SWIG_OBJECT(IMP::isd, GaussianProcessInterpolationRestraint, GaussianProcess IMP_SWIG_OBJECT(IMP::isd, MolecularDynamics, MolecularDynamicss); IMP_SWIG_OBJECT(IMP::isd, MolecularDynamicsMover, MolecularDynamicsMovers); IMP_SWIG_OBJECT(IMP::isd, HybridMonteCarlo, HybridMonteCarlos); -IMP_SWIG_OBJECT(IMP::isd, FretData, FretDatas); -IMP_SWIG_OBJECT(IMP::isd, FretRestraint, FretRestraints); -IMP_SWIG_OBJECT(IMP::isd, CrossLinkData, CrossLinkDatas); -IMP_SWIG_OBJECT(IMP::isd, CysteineCrossLinkData, CysteineCrossLinkDatas); -IMP_SWIG_OBJECT(IMP::isd, CysteineCrossLinkRestraint, CysteineCrossLinkRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, FretData, FretDatas); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, FretRestraint, FretRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, CrossLinkData, CrossLinkDatas); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, CysteineCrossLinkData, CysteineCrossLinkDatas); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, CysteineCrossLinkRestraint, CysteineCrossLinkRestraints); IMP_SWIG_OBJECT(IMP::isd, WeightMover, WeightMovers); IMP_SWIG_OBJECT(IMP::isd, WeightRestraint, WeightRestraints); -IMP_SWIG_OBJECT(IMP::isd, AtomicCrossLinkMSRestraint, AtomicCrossLinkMSRestraints); -IMP_SWIG_OBJECT(IMP::isd, GaussianEMRestraint, GaussianEMRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, AtomicCrossLinkMSRestraint, AtomicCrossLinkMSRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::isd, GaussianEMRestraint, GaussianEMRestraints); IMP_SWIG_OBJECT(IMP::isd, GaussianAnchorEMRestraint, GaussianAnchorEMRestraints); IMP_SWIG_OBJECT(IMP::isd, GammaPrior, GammaPriors); IMP_SWIG_OBJECT(IMP::isd, ResidueProteinProximityRestraint, ResidueProteinProximityRestraints); +%extend IMP::isd::CrossLinkMSRestraint { + %pythoncode %{ + def _get_contributions_sigma_numpy(self): + import numpy + n = self.get_number_of_contributions() + ret = numpy.empty((n, 2), int) + for i in range(n): + ret[i] = self.get_contribution_sigma_indexes(i) + return ret + + def _get_contributions_psi_numpy(self): + import numpy + n = self.get_number_of_contributions() + ret = numpy.empty(n, int) + for i in range(n): + ret[i] = self.get_contribution_psi_index(i) + return ret + + def _get_contributions_particles_numpy(self): + import numpy + n = self.get_number_of_contributions() + ret = numpy.empty((n, 2), int) + for i in range(n): + ret[i] = self.get_contribution_particle_indexes(i) + return ret + + def _get_python_evaluate(self): + from numba import njit + import numpy.linalg + import math + + @njit + def sphere_cap(r1, r2, d): + sc = 0. + if d <= max(r1, r2) - min(r1, r2): + sc = min(4.0 / 3.0 * math.pi * r1 * r1 * r1, + 4.0 / 3.0 * math.pi * r2 * r2 * r2) + elif d >= r1 + r2: + sc = 0. + else: + sc = ((math.pi / 12 / d * (r1 + r2 - d) * (r1 + r2 - d)) * + (d * d + 2 * d * r1 - 3 * r1 * r1 + 2 * d * r2 + + 6 * r1 * r2 - 3 * r2 * r2)) + return sc + + @njit + def get_probability(xyz, scale, ps, ncontrib, sigma, psi, length, + slope): + onemprob = 1.0 + for k in range(ncontrib): + dist = numpy.linalg.norm(xyz[ps[k, 0]] - xyz[ps[k, 1]]) + if dist < 0.0001: + dist = 0.0001 + psik = scale[psi[k]] + sigmai = scale[sigma[k, 0]] + sigmaj = scale[sigma[k, 1]] + + voli = 4.0 / 3.0 * math.pi * sigmai * sigmai * sigmai + volj = 4.0 / 3.0 * math.pi * sigmaj * sigmaj * sigmaj + + if dist < sigmai + sigmaj: + xlvol = (4.0 / 3.0 * math.pi * (length / 2.) + * (length / 2.) * (length / 2)) + fi = min(voli, xlvol) + fj = min(volj, xlvol) + else: + di = dist - sigmaj - length / 2. + dj = dist - sigmai - length / 2. + fi = sphere_cap(sigmai, length / 2., abs(di)) + fj = sphere_cap(sigmaj, length / 2., abs(dj)) + + pofr = fi * fj / voli / volj + if slope is not None: + prior = math.exp(slope * dist) + onemprob = onemprob * (1.0 - (psik * (1.0 - pofr) + + pofr * (1 - psik)) * prior) + else: + onemprob = onemprob * (1.0 - (psik * (1.0 - pofr) + + pofr * (1 - psik))) + return 1.0 - onemprob + + if self.get_is_length_variable(): + raise NotImplementedError("Only implemented for fixed-length") + m = self.get_model() + xyz, radius = m.get_spheres_numpy() + scale = m.get_floats_numpy(IMP.isd.Scale.get_scale_key()) + sigma = self._get_contributions_sigma_numpy() + psi = self._get_contributions_psi_numpy() + pis = self._get_contributions_particles_numpy() + get_log_prob = self.get_log_prob() + length = self.get_length() + ncontrib = len(sigma) + slope = self.get_slope() if self.get_has_slope() else None + + @njit + def scorefunc(): + prob = get_probability(xyz, scale, pis, ncontrib, sigma, psi, + length, slope) + if get_log_prob: + return -math.log(prob) + else: + return prob + + return scorefunc + %} +} + /* One can add python methods to your module by putting code in %pythoncode blocks This function can be called as IMP.isds.say_hello(). */ %pythoncode %{ diff --git a/modules/isd/src/AmbiguousNOERestraint.cpp b/modules/isd/src/AmbiguousNOERestraint.cpp index 28e355b2c8..906dcfd44d 100644 --- a/modules/isd/src/AmbiguousNOERestraint.cpp +++ b/modules/isd/src/AmbiguousNOERestraint.cpp @@ -100,4 +100,6 @@ ModelObjectsTemp AmbiguousNOERestraint::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::AmbiguousNOERestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/AmbiguousRestraint.cpp b/modules/isd/src/AmbiguousRestraint.cpp index 0052fbce2d..dfef9535dc 100644 --- a/modules/isd/src/AmbiguousRestraint.cpp +++ b/modules/isd/src/AmbiguousRestraint.cpp @@ -56,4 +56,6 @@ ModelObjectsTemp AmbiguousRestraint::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::AmbiguousRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/AtomicCrossLinkMSRestraint.cpp b/modules/isd/src/AtomicCrossLinkMSRestraint.cpp index c0f53e684e..5b1c8c9a74 100644 --- a/modules/isd/src/AtomicCrossLinkMSRestraint.cpp +++ b/modules/isd/src/AtomicCrossLinkMSRestraint.cpp @@ -141,4 +141,6 @@ ModelObjectsTemp AtomicCrossLinkMSRestraint::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::AtomicCrossLinkMSRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/CrossLinkMSRestraint.cpp b/modules/isd/src/CrossLinkMSRestraint.cpp index a94993c5d7..47db733b3f 100644 --- a/modules/isd/src/CrossLinkMSRestraint.cpp +++ b/modules/isd/src/CrossLinkMSRestraint.cpp @@ -179,4 +179,36 @@ ModelObjectsTemp CrossLinkMSRestraint::do_get_inputs() const { return ret; } +RestraintInfo *CrossLinkMSRestraint::get_static_info() const { + if (protein1_.empty() || protein2_.empty()) { + return nullptr; + } else { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("protein1", protein1_); + ri->add_string("protein2", protein2_); + ri->add_int("residue1", residue1_); + ri->add_int("residue2", residue2_); + + ParticleIndexes ps; + for (const auto &sigma : sigmass_) { + ps.push_back(sigma[0]); + ps.push_back(sigma[1]); + } + ri->add_particle_indexes("sigmas", ps); + + ri->add_particle_indexes("psis", psis_); + + ps.clear(); + for (const auto &ppi : ppis_) { + ps.push_back(ppi[0]); + ps.push_back(ppi[1]); + } + ri->add_particle_indexes("endpoints", ps); + + return ri.release(); + } +} + +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::CrossLinkMSRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/CysteineCrossLinkRestraint.cpp b/modules/isd/src/CysteineCrossLinkRestraint.cpp index 833d119807..befcb9694c 100644 --- a/modules/isd/src/CysteineCrossLinkRestraint.cpp +++ b/modules/isd/src/CysteineCrossLinkRestraint.cpp @@ -295,4 +295,6 @@ ModelObjectsTemp CysteineCrossLinkRestraint::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::CysteineCrossLinkRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/FretRestraint.cpp b/modules/isd/src/FretRestraint.cpp index cb65393f32..71d86f9233 100644 --- a/modules/isd/src/FretRestraint.cpp +++ b/modules/isd/src/FretRestraint.cpp @@ -25,19 +25,19 @@ IMPISD_BEGIN_NAMESPACE // First constructor, with particles for multiple donors and acceptors // Bayesian parameters are: kda, Ida, R0, uncertainty, // and photobleaching survival rate -FretRestraint::FretRestraint(Particles pd, Particles pa, +FretRestraint::FretRestraint(ParticlesTemp pd, ParticlesTemp pa, Particle *kda, Particle *Ida, Particle *R0, Particle *sigma0, Particle *Pbl, double fexp, double m_d, double m_a) : Restraint(kda->get_model(), "FretRestraint%1%"), - pd_(pd), - pa_(pa), - kda_(kda), - Ida_(Ida), - R0_(R0), - sigma0_(sigma0), - Pbl_(Pbl), + pd_(IMP::get_indexes(pd)), + pa_(IMP::get_indexes(pa)), + kda_(kda->get_index()), + Ida_(Ida->get_index()), + R0_(R0->get_index()), + sigma0_(sigma0->get_index()), + Pbl_(Pbl->get_index()), fexp_(fexp), multi_d_(m_d), constr_type_(0) { @@ -61,11 +61,11 @@ FretRestraint::FretRestraint(Particle *kda, Particle *Ida, Particle *sumFi, Particle *sigma0, Particle *Pbl, double fexp) : Restraint(kda->get_model(), "FretRestraint%1%"), - kda_(kda), - Ida_(Ida), - sumFi_(sumFi), - sigma0_(sigma0), - Pbl_(Pbl), + kda_(kda->get_index()), + Ida_(Ida->get_index()), + sumFi_(sumFi->get_index()), + sigma0_(sigma0->get_index()), + Pbl_(Pbl->get_index()), fexp_(fexp), constr_type_(1) {}; @@ -81,16 +81,16 @@ FretRestraint::FretRestraint(Particle *prd, algebra::Vector3D GMMterd, Particle *Ida, Particle *sigma0, Particle *Pbl, FretData *data, double fexp) : Restraint(kda->get_model(), "FretRestraint%1%"), - prd_(prd), + prd_(prd->get_index()), GMMterd_(GMMterd), GMMctrd_(GMMctrd), - pra_(pra), + pra_(pra->get_index()), GMMtera_(GMMtera), GMMctra_(GMMctra), - kda_(kda), - Ida_(Ida), - sigma0_(sigma0), - Pbl_(Pbl), + kda_(kda->get_index()), + Ida_(Ida->get_index()), + sigma0_(sigma0->get_index()), + Pbl_(Pbl->get_index()), data_(data), fexp_(fexp), constr_type_(2) { @@ -110,7 +110,7 @@ void FretRestraint::set_experimental_value(double fexp) { fexp_ = fexp; } // get average sigma double FretRestraint::get_average_sigma(double fmod) const { - double sigma0 = Scale(sigma0_).get_scale(); + double sigma0 = Scale(get_model(), sigma0_).get_scale(); double B = 0.5 * log(fexp_ / fmod) * log(fexp_ / fmod) + sigma0 * sigma0; @@ -195,13 +195,14 @@ double FretRestraint::get_sumFi(double Pbleach) const { // type 0 double FretRestraint::get_model_fretr_type_0() const { + Model *m = get_model(); // thresold for forster factor const double thres = 0.01; // get scales - double Ida = Scale(Ida_).get_scale(); - double kda = Scale(kda_).get_scale(); - double R0 = Scale(R0_).get_scale(); - double Pbl = Scale(Pbl_).get_scale(); + double Ida = Scale(m, Ida_).get_scale(); + double kda = Scale(m, kda_).get_scale(); + double R0 = Scale(m, R0_).get_scale(); + double Pbl = Scale(m, Pbl_).get_scale(); double sumFi = 0.; double sumFi_bl = 0.; @@ -209,9 +210,9 @@ double FretRestraint::get_model_fretr_type_0() const { for (unsigned i = 0; i < pd_.size(); ++i) { power6_.clear(); for (unsigned j = 0; j < pa_.size(); ++j) { - double dist = - std::max(core::get_distance(core::XYZ(pd_[i]), core::XYZ(pa_[j])), - std::numeric_limits::epsilon()); + double dist = std::max( + core::get_distance(core::XYZ(m, pd_[i]), core::XYZ(m, pa_[j])), + std::numeric_limits::epsilon()); double R = R0 / dist; double R6 = R * R * R * R * R * R; if (R6 > thres) { @@ -245,7 +246,7 @@ double FretRestraint::get_model_fretr_type_0() const { } algebra::Vector3Ds FretRestraint::get_current_centers( - Particle *p, const algebra::Vector3Ds &ctrs) const { + ParticleIndex p, const algebra::Vector3Ds &ctrs) const { algebra::Vector3Ds new_ctrs; for (unsigned i = 0; i < ctrs.size(); ++i) { @@ -255,9 +256,10 @@ algebra::Vector3Ds FretRestraint::get_current_centers( } algebra::Vector3D FretRestraint::get_current_center( - Particle *p, const algebra::Vector3D &ctr) const { + ParticleIndex p, const algebra::Vector3D &ctr) const { - algebra::ReferenceFrame3D rf = core::RigidBody(p).get_reference_frame(); + algebra::ReferenceFrame3D + rf = core::RigidBody(get_model(), p).get_reference_frame(); return rf.get_global_coordinates(ctr); } @@ -287,15 +289,16 @@ double FretRestraint::get_sumFi() const { } double FretRestraint::get_model_fretr_type_1() const { + Model *m = get_model(); double sumFi; if (constr_type_ == 1) { - sumFi = Scale(sumFi_).get_scale(); + sumFi = Scale(m, sumFi_).get_scale(); } else { sumFi = get_sumFi(); } - double Ida = Scale(Ida_).get_scale(); - double kda = Scale(kda_).get_scale(); - double Pbl = Scale(Pbl_).get_scale(); + double Ida = Scale(m, Ida_).get_scale(); + double kda = Scale(m, kda_).get_scale(); + double Pbl = Scale(m, Pbl_).get_scale(); double fretr = (Ida * sumFi + 1. + kda * (1. - sumFi)) / (Ida * (Pbl * sumFi + (1. - Pbl)) + 1.); @@ -311,7 +314,7 @@ double FretRestraint::get_probability() const { double log_eps = log(fexp_ / fretr); - double sigma0 = Scale(sigma0_).get_scale(); + double sigma0 = Scale(get_model(), sigma0_).get_scale(); double prob = sqrt(2.) * sigma0 / fexp_ / IMP::PI / (log_eps * log_eps + 2. * sigma0 * sigma0); @@ -341,24 +344,27 @@ double FretRestraint::unprotected_evaluate(DerivativeAccumulator *accum) const { /* Return all particles whose attributes are read by the restraints. To do this, ask the pair score what particles it uses.*/ ModelObjectsTemp FretRestraint::do_get_inputs() const { + Model *m = get_model(); ParticlesTemp ret; - ret.push_back(Ida_); - ret.push_back(kda_); - ret.push_back(sigma0_); - ret.push_back(Pbl_); + ret.push_back(m->get_particle(Ida_)); + ret.push_back(m->get_particle(kda_)); + ret.push_back(m->get_particle(sigma0_)); + ret.push_back(m->get_particle(Pbl_)); if (constr_type_ == 0) { - ret.insert(ret.end(), pd_.begin(), pd_.end()); - ret.insert(ret.end(), pa_.begin(), pa_.end()); - ret.push_back(R0_); + ret += IMP::get_particles(m, pd_); + ret += IMP::get_particles(m, pa_); + ret.push_back(m->get_particle(R0_)); } if (constr_type_ == 1) { - ret.push_back(sumFi_); + ret.push_back(m->get_particle(sumFi_)); } if (constr_type_ == 2) { - ret.push_back(prd_); - ret.push_back(pra_); + ret.push_back(m->get_particle(prd_)); + ret.push_back(m->get_particle(pra_)); } return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::FretRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/GaussianEMRestraint.cpp b/modules/isd/src/GaussianEMRestraint.cpp index 6a09457f60..8833758bce 100644 --- a/modules/isd/src/GaussianEMRestraint.cpp +++ b/modules/isd/src/GaussianEMRestraint.cpp @@ -85,14 +85,7 @@ GaussianEMRestraint::GaussianEMRestraint( "Density particles must have Mass"); } - //Set up md container - md_container_ = new container::CloseBipartitePairContainer( - new container::ListSingletonContainer(mdl,model_ps), - new container::ListSingletonContainer(mdl,density_ps),density_cutoff_dist); - - mm_container_ = new container::ClosePairContainer( - new container::ListSingletonContainer(mdl,model_ps),model_cutoff_dist); - + create_containers(); compute_initial_scores(); if (backbone_slope){ @@ -110,6 +103,19 @@ GaussianEMRestraint::GaussianEMRestraint( else slope_ps_ = model_ps_; } +void GaussianEMRestraint::create_containers() { + Model *mdl = get_model(); + //Set up md container + md_container_ = new container::CloseBipartitePairContainer( + new container::ListSingletonContainer(mdl,model_ps_), + new container::ListSingletonContainer(mdl,density_ps_), + density_cutoff_dist_); + + mm_container_ = new container::ClosePairContainer( + new container::ListSingletonContainer(mdl,model_ps_), + model_cutoff_dist_); +} + void GaussianEMRestraint::compute_initial_scores() { // precalculate DD score @@ -261,4 +267,6 @@ RestraintInfo *GaussianEMRestraint::get_dynamic_info() const { return ri.release(); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::GaussianEMRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/JeffreysRestraint.cpp b/modules/isd/src/JeffreysRestraint.cpp index 5ca633c886..4014b9f267 100644 --- a/modules/isd/src/JeffreysRestraint.cpp +++ b/modules/isd/src/JeffreysRestraint.cpp @@ -2,7 +2,7 @@ * \file isd/JeffreysRestraint.cpp * \brief Restrain a scale particle with log(scale) * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -13,13 +13,13 @@ IMPISD_BEGIN_NAMESPACE JeffreysRestraint::JeffreysRestraint(Model *m, Particle *p) - : Restraint(m, "JeffreysRestraint_" + p->get_name()), p_(p) {} + : Restraint(m, "JeffreysRestraint_" + p->get_name()), pi_(p->get_index()) {} /* Apply the score if it's a scale decorator. */ double JeffreysRestraint::unprotected_evaluate(DerivativeAccumulator *accum) const { - Scale sig(p_); + Scale sig(get_model(), pi_); double score; if (sig.get_scale() <= 0) { // std::cout << sig << std::endl; @@ -38,7 +38,9 @@ double JeffreysRestraint::unprotected_evaluate(DerivativeAccumulator *accum) /* Return all particles whose attributes are read by the restraints. To do this, ask the pair score what particles it uses.*/ ModelObjectsTemp JeffreysRestraint::do_get_inputs() const { - return ParticlesTemp(1, p_); + return ParticlesTemp(1, get_model()->get_particle(pi_)); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::JeffreysRestraint); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/LogWrapper.cpp b/modules/isd/src/LogWrapper.cpp index 73e1465ecb..eefcb5e0bc 100644 --- a/modules/isd/src/LogWrapper.cpp +++ b/modules/isd/src/LogWrapper.cpp @@ -208,4 +208,6 @@ void LogWrapper::show_it(std::ostream &out) const { out << "... end LogWrapper " << get_name() << std::endl; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::LogWrapper); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/Nuisance.cpp b/modules/isd/src/Nuisance.cpp index bc90e737ef..26d59a547f 100644 --- a/modules/isd/src/Nuisance.cpp +++ b/modules/isd/src/Nuisance.cpp @@ -25,7 +25,6 @@ FloatKey Nuisance::get_nuisance_key() { } void Nuisance::set_nuisance(Float d) { Float d_ = d; - Particle *p = get_particle(); if (get_has_lower()) { Float lo = get_lower(); if (d < lo) d_ = lo; @@ -34,7 +33,7 @@ void Nuisance::set_nuisance(Float d) { Float up = get_upper(); if (d > up) d_ = up; } - p->set_value(get_nuisance_key(), d_); + get_model()->set_attribute(get_nuisance_key(), get_particle_index(), d_); } bool Nuisance::get_has_lower() const { @@ -190,21 +189,24 @@ void Nuisance::remove_bounds() { void NuisanceScoreState::do_before_evaluate() { IMP_LOG_TERSE("NSS: do_before_evaluate()" << std::endl); - Nuisance nuis(p_); + Nuisance nuis(get_model(), pi_); nuis.set_nuisance(nuis.get_nuisance()); } void NuisanceScoreState::do_after_evaluate(DerivativeAccumulator *) {} ModelObjectsTemp NuisanceScoreState::do_get_inputs() const { + Particle *p = get_model()->get_particle(pi_); ModelObjectsTemp pt; - pt.push_back(p_); - ParticleIndexKey pu(Nuisance(p_).get_upper_particle_key()); - if (p_->has_attribute(pu)) pt.push_back(p_->get_value(pu)); - ParticleIndexKey pd(Nuisance(p_).get_lower_particle_key()); - if (p_->has_attribute(pd)) pt.push_back(p_->get_value(pd)); + pt.push_back(p); + ParticleIndexKey pu(Nuisance(p).get_upper_particle_key()); + if (p->has_attribute(pu)) pt.push_back(p->get_value(pu)); + ParticleIndexKey pd(Nuisance(p).get_lower_particle_key()); + if (p->has_attribute(pd)) pt.push_back(p->get_value(pd)); return pt; } ModelObjectsTemp NuisanceScoreState::do_get_outputs() const { - return ModelObjectsTemp(1, p_); + return ModelObjectsTemp(1, get_model()->get_particle(pi_)); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::NuisanceScoreState); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/UniformPrior.cpp b/modules/isd/src/UniformPrior.cpp index 517df66790..71160fcaa8 100644 --- a/modules/isd/src/UniformPrior.cpp +++ b/modules/isd/src/UniformPrior.cpp @@ -2,7 +2,7 @@ * \file IMP/isd/UniformPrior.cpp * \brief Restrain a scale particle with log(scale) * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,28 +12,28 @@ IMPISD_BEGIN_NAMESPACE -UniformPrior::UniformPrior(IMP::Model *m, Particle *p, Float k, - Float upperb, Float lowerb, std::string name): - Restraint(m, name), p_(p), upperb_(upperb), lowerb_(lowerb), k_(k) {} - +UniformPrior::UniformPrior(IMP::Model *m, Particle *p, double k, + double upperb, double lowerb, std::string name): + Restraint(m, name), pi_(p->get_index()), upperb_(upperb), + lowerb_(lowerb), k_(k) {} /* Apply the score if it's a scale decorator. */ double UniformPrior::unprotected_evaluate(DerivativeAccumulator *accum) const { - IMP::isd::Scale sig(p_); + IMP::isd::Scale sig(get_model(), pi_); double score=0.0; double s=sig.get_scale(); - + if (s <= lowerb_) { score=0.5*k_*(s-lowerb_)*(s-lowerb_); } else if (s >= upperb_){ - score=0.5*k_*(s-upperb_)*(s-upperb_); + score=0.5*k_*(s-upperb_)*(s-upperb_); } - + if (accum) { } return score; @@ -43,7 +43,7 @@ UniformPrior::unprotected_evaluate(DerivativeAccumulator *accum) const do this, ask the pair score what particles it uses.*/ ModelObjectsTemp UniformPrior::do_get_inputs() const { - return ParticlesTemp(1,p_); + return ModelObjectsTemp(1, get_model()->get_particle(pi_)); } RestraintInfo *UniformPrior::get_static_info() const { @@ -57,8 +57,10 @@ RestraintInfo *UniformPrior::get_static_info() const { RestraintInfo *UniformPrior::get_dynamic_info() const { IMP_NEW(RestraintInfo, ri, ()); - ri->add_particle_indexes("particle", ParticleIndexes(1, p_->get_index())); + ri->add_particle_indexes("particle", ParticleIndexes(1, pi_)); return ri.release(); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::isd::UniformPrior); + IMPISD_END_NAMESPACE diff --git a/modules/isd/src/Weight.cpp b/modules/isd/src/Weight.cpp index f7ddfc8528..bfb411745d 100644 --- a/modules/isd/src/Weight.cpp +++ b/modules/isd/src/Weight.cpp @@ -49,14 +49,6 @@ bool Weight::get_is_setup(Model *m, ParticleIndex pi) { return true; } -IntKey Weight::get_nstates_key() { - IMPISD_DEPRECATED_METHOD_DEF( - 2.12, - "Use get_number_of_weights_key() instead." - ); - return get_number_of_weights_key(); -} - IntKey Weight::get_number_of_weights_key() { static IntKey k("nweights"); return k; diff --git a/modules/isd/test/expensive_test_CysteineCrossLinkRestraint.py b/modules/isd/test/expensive_test_CysteineCrossLinkRestraint.py index 0c968b7ee1..2f2b93abb6 100644 --- a/modules/isd/test/expensive_test_CysteineCrossLinkRestraint.py +++ b/modules/isd/test/expensive_test_CysteineCrossLinkRestraint.py @@ -6,6 +6,7 @@ from math import exp, log from random import sample import ast +import pickle # imp general import IMP @@ -160,6 +161,13 @@ def testSetupAndEvaluate(self): cystrest.add_contribution(ps[0], ps[1]) cystrest.add_contribution(ps[0], ps[2]) restdict[fexp] = cystrest + r1 = restdict[0.0] + # Test pickle + self.assertAlmostEqual(r1.evaluate(False), 2.929, delta=1e-3) + dump = pickle.dumps(r1) + newr1 = pickle.loads(dump) + self.assertAlmostEqual(newr1.evaluate(False), 2.929, delta=1e-3) + del newr1 f = gzip.open( self.get_input_file_name('test_CysteineCrosslink.data.gz'), @@ -188,5 +196,22 @@ def testSetupAndEvaluate(self): self.assertAlmostEqual(restdict[t[0]].get_model_frequency(), t[7], delta=0.000001) + def test_cross_link_data_pickle(self): + """Test pickle of CrossLinkData""" + disttuple = (0.0, 25.0, 1000) + omegatuple = (1.0, 1000.0, 50) + sigmatuple = (1.0, 1.0, 1) + + crossdata = self.get_cross_link_data( + "cysteine", "cysteine_CA_FES.txt.standard", + disttuple, omegatuple, sigmatuple) + self.assertAlmostEqual(crossdata.get_marginal_maximum(), + 0.344, delta=1e-3) + dump = pickle.dumps(crossdata) + newcd = pickle.loads(dump) + self.assertAlmostEqual(newcd.get_marginal_maximum(), + 0.344, delta=1e-3) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/expensive_test_atomic_xl.py b/modules/isd/test/expensive_test_atomic_xl.py index 88c5d9d2a5..15287570cf 100644 --- a/modules/isd/test/expensive_test_atomic_xl.py +++ b/modules/isd/test/expensive_test_atomic_xl.py @@ -3,6 +3,8 @@ import IMP.isd import IMP.algebra import IMP.test +import pickle + def score_1state(p0, p1): pass @@ -69,6 +71,25 @@ def test_atomic_xl_derivatives_with_slope(self): tolerance=1e-2, percentage=3.0) + def test_serialize(self): + """Test (un-)serialize of AtomicCrossLinkMSRestraint""" + self.assertAlmostEqual(self.xl.evaluate(False), 0.22314, delta=1e-4) + self.xl.set_name("foo") + dump = pickle.dumps(self.xl) + newxl = pickle.loads(dump) + self.assertEqual(newxl.get_name(), "foo") + self.assertAlmostEqual(newxl.evaluate(False), 0.22314, delta=1e-4) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of AtomicCrossLinkMSRestraint via polymorphic + pointer""" + self.xl.set_name("foo") + dump = pickle.dumps(self.sf) + newsf = pickle.loads(dump) + newxl, = newsf.restraints + self.assertEqual(newxl.get_name(), "foo") + self.assertAlmostEqual(newxl.evaluate(False), 0.22314, delta=1e-4) + class TestAtomicXL_ManyState(IMP.test.TestCase): def setUp(self): diff --git a/modules/isd/test/medium_test_gaussian_em_restraint.py b/modules/isd/test/medium_test_gaussian_em_restraint.py index 44cffe3652..c82f5f0145 100644 --- a/modules/isd/test/medium_test_gaussian_em_restraint.py +++ b/modules/isd/test/medium_test_gaussian_em_restraint.py @@ -11,6 +11,7 @@ from math import cos, sin, pi, sqrt, exp, log from copy import deepcopy import itertools +import pickle def create_test_points(mu, radii): @@ -169,6 +170,22 @@ def test_info(self): self.gem.get_cross_correlation_coefficient(), delta=1e-4) + def test_serialize(self): + """Test (un-)serialize of GaussianEMRestraint""" + origscore = self.gem.evaluate(False) + dump = pickle.dumps(self.gem) + newgem = pickle.loads(dump) + newscore = newgem.evaluate(False) + self.assertAlmostEqual(newscore, origscore, delta=1e-3) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of GaussianEMRestraint via polymorphic ptr""" + origscore = self.sf.evaluate(False) + dump = pickle.dumps(self.sf) + newsf = pickle.loads(dump) + newscore = newsf.evaluate(False) + self.assertAlmostEqual(newscore, origscore, delta=1e-3) + def test_gem_score(self): """test accuracy of GMM score""" for nt in range(10): diff --git a/modules/isd/test/test_AmbiguousNOERestraint.py b/modules/isd/test/test_AmbiguousNOERestraint.py index 8686e88cfd..2158d529e5 100644 --- a/modules/isd/test/test_AmbiguousNOERestraint.py +++ b/modules/isd/test/test_AmbiguousNOERestraint.py @@ -3,7 +3,7 @@ # general imports from numpy import * from random import uniform - +import pickle # imp general import IMP @@ -300,5 +300,30 @@ def testSanityPE(self): self.assertAlmostEqual(self.noe.get_probability(), exp(-self.noe.unprotected_evaluate(self.DA)), delta=0.001) + def test_serialize(self): + """Test (un-)serialize of AmbiguousNOERestraint""" + self.assertAlmostEqual(self.noe.unprotected_evaluate(None), + 2.8517, delta=1e-4) + self.noe.set_name("foo") + dump = pickle.dumps(self.noe) + newnoe = pickle.loads(dump) + self.assertAlmostEqual(newnoe.unprotected_evaluate(None), + 2.8517, delta=1e-4) + self.assertEqual(newnoe.get_name(), "foo") + + def test_serialize_polymorphic(self): + """Test (un-)serialize of AmbiguousNOERestraint via polymorphic ptr""" + self.assertAlmostEqual(self.noe.unprotected_evaluate(None), + 2.8517, delta=1e-4) + self.noe.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([self.noe]) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newnoe, = newsf.restraints + self.assertAlmostEqual(newnoe.unprotected_evaluate(None), + 2.8517, delta=1e-4) + self.assertEqual(newnoe.get_name(), "foo") + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/test_FretRestraint.py b/modules/isd/test/test_FretRestraint.py index 4c9a2b583a..5010d70a27 100644 --- a/modules/isd/test/test_FretRestraint.py +++ b/modules/isd/test/test_FretRestraint.py @@ -3,6 +3,7 @@ # general imports from numpy import * from random import uniform +import pickle # imp general import IMP @@ -210,5 +211,23 @@ def testValuePSigma(self): self.assertAlmostEqual(self.fret1.get_probability(), expected1, delta=0.001) + def test_serialize(self): + """Test (un-)serialize of FretRestraint""" + self.assertAlmostEqual(self.fret0.evaluate(False), 0.0956, delta=1e-3) + self.assertAlmostEqual(self.fret1.evaluate(False), 1.5726, delta=1e-3) + dump = pickle.dumps((self.fret0, self.fret1)) + newf0, newf1 = pickle.loads(dump) + self.assertAlmostEqual(newf0.evaluate(False), 0.0956, delta=1e-3) + self.assertAlmostEqual(newf1.evaluate(False), 1.5726, delta=1e-3) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of FretRestraint via polymorphic pointer""" + sf = IMP.core.RestraintsScoringFunction([self.fret0, self.fret1]) + self.assertAlmostEqual(sf.evaluate(False), 1.6682, delta=1e-3) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + self.assertAlmostEqual(newsf.evaluate(False), 1.6682, delta=1e-3) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/test_JeffreysRestraint.py b/modules/isd/test/test_JeffreysRestraint.py index 9e4a6fd2a5..a38cbf702f 100644 --- a/modules/isd/test/test_JeffreysRestraint.py +++ b/modules/isd/test/test_JeffreysRestraint.py @@ -3,7 +3,7 @@ # general imports from numpy import * from random import uniform - +import pickle # imp general import IMP @@ -99,6 +99,28 @@ def testSanityPE(self): self.assertAlmostEqual(self.J.get_probability(), exp(-self.J.unprotected_evaluate(self.DA))) + def test_serialize(self): + """Test (un-)serialize of JeffreysRestraint""" + self.sigma.set_scale(50.) + self.J.set_name("foo") + self.assertAlmostEqual(self.J.evaluate(True), 3.912, delta=0.001) + dump = pickle.dumps(self.J) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(True), 3.912, delta=0.001) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of JeffreysRestraint via polymorphic pointer""" + self.sigma.set_scale(50.) + self.J.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([self.J]) + self.assertAlmostEqual(sf.evaluate(True), 3.912, delta=0.001) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(True), 3.912, delta=0.001) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/test_NuisanceScoreState.py b/modules/isd/test/test_NuisanceScoreState.py index f418f97663..261138853b 100644 --- a/modules/isd/test/test_NuisanceScoreState.py +++ b/modules/isd/test/test_NuisanceScoreState.py @@ -3,7 +3,7 @@ # general imports from numpy import * from random import uniform - +import pickle # imp general import IMP @@ -168,5 +168,30 @@ def test_NormalMover_MC_fails(self): self.assertTrue(nuis.get_nuisance() >= nuis.get_lower() and nuis.get_nuisance() <= nuis.get_upper()) + def test_pickle_polymorphic(self): + """Test (un-)pickle of NuisanceScoreState via polymorphic pointer""" + nuis = Nuisance.setup_particle(IMP.Particle(self.m), 50.0) + nuis.set_nuisance(2.) + nuis.set_upper(1.) + # NuisanceScoreState is not exposed to Python, but it should be in + # the model + dump = pickle.dumps(self.m) + newm = pickle.loads(dump) + # New model should contain an identical Nuisance particle + newnuisp, = newm.get_particle_indexes() + self.assertTrue(Nuisance.get_is_setup(newm, newnuisp)) + newnuis = Nuisance(newm, newnuisp) + self.assertAlmostEqual(newnuis.get_nuisance(), 2., delta=1e-5) + # Updating the original model should call NuisanceScoreState on it, + # which should enforce the upper bound - but the new model should + # not be affected: + self.m.update() + self.assertAlmostEqual(nuis.get_nuisance(), 1., delta=1e-5) + self.assertAlmostEqual(newnuis.get_nuisance(), 2., delta=1e-5) + # Updating the new model should enforce the upper bound there: + newm.update() + self.assertAlmostEqual(newnuis.get_nuisance(), 1., delta=1e-5) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/test_ambiguous_restraint.py b/modules/isd/test/test_ambiguous_restraint.py new file mode 100644 index 0000000000..52f21c0706 --- /dev/null +++ b/modules/isd/test/test_ambiguous_restraint.py @@ -0,0 +1,54 @@ +import IMP +import IMP.algebra +import IMP.core +import IMP.isd +import IMP.test +import pickle + + +def _make_test_restraint(): + m = IMP.Model() + p1 = IMP.core.XYZ.setup_particle(IMP.Particle(m), + IMP.algebra.Vector3D(0,0,0)) + p2 = IMP.core.XYZ.setup_particle(IMP.Particle(m), + IMP.algebra.Vector3D(3,3,3)) + p3 = IMP.core.XYZ.setup_particle(IMP.Particle(m), + IMP.algebra.Vector3D(9,9,9)) + d1 = IMP.core.DistanceRestraint(m, IMP.core.Harmonic(1, 1), p1, p2) + d2 = IMP.core.DistanceRestraint(m, IMP.core.Harmonic(1, 1), p2, p3) + r = IMP.isd.AmbiguousRestraint(m, -10, d1, d2) + return m, r + + +class Tests(IMP.test.TestCase): + + def test_simple(self): + """Simple test of AmbiguousRestraint""" + m, r = _make_test_restraint() + self.assertAlmostEqual(r.evaluate(True), 8.8038, delta=0.001) + + def test_serialize(self): + """Test (un-)serialize of AmbiguousRestraint""" + m, r = _make_test_restraint() + r.set_name("foo") + self.assertAlmostEqual(r.evaluate(True), 8.8038, delta=0.001) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(True), 8.8038, delta=0.001) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of AmbiguousRestraint via polymorphic pointer""" + m, r = _make_test_restraint() + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + self.assertAlmostEqual(sf.evaluate(True), 8.8038, delta=0.001) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(True), 8.8038, delta=0.001) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/isd/test/test_crosslinkms.py b/modules/isd/test/test_crosslinkms.py index 6500266da3..2e45c69c7d 100644 --- a/modules/isd/test/test_crosslinkms.py +++ b/modules/isd/test/test_crosslinkms.py @@ -3,6 +3,7 @@ import IMP.core import IMP.isd import IMP.test +import pickle from random import sample from math import pi, log, exp @@ -20,6 +21,31 @@ def setupnuisance(m, initialvalue, minvalue, maxvalue, isoptimized=True): return nuisance +def make_test_restraint(): + m = IMP.Model() + p1 = IMP.Particle(m) + p2 = IMP.Particle(m) + + slope = 0.01 + length = 10 + + xyz1 = IMP.core.XYZ.setup_particle(p1) + xyz2 = IMP.core.XYZ.setup_particle(p2) + + xyz1.set_coordinates((0, 0, 0)) + xyz2.set_coordinates((0, 0, 0)) + + sigma1 = setupnuisance(m, 5, 0, 100, False) + sigma2 = setupnuisance(m, 5, 0, 100, False) + psi = setupnuisance(m, 0.1, 0.0, 0.5, False) + + dr = IMP.isd.CrossLinkMSRestraint(m, length, slope) + dr.set_weight(0.10) + dr.set_name("test restraint") + dr.add_contribution((p1, p2), (sigma1, sigma2), psi) + return m, p1, p2, sigma1, sigma2, psi, dr + + class CrossLinkMS(object): """Defining a dummy python restraint with the same interface as the one that has to be tested @@ -90,6 +116,11 @@ def sphere_cap(self,r1, r2, d): class TestXLRestraintSimple(IMP.test.TestCase): + def test_default(self): + """Test default-constructed restraint""" + dr = IMP.isd.CrossLinkMSRestraint() + self.assertRaisesUsageException(dr.evaluate, False) + def test_score_simple(self): """ Test the straight pairwise restraint @@ -160,6 +191,52 @@ def test_score_simple(self): self.assertAlmostEqual(score,scoretest,places=4) self.assertAlmostEqual(score_lp,scoretest,places=4) + def test_serialize(self): + """Test (un-)serialize of CrossLinkMSRestraint""" + m, p1, p2, sigma1, sigma2, psi, dr = make_test_restraint() + dr.set_source_residue1(1) + dr.set_source_residue2(4) + dr.set_source_protein1("r1") + dr.set_source_protein2("r2") + dump = pickle.dumps(dr) + del dr + + # Should be able to restore restraint parameters + newdr = pickle.loads(dump) + self.assertAlmostEqual(newdr.get_weight(), 0.10, 0.01) + self.assertEqual(newdr.get_name(), "test restraint") + self.assertEqual(newdr.get_number_of_contributions(), 1) + self.assertEqual(newdr.get_contribution_particle_indexes(0), + (p1.get_index(), p2.get_index())) + self.assertEqual(newdr.get_contribution_psi_index(0), + psi.get_particle_index()) + self.assertEqual(newdr.get_contribution_sigma_indexes(0), + (sigma1.get_particle_index(), + sigma2.get_particle_index())) + self.assertAlmostEqual(newdr.get_slope(), 0.01, delta=1e-4) + self.assertAlmostEqual(newdr.get_length(), 10.0, delta=1e-4) + + self.assertEqual(newdr.get_source_residue1(), 1) + self.assertEqual(newdr.get_source_residue2(), 4) + self.assertEqual(newdr.get_source_protein1(), "r1") + self.assertEqual(newdr.get_source_protein2(), "r2") + + del newdr + m2 = IMP.Model() + del m + # Cannot restore a Restraint if the Model it acts on is gone + self.assertRaises(ValueError, pickle.loads, dump) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of CrossLinkMSRestraint via polymorphic + pointer""" + m, p1, p2, sigma1, sigma2, psi, dr = make_test_restraint() + sf = IMP.core.RestraintsScoringFunction([dr]) + dump = pickle.dumps(sf) + + newsf = pickle.loads(dump) + newdr, = newsf.restraints + self.assertEqual(newdr.get_name(), "test restraint") def test_score_multiple_restraints(self): """Intensive random test, it tests manifold ambiguity, sameparticle, particle positions @@ -358,5 +435,26 @@ def test_score_two_fold_ambiguity(self): self.assertAlmostEqual(score,scoretest,places=4) self.assertAlmostEqual(score_lp,scoretest,places=4) + def test_static_info(self): + """Test restraint static info""" + m, p1, p2, sigma1, sigma2, psi, dr = make_test_restraint() + self.assertIsNone(dr.get_static_info()) + dr.set_source_residue1(1) + dr.set_source_residue2(4) + dr.set_source_protein1("foo") + dr.set_source_protein2("bar") + s = dr.get_static_info() + self.assertEqual(s.get_number_of_string(), 2) + self.assertEqual(s.get_string_key(0), "protein1") + self.assertEqual(s.get_string_value(0), "foo") + self.assertEqual(s.get_string_key(1), "protein2") + self.assertEqual(s.get_string_value(1), "bar") + self.assertEqual(s.get_number_of_int(), 2) + self.assertEqual(s.get_int_key(0), "residue1") + self.assertEqual(s.get_int_value(0), 1) + self.assertEqual(s.get_int_key(1), "residue2") + self.assertEqual(s.get_int_value(1), 4) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/test_log_wrapper.py b/modules/isd/test/test_log_wrapper.py index 1daaf298c3..0eebf125ec 100644 --- a/modules/isd/test/test_log_wrapper.py +++ b/modules/isd/test/test_log_wrapper.py @@ -2,6 +2,7 @@ import IMP import IMP.isd import IMP.test +import pickle class LogRestraint(IMP.Restraint): @@ -116,6 +117,31 @@ def test_aggregate(self): self.assertFalse(r1.get_is_aggregate()) self.assertTrue(lw.get_is_aggregate()) + def test_pickle(self): + """Test that LogWrapper can be (un-)pickled""" + m = IMP.Model() + r0 = IMP._ConstRestraint(m, [], 100) + lw = IMP.isd.LogWrapper([r0], 1.0) + lw.set_name("foo") + self.assertAlmostEqual(lw.evaluate(False), -4.605, delta=1e-3) + dump = pickle.dumps(lw) + newlw = pickle.loads(dump) + self.assertEqual(newlw.get_name(), "foo") + self.assertEqual([lw.get_name() for r in newlw.restraints], ["foo"]) + self.assertAlmostEqual(newlw.evaluate(False), -4.605, delta=1e-3) + + def test_pickle_polymorphic(self): + """Test that LogWrapper can be (un-)pickled via polymorphic pointer""" + m = IMP.Model() + r0 = IMP._ConstRestraint(m, [], 100) + lw = IMP.isd.LogWrapper([r0], 1.0) + rs = IMP.RestraintSet(m, 12.0) + rs.restraints.append(lw) + self.assertAlmostEqual(rs.evaluate(False), -55.262, delta=1e-3) + dump = pickle.dumps(rs) + newrs = pickle.loads(dump) + self.assertAlmostEqual(newrs.evaluate(False), -55.262, delta=1e-3) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/isd/test/test_uniform_prior.py b/modules/isd/test/test_uniform_prior.py index 09249d3f1a..8991782230 100644 --- a/modules/isd/test/test_uniform_prior.py +++ b/modules/isd/test/test_uniform_prior.py @@ -1,15 +1,20 @@ import IMP import IMP.isd import IMP.test +import pickle +def _make_test_restraint(): + m = IMP.Model() + sigmap = IMP.Particle(m) + sigma = IMP.isd.Scale.setup_particle(sigmap, 1.0) + p = IMP.isd.UniformPrior(m, sigma, 1000, 100, 0.01) + return m, sigma, p + class Tests(IMP.test.TestCase): def test_uniform_prior(self): """Test UniformPrior""" - m = IMP.Model() - sigmap = IMP.Particle(m) - sigma = IMP.isd.Scale.setup_particle(sigmap, 1.0) - p = IMP.isd.UniformPrior(m, sigma, 1000, 100, 0.01) + m, sigma, p = _make_test_restraint() self.assertAlmostEqual(p.get_probability(), 1.0, delta=1e-6) self.assertAlmostEqual(p.evaluate(False), 0.0, delta=1e-6) s = p.get_static_info() @@ -32,7 +37,32 @@ def test_uniform_prior(self): s.set_was_used(True) self.assertEqual(s.get_number_of_particle_indexes(), 1) self.assertEqual(s.get_particle_indexes_key(0), "particle") - self.assertEqual(s.get_particle_indexes_value(0), [sigmap.get_index()]) + self.assertEqual(s.get_particle_indexes_value(0), + [sigma.get_particle_index()]) + + def test_serialize(self): + """Test (un-)serialize of UniformPrior""" + m, sigma, r = _make_test_restraint() + sigma.set_scale(105.) + r.set_name("foo") + self.assertAlmostEqual(r.evaluate(True), 12500.0, delta=0.001) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(True), 12500.0, delta=0.001) + + def test_serialize_polymorphic(self): + """Test (un-)serialize of UniformPrior via polymorphic pointer""" + m, sigma, r = _make_test_restraint() + sigma.set_scale(105.) + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + self.assertAlmostEqual(sf.evaluate(True), 12500.0, delta=0.001) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(True), 12500.0, delta=0.001) if __name__ == '__main__': diff --git a/modules/kernel/compiler/has_cereal_raw_pointer.cpp b/modules/kernel/compiler/has_cereal_raw_pointer.cpp new file mode 100644 index 0000000000..9d635989ff --- /dev/null +++ b/modules/kernel/compiler/has_cereal_raw_pointer.cpp @@ -0,0 +1,21 @@ +/** + * \file has_cereal_raw_pointer.cpp + * \brief Check if cereal uses raw pointers for registerSharedPointer() + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#include +#include + +int main() +{ + void *void_ptr = nullptr; + std::stringstream ss; + cereal::BinaryOutputArchive oarchive(ss); + // Old versions of cereal use a raw pointer here; newer versions want + // a shared_ptr instead + oarchive.registerSharedPointer(void_ptr); + return 0; +} diff --git a/modules/kernel/dependencies.py b/modules/kernel/dependencies.py index 4adc52ea62..f4029fb756 100644 --- a/modules/kernel/dependencies.py +++ b/modules/kernel/dependencies.py @@ -1,4 +1,4 @@ required_modules = '' lib_only_required_modules = '' -required_dependencies = 'Boost.FileSystem:Boost.ProgramOptions:Boost.System:Boost.Serialization' +required_dependencies = 'Boost.FileSystem:Boost.ProgramOptions:Boost.System' optional_dependencies = 'GPerfTools:TCMalloc_HeapProfiler:TCMalloc_HeapChecker:Boost.Random:NumPy' diff --git a/modules/kernel/examples/basic_optimization.py b/modules/kernel/examples/basic_optimization.py index 5fac616be3..9d53cc46fe 100644 --- a/modules/kernel/examples/basic_optimization.py +++ b/modules/kernel/examples/basic_optimization.py @@ -4,21 +4,32 @@ # from __future__ import print_function -import IMP.example +import IMP.container import IMP.statistics import sys IMP.setup_from_argv(sys.argv, "Basic optimization") -(m, c) = IMP.example.create_model_and_particles() +# Make 100 particles randomly distributed in a cubic box +m = IMP.Model() +lsc = IMP.container.ListSingletonContainer(m) +b = IMP.algebra.BoundingBox3D(IMP.algebra.Vector3D(0,0,0), + IMP.algebra.Vector3D(10,10,10)) +for i in range(100): + p = m.add_particle("p") + lsc.add(p) + d = IMP.core.XYZR.setup_particle(m, p, + IMP.algebra.Sphere3D(IMP.algebra.get_random_vector_in(b), 1)) + d.set_coordinates_are_optimized(True) + ps = IMP.core.DistancePairScore(IMP.core.HarmonicLowerBound(1, 1)) -r = IMP.container.PairsRestraint(ps, IMP.container.ClosePairContainer(c, 2.0)) +r = IMP.container.PairsRestraint(ps, IMP.container.ClosePairContainer(lsc, 2.0)) sf = IMP.core.RestraintsScoringFunction([r]) # we don't want to see lots of log messages about restraint evaluation m.set_log_level(IMP.WARNING) -# the container (c) stores a list of particle indices -pis = c.get_contents() +# the container (lsc) stores a list of particle indices +pis = lsc.get_contents() s = IMP.core.MCCGSampler(m) s.set_scoring_function(sf) @@ -36,7 +47,7 @@ print(sphere) # cluster the solutions based on their coordinates -e = IMP.statistics.ConfigurationSetXYZEmbedding(configs, c) +e = IMP.statistics.ConfigurationSetXYZEmbedding(configs, lsc) # of course, this doesn't return anything of interest since the points are # randomly distributed, but, again, why not? diff --git a/modules/kernel/examples/graph.py b/modules/kernel/examples/graph.py index 27092d8a85..6fd71b9724 100644 --- a/modules/kernel/examples/graph.py +++ b/modules/kernel/examples/graph.py @@ -1,5 +1,5 @@ ## \example kernel/graph.py -# A simple example showing how to use the graph interface for in Python. +# A simple example showing how to use the graph interface in Python. from __future__ import print_function import IMP diff --git a/modules/kernel/include/Array.h b/modules/kernel/include/Array.h index 8c364216ca..67901bdbe0 100644 --- a/modules/kernel/include/Array.h +++ b/modules/kernel/include/Array.h @@ -15,29 +15,37 @@ #include "hash_macros.h" #include "check_macros.h" #include "showable_macros.h" -#include +#include +#include +#include +#include IMPKERNEL_BEGIN_NAMESPACE -//! A class to store an fixed array of same-typed values. +//! A class to store a fixed array of same-typed values. /** Only the constructor with the correct number of arguments for the - dimensionality can be used. + dimensionality can be used. - \note These are mapped to/from Python tuples, so there is - no need to use types that are typedefs of this on the Python - side. + \note These are mapped to/from Python tuples, so there is + no need to use types that are typedefs of this on the Python side. - \see ConstVector - */ + \see ConstVector + */ template class Array : public Value { - typedef boost::array Storage; + typedef std::array Storage; Storage d_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(d_); + } + int compare(const Array& o) const { for (unsigned int i = 0; i < D; ++i) { - if (d_[i] < o[i]) + if (d_[i] < o.get(i)) return -1; - else if (d_[i] > o[i]) + else if (d_[i] > o.get(i)) return 1; } return 0; @@ -51,28 +59,30 @@ class Array : public Value { return D; }; Array() {} + + template::type* = nullptr> Array(SwigData x, SwigData y) { - IMP_USAGE_CHECK(D == 2, "Need " << D << " to construct a " << D - << "-tuple."); d_[0] = x; d_[1] = y; } + + template::type* = nullptr> Array(SwigData x, SwigData y, SwigData z) { - IMP_USAGE_CHECK(D == 3, "Need " << D << " to construct a " << D - << "-tuple."); d_[0] = x; d_[1] = y; d_[2] = z; } + + template::type* = nullptr> Array(SwigData x0, SwigData x1, SwigData x2, SwigData x3) { - IMP_USAGE_CHECK(D == 4, "Need " << D << " to construct a " << D - << "-tuple."); d_[0] = x0; d_[1] = x1; d_[2] = x2; d_[3] = x3; } + SwigData get(unsigned int i) const { return d_[i]; } + IMP_HASHABLE_INLINE(Array, std::size_t seed = 0; for (unsigned int i = 0; i < D; ++i) { boost::hash_combine(seed, d_[i]); @@ -141,6 +151,13 @@ class Array : public Value { } }; +#if !defined(IMP_DOXYGEN) && !defined(SWIG) +template +inline std::size_t hash_value(const Array &t) { + return t.__hash__(); +} +#endif + IMPKERNEL_END_NAMESPACE #endif /* IMPKERNEL_ARRAY_H */ diff --git a/modules/kernel/include/AttributeOptimizer.h b/modules/kernel/include/AttributeOptimizer.h index d717d61dd5..ecc31d9504 100644 --- a/modules/kernel/include/AttributeOptimizer.h +++ b/modules/kernel/include/AttributeOptimizer.h @@ -11,6 +11,8 @@ #include #include "Optimizer.h" +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -22,6 +24,7 @@ IMPKERNEL_BEGIN_NAMESPACE class IMPKERNELEXPORT AttributeOptimizer : public Optimizer { public: AttributeOptimizer(Model *m, std::string name = "Optimizer %1%"); + AttributeOptimizer() {} protected: /** @name Methods for getting and setting optimized attributes @@ -95,6 +98,15 @@ class IMPKERNELEXPORT AttributeOptimizer : public Optimizer { //!@} private: mutable Floats widths_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + if (std::is_base_of::value) { + clear_range_cache(); + } + } }; IMP_OBJECTS(AttributeOptimizer, AttributeOptimizers); diff --git a/modules/kernel/include/ConstVector.h b/modules/kernel/include/ConstVector.h index 2083daa6b6..a975568c28 100644 --- a/modules/kernel/include/ConstVector.h +++ b/modules/kernel/include/ConstVector.h @@ -14,8 +14,7 @@ #include "exception.h" #include "Value.h" #include -#include -#include +#include #include #include @@ -55,27 +54,18 @@ class ConstVector : public Value { std::copy(b, e, v_.get()); } -#ifndef SWIG - friend class boost::serialization::access; + friend class cereal::access; - template void save(Archive &ar, const unsigned int) const { - ar << sz_; - for (unsigned int i = 0; i < sz_; ++i) { - ar << v_[i]; + template void serialize(Archive &ar) { + ar(sz_); + if (std::is_base_of::value) { + create(sz_); } - } - - template void load(Archive &ar, const unsigned int) { - ar >> sz_; - create(sz_); for (unsigned int i = 0; i < sz_; ++i) { - ar >> v_[i]; + ar(v_[i]); } } - BOOST_SERIALIZATION_SPLIT_MEMBER() -#endif - public: ~ConstVector() {} ConstVector(unsigned int sz, Data fill) { diff --git a/modules/kernel/include/Constraint.h b/modules/kernel/include/Constraint.h index 61c5e12ad0..98393e6ce9 100644 --- a/modules/kernel/include/Constraint.h +++ b/modules/kernel/include/Constraint.h @@ -49,6 +49,7 @@ IMPKERNEL_BEGIN_NAMESPACE class IMPKERNELEXPORT Constraint : public ScoreState { public: Constraint(Model *m, std::string name = "Constraint %1%"); + Constraint() {} virtual void do_update_attributes() = 0; virtual void do_update_derivatives(DerivativeAccumulator *da) = 0; diff --git a/modules/kernel/include/Decorator.h b/modules/kernel/include/Decorator.h index ea23cb58ca..f6e688c295 100644 --- a/modules/kernel/include/Decorator.h +++ b/modules/kernel/include/Decorator.h @@ -1,7 +1,7 @@ /** * \file IMP/Decorator.h \brief The base class for decorators. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -20,6 +20,7 @@ #include #include #include +#include IMPKERNEL_BEGIN_NAMESPACE class ParticleAdaptor; @@ -120,6 +121,26 @@ class IMPKERNELEXPORT Decorator : public Value { WeakPointer model_; ParticleIndex pi_; bool is_valid_; // false if constructed with default constructor + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(is_valid_); + if (is_valid_) { + if (std::is_base_of::value) { + uint32_t model_id = get_model_id(); + ar(model_id); + } else { + uint32_t model_id; + ar(model_id); + set_model_from_id(model_id); + } + ar(pi_); + } + } + + void set_model_from_id(uint32_t model_id); + uint32_t get_model_id() const; + int compare(Object* o) const { if (o < get_particle()) return -1; diff --git a/modules/kernel/include/Index.h b/modules/kernel/include/Index.h index a2671df008..5bde6a33bc 100644 --- a/modules/kernel/include/Index.h +++ b/modules/kernel/include/Index.h @@ -2,7 +2,7 @@ * \file IMP/Index.h * \brief Utility types to refer to various types of indices * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -13,6 +13,7 @@ #include "bracket_macros.h" #include "showable_macros.h" #include "Value.h" +#include #include IMPKERNEL_BEGIN_NAMESPACE @@ -25,6 +26,12 @@ template class Index : public Value { int i_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(i_); + } + public: explicit Index(int i) : i_(i) {} Index() : i_(-2) {} @@ -52,11 +59,74 @@ inline Index get_invalid_index() { return Index(-1); } +// Compression types for serialization of IndexVector. +// Since these vectors are often sparse, we do basic compression on +// the serialized data. The data is written out in a number of blocks, +// each starting with one of these compression types, until we hit COMP_END. +namespace { + // No compression: this is followed by a size N and then N values + static const unsigned char COMP_NONE = 0; + + // Simple run-length encoding: followed by a size N and a single value + static const unsigned char COMP_RLE = 1; + + // More compression types can be added here... + + // End of serialization: we are done serializing this vector + static const unsigned char COMP_END = 100; +} + //! Implements a vector tied to a particular index of type Index. template class IndexVector : public Vector { typedef Vector P; + friend class cereal::access; + + // No compression on output (use CompressedIndexVector for that) + template void save(Archive &ar) const { + size_t sz = P::size(); + ar(sz); + // Write a single no-compression block. This allows us to add compression + // for this class in future without breaking the format. + ar(COMP_NONE); ar(sz); + auto it = P::begin(); + while(sz-- > 0) { + ar(*it++); + } + ar(COMP_END); + } + + // Read both non-compressed and compressed serialized streams + template void load(Archive &ar) { + P::resize(0); + size_t sz; + ar(sz); + P::reserve(sz); + unsigned char comp_type; + ar(comp_type); + while(comp_type != COMP_END) { + if (comp_type == COMP_NONE) { + ar(sz); + while(sz-- > 0) { + T val; + ar(val); + P::push_back(val); + } + } else if (comp_type == COMP_RLE) { + ar(sz); + T val; + ar(val); + while(sz-- > 0) { + P::push_back(val); + } + } else { + IMP_THROW("Unsupported IndexVector compression type", ValueException); + } + ar(comp_type); + } + } + public: IndexVector(unsigned int sz, const T &t = T()) : P(sz, t) {} IndexVector() {} @@ -64,6 +134,58 @@ class IndexVector : public Vector { return P::operator[](get_as_unsigned_int(i))); }; +// This class functions identically to IndexVector but compresses +// the data during serialization +template +class CompressedIndexVector : public IndexVector { + typedef Vector P; + + template void write_no_compression( + Archive &ar, typename P::const_iterator start, + typename P::const_iterator end) const { + size_t sz = end - start; + ar(COMP_NONE); ar(sz); + while(start != end) { + ar(*start++); + } + } + + template void write_rle( + Archive &ar, typename P::const_iterator start, + typename P::const_iterator end) const { + size_t sz = end - start; + ar(COMP_RLE); ar(sz); + ar(*start); + } + + friend class cereal::access; + template void save(Archive &ar) const { + size_t sz = P::size(); + ar(sz); + typename P::const_iterator pos = P::begin(), start = P::begin(), runend; + while (pos != P::end()) { + const T& val = *pos; + // update runend to point past the end of a run of same values, + // starting at pos + for (runend = pos + 1; runend != P::end() && *runend == val; ++runend) {} + // exclude very short runs + if (runend - pos > 10) { + if (pos > P::begin() && pos > start) { + // Write previous set of non-RLE values + write_no_compression(ar, start, pos); + } + write_rle(ar, pos, runend); + start = runend; + } + pos = runend; + } + if (start != P::end()) { + write_no_compression(ar, start, P::end()); + } + ar(COMP_END); + } +}; + template void resize_to_fit(Container &v, Index i, const T &default_value = T()) { if (v.size() <= get_as_unsigned_int(i)) { @@ -73,4 +195,16 @@ void resize_to_fit(Container &v, Index i, const T &default_value = T()) { IMPKERNEL_END_NAMESPACE +namespace cereal { + template + struct specialize, + cereal::specialization::member_load_save> {}; +} + +namespace cereal { + template + struct specialize, + cereal::specialization::member_load_save> {}; +} + #endif /* IMPKERNEL_INDEX_H */ diff --git a/modules/kernel/include/Key.h b/modules/kernel/include/Key.h index bca90ae7ae..84ae6241aa 100644 --- a/modules/kernel/include/Key.h +++ b/modules/kernel/include/Key.h @@ -16,6 +16,7 @@ #include #include #include +#include #include IMPKERNEL_BEGIN_NAMESPACE @@ -57,6 +58,21 @@ class Key : public Value { private: int str_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + // Serialize Keys by string, not the internal index, which could change + if (std::is_base_of::value) { + std::string name = get_string(); + ar(name); + } else { + std::string name; + ar(name); + str_ = find_or_add_index(name); + } + } + static const internal::KeyData::Map& get_map() { return get_key_data().get_map(); } diff --git a/modules/kernel/include/Model.h b/modules/kernel/include/Model.h index 4de56fa650..beedd360b8 100644 --- a/modules/kernel/include/Model.h +++ b/modules/kernel/include/Model.h @@ -22,13 +22,17 @@ #include "internal/AttributeTable.h" #include "internal/attribute_tables.h" #include "internal/moved_particles_cache.h" +#include "internal/KeyVector.h" #include #include +#include #include #include #include #include #include +#include +#include #include @@ -52,6 +56,15 @@ enum Stage { class Model; +#if !defined(SWIG) && !defined(IMP_DOXYGEN) +// This is needed as NodeInfo (below) needs to be showable, and Edges are not +inline std::ostream &operator<<( + std::ostream &out, const std::set &) { + out << "(set of ModelObject)"; + return out; +} +#endif + //! Class for storing model, its restraints, constraints, and particles. /** The Model maintains a standard \imp container for each of Particle, ScoreState and Restraint object types. @@ -88,7 +101,7 @@ class IMPKERNELEXPORT Model : public Object public internal::ParticlesAttributeTable #endif { - typedef Vector Edges; + typedef std::set Edges; // must be up top // we don't want any liveness checks IMP_NAMED_TUPLE_5(NodeInfo, NodeInfos, Edges, inputs, Edges, input_outputs, @@ -106,7 +119,24 @@ class IMPKERNELEXPORT Model : public Object IndexVector > particle_index_; IndexVector undecorators_index_; - Vector > model_data_; + internal::KeyVector > model_data_; + +#if !defined(IMP_DOXYGEN) + // Map unique ID to Model* + class ModelMap { + std::map map_; + internal::IDGenerator id_gen_; + public: + ModelMap() {} + uint32_t add_new_model(Model *m); + void add_model_with_id(Model *m, uint32_t id); + void remove_model(Model *m); + Model *get(uint32_t id) const; + }; + + static ModelMap model_map_; + uint32_t unique_id_; +#endif void do_add_dependencies(const ModelObject *mo); void do_clear_required_score_states(ModelObject *mo); @@ -139,6 +169,73 @@ class IMPKERNELEXPORT Model : public Object // time when moved_particles_*_cache_ were last updated, or 0 unsigned moved_particles_cache_age_; + void register_unique_id(); + + friend class cereal::access; + + template void serialize(Archive &ar, + std::uint32_t const version) { + ar(cereal::base_class(this)); + // We need to get unique_id_ early on read, so that any ModelObjects + // that reference it get correctly associated with this model + ar(unique_id_); + if (std::is_base_of::value) { + register_unique_id(); + } + ar(cereal::base_class(this), + cereal::base_class(this), + cereal::base_class(this), + cereal::base_class(this), + cereal::base_class(this), + cereal::base_class(this), + cereal::base_class(this)); + + if (std::is_base_of::value) { + size_t count; + free_particles_.clear(); + ar(count); + particle_index_.clear(); + while(count-- > 0) { + std::string name; + ar(name); + add_particle(name); + } + ParticleIndexes to_free; + ar(to_free); + for (auto pi : to_free) { + remove_particle(pi); + } + } else { + size_t count = particle_index_.size(); + ar(count); + for (size_t i = 0; i < count; ++i) { + std::string name; + if (get_has_particle(ParticleIndex(i))) { + name = get_particle_name(ParticleIndex(i)); + } + ar(name); + } + ar(free_particles_); + } + + // Need particle info before anything that might refer to a particle + // (ScoreState, or arbitrary Object) + ar(cereal::base_class(this), + cereal::base_class(this), + cereal::base_class(this), + model_data_, mutable_access_score_states()); + + if (std::is_base_of::value) { + // clear caches + age_counter_ = 1; + trigger_age_.clear(); + dependencies_age_ = 0; + saved_dependencies_age_ = 0; + dependencies_saved_ = false; + moved_particles_cache_age_ = 0; + } + } + // update model age (can never be zero, even if it wraps) void increase_age() { age_counter_++; @@ -263,7 +360,7 @@ class IMPKERNELEXPORT Model : public Object ScoreStates maintain invariants in the Model (see ScoreState for more information.) - ScoreStates do not need to be explictly added to the Model, but they + ScoreStates do not need to be explicitly added to the Model, but they can be if desired in order to keep them alive as long as the model is alive. @@ -504,6 +601,19 @@ class IMPKERNELEXPORT Model : public Object and every ParticleIndex will be smaller than this value. */ unsigned get_particles_size() const { return particle_index_.size(); } + //! Get the unique ID of this Model. + /** When multiple Models exist simultaneously, each has a different unique ID. + */ + uint32_t get_unique_id() const { + return unique_id_; + } + + //! Return the Model with the given unique ID. + /** If no Model with this ID exists, nullptr is returned. */ + static Model* get_by_unique_id(uint32_t id) { + return model_map_.get(id); + } + IMP_OBJECT_METHODS(Model); public: @@ -514,6 +624,11 @@ class IMPKERNELEXPORT Model : public Object IMPKERNEL_END_NAMESPACE +CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( + IMP::Model, cereal::specialization::member_serialize); + +CEREAL_CLASS_VERSION(IMP::Model, 1); + // This is needed for per cpp compilations, a not even sure why // (perhaps cause Model returns ParticleIterator here and there?) // - Feel free to remove if you *really* know what you're doing diff --git a/modules/kernel/include/ModelObject.h b/modules/kernel/include/ModelObject.h index 634bc99aea..8a3b593d65 100644 --- a/modules/kernel/include/ModelObject.h +++ b/modules/kernel/include/ModelObject.h @@ -12,6 +12,8 @@ #include "base_types.h" #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -27,6 +29,25 @@ class IMPKERNELEXPORT ModelObject : public Object { friend class Model; WeakPointer model_; +#ifndef SWIG + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + if (std::is_base_of::value) { + uint32_t model_id = get_model_id(); + ar(model_id); + } else { + uint32_t model_id; + ar(model_id); + set_model_from_id(model_id); + } + } + + void set_model_from_id(uint32_t model_id); + uint32_t get_model_id() const; +#endif + // for cleanup void set_model(Model *m); @@ -37,6 +58,7 @@ class IMPKERNELEXPORT ModelObject : public Object { #endif ModelObject(Model *m, std::string name); + ModelObject(); ~ModelObject(); Model *get_model() const { return model_; } diff --git a/modules/kernel/include/Object.h b/modules/kernel/include/Object.h index 2bbaf08f25..8f5aa5f056 100644 --- a/modules/kernel/include/Object.h +++ b/modules/kernel/include/Object.h @@ -24,6 +24,11 @@ #include #include "hash.h" #include +#include + +// Make sure that binary archives are registered with cereal +// before any Object subclass that uses CEREAL_REGISTER_TYPE +#include #if !defined(IMP_HAS_CHECKS) #error "IMP_HAS_CHECKS not defined, something is broken" @@ -125,6 +130,24 @@ class IMPKERNELEXPORT Object : public NonCopyable { static void remove_live_object(Object* o); #endif + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(name_); +#if IMP_HAS_LOG != IMP_NONE + ar(log_level_); +#endif +#if IMP_HAS_CHECKS >= IMP_USAGE + ar(check_level_, was_owned_, check_value_); +#endif + if (std::is_base_of::value) { + // set quoted_name from name + set_name_internal(name_); + } + } + + void set_name_internal(std::string name); + void initialize(std::string name); int compare(const Object& o) const { @@ -136,6 +159,16 @@ class IMPKERNELEXPORT Object : public NonCopyable { return 0; } + typedef std::function SaveFunc; + typedef std::function LoadFunc; + struct OutputSerializer { + std::string class_name; + SaveFunc save_func; + }; + + static std::map &get_output_serializers(); + static std::map &get_input_serializers(); + protected: //! Construct an object with the given name /** An instance of "%1%" in the string will be replaced by a unique @@ -208,6 +241,16 @@ class IMPKERNELEXPORT Object : public NonCopyable { void unref() const; void release() const; const char* get_quoted_name_c_string() const { return quoted_name_.get(); } + + /** \see IMP_OBJECT_SERIALIZE_DECL */ + static bool register_serialize(const std::type_info &t, std::string name, + SaveFunc save_func, LoadFunc load_func); + + //! Save the most-derived Object subclass to the given binary archive + void poly_serialize(cereal::BinaryOutputArchive &ar); + + //! Create most-derived Object subclass from the given binary archive + static Object *poly_unserialize(cereal::BinaryInputArchive &ar); #endif void _on_destruction(); diff --git a/modules/kernel/include/Optimizer.h b/modules/kernel/include/Optimizer.h index 13a7cacd37..68c0ccb482 100644 --- a/modules/kernel/include/Optimizer.h +++ b/modules/kernel/include/Optimizer.h @@ -20,6 +20,8 @@ #include #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -44,11 +46,21 @@ IMPKERNEL_BEGIN_NAMESPACE \see Sampler */ class IMPKERNELEXPORT Optimizer : public ModelObject { - mutable Floats widths_; - Pointer my_model_; bool stop_on_good_score_; Pointer scoring_function_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), stop_on_good_score_, + scoring_function_, mutable_access_optimizer_states()); + if (std::is_base_of::value) { + for (auto &obj : mutable_access_optimizer_states()) { + set_optimizer_state_optimizer(obj, this); + } + } + } + static void set_optimizer_state_optimizer(OptimizerState *os, Optimizer *o); protected: @@ -67,6 +79,7 @@ class IMPKERNELEXPORT Optimizer : public ModelObject { public: Optimizer(Model *m, std::string name = "Optimizer %1%"); + Optimizer() {} //! Optimize the model for up to max_steps iterations /** Optimize the model diff --git a/modules/kernel/include/OptimizerState.h b/modules/kernel/include/OptimizerState.h index e2dd7af4eb..be649bb843 100644 --- a/modules/kernel/include/OptimizerState.h +++ b/modules/kernel/include/OptimizerState.h @@ -12,7 +12,8 @@ #include "ModelObject.h" #include #include - +#include +#include #include IMPKERNEL_BEGIN_NAMESPACE @@ -21,9 +22,10 @@ class Optimizer; //! Shared optimizer state that is invoked upon commitment of new coordinates. /** An OptimizerState update() method is called every time that an - owning Optimizer commits to a new set of coordinates. The update() - method, in turn, invokes do_update(), which can be overridden by - inheriting classes. + owning Optimizer commits to a new set of coordinates. (For example, this + is typically every step during molecular dynamics, or every accepted move + during Monte Carlo.) The update() method, in turn, invokes do_update(), + which can be overridden by inheriting classes. @note An OptimizerState may have periodicity by its set_period() method. @@ -44,11 +46,21 @@ class IMPKERNELEXPORT OptimizerState : public ModelObject { friend class Optimizer; unsigned int period_, call_number_, update_number_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), period_, call_number_, + update_number_, is_optimizing_); + if (std::is_base_of::value) { + optimizer_ = nullptr; + } + } + void set_optimizer(Optimizer* optimizer); public: //! Constructor. - /** Constructs an optimizer state whose update() method is invoked + /** Constructs an optimizer state whose update() method is invoked every time that a set of model coordinates is committed by an optimizer. @@ -58,6 +70,7 @@ class IMPKERNELEXPORT OptimizerState : public ModelObject { method. */ OptimizerState(Model* m, std::string name); + OptimizerState(); //! Called when the Optimizer accepts a new conformation /** diff --git a/modules/kernel/include/Particle.h b/modules/kernel/include/Particle.h index 73a9ad298d..8da62cfe57 100644 --- a/modules/kernel/include/Particle.h +++ b/modules/kernel/include/Particle.h @@ -3,7 +3,7 @@ * \brief Classes to handle individual model particles. * (Note that implementation of inline functions is in internal) * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -23,6 +23,8 @@ #include #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -55,6 +57,7 @@ class IMPKERNELEXPORT Particle : public ModelObject { Particle(Model *m); #ifndef IMP_DOXYGEN + Particle() {} #define IMP_KERNEL_PARTICLE_ATTRIBUTE_TYPE_DECL(UCName, lcname, Value) \ inline void add_attribute(UCName##Key name, Value initial_value); \ @@ -145,19 +148,31 @@ class IMPKERNELEXPORT Particle : public ModelObject { virtual ModelObjectsTemp do_get_outputs() const override final { return ModelObjectsTemp(); } + + private: + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), id_); + } }; // for swig class Decorator; -/** Take Decorator or Particle. */ +/** An adaptor that enable to implicitly pass particles to other + functions or constructors by passing either the particle itself + (in Python), a decorator to the particle, or a raw/smart IMP + pointer to the particle (in C++) +*/ class IMPKERNELEXPORT ParticleAdaptor : public InputAdaptor { Model *m_; ParticleIndex pi_; public: ParticleAdaptor() : m_(nullptr), pi_() {} + //! convert p to itself ParticleAdaptor(Particle *p) : m_(p->get_model()), pi_(p->get_index()) {} + //! convert d to the particle it decorates ParticleAdaptor(const Decorator &d); #ifndef SWIG ParticleAdaptor(IMP::Pointer p) diff --git a/modules/kernel/include/Pointer.h b/modules/kernel/include/Pointer.h index ad1d50943a..cae8a73de7 100644 --- a/modules/kernel/include/Pointer.h +++ b/modules/kernel/include/Pointer.h @@ -101,13 +101,10 @@ struct Pointer P::operator=(o); return *this; } -#if (defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_NO_NULLPTR)) && \ - !defined(nullptr) - Pointer& operator=(nullptr_t o) { + Pointer& operator=(std::nullptr_t o) { P::operator=(o); return *this; } -#endif Pointer& operator=(const P& o) { P::operator=(o); return *this; @@ -160,13 +157,10 @@ struct PointerMember P::operator=(o); return *this; } -#if (defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_NO_NULLPTR)) && \ - !defined(nullptr) - PointerMember& operator=(nullptr_t o) { + PointerMember& operator=(std::nullptr_t o) { P::operator=(o); return *this; } -#endif PointerMember& operator=(const P& o) { P::operator=(o); return *this; diff --git a/modules/kernel/include/Restraint.h b/modules/kernel/include/Restraint.h index 1749921141..6d03131e6a 100644 --- a/modules/kernel/include/Restraint.h +++ b/modules/kernel/include/Restraint.h @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include IMPKERNEL_BEGIN_NAMESPACE class DerivativeAccumulator; @@ -52,54 +55,47 @@ class DerivativeAccumulator; */ class IMPKERNELEXPORT Restraint : public ModelObject { public: - /** Create a restraint and register it with the model. The restraint is - not added to the implicit scoring function in the Model.*/ + //! Create a restraint and register it with the model. Restraint(Model *m, std::string name); + //! Default constructor. + /** Default-constructed restraints cannot be evaluated. */ + Restraint(); + /** Compute and return the current score for the restraint. */ double get_score() const; -#ifndef IMP_DOXYGEN - //! Return the score for this restraint for the current state of the model. - /** \return Current score. + /** \name Evaluation convenience methods + These are convenience methods to get the score of just this restraint; + each just calls the equivalent method in the ScoringFunction class. + @{ */ - double evaluate(bool calc_derivs) const; - - //! Score the restraint when some particles have moved. - /** No particles in the model other those listed should have been - changed (e.g. by Monte Carlo movers) since the last evaluation (although - ScoreStates may have moved particles not in this list, as a function of - particles that *are* in the list). This method should behave - identically to evaluate() but may be more efficient if it can - skip terms that involve unchanged particles. - \param calc_derivs Whether to calculate first derivatives. - \param moved_pis Particles that have moved since the last - scoring function evaluation. - \param reset_pis Particles that have moved, but back to the - positions they had at the last-but-one evaluation - (e.g. due to a rejected Monte Carlo move). + //! \see ScoringFunction::evaluate + double evaluate(bool calc_derivs) const; - \return Current score. - */ + //! \see ScoringFunction::evaluate_moved double evaluate_moved(bool calc_derivs, const ParticleIndexes &moved_pis, const ParticleIndexes &reset_pis) const; + //! \see ScoringFunction::evaluate_moved_if_below double evaluate_moved_if_below(bool calc_derivatives, const ParticleIndexes &moved_pis, const ParticleIndexes &reset_pis, double max) const; + //! \see ScoringFunction::evaluate_moved_if_good double evaluate_moved_if_good(bool calc_derivatives, const ParticleIndexes &moved_pis, const ParticleIndexes &reset_pis) const; + //! \see ScoringFunction::evaluate_if_good double evaluate_if_good(bool calc_derivatives) const; - //! \see Model::evaluate_with_maximum() + //! \see ScoringFunction::evaluate_if_below double evaluate_if_below(bool calc_derivatives, double max) const; -#endif +/** @} */ /** \name Evaluation implementation These methods are called in order to perform the actual restraint @@ -343,6 +339,19 @@ class IMPKERNELEXPORT Restraint : public ModelObject { mutable double last_last_score_; // cannot be released outside the class mutable Pointer cached_internal_scoring_function_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + ar(weight_, max_); + // Clear caches + if (std::is_base_of::value) { + last_score_ = last_last_score_ = BAD_SCORE; + cached_internal_scoring_function_ = nullptr; + } + } + }; //! Provide a consistent interface for things that take Restraints as arguments. diff --git a/modules/kernel/include/RestraintInfo.h b/modules/kernel/include/RestraintInfo.h index c92196401e..d96a2c5765 100644 --- a/modules/kernel/include/RestraintInfo.h +++ b/modules/kernel/include/RestraintInfo.h @@ -22,15 +22,27 @@ IMPKERNEL_BEGIN_NAMESPACE about a Restraint instance as a set of key:value pairs. The primary purpose is to allow restraints to be written to files, such as RMF. + Key names are generally lowercase, full words, space-separated, for + example "force constant" rather than "force_constant", "ForceConstant", + or "k". + Values can be simple types (int, float, string) or lists of them; filename(s) (treated similarly to strings but paths are made relative to that of the output file); or particles. - Particle values are used to reference particles that contain restraint - information (either static or dynamic) that generally exist + Note that when written to RMF files, RMF stores both string and filename + keys as strings. To help it distinguish the two, the convention is + for filename key names to end in "filename" or "filenames". + + Particle index values are generally used for one of two purposes. + First, to reference particles that contain restraint + information (either static or dynamic) that often exist outside of the molecular hierarchy, such as Bayesian nuisances - or Gaussians for an EM density map. The particles must live in - the same model as the restraint. + or Gaussians for an EM density map. Second, to explicitly group or + sort restraint particles (as the default list of restraint inputs is + unsorted and does not contain duplicates) such as each endpoint of + a pairwise restraint, or the two groups of particles in a bipartite + restraint. The particles must live in the same model as the restraint. */ class IMPKERNELEXPORT RestraintInfo : public Object { public: diff --git a/modules/kernel/include/RestraintSet.h b/modules/kernel/include/RestraintSet.h index 79f7f6bcff..e4db1cc74c 100644 --- a/modules/kernel/include/RestraintSet.h +++ b/modules/kernel/include/RestraintSet.h @@ -11,8 +11,12 @@ #include #include "Restraint.h" +#include "ScoringFunction.h" #include "container_macros.h" #include +#include +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -40,6 +44,14 @@ class IMPKERNELEXPORT RestraintSet : public Restraint { static void on_remove(RestraintSet *container, Restraint *r); void show_it(std::ostream &out) const; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), mutable_access_restraints()); + } + + IMP_OBJECT_SERIALIZE_DECL(RestraintSet); + public: //! Create an empty set that is registered with the model RestraintSet(Model *m, double weight, @@ -49,6 +61,7 @@ class IMPKERNELEXPORT RestraintSet : public Restraint { //! Create a set that is registered with the model RestraintSet(const RestraintsTemp &rs, double weight, const std::string &name = "RestraintSet %1%"); + RestraintSet() {} double unprotected_evaluate(DerivativeAccumulator *da) const override; diff --git a/modules/kernel/include/ScoreAccumulator.h b/modules/kernel/include/ScoreAccumulator.h index 22691f704d..8a0635a8fc 100644 --- a/modules/kernel/include/ScoreAccumulator.h +++ b/modules/kernel/include/ScoreAccumulator.h @@ -19,6 +19,7 @@ #include #include #include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -31,6 +32,13 @@ struct EvaluationState { EvaluationState(double oscore, bool ogood) : score(oscore), good(ogood) {} EvaluationState() : score(BAD_SCORE), good(false) {} IMP_SHOWABLE_INLINE(EvaluationState, out << score << " " << good;); + +private: + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(score, good); + } }; IMP_VALUES(EvaluationState, EvaluationStates); diff --git a/modules/kernel/include/ScoreState.h b/modules/kernel/include/ScoreState.h index e1bfbc63fc..9c08ea2934 100644 --- a/modules/kernel/include/ScoreState.h +++ b/modules/kernel/include/ScoreState.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -55,6 +57,15 @@ class IMPKERNELEXPORT ScoreState : public ModelObject { int update_order_; bool can_skip_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), can_skip_); + if (std::is_base_of::value) { + update_order_ = -1; + } + } + protected: //! Set whether we can skip during model evaluation if appropriate /** This should be set only once before the state is used (ideally in the @@ -67,6 +78,7 @@ class IMPKERNELEXPORT ScoreState : public ModelObject { public: ScoreState(Model *m, std::string name); + ScoreState() {} //! Force update of the structure. void before_evaluate(); @@ -109,6 +121,12 @@ class IMPKERNELEXPORT ScoreState : public ModelObject { the score states in. */ IMPKERNELEXPORT ScoreStatesTemp get_update_order(ScoreStatesTemp input); +#ifndef SWIG +/** Return an appropriate (topologically sorted) order to update + the score states in. */ +IMPKERNELEXPORT ScoreStatesTemp get_update_order(std::set input); +#endif + IMPKERNEL_END_NAMESPACE #endif /* IMPKERNEL_SCORE_STATE_H */ diff --git a/modules/kernel/include/ScoringFunction.h b/modules/kernel/include/ScoringFunction.h index 4f9d2096c3..8b2fc5c033 100644 --- a/modules/kernel/include/ScoringFunction.h +++ b/modules/kernel/include/ScoringFunction.h @@ -17,7 +17,8 @@ #include "internal/moved_particles_cache.h" #include #include - +#include +#include #include IMPKERNEL_BEGIN_NAMESPACE @@ -46,6 +47,17 @@ class IMPKERNELEXPORT ScoringFunction : public ModelObject { // time when moved_particles_cache_ was last updated, or 0 unsigned moved_particles_cache_age_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), es_); + // clear caches + if (std::is_base_of::value) { + moved_particles_cache_.clear(); + moved_particles_cache_age_ = 0; + } + } + ScoreStatesTemp get_moved_required_score_states( const ParticleIndexes &moved_pis, const ParticleIndexes &reset_pis); @@ -85,14 +97,13 @@ class IMPKERNELEXPORT ScoringFunction : public ModelObject { public: ScoringFunction(Model *m, std::string name); + ScoringFunction(); virtual ModelObjectsTemp do_get_outputs() const override { return ModelObjectsTemp(); } - double evaluate_if_good(bool derivatives); - - //! Evaluate and return the score + //! Evaluate and return the score for the current state of the model. /** \return the resulting score @param derivatives if true, updates the derivatives of the @@ -100,12 +111,21 @@ class IMPKERNELEXPORT ScoringFunction : public ModelObject { */ double evaluate(bool derivatives); + double evaluate_if_good(bool derivatives); + + double evaluate_if_below(bool derivatives, double max); + //! Score when some particles have moved. - /** This should behave identically to evaluate() but may be more - efficient if it can skip restraint terms that involve unchanged particles. + /** No particles in the model other those listed should have been + changed (e.g. by Monte Carlo movers) since the last evaluation (although + ScoreStates may have moved particles not in this list, as a function of + particles that *are* in the list). This should behave identically to + evaluate() but may be more efficient if it can skip restraint terms + that involve unchanged particles. \see IMP::core::MonteCarlo::set_score_moved + \param calc_derivs Whether to calculate first derivatives. \param moved_pis Particles that have moved since the last scoring function evaluation. \param reset_pis Particles that have moved, but back to the @@ -125,8 +145,6 @@ class IMPKERNELEXPORT ScoringFunction : public ModelObject { bool derivatives, const ParticleIndexes &moved_pis, const ParticleIndexes &reset_pis); - double evaluate_if_below(bool derivatives, double max); - /** Return true if the last evaluate satisfied all the restraint thresholds.*/ bool get_had_good_score() const { return es_.good; } diff --git a/modules/kernel/include/UnaryFunction.h b/modules/kernel/include/UnaryFunction.h index 1759798777..0b797c3b6b 100644 --- a/modules/kernel/include/UnaryFunction.h +++ b/modules/kernel/include/UnaryFunction.h @@ -10,6 +10,8 @@ #include #include "base_types.h" #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -51,6 +53,13 @@ class IMPKERNELEXPORT UnaryFunction : public IMP::Object { } IMP_REF_COUNTED_DESTRUCTOR(UnaryFunction); + +private: + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } }; IMP_OBJECTS(UnaryFunction, UnaryFunctions); diff --git a/modules/kernel/include/Vector.h b/modules/kernel/include/Vector.h index bc33405fed..1d26216061 100644 --- a/modules/kernel/include/Vector.h +++ b/modules/kernel/include/Vector.h @@ -13,11 +13,11 @@ #include "Showable.h" #include "Value.h" #include -#include -#include +#include #include "hash.h" #if defined(_MSC_VER) && _MSC_VER == 1500 +# include # include # include #endif @@ -56,38 +56,34 @@ class Vector : public Value typedef std::vector V; #endif -#ifndef SWIG - friend class boost::serialization::access; + friend class cereal::access; - template void save(Archive &ar, const unsigned int) const { + template void save(Archive &ar) const { size_t sz = V::size(); - ar << sz; + ar(sz); auto it = V::begin(); while(sz-- > 0) { - ar << *it++; + ar(*it++); } } - template void load(Archive &ar, const unsigned int) { + template void load(Archive &ar) { size_t sz; - ar >> sz; + ar(sz); V::resize(sz); auto it = V::begin(); while(sz-- > 0) { - ar >> *it++; + ar(*it++); } } - BOOST_SERIALIZATION_SPLIT_MEMBER() -#endif - public: Vector() {} explicit Vector(unsigned int sz, const T &t = T()) : V(sz, t) {} #if defined(_MSC_VER) && _MSC_VER == 1500 template Vector(It b, It e, - typename boost::disable_if >::type *t=0) { + typename boost::disable_if::value>::type *t=0) { for (It it = b; it != e; ++it) { push_back(T(*it)); } @@ -164,4 +160,10 @@ inline std::size_t hash_value(const __gnu_debug::vector &t) { IMPKERNEL_END_NAMESPACE +namespace cereal { + template + struct specialize, + cereal::specialization::member_load_save> {}; +} + #endif /* IMPKERNEL_CONVERTIBLE_VECTOR_H */ diff --git a/modules/kernel/include/VersionInfo.h b/modules/kernel/include/VersionInfo.h index a49f1a7c33..0c713d7e6b 100644 --- a/modules/kernel/include/VersionInfo.h +++ b/modules/kernel/include/VersionInfo.h @@ -15,7 +15,7 @@ #include "showable_macros.h" #include "value_macros.h" #include "Value.h" -#include +#include #include IMPKERNEL_BEGIN_NAMESPACE @@ -45,10 +45,10 @@ class IMPKERNELEXPORT VersionInfo : public Value { private: std::string module_, version_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & module_ & version_; + template void serialize(Archive &ar) { + ar(module_, version_); } }; IMP_VALUES(VersionInfo, VersionInfos); diff --git a/modules/kernel/include/WeakPointer.h b/modules/kernel/include/WeakPointer.h index 7827ce42fd..ef0427292c 100644 --- a/modules/kernel/include/WeakPointer.h +++ b/modules/kernel/include/WeakPointer.h @@ -8,6 +8,7 @@ #ifndef IMPKERNEL_WEAK_POINTER_H #define IMPKERNEL_WEAK_POINTER_H + #include #include "internal/PointerBase.h" @@ -48,7 +49,7 @@ struct UncheckedWeakPointer } #if(defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_NO_NULLPTR)) && \ !defined(nullptr) - UncheckedWeakPointer& operator=(nullptr_t o) { + UncheckedWeakPointer& operator=(std::nullptr_t o) { P::operator=(o); return *this; } @@ -92,7 +93,7 @@ struct WeakPointer } #if(defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_NO_NULLPTR)) && \ !defined(nullptr) - WeakPointer& operator=(nullptr_t o) { + WeakPointer& operator=(std::nullptr_t o) { P::operator=(o); return *this; } diff --git a/modules/kernel/include/base_utility.h b/modules/kernel/include/base_utility.h index 5fb8d67ca0..c09ce2670b 100644 --- a/modules/kernel/include/base_utility.h +++ b/modules/kernel/include/base_utility.h @@ -66,6 +66,9 @@ inline Out get_as(const In &in) { /** This is done by replacing %1% with a sequential number.*/ IMPKERNELEXPORT std::string get_unique_name(std::string templ); +//! Get the IMP copyright notice +IMPKERNELEXPORT std::string get_copyright(); + IMPKERNEL_END_NAMESPACE #endif /* IMPKERNEL_BASE_UTILITY_H */ diff --git a/modules/kernel/include/compiler_macros.h b/modules/kernel/include/compiler_macros.h index b10adf2737..75d5f7d9d4 100644 --- a/modules/kernel/include/compiler_macros.h +++ b/modules/kernel/include/compiler_macros.h @@ -8,9 +8,6 @@ #ifndef IMPKERNEL_COMPILER_MACROS_H #define IMPKERNEL_COMPILER_MACROS_H -// Deprecated: just use C++11 range-based for instead -#define IMP_FOREACH(v, r) for (v : r) - #define IMP_STRINGIFY(x) #x // recommended by http://gcc.gnu.org/gcc/Function-Names.html @@ -54,45 +51,22 @@ #endif -// Deprecated: just use the 'override' keyword directly -#ifdef IMP_DOXYGEN -#define IMP_OVERRIDE -#else -#define IMP_OVERRIDE override -#endif - #ifdef IMP_DOXYGEN -#define IMP_FINAL //! Have the compiler report an error if anything overrides this method #define IMP_SWIG_FINAL #else #if defined(IMP_SWIG_WRAPPER) || defined(SWIG) -#define IMP_FINAL #define IMP_SWIG_FINAL #else -#define IMP_FINAL final #define IMP_SWIG_FINAL final #endif #endif -#if defined(__GNUC__) && __cplusplus >= 201103L -#define IMP_HAS_NOEXCEPT 1 -#elif defined(__clang__) && defined(__has_feature) -#define IMP_HAS_NOEXCEPT __has_feature(cxx_noexcept) -#else -#define IMP_HAS_NOEXCEPT 0 -#endif - -#if IMP_HAS_NOEXCEPT +// Deprecated: just use 'noexcept' directly #define IMP_NOEXCEPT noexcept #define IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(Name) \ Name(const Name &) = default; \ Name &operator=(const Name &) = default -#else -// probably should be finer here -#define IMP_NOEXCEPT throw() -#define IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(Name) -#endif #if defined(__clang__) || defined(__GNUC__) #define IMP_PRAGMA(x) _Pragma(IMP_STRINGIFY(x)) @@ -170,7 +144,7 @@ #define IMP_HELPER_MACRO_POP_WARNINGS #endif -// Warn about missing IMP_OVERRIDE on virtual methods if gcc is new enough +// Warn about missing override on virtual methods if gcc is new enough #if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #ifdef IMP_SWIG_WRAPPER #define IMP_GCC_OVERRIDE diff --git a/modules/kernel/include/container_base.h b/modules/kernel/include/container_base.h index 40b2d771af..45f7df8d04 100644 --- a/modules/kernel/include/container_base.h +++ b/modules/kernel/include/container_base.h @@ -2,7 +2,7 @@ * \file IMP/container_base.h * \brief Abstract base class for containers of particles. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -17,6 +17,8 @@ #include #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE class Particle; @@ -46,8 +48,20 @@ class IMPKERNELEXPORT Container : public ModelObject { bool readable_; bool writeable_; #endif + + friend class cereal::access; + + template void serialize(Archive &ar) { +#if IMP_HAS_CHECKS < IMP_INTERNAL + // serialize the same data regardless of the check level, so we are portable + bool readable_ = true, writeable_ = true; +#endif + ar(cereal::base_class(this), readable_, writeable_); + } + protected: Container(Model *m, std::string name = "Container %1%"); + Container() {} virtual std::size_t do_get_contents_hash() const = 0; diff --git a/modules/kernel/include/container_macros.h b/modules/kernel/include/container_macros.h index 709a9b2a83..7a0294d615 100644 --- a/modules/kernel/include/container_macros.h +++ b/modules/kernel/include/container_macros.h @@ -195,7 +195,7 @@ public: \ stop = std::min(stop, num_of); \ unsigned int indx = start; \ for (Ucname##Iterator it = lcnames##_begin() + start; \ - it != lcnames##_end(); ++it, ++indx) { \ + indx < stop; ++it, ++indx) { \ if (*it == d) { \ found = true; \ break; \ diff --git a/modules/kernel/include/decorator_macros.h b/modules/kernel/include/decorator_macros.h index b24bb4b0ae..7bb1dc275f 100644 --- a/modules/kernel/include/decorator_macros.h +++ b/modules/kernel/include/decorator_macros.h @@ -107,22 +107,28 @@ defined. */ #define IMP_DECORATOR_SETUP_0(Name) \ - /** Setup the particle so it can be used with this decorator. */ \ - static Name setup_particle(Model *m, ParticleIndex pi) { \ + /** + @return a Name object that decorates particle pi + */ \ + static Name setup_particle(Model *m, ParticleIndex pi) { \ IMP_USAGE_CHECK(!get_is_setup(m, pi), \ "Particle " << m->get_particle_name(pi) \ << " already set up as " << #Name); \ do_setup_particle(m, pi); \ return Name(m, pi); \ } \ - static Name setup_particle(IMP::ParticleAdaptor decorator) { \ - return setup_particle(decorator.get_model(), \ - decorator.get_particle_index()); \ + /** @return a Name object that decorates the particle specified by pa + \see setup_particle(m, p) */ \ + static Name setup_particle(IMP::ParticleAdaptor pa) { \ + return setup_particle(pa.get_model(), \ + pa.get_particle_index()); \ } /** \see IMP_DECORATOR_SETUP_0() */ #define IMP_DECORATOR_SETUP_1(Name, FirstArgumentType, first_argument_name) \ - /** Setup the particle so that it can be used with this decorator */ \ - static Name setup_particle(Model *m, ParticleIndex pi, \ + /** + @return a Name object that decorates particle pi + */ \ + static Name setup_particle(Model *m, ParticleIndex pi, \ FirstArgumentType first_argument_name) { \ IMP_USAGE_CHECK(!get_is_setup(m, pi), \ "Particle " << m->get_particle_name(pi) \ @@ -130,19 +136,22 @@ do_setup_particle(m, pi, first_argument_name); \ return Name(m, pi); \ } \ - /** \see setup_particle(m, pi, first_argument_name) */ \ - static Name setup_particle(IMP::ParticleAdaptor decorator, \ + /** @return a Name object that decorates the particle specified by pa + \see setup_particle(m, pi, first_argument_name) */ \ + static Name setup_particle(IMP::ParticleAdaptor pa, \ FirstArgumentType first_argument_name) { \ - return setup_particle(decorator.get_model(), \ - decorator.get_particle_index(), \ + return setup_particle(pa.get_model(), \ + pa.get_particle_index(), \ first_argument_name); \ } /** \see IMP_DECORATOR_SETUP_0() */ #define IMP_DECORATOR_SETUP_2(Name, FirstArgumentType, first_argument_name, \ SecondArgumentType, second_argument_name) \ - /** Setup the particle so it can be used with this decorator. */ \ - static Name setup_particle(Model *m, ParticleIndex pi, \ + /** + @return a Name object that decorates particle pi + */ \ + static Name setup_particle(Model *m, ParticleIndex pi, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name) { \ IMP_USAGE_CHECK(!get_is_setup(m, pi), \ @@ -151,19 +160,24 @@ do_setup_particle(m, pi, first_argument_name, second_argument_name); \ return Name(m, pi); \ } \ - static Name setup_particle(IMP::ParticleAdaptor decorator, \ + /** @return a Name object that decorates the particle specified by pa + \see setup_particle(m, p, first_argument_name, second_argument_name) + */ \ + static Name setup_particle(IMP::ParticleAdaptor pa, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name) { \ - return setup_particle(decorator.get_model(), \ - decorator.get_particle_index(), first_argument_name, \ + return setup_particle(pa.get_model(), \ + pa.get_particle_index(), first_argument_name, \ second_argument_name); \ } /** \see IMP_DECORATOR_SETUP_0() */ #define IMP_DECORATOR_SETUP_3(Name, FirstArgumentType, first_argument_name, \ SecondArgumentType, second_argument_name, \ ThirdArgumentType, third_argument_name) \ - /** Setup the particle so it can be used with this decorator. */ \ - static Name setup_particle(Model *m, ParticleIndex pi, \ + /** + @return a Name object that decorates particle pi + */ \ + static Name setup_particle(Model *m, ParticleIndex pi, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name, \ ThirdArgumentType third_argument_name) { \ @@ -173,13 +187,16 @@ do_setup_particle(m, pi, first_argument_name, second_argument_name, \ third_argument_name); \ return Name(m, pi); \ - } \ - static Name setup_particle(IMP::ParticleAdaptor decorator, \ + } \ + /** @return a Name object that decorates the particle specified by pa + \see setup_particle(m, pi, first_argument_name, second_argument_name, + third_argument_name) */ \ + static Name setup_particle(IMP::ParticleAdaptor pa, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name, \ ThirdArgumentType third_argument_name) { \ - return setup_particle(decorator.get_model(), \ - decorator.get_particle_index(), first_argument_name, \ + return setup_particle(pa.get_model(), \ + pa.get_particle_index(), first_argument_name, \ second_argument_name, third_argument_name); \ } /** \see IMP_DECORATOR_SETUP_0() */ @@ -187,8 +204,10 @@ SecondArgumentType, second_argument_name, \ ThirdArgumentType, third_argument_name, \ FourthArgumentType, fourth_argument_name) \ - /** Setup the particle so it can be used with this decorator. */ \ - static Name setup_particle(Model *m, ParticleIndex pi, \ + /** + @return a Name object that decorates particle pi + */ \ + static Name setup_particle(Model *m, ParticleIndex pi, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name, \ ThirdArgumentType third_argument_name, \ @@ -199,14 +218,17 @@ do_setup_particle(m, pi, first_argument_name, second_argument_name, \ third_argument_name, fourth_argument_name); \ return Name(m, pi); \ - } \ - static Name setup_particle(IMP::ParticleAdaptor decorator, \ + } \ + /** @return a Name object that decorates the particle specified by pa + \see setup_particle(m, pi, first_argument_name, second_argument_name, + third_argument_name, fourth_argument_name) */ \ + static Name setup_particle(IMP::ParticleAdaptor pa, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name, \ ThirdArgumentType third_argument_name, \ FourthArgumentType fourth_argument_name) { \ - return setup_particle(decorator.get_model(), \ - decorator.get_particle_index(), first_argument_name, \ + return setup_particle(pa.get_model(), \ + pa.get_particle_index(), first_argument_name, \ second_argument_name, third_argument_name, \ fourth_argument_name); \ } @@ -218,13 +240,15 @@ ThirdArgumentType, third_argument_name, \ FourthArgumentType, fourth_argument_name, \ FifthArgumentType, fifth_argument_name) \ - /** Setup the particle so it can be used with this decorator. */ \ + /** + @return a Name object that decorates particle pi + */ \ static Name setup_particle(Model *m, ParticleIndex pi, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name, \ ThirdArgumentType third_argument_name, \ FourthArgumentType fourth_argument_name, \ - FifthArgumentType fifth_argument_name) { \ + FifthArgumentType fifth_argument_name) { \ IMP_USAGE_CHECK(!get_is_setup(m, pi), \ "Particle " << m->get_particle_name(pi) \ << " already set up as " << #Name); \ @@ -233,14 +257,17 @@ fifth_argument_name); \ return Name(m, pi); \ } \ - static Name setup_particle(IMP::ParticleAdaptor decorator, \ + /** @return a Name object that decorates the particle specified by pa + \see setup_particle(m, pi, first_argument_name, second_argument_name, + third_argument_name, fourth_argument_name, fifth_argument_name) */ \ + static Name setup_particle(IMP::ParticleAdaptor pa, \ FirstArgumentType first_argument_name, \ SecondArgumentType second_argument_name, \ ThirdArgumentType third_argument_name, \ FourthArgumentType fourth_argument_name, \ - FifthArgumentType fifth_argument_name) { \ - return setup_particle(decorator.get_model(), \ - decorator.get_particle_index(), first_argument_name, \ + FifthArgumentType fifth_argument_name) { \ + return setup_particle(pa.get_model(), \ + pa.get_particle_index(), first_argument_name, \ second_argument_name, third_argument_name, \ fourth_argument_name, fifth_argument_name); \ } @@ -252,7 +279,9 @@ defined. But any docs needed before the macro invocation. */ #define IMP_DECORATOR_TRAITS_SETUP_0(Name) \ - /** Setup the particle so it can be used with this decorator. */ \ + /** + @return a Name object that decorates particle pi + */ \ static Name setup_particle( \ Model *m, ParticleIndex pi, \ DecoratorTraits tr = get_default_decorator_traits()) { \ diff --git a/modules/kernel/include/dependency_graph.h b/modules/kernel/include/dependency_graph.h index 3d6f2f6bd6..ff9a8a9b99 100644 --- a/modules/kernel/include/dependency_graph.h +++ b/modules/kernel/include/dependency_graph.h @@ -62,23 +62,11 @@ IMPKERNELEXPORT ParticlesTemp #ifndef IMP_DOXYGEN -IMPKERNEL_DEPRECATED_FUNCTION_DECL(2.17) -IMPKERNELEXPORT RestraintsTemp - get_dependent_restraints(Model *m, ParticleIndex pi); - -IMPKERNEL_DEPRECATED_FUNCTION_DECL(2.17) -IMPKERNELEXPORT ScoreStatesTemp - get_dependent_score_states(Model *m, ParticleIndex pi); - //! Return all ScoreStates that are required by this Particle. /** \note The list may contain duplicates. */ IMPKERNELEXPORT ScoreStatesTemp get_required_score_states(Model *m, ParticleIndex pi); -IMPKERNEL_DEPRECATED_FUNCTION_DECL(2.17) -IMPKERNELEXPORT ParticlesTemp - get_dependent_particles(Model *m, ParticleIndex pi); - #endif IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/include/exception.h b/modules/kernel/include/exception.h index 926ceab15a..698de26346 100644 --- a/modules/kernel/include/exception.h +++ b/modules/kernel/include/exception.h @@ -52,11 +52,11 @@ class IMPKERNELEXPORT Exception { public: #if defined(SWIG) || defined(IMP_DOXYGEN) - const char *what() const IMP_NOEXCEPT; + const char *what() const noexcept; #endif IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(Exception); Exception(const char *message); - ~Exception() IMP_NOEXCEPT; + ~Exception() noexcept; }; #endif @@ -106,7 +106,7 @@ struct IMPKERNELEXPORT InternalException IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(InternalException); InternalException(const char *msg = "Fatal error") : std::runtime_error(msg) {} - ~InternalException() IMP_NOEXCEPT; + ~InternalException() noexcept; }; //! An exception for an invalid usage of \imp @@ -127,7 +127,7 @@ class IMPKERNELEXPORT UsageException public: IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(UsageException); UsageException(const char *t) : std::runtime_error(t) {} - ~UsageException() IMP_NOEXCEPT; + ~UsageException() noexcept; }; //! An exception for an invalid value being passed to \imp @@ -137,7 +137,7 @@ class IMPKERNELEXPORT ValueException : public Exception { public: IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(ValueException); ValueException(const char *t) : Exception(t) {} - ~ValueException() IMP_NOEXCEPT; + ~ValueException() noexcept; }; //! An exception for an invalid type being passed to \imp @@ -147,7 +147,7 @@ class IMPKERNELEXPORT TypeException : public Exception { public: IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(TypeException); TypeException(const char *t) : Exception(t) {} - ~TypeException() IMP_NOEXCEPT; + ~TypeException() noexcept; }; //! An exception for a request for an invalid member of a container @@ -158,7 +158,7 @@ class IMPKERNELEXPORT IndexException : public Exception { IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(IndexException); //! Create exception with an error message IndexException(const char *t) : Exception(t) {} - ~IndexException() IMP_NOEXCEPT; + ~IndexException() noexcept; }; //! An input/output exception @@ -174,7 +174,7 @@ class IMPKERNELEXPORT IOException : public Exception { public: IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(IOException); IOException(const char *t) : Exception(t) {} - ~IOException() IMP_NOEXCEPT; + ~IOException() noexcept; }; /** \brief An exception which is thrown when the Model has @@ -190,7 +190,7 @@ class IMPKERNELEXPORT ModelException : public Exception { IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(ModelException); //! Create exception with an error message ModelException(const char *t) : Exception(t) {} - ~ModelException() IMP_NOEXCEPT; + ~ModelException() noexcept; }; //! An exception that signifies some event occurred. @@ -205,7 +205,7 @@ class IMPKERNELEXPORT EventException : public Exception { IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(EventException); //! Create exception with an error message EventException(const char *t = "") : Exception(t) {} - ~EventException() IMP_NOEXCEPT; + ~EventException() noexcept; }; #endif diff --git a/modules/kernel/include/file.h b/modules/kernel/include/file.h index 2d0f5164bf..03b97466ab 100644 --- a/modules/kernel/include/file.h +++ b/modules/kernel/include/file.h @@ -19,7 +19,7 @@ #include "InputAdaptor.h" #include "value_macros.h" #include "check_macros.h" -#include +#include #include #include @@ -48,7 +48,7 @@ struct TextProxy { \see TextInput */ class IMPKERNELEXPORT TextOutput : public InputAdaptor { - boost::shared_ptr > out_; + std::shared_ptr > out_; public: #ifndef IMP_DOXYGEN @@ -87,7 +87,7 @@ class IMPKERNELEXPORT TextOutput : public InputAdaptor { \see TextOutput */ class IMPKERNELEXPORT TextInput : public InputAdaptor { - boost::shared_ptr > in_; + std::shared_ptr > in_; public: #ifndef IMP_DOXYGEN diff --git a/modules/kernel/include/hash.h b/modules/kernel/include/hash.h index bd028ca540..69e0232540 100644 --- a/modules/kernel/include/hash.h +++ b/modules/kernel/include/hash.h @@ -49,6 +49,11 @@ template inline std::size_t hash_value(const std::vector &t) { return boost::hash_range(t.begin(), t.end()); } + +template +inline std::size_t hash_value(const std::set &t) { + return boost::hash_range(t.begin(), t.end()); +} IMPKERNEL_END_NAMESPACE #endif /* IMPKERNEL_HASH_H */ diff --git a/modules/kernel/include/internal/AttributeTable.h b/modules/kernel/include/internal/AttributeTable.h index 094811a944..5320af4701 100644 --- a/modules/kernel/include/internal/AttributeTable.h +++ b/modules/kernel/include/internal/AttributeTable.h @@ -15,9 +15,31 @@ #include #include "../particle_index.h" #include +#include +#include +#include #include +// Add serialization support for boost::dynamic_bitset +namespace cereal { + template + inline void save(Archive &ar, + boost::dynamic_bitset const &t) { + std::string bits; + boost::to_string(t, bits); + ar(bits); + } + + template + inline void load(Archive &ar, + boost::dynamic_bitset &t) { + std::string bits; + ar(bits); + t = boost::dynamic_bitset(bits); + } +} + IMPKERNEL_BEGIN_NAMESPACE class Particle; @@ -37,7 +59,7 @@ IMPKERNEL_BEGIN_INTERNAL_NAMESPACE template struct DefaultTraits { //! a container storing the attribute data for all particles (indexed by ParticleIndex) - typedef IndexVector Container; + typedef CompressedIndexVector Container; typedef T Value; typedef T PassValue; typedef K Key; @@ -113,7 +135,7 @@ struct ObjectAttributeTableTraits { typedef Object *Value; typedef Object *PassValue; typedef ObjectKey Key; - typedef IndexVector > + typedef CompressedIndexVector > Container; typedef Pointer const* ContainerConstDataAccess; typedef Pointer* ContainerDataAccess; @@ -132,7 +154,7 @@ struct WeakObjectAttributeTableTraits { typedef Object *Value; typedef Object *PassValue; typedef WeakObjectKey Key; - typedef IndexVector > + typedef CompressedIndexVector > Container; typedef WeakPointer const* ContainerConstDataAccess; typedef WeakPointer* ContainerDataAccess; @@ -150,7 +172,7 @@ struct ObjectsAttributeTableTraits { typedef Objects Value; typedef const Objects &PassValue; typedef ObjectsKey Key; - typedef IndexVector Container; + typedef CompressedIndexVector Container; typedef Objects const* ContainerConstDataAccess; typedef Objects* ContainerDataAccess; static Value get_invalid() { return Value(); } @@ -181,6 +203,12 @@ struct IntAttributeTableTraits : public DefaultTraits { struct BoolAttributeTableTraits : public DefaultTraits { struct Container : public boost::dynamic_bitset<> { + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class >(this)); + } + typedef boost::dynamic_bitset<> P; P::reference operator[](Index i) { return P::operator[](get_as_unsigned_int(i)); @@ -238,4 +266,8 @@ inline int use_xyz_to_disable_warning() { IMPKERNEL_END_INTERNAL_NAMESPACE +CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( + IMP::internal::BoolAttributeTableTraits::Container, + cereal::specialization::member_serialize); + #endif /* IMPKERNEL_ATTRIBUTE_TABLE_H */ diff --git a/modules/kernel/include/internal/BoostProgressDisplay.h b/modules/kernel/include/internal/BoostProgressDisplay.h new file mode 100644 index 0000000000..760602a4ab --- /dev/null +++ b/modules/kernel/include/internal/BoostProgressDisplay.h @@ -0,0 +1,29 @@ +/** + * \file internal/BoostProgressDisplay.h + * \brief Get the most appropriate Boost class to Display progress + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + */ + +#ifndef IMPKERNEL_INTERNAL_BOOST_PROGRESS_DISPLAY_H +#define IMPKERNEL_INTERNAL_BOOST_PROGRESS_DISPLAY_H + +#include +#include +#if BOOST_VERSION >= 107200 +# include +#else +# include +#endif + +IMPKERNEL_BEGIN_INTERNAL_NAMESPACE + +#if BOOST_VERSION >= 107200 +typedef boost::timer::progress_display BoostProgressDisplay; +#else +typedef boost::progress_display BoostProgressDisplay; +#endif + +IMPKERNEL_END_INTERNAL_NAMESPACE + +#endif /* IMPKERNEL_INTERNAL_BOOST_PROGRESS_DISPLAY_H */ diff --git a/modules/kernel/include/internal/ContainerConstraint.h b/modules/kernel/include/internal/ContainerConstraint.h index 6d01be97f6..7ddc164d61 100644 --- a/modules/kernel/include/internal/ContainerConstraint.h +++ b/modules/kernel/include/internal/ContainerConstraint.h @@ -1,8 +1,8 @@ /** - * \file core/generic.h \brief Various important functionality - * for implementing decorators. + * \file ContainerConstraint.h + * \brief Templated and more efficient constraint implementation. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -12,11 +12,13 @@ #include #include "../base_types.h" #include "../Constraint.h" +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE -/** Create a constraint tied to particular modifiers and contains. This - functionality, which is only available in C++ can result in faster +/** Create a constraint tied to particular modifiers and containers. This + functionality, which is only available in C++, can result in faster evaluates. */ template @@ -25,11 +27,18 @@ class ContainerConstraint : public Constraint { IMP::PointerMember af_; IMP::PointerMember c_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), f_, af_, c_); + } + public: ContainerConstraint(Before *before, After *after, Container *c, std::string name="ContainerConstraint %1%", bool can_skip=false); + ContainerConstraint() {} + //! Apply this modifier to all the elements after an evaluate void set_after_evaluate_modifier(After *f) { af_ = f; } diff --git a/modules/kernel/include/internal/ContainerRestraint.h b/modules/kernel/include/internal/ContainerRestraint.h index 6aae3c34a4..4e8f7f4967 100644 --- a/modules/kernel/include/internal/ContainerRestraint.h +++ b/modules/kernel/include/internal/ContainerRestraint.h @@ -15,6 +15,8 @@ #include "create_decomposition.h" #include "AccumulatorScoreModifier.h" #include "functors.h" +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE /** When programming in C++, you can use ContainerRestraint instead @@ -24,12 +26,26 @@ IMPKERNEL_BEGIN_INTERNAL_NAMESPACE template class ContainerRestraint : public Restraint { IMP::PointerMember pc_; + IMP::Pointer ss_; IMP::Pointer > acc_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), pc_, ss_); + + // recreate the AccumulatorScoreModifier + if (std::is_base_of::value) { + acc_ = create_accumulator_score_modifier(ss_.get(), pc_.get()); + } + } + public: ContainerRestraint(Score *ss, Container *pc, std::string name = "GroupnamesRestraint %1%"); + ContainerRestraint() {} + public: void do_add_score_and_derivatives(IMP::ScoreAccumulator sa) const override; @@ -74,6 +90,7 @@ ContainerRestraint::ContainerRestraint(Score *ss, C *pc, std::string name) : Restraint(pc->get_model(), name), pc_(pc), + ss_(ss), acc_(create_accumulator_score_modifier(ss, pc)) {} template diff --git a/modules/kernel/include/internal/IDGenerator.h b/modules/kernel/include/internal/IDGenerator.h new file mode 100644 index 0000000000..ab4d6dbaaa --- /dev/null +++ b/modules/kernel/include/internal/IDGenerator.h @@ -0,0 +1,48 @@ +/** + * \file internal/IDGenerator.h + * \brief Generation of simple unique IDs. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + */ + +#ifndef IMPKERNEL_INTERNAL_ID_GENERATOR_H +#define IMPKERNEL_INTERNAL_ID_GENERATOR_H + +#include +#include +#include +#include + +IMPKERNEL_BEGIN_INTERNAL_NAMESPACE + +//! Generator of simple IDs +/** These IDs are intended to be used to uniquely identify IMP Objects + such as Model, to prevent users accidentally confusing multiple objects + with the same name. These are generated with a simple random number + generator - the chance of collision is very small (although not zero). + The object pointer is not used as - depending on the dynamic memory + implementation - a new object may get the address of a previously freed one. + */ +class IDGenerator { + std::mt19937 rng_; +public: + + //! Constructor + IDGenerator() { + // Use system time to seed (don't use the regular IMP RNG as that may have + // been seeded by the user) + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + rng_.seed(seed); + } + + //! Generate and return a new ID + uint32_t operator()() { + // mt19937 returns a uint_fast32_t, which might be a larger type, + // but we want exactly 32 bits + return static_cast(rng_()); + } +}; + +IMPKERNEL_END_INTERNAL_NAMESPACE + +#endif /* IMPKERNEL_INTERNAL_ID_GENERATOR_H */ diff --git a/modules/kernel/include/internal/KeyVector.h b/modules/kernel/include/internal/KeyVector.h new file mode 100644 index 0000000000..3f6613e4d2 --- /dev/null +++ b/modules/kernel/include/internal/KeyVector.h @@ -0,0 +1,71 @@ +/** + * \file internal/KeyVector.h + * \brief A class for storing data indexed by a Key. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#ifndef IMPKERNEL_INTERNAL_KEY_VECTOR_H +#define IMPKERNEL_INTERNAL_KEY_VECTOR_H + +#include +#include +#include + +IMPKERNEL_BEGIN_INTERNAL_NAMESPACE + +//! A class for storing data indexed by a Key. +/** This class acts just like a regular IMP vector, indexed by a Key index, + except for serialization. We can't serialize the raw vector, since the + Key indexes may change between serialization time and deserialization time + (e.g. a given Key may not exist when the object is deserialized, or the + Keys may have been created in a different order and so have different + indexes). Instead, we must include the Key string names in the serialized + data. + */ +template +class KeyVector : public Vector +{ +#if IMP_COMPILER_HAS_DEBUG_VECTOR &&IMP_HAS_CHECKS >= IMP_INTERNAL + typedef __gnu_debug::vector V; +#else + typedef std::vector V; +#endif + + friend class cereal::access; + + template void serialize(Archive &ar) { + if (std::is_base_of::value) { + ar(V::size()); + for (unsigned int i = 0; i < V::size(); ++i) { + Key k(i); + ar(k); + ar(V::operator[](i)); + } + } else { + size_t sz; + ar(sz); + V::clear(); + for (unsigned int i = 0; i < sz; ++i) { + Key k; + ar(k); + unsigned int kindex = k.get_index(); + if (V::size() <= kindex) { + V::resize(kindex + 1); + } + ar(V::operator[](kindex)); + } + } + } +}; + +IMPKERNEL_END_INTERNAL_NAMESPACE + +namespace cereal { + template + struct specialize, + cereal::specialization::member_serialize> {}; +} + +#endif /* IMPKERNEL_INTERNAL_KEY_VECTOR_H */ diff --git a/modules/kernel/include/internal/ListLikeContainer.h b/modules/kernel/include/internal/ListLikeContainer.h index 2b23393272..be64d8cbdd 100644 --- a/modules/kernel/include/internal/ListLikeContainer.h +++ b/modules/kernel/include/internal/ListLikeContainer.h @@ -16,6 +16,8 @@ #include "container_helpers.h" #include #include +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -29,6 +31,16 @@ class ListLikeContainer : public Base { return version_; } + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), data_); + // reset version (cache) + if (std::is_base_of::value) { + version_ = 0; + } + } + protected: //! swap internal data_ with data in cur - effectively make the container contain cur void swap(typename Base::ContainedIndexTypes &cur) { @@ -39,6 +51,8 @@ class ListLikeContainer : public Base { ListLikeContainer(Model *m, std::string name) : Base(m, name), version_(0) {} + ListLikeContainer() {} + public: //! apply f->apply_indexes to data_. Use parallel mode using IMP_TASK //! if get_number_of_threads()>=2 diff --git a/modules/kernel/include/internal/PointerBase.h b/modules/kernel/include/internal/PointerBase.h index 6b89bd5f3c..d0b0ff05d2 100644 --- a/modules/kernel/include/internal/PointerBase.h +++ b/modules/kernel/include/internal/PointerBase.h @@ -2,7 +2,7 @@ * \file base/internal/PointerBase.h * \brief A nullptr-initialized pointer to an IMP ref-counted Object. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -14,6 +14,11 @@ #include "../warning_macros.h" #include "../hash.h" #include "../hash_macros.h" +#include "../Object.h" +#include +#include +#include +#include #if defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_NO_NULLPTR) #include @@ -23,6 +28,31 @@ #endif IMPKERNEL_BEGIN_INTERNAL_NAMESPACE + +#if !defined(IMP_DOXYGEN) && !defined(SWIG) +namespace { +template +typename std::enable_if::value, O*>::type +make_empty_object() { + return new O; +} + +template +typename std::enable_if::value, O*>::type +make_empty_object() { + IMP_THROW("Cannot load non-default-constructible object", TypeException); +} + +class PtrWrapper { + Object *o_; +public: + PtrWrapper(Object *o) : o_(o) {} + Object *get_object() { return o_; } +}; + +} // namespace +#endif + template struct RefCountedPointerTraits { typedef TT Type; @@ -78,21 +108,21 @@ struct GetPointer { template struct GetPointer >, - boost::mpl::not_ > > >::type> { + boost::mpl::not_::value>, + boost::mpl::not_::value> > >::type> { static O* get_pointer(const OO& o) { return o; } static const O* get_const_pointer(const OO& o) { return o; } }; template struct GetPointer >::type> { + typename boost::enable_if::value>::type> { static O* get_pointer(OO* o) { return o; } static const O* get_const_pointer(const OO* o) { return o; } }; template struct GetPointer >::type> { + typename boost::enable_if::value>::type> { static O* get_pointer(const OO& o) { IMP_INTERNAL_CHECK_VARIABLE(o) IMP_INTERNAL_CHECK(o == 0, "Non-zero pointer constant found."); @@ -105,9 +135,11 @@ struct GetPointer -struct GetPointer { - static O* get_pointer(const nullptr_t&) { return static_cast(nullptr); } - static const O* get_const_pointer(const nullptr_t&) { +struct GetPointer { + static O* get_pointer(const std::nullptr_t&) { + return static_cast(nullptr); + } + static const O* get_const_pointer(const std::nullptr_t&) { return static_cast(nullptr); } }; @@ -155,6 +187,89 @@ class PointerBase { struct UnusedClass {}; + friend class cereal::access; + + static void null_deleter(Object *) {} + + void serialize(cereal::BinaryOutputArchive &ar) { + O* rawptr = o_; + if (rawptr == nullptr) { + char ptr_type = 0; // null pointer + ar(ptr_type); + } else { +#if IMP_COMPILER_HAS_CEREAL_RAW_POINTER + uint32_t id = ar.registerSharedPointer(rawptr); +#else + // Recent cereal wants a shared_ptr instead of a null pointer, + // but we manage the storage for Object ourselves, so provide a null + // deleter. This will potentially make multiple shared_ptr objects + // pointing to the same Object*, but that's OK here because cereal only + // uses the underlying pointer anyway. + std::shared_ptr shared_rawptr(rawptr, null_deleter); + uint32_t id = ar.registerSharedPointer(shared_rawptr); +#endif + if (typeid(*rawptr) == typeid(O)) { + char ptr_type = 1; // non-polymorphic pointer + ar(ptr_type); + ar(id); + // only serialize if this is the first time we've seen this ID + if (id & cereal::detail::msb_32bit) { + ar(*rawptr); + } + } else { + char ptr_type = 2; // polymorphic pointer + ar(ptr_type); + ar(id); + // only serialize if this is the first time we've seen this ID + if (id & cereal::detail::msb_32bit) { + rawptr->poly_serialize(ar); + } + } + } + } + + void serialize(cereal::BinaryInputArchive &ar) { + char ptr_type; + uint32_t id; + ar(ptr_type); + if (ptr_type == 0) { // null pointer + set_pointer(nullptr); + } else { + ar(id); + if (ptr_type == 1) { // non-polymorphic pointer + // only deserialize if this is the first time we've seen this ID + if (id & cereal::detail::msb_32bit) { + std::unique_ptr ptr(make_empty_object()); + ar(*ptr); + auto ptr_wrapper = std::make_shared(ptr.get()); + set_pointer(ptr.release()); + ar.registerSharedPointer(id, ptr_wrapper); + } else { + set_pointer_from_id(id, ar); + } + } else { // polymorphic pointer + // only deserialize if this is the first time we've seen this ID + if (id & cereal::detail::msb_32bit) { + O* rawptr = dynamic_cast(Object::poly_unserialize(ar)); + IMP_INTERNAL_CHECK(rawptr != nullptr, "Wrong type returned"); + set_pointer(rawptr); + auto ptr_wrapper = std::make_shared(rawptr); + ar.registerSharedPointer(id, ptr_wrapper); + } else { + set_pointer_from_id(id, ar); + } + } + } + } + + void set_pointer_from_id(uint32_t id, cereal::BinaryInputArchive &ar) { + auto ptr_wrapper = std::static_pointer_cast( + ar.getSharedPointer(id)); + O* rawptr = dynamic_cast(ptr_wrapper->get_object()); + IMP_INTERNAL_CHECK(rawptr != nullptr, "Wrong type returned"); + set_pointer(rawptr); + } + public: //! initialize to nullptr PointerBase() : o_(nullptr) {} @@ -248,13 +363,10 @@ class PointerBase { } return *this; } -#if (defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_NO_NULLPTR)) && \ - !defined(nullptr) - PointerBase& operator=(nullptr_t) { + PointerBase& operator=(std::nullptr_t) { set_pointer(nullptr); return *this; } -#endif PointerBase& operator=(const PointerBase& o) { set_pointer(o.o_); return *this; @@ -284,12 +396,8 @@ inline void swap(PointerBase& a, PointerBase& b) { a.swap_with(b); } -#if IMP_COMPILER_HAS_THREE_WAY -template -inline std::strong_ordering operator<=>(OT* o, const PointerBase& p) { - return p <=> o; -} -#else +// Reversed operators are not needed in C++20 +#ifndef IMP_COMPILER_HAS_THREE_WAY template inline bool operator==(OT* o, const PointerBase& p) { return p == o; diff --git a/modules/kernel/include/internal/RestraintsScoringFunction.h b/modules/kernel/include/internal/RestraintsScoringFunction.h index 5bf57d4cb0..6de61e34c6 100644 --- a/modules/kernel/include/internal/RestraintsScoringFunction.h +++ b/modules/kernel/include/internal/RestraintsScoringFunction.h @@ -14,6 +14,8 @@ #include "../container_macros.h" #include "restraint_evaluation.h" #include "container_helpers.h" +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -28,6 +30,12 @@ class GenericRestraintsScoringFunction : public ScoringFunction { double max_; Storage restraints_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), weight_, max_, restraints_); + } + protected: GenericRestraintsScoringFunction(Model *m, double weight = 1.0, double max = NO_MAX, @@ -45,6 +53,8 @@ class GenericRestraintsScoringFunction : public ScoringFunction { max_(max), restraints_(rs.begin(), rs.end()) {} + GenericRestraintsScoringFunction() {} + void do_add_score_and_derivatives(IMP::ScoreAccumulator sa, const ScoreStatesTemp &ss) override { IMP_OBJECT_LOG; @@ -68,11 +78,66 @@ class GenericRestraintsScoringFunction : public ScoringFunction { return Restraints(1, rs); } ModelObjectsTemp do_get_inputs() const override { return restraints_; } + + /* Provide methods to get/set the restraints in this scoring function. + Note that we can't use the IMP_LIST macro here since this class + is templated. */ const Storage &get_restraints() const { return restraints_; } + void set_restraints(const RestraintsTemp &s) { set_has_dependencies(false); restraints_ = s; } + + unsigned int get_number_of_restraints() const { + return restraints_.size(); + } + + void clear_restraints() { + set_has_dependencies(false); + restraints_.clear(); + } + + Restraint *get_restraint(unsigned int i) const { + return restraints_[i]; + } + + void erase_restraint(unsigned int i) { + set_has_dependencies(false); + restraints_.erase(restraints_.begin() + i); + } + + unsigned int add_restraint(Restraint *r) { + set_has_dependencies(false); + unsigned int index = restraints_.size(); + restraints_.push_back(r); + return index; + } + + void add_restraints(const Storage &r) { + set_has_dependencies(false); + restraints_.insert(restraints_.end(), r.begin(), r.end()); + } + + unsigned int _python_index_restraint(Restraint *r, unsigned int start, + unsigned int stop) { + bool found = false; + unsigned int num_of = get_number_of_restraints(); + start = std::min(start, num_of); + stop = std::min(stop, num_of); + unsigned int indx = start; + for (auto it = restraints_.begin() + start; indx < stop; ++it, ++indx) { + if (*it == r) { + found = true; + break; + } + } + if (!found) { + IMP_THROW(r << " is not in list", ValueException); + } + return indx; + } + IMP_OBJECT_METHODS(GenericRestraintsScoringFunction); }; diff --git a/modules/kernel/include/internal/SimpleTimer.h b/modules/kernel/include/internal/SimpleTimer.h new file mode 100644 index 0000000000..dfee6fc026 --- /dev/null +++ b/modules/kernel/include/internal/SimpleTimer.h @@ -0,0 +1,37 @@ +/** + * \file internal/SimpleTimer.h + * \brief Simple subsecond timer for benchmarking or logging + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + */ + +#ifndef IMPKERNEL_INTERNAL_SIMPLE_TIMER_H +#define IMPKERNEL_INTERNAL_SIMPLE_TIMER_H + +#include +#include + +IMPKERNEL_BEGIN_INTERNAL_NAMESPACE + +class SimpleTimer { + std::chrono::steady_clock::time_point start_time_; +public: + SimpleTimer() { + restart(); + } + + void restart() { + start_time_ = std::chrono::steady_clock::now(); + } + + double elapsed() const { + auto end_time = std::chrono::steady_clock::now(); + auto time_span = std::chrono::duration_cast< + std::chrono::duration >(end_time - start_time_); + return time_span.count(); + } +}; + +IMPKERNEL_END_INTERNAL_NAMESPACE + +#endif /* IMPKERNEL_INTERNAL_SIMPLE_TIMER_H */ diff --git a/modules/kernel/include/internal/StaticListContainer.h b/modules/kernel/include/internal/StaticListContainer.h index 05a397f2df..f105a4b33e 100644 --- a/modules/kernel/include/internal/StaticListContainer.h +++ b/modules/kernel/include/internal/StaticListContainer.h @@ -3,7 +3,7 @@ * * BLURB * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPKERNEL_INTERNAL_STATIC_LIST_CONTAINER_H @@ -13,6 +13,8 @@ #include "ListLikeContainer.h" #include "container_helpers.h" #include +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -20,8 +22,16 @@ template class StaticListContainer : public ListLikeContainer { typedef ListLikeContainer P; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); + } + IMP_OBJECT_SERIALIZE_DECL(StaticListContainer); + public: StaticListContainer(Model *m, std::string name) : P(m, name) {} + StaticListContainer() {} void add(typename Base::PassContainedIndexType vt) { Base::set_has_dependencies(false); typename Base::ContainedIndexTypes cur; diff --git a/modules/kernel/include/internal/TupleConstraint.h b/modules/kernel/include/internal/TupleConstraint.h index 014bf4fe1f..d7b779b8e4 100644 --- a/modules/kernel/include/internal/TupleConstraint.h +++ b/modules/kernel/include/internal/TupleConstraint.h @@ -12,6 +12,8 @@ #include "../Constraint.h" #include "container_helpers.h" #include +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -21,17 +23,19 @@ class TupleConstraint : public Constraint { IMP::PointerMember af_; typename Before::IndexArgument v_; - public: - TupleConstraint(Before *before, After *after, - const typename Before::Argument &vt, - std::string name = "TupleConstraint %1%", - bool can_skip=false); + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), f_, af_, v_); + } + public: TupleConstraint(Before *before, After *after, Model *m, const typename Before::IndexArgument &vt, std::string name = "TupleConstraint %1%", bool can_skip=false); + TupleConstraint() {} + //! Apply this modifier to all the elements after an evaluate void set_after_evaluate_modifier(After *f) { af_ = f; } @@ -51,16 +55,6 @@ class TupleConstraint : public Constraint { ; }; -template -TupleConstraint::TupleConstraint( - Before *before, After *after, const typename Before::Argument &vt, - std::string name, bool can_skip) - : Constraint(internal::get_model(vt), name), v_(get_index(vt)) { - if (before) f_ = before; - if (after) af_ = after; - set_can_skip(can_skip); -} - template TupleConstraint::TupleConstraint( Before *before, After *after, Model *m, @@ -121,7 +115,8 @@ inline Constraint *create_tuple_constraint(Before *b, After *a, if (b) name += " and " + b->get_name(); if (a) name += " and " + a->get_name(); } - return new internal::TupleConstraint(b, a, t, name, can_skip); + return new internal::TupleConstraint( + b, a, internal::get_model(t), get_index(t), name, can_skip); } #ifndef IMP_DOXYGEN diff --git a/modules/kernel/include/internal/TupleRestraint.h b/modules/kernel/include/internal/TupleRestraint.h index b8515be971..7632324757 100644 --- a/modules/kernel/include/internal/TupleRestraint.h +++ b/modules/kernel/include/internal/TupleRestraint.h @@ -14,6 +14,8 @@ #include "container_helpers.h" #include #include "../constants.h" +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -22,6 +24,12 @@ class TupleRestraint : public Restraint { IMP::PointerMember ss_; typename Score::IndexArgument v_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), ss_, v_); + } + public: //! Create the restraint. /** This function takes the function to apply to the @@ -29,6 +37,7 @@ class TupleRestraint : public Restraint { */ TupleRestraint(Score *ss, Model *m, const typename Score::IndexArgument &vt, std::string name = "TupleRestraint %1%"); + TupleRestraint() {} Score *get_score() const { return ss_; } typename Score::Argument get_argument() const { diff --git a/modules/kernel/include/internal/attribute_tables.h b/modules/kernel/include/internal/attribute_tables.h index 4adb7945ec..7aa742743b 100644 --- a/modules/kernel/include/internal/attribute_tables.h +++ b/modules/kernel/include/internal/attribute_tables.h @@ -11,10 +11,12 @@ #include #include +#include #include "../Key.h" #include "../utility.h" #include "../FloatIndex.h" #include "input_output_exception.h" +#include "KeyVector.h" #include #include #include @@ -70,12 +72,19 @@ class BasicAttributeTable { typedef typename Traits::Key Key; private: - Vector data_; + KeyVector data_; #if IMP_HAS_CHECKS >= IMP_INTERNAL Mask *read_mask_, *write_mask_, *add_remove_mask_; #endif IMP_KERNEL_SMALL_UNORDERED_SET caches_; + friend class cereal::access; + + template void serialize(Archive &ar) { + // Note that we don't serialize masks; they are handled by Model + ar(caches_, data_); + } + void do_add_attribute(Key k, ParticleIndex particle, typename Traits::PassValue value) { IMP_USAGE_CHECK(Traits::get_is_valid(value), @@ -289,6 +298,15 @@ class FloatAttributeTable { Mask *read_mask_, *write_mask_, *add_remove_mask_, *read_derivatives_mask_, *write_derivatives_mask_; #endif + + friend class cereal::access; + + template void serialize(Archive &ar) { + // Note that we don't serialize masks; they are handled by Model + ar(spheres_, sphere_derivatives_, internal_coordinates_); + ar(internal_coordinate_derivatives_, data_, derivatives_, optimizeds_); + } + algebra::Sphere3D get_invalid_sphere() const { double iv = internal::FloatAttributeTableTraits::get_invalid(); algebra::Sphere3D ivs(algebra::Vector3D(iv, iv, iv), iv); diff --git a/modules/kernel/include/internal/base_graph_utility.h b/modules/kernel/include/internal/base_graph_utility.h index 196b508a45..e95395efb3 100644 --- a/modules/kernel/include/internal/base_graph_utility.h +++ b/modules/kernel/include/internal/base_graph_utility.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ using boost::mpl::and_; using boost::mpl::not_; using boost::is_convertible; using boost::is_base_of; -using boost::is_pointer; +using std::is_pointer; template class ObjectNameWriter { diff --git a/modules/kernel/include/internal/input_output_exception.h b/modules/kernel/include/internal/input_output_exception.h index 30a3577f90..13fc80b3c8 100644 --- a/modules/kernel/include/internal/input_output_exception.h +++ b/modules/kernel/include/internal/input_output_exception.h @@ -24,7 +24,7 @@ struct IMPKERNELEXPORT InputOutputException : public std::runtime_error { InputOutputException(int particle_index, int operation, int entity, std::string key_name); InputOutputException(std::string container_name, int entity); - ~InputOutputException() IMP_NOEXCEPT; + ~InputOutputException() noexcept; enum AccessEntity { NO_ENTITY, ATTRIBUTE, diff --git a/modules/kernel/include/internal/log_stream.h b/modules/kernel/include/internal/log_stream.h index bec7a165fa..c0af5891be 100644 --- a/modules/kernel/include/internal/log_stream.h +++ b/modules/kernel/include/internal/log_stream.h @@ -13,17 +13,17 @@ #include "../file.h" #include "base_static.h" +#include "SimpleTimer.h" #include #include #include #include #include -#include IMPKERNEL_BEGIN_NAMESPACE namespace internal { -IMPKERNELEXPORT extern boost::timer log_timer; +IMPKERNELEXPORT extern SimpleTimer log_timer; class LogStream : public boost::iostreams::filtering_stream, diff --git a/modules/kernel/include/internal/swig.h b/modules/kernel/include/internal/swig.h index 029eaa8c0b..338b8ea582 100644 --- a/modules/kernel/include/internal/swig.h +++ b/modules/kernel/include/internal/swig.h @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -28,15 +31,21 @@ IMPKERNEL_BEGIN_INTERNAL_NAMESPACE // probably not legal C++, but for python class IMPKERNELEXPORT _ConstRestraint : public Restraint { double v_; - const ParticlesTemp ps_; + ParticleIndexes pis_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), v_, pis_); + } + + IMP_OBJECT_SERIALIZE_DECL(_ConstRestraint); public: - _ConstRestraint(double v, const ParticlesTemp ps) - : Restraint(internal::get_model(ps), "ConstRestraint%1%"), - v_(v), - ps_(ps) {} _ConstRestraint(Model *m, const ParticleIndexes &pis, double v) - : Restraint(m, "ConstRestraint%1%"), v_(v), ps_(get_particles(m, pis)) {} + : Restraint(m, "ConstRestraint%1%"), v_(v), pis_(pis) {} + _ConstRestraint() {} + double get_value() const { return v_; } Restraints do_create_decomposition() const override; double unprotected_evaluate(IMP::DerivativeAccumulator *accum) const @@ -50,8 +59,15 @@ IMP_OBJECTS(_ConstRestraint, _ConstRestraints); class _ConstSingletonScore : public SingletonScore { double v_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), v_); + } + IMP_OBJECT_SERIALIZE_DECL(_ConstSingletonScore); + public: _ConstSingletonScore(double v) : v_(v) {} + _ConstSingletonScore() {} virtual double evaluate_index(Model *, ParticleIndex, DerivativeAccumulator *) const override { return v_; @@ -68,8 +84,15 @@ IMP_OBJECTS(_ConstSingletonScore, _ConstSingletonScores); class IMPKERNELEXPORT _ConstPairScore : public PairScore { double v_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), v_); + } + IMP_OBJECT_SERIALIZE_DECL(_ConstPairScore); + public: _ConstPairScore(double v) : v_(v) {} + _ConstPairScore() {} virtual double evaluate_index(Model *, const ParticleIndexPair &, DerivativeAccumulator *) const override { return v_; @@ -127,8 +150,15 @@ IMP_DECORATORS_WITH_TRAITS(_TrivialTraitsDecorator, _TrivialTraitsDecorators, Particles); class IMPKERNELEXPORT _ConstOptimizer : public Optimizer { + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + public: _ConstOptimizer(Model *m) : Optimizer(m, "ConstOptimizer%1%") {} + _ConstOptimizer() {} virtual Float do_optimize(unsigned int max_steps) override; IMP_OBJECT_METHODS(_ConstOptimizer); }; diff --git a/modules/kernel/include/internal/swig_base.h b/modules/kernel/include/internal/swig_base.h index f39234a74a..36cf8befd7 100644 --- a/modules/kernel/include/internal/swig_base.h +++ b/modules/kernel/include/internal/swig_base.h @@ -18,6 +18,9 @@ #include "../tuple_macros.h" #include #include +#include +#include +#include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -241,6 +244,12 @@ IMPKERNELEXPORT IntsLists _pass_ints_lists(const IntsLists &input); IMPKERNELEXPORT const Strings &_pass_strings(const Strings &input); class _TestObject : public Object { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(_TestObject); + public: _TestObject() : Object("TestObject%1%") {} IMP_OBJECT_METHODS(_TestObject); diff --git a/modules/kernel/include/internal/swig_helpers.h b/modules/kernel/include/internal/swig_helpers.h index 2b0914b766..bdb21e29e8 100644 --- a/modules/kernel/include/internal/swig_helpers.h +++ b/modules/kernel/include/internal/swig_helpers.h @@ -174,7 +174,7 @@ struct Convert< return ConvertValueBase::get_cpp_object(o, symname, argnum, argtype, st, particle_st, decorator_st); } - catch (ValueException) { + catch (ValueException &) { Particle *p = Convert::get_cpp_object( o, symname, argnum, argtype, particle_st, particle_st, decorator_st); if (!T::get_is_setup(p)) { diff --git a/modules/kernel/include/internal/swig_helpers_base.h b/modules/kernel/include/internal/swig_helpers_base.h index 63badf3db1..9ec5f9595a 100644 --- a/modules/kernel/include/internal/swig_helpers_base.h +++ b/modules/kernel/include/internal/swig_helpers_base.h @@ -21,6 +21,8 @@ #include #if IMP_KERNEL_HAS_NUMPY +// Silence warnings about old NumPy API +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include // This should be defined in the including module's SWIG wrapper extern int numpy_import_retval; @@ -211,7 +213,7 @@ inline std::string get_convert_error(const char *err, const char *symname, template struct ConvertAllBase { - BOOST_STATIC_ASSERT(!boost::is_pointer::value); + BOOST_STATIC_ASSERT(!std::is_pointer::value); template static bool get_is_cpp_object(PyObject* o, SwigData st, SwigData, SwigData) { void* vp; @@ -222,7 +224,7 @@ struct ConvertAllBase { template struct ConvertValueBase : public ConvertAllBase { - BOOST_STATIC_ASSERT(!boost::is_pointer::value); + BOOST_STATIC_ASSERT(!std::is_pointer::value); BOOST_STATIC_ASSERT(!(boost::is_base_of::value)); template static const T& get_cpp_object(PyObject* o, const char *symname, int argnum, @@ -250,7 +252,7 @@ struct ConvertValueBase : public ConvertAllBase { // T should not be a pointer to the object template struct ConvertObjectBase : public ConvertAllBase { - BOOST_STATIC_ASSERT(!boost::is_pointer::value); + BOOST_STATIC_ASSERT(!std::is_pointer::value); BOOST_STATIC_ASSERT((boost::is_base_of::value) || (boost::is_same::value)); template @@ -283,7 +285,7 @@ struct ConvertObjectBase : public ConvertAllBase { // T should not be a pointer to the object template struct ConvertRAII : public ConvertAllBase { - BOOST_STATIC_ASSERT(!boost::is_pointer::value); + BOOST_STATIC_ASSERT(!std::is_pointer::value); template static T* get_cpp_object(PyObject* o, const char *symname, int argnum, const char *argtype, SwigData st, SwigData, @@ -355,7 +357,7 @@ struct Convert struct ConvertSequenceHelper { typedef typename ValueOrObject::type V; - BOOST_STATIC_ASSERT(!boost::is_pointer::value); + BOOST_STATIC_ASSERT(!std::is_pointer::value); template static bool get_is_cpp_object(PyObject* in, SwigData st, SwigData particle_st, SwigData decorator_st) { @@ -399,7 +401,7 @@ struct ConvertSequence {}; template struct ConvertSequence, ConvertT> { static const int converter = 6; - typedef boost::array Intermediate; + typedef std::array Intermediate; typedef ConvertSequenceHelper Helper; typedef typename ValueOrObject::type VT; template @@ -573,7 +575,8 @@ struct ConvertSequence : public ConvertVectorBase< PyReceivePointer ret(PyArray_SimpleNew(1, dims, NPY_INT)); if (t.size() > 0) { PyObject *obj = ret; - memcpy(PyArray_DATA(obj), &t[0], t.size() * sizeof(int)); + memcpy(PyArray_DATA((PyArrayObject*)obj), &t[0], + t.size() * sizeof(int)); } return ret.release(); } else { @@ -619,7 +622,8 @@ struct ConvertSequence : public ConvertVectorBase< PyReceivePointer ret(PyArray_SimpleNew(1, dims, NPY_DOUBLE)); if (t.size() > 0) { PyObject *obj = ret; - memcpy(PyArray_DATA(obj), &t[0], t.size() * sizeof(double)); + memcpy(PyArray_DATA((PyArrayObject*)obj), + &t[0], t.size() * sizeof(double)); } return ret.release(); } else { @@ -672,7 +676,8 @@ struct ConvertSequence : public ConvertVectorBase< PyReceivePointer ret(PyArray_SimpleNew(1, dims, NPY_INT)); if (t.size() > 0) { PyObject *obj = ret; - memcpy(PyArray_DATA(obj), &t[0], t.size() * sizeof(int)); + memcpy(PyArray_DATA((PyArrayObject*)obj), + &t[0], t.size() * sizeof(int)); } return ret.release(); } else { @@ -689,8 +694,8 @@ static IndexArray create_index_array_cpp(PyObject *o) { IndexArray arr(sz); if (sz > 0) { - char *data = (char *)PyArray_DATA(o); - for (size_t i = 0; i < sz; ++i) { + char *data = (char *)PyArray_DATA(a); + for (npy_intp i = 0; i < sz; ++i) { memcpy(arr[i].data(), data + i * D * sizeof(int), sizeof(int) * D); } } @@ -706,7 +711,7 @@ static PyObject* create_index_array_numpy(const IndexArray &t) { PyReceivePointer ret(PyArray_SimpleNew(2, dims, NPY_INT)); if (t.size() > 0) { PyObject *obj = ret; - char *data = (char *)PyArray_DATA(obj); + char *data = (char *)PyArray_DATA((PyArrayObject*)obj); for (size_t i = 0; i < t.size(); ++i) { memcpy(data + i * D * sizeof(int), t[i].data(), sizeof(int) * D); } diff --git a/modules/kernel/include/internal/utility.h b/modules/kernel/include/internal/utility.h index bab3b86d4b..9e44cb3b01 100644 --- a/modules/kernel/include/internal/utility.h +++ b/modules/kernel/include/internal/utility.h @@ -13,6 +13,12 @@ #include #include #include +#include +#include +#ifndef _MSC_VER +#include +#include +#endif IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -95,6 +101,19 @@ struct SFResetBitset { IMPKERNELEXPORT void show_dg_node(ModelObject *mo, TextOutput to); +//! Transform a C++ ABI ID (from typeid) to C++ source identifier +inline std::string demangle_cxx(std::string const &name) { +#ifdef _MSC_VER + return name; +#else // clang or gcc + int status; + char *realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status); + std::string dname(realname); + free(realname); + return dname; +#endif +} + IMPKERNEL_END_INTERNAL_NAMESPACE #endif /* IMPKERNEL_INTERNAL_UTILITY_H */ diff --git a/modules/kernel/include/nullptr.h b/modules/kernel/include/nullptr.h deleted file mode 100644 index b2c5119e43..0000000000 --- a/modules/kernel/include/nullptr.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * \file IMP/nullptr.h - * \brief Provide a nullptr keyword analog. - * - * Copyright 2007-2022 IMP Inventors. All rights reserved. - */ - -#ifndef IMPKERNEL_NULLPTR_H -#define IMPKERNEL_NULLPTR_H - -#include - -#ifndef IMP_SWIG_WRAPPER -IMPKERNEL_DEPRECATED_HEADER( - 2.17, "Use the nullptr keyword or std::nullptr_t type directly"); -#endif -// Does nothing: the nullptr keyword should now be available on all -// supported IMP build platforms - -#endif /* IMPKERNEL_NULLPTR_H */ diff --git a/modules/kernel/include/nullptr_macros.h b/modules/kernel/include/nullptr_macros.h deleted file mode 100644 index d298fc438a..0000000000 --- a/modules/kernel/include/nullptr_macros.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * \file IMP/nullptr_macros.h - * \brief Provide a nullptr keyword analog. - * - * Copyright 2007-2022 IMP Inventors. All rights reserved. - */ - -#ifndef IMPKERNEL_NULLPTR_MACROS_H -#define IMPKERNEL_NULLPTR_MACROS_H - -#include - -#ifndef IMP_SWIG_WRAPPER -IMPKERNEL_DEPRECATED_HEADER( - 2.17, "Use the nullptr keyword or std::nullptr_t type directly"); -#endif - -#define IMP_NULLPTR nullptr -#define IMP_NULLPTR_T std::nullptr_t - -#endif /* IMPKERNEL_NULLPTR_MACROS_H */ diff --git a/modules/kernel/include/object_macros.h b/modules/kernel/include/object_macros.h index 58517c00cf..f5fa513eb5 100644 --- a/modules/kernel/include/object_macros.h +++ b/modules/kernel/include/object_macros.h @@ -20,7 +20,7 @@ /** This defines - IMP::Object::get_version_info() - IMP::Object::get_type_name() - - a protected destructor + - a virtual destructor */ #define IMP_OBJECT_METHODS(Name) \ public: \ @@ -29,7 +29,7 @@ return ::IMP::VersionInfo(get_module_name(), get_module_version()); \ } \ \ - protected: \ + public: \ virtual ~Name() { IMP::Object::_on_destruction(); } \ \ public: @@ -49,12 +49,12 @@ //! Typedefs a default instantiation for a generic (templated) object /** - Define type [Name] to be an an instantiation of of Generic[Name] with + Define type [Name] to be an instantiation of Generic[Name] with template targument, and a function create_[lcname]() that generates a - newly allocated object of type [Name], taking parameters [crguments] + newly allocated object of type [Name], taking parameters [carguments] and internally paassing [cparguments] to the constructor. - @note doxygen documentatio prior to this macro will be applied to the type + @note doxygen documentation prior to this macro will be applied to the type definition */ #define IMP_GENERIC_OBJECT(Name, lcname, targument, carguments, cparguments) \ @@ -74,4 +74,45 @@ #define IMP_NEW(Typename, varname, args) \ IMP::Pointer varname(new Typename args) +//! Declare methods needed for serialization of Object pointers +/** When an Object subclass is serialized via an IMP::Pointer, the + serialization subsystem needs to know the most derived type so that + the full information is saved/loaded. This macro ensures that the + necessary machinery is added, and should be placed in the header file + inside the declaration of the Object subclass. + It is similar to cereal's CEREAL_REGISTER_TYPE macro, but stores the + type information in precisely one place (the IMP::Object class) rather + than relying on the linker to keep this information unique, as cereal + attempts to do. + + This macro needs to be paired with IMP_OBJECT_SERIALIZE_IMPL, which is + usually placed in the corresponding .cpp file for the class. + + \see IMP_OBJECT_SERIALIZE_IMPL + + \param[in] Name The name of the class. + */ +#define IMP_OBJECT_SERIALIZE_DECL(Name) \ +private: \ + static bool dummy_serialize_init_; \ + static void save_cereal(Object *o, cereal::BinaryOutputArchive &ar) { \ + Name *cast = dynamic_cast(o); \ + if (!cast) { std::cerr << "bad cast" << std::endl; } \ + ar(*cast); \ + } \ + static Object *load_cereal(cereal::BinaryInputArchive &ar) { \ + std::unique_ptr p(new Name()); \ + ar(*p); \ + return p.release(); \ + } + +//! Add machinery needed for serialization of Object pointers +/** \see IMP_OBJECT_SERIALIZE_DECL + + \param[in] Name The fully-qualified name of the class. + */ +#define IMP_OBJECT_SERIALIZE_IMPL(Name) \ +bool Name::dummy_serialize_init_ = Object::register_serialize( \ + typeid(Name), #Name, Name::save_cereal, Name::load_cereal); + #endif /* IMPKERNEL_OBJECT_MACROS_H */ diff --git a/modules/kernel/include/particle_index.h b/modules/kernel/include/particle_index.h index 53703b4a7e..fe4e21883e 100644 --- a/modules/kernel/include/particle_index.h +++ b/modules/kernel/include/particle_index.h @@ -11,7 +11,7 @@ #include #include "base_types.h" -#include +#include IMPKERNEL_BEGIN_NAMESPACE @@ -48,7 +48,7 @@ class IMPKERNELEXPORT ParticleIndexAdaptor //! Take Decorator, Particle or ParticleIndex. class IMPKERNELEXPORT ParticleIndexesAdaptor : public InputAdaptor { - boost::shared_ptr tmp_; + std::shared_ptr tmp_; const ParticleIndexes *val_; public: diff --git a/modules/kernel/include/random.h b/modules/kernel/include/random.h index ad47561c91..367b34475f 100644 --- a/modules/kernel/include/random.h +++ b/modules/kernel/include/random.h @@ -10,14 +10,14 @@ #include #include -#include +#include IMPKERNEL_BEGIN_NAMESPACE #ifndef SWIG // the RNG is defined explicitly in pyext/IMP_kernel.random.i -class RandomNumberGenerator : public ::boost::mt19937 { - typedef ::boost::mt19937 T; +class RandomNumberGenerator : public std::mt19937 { + typedef std::mt19937 T; T::result_type last_seed_; unsigned seed_counter_; diff --git a/modules/kernel/include/ref_counted_macros.h b/modules/kernel/include/ref_counted_macros.h index 488f246ac3..87262f4486 100644 --- a/modules/kernel/include/ref_counted_macros.h +++ b/modules/kernel/include/ref_counted_macros.h @@ -11,49 +11,14 @@ #include #include "utility_macros.h" -#ifdef _MSC_VER -// VC doesn't understand friends properly -#define IMP_REF_COUNTED_DESTRUCTOR(Name) \ - public: \ - virtual ~Name() {} \ - IMP_REQUIRE_SEMICOLON_CLASS(destructor) - -#define IMP_REF_COUNTED_INLINE_DESTRUCTOR(Name, dest) \ - public: \ - virtual ~Name() { dest } \ - IMP_REQUIRE_SEMICOLON_CLASS(destructor) - -#define IMP_REF_COUNTED_NONTRIVIAL_DESTRUCTOR(Name) \ - public: \ - virtual ~Name() - -#elif defined(SWIG) -// SWIG doesn't do friends right either, but we don't care as much -#define IMP_REF_COUNTED_DESTRUCTOR(Name) \ - public: \ - virtual ~Name() {} \ - IMP_REQUIRE_SEMICOLON_CLASS(destructor) - -#define IMP_REF_COUNTED_INLINE_DESTRUCTOR(Name, dest) \ - public: \ - virtual ~Name() { dest } \ - IMP_REQUIRE_SEMICOLON_CLASS(destructor) - -#define IMP_REF_COUNTED_NONTRIVIAL_DESTRUCTOR(Name) \ - public: \ - virtual ~Name() - -#elif defined(IMP_DOXYGEN) -/* The destructor is unprotected for SWIG since if it is protected - SWIG does not wrap the Python proxy destruction and so does not - dereference the ref counted pointer. SWIG also gets confused - on template friends. -*/ -//! Ref counted objects should have private destructors -/** This macro defines a private destructor and adds the appropriate - friend methods so that the class can be used with ref counting. - By defining a private destructor, you make it so that the object - cannot be declared on the stack and so must be ref counted. +#if defined(IMP_DOXYGEN) +//! Set up destructor for a ref counted object +/** This macro defines a virtual destructor for a ref counted object. + Ideally, the destructor would be defined private, so that the object + cannot be declared on the stack and so must be ref counted, but in + practice this breaks usage of the object with SWIG, some older compilers, + C++11 smart pointers (e.g. std::unique_ptr, std::shared_ptr), and + serialization, so a public destructor is used. \see IMP_REF_COUNTED_NONTRIVIAL_DESTRUCTOR() */ @@ -71,24 +36,18 @@ #else #define IMP_REF_COUNTED_DESTRUCTOR(Name) \ - protected: \ - virtual ~Name() {} \ - \ public: \ + virtual ~Name() {} \ IMP_REQUIRE_SEMICOLON_CLASS(destructor) #define IMP_REF_COUNTED_INLINE_DESTRUCTOR(Name, dest) \ - protected: \ - virtual ~Name() { dest } \ - \ public: \ + virtual ~Name() { dest } \ IMP_REQUIRE_SEMICOLON_CLASS(destructor) #define IMP_REF_COUNTED_NONTRIVIAL_DESTRUCTOR(Name) \ - protected: \ - virtual ~Name(); \ - \ public: \ + virtual ~Name(); \ IMP_REQUIRE_SEMICOLON_CLASS(destructor) #endif diff --git a/modules/kernel/include/set_map_macros.h b/modules/kernel/include/set_map_macros.h index e239966096..df95dc5d4b 100644 --- a/modules/kernel/include/set_map_macros.h +++ b/modules/kernel/include/set_map_macros.h @@ -67,10 +67,43 @@ #else #include // IWYU pragma: export #include // IWYU pragma: export +#include #define IMP_KERNEL_SMALL_ORDERED_SET boost::container::flat_set #define IMP_KERNEL_SMALL_ORDERED_MAP boost::container::flat_map #define IMP_KERNEL_SMALL_UNORDERED_SET boost::container::flat_set #define IMP_KERNEL_SMALL_UNORDERED_MAP boost::container::flat_map + +// Allow serialization of boost::container::flat_set +namespace cereal { + template + inline void save(Archive &ar, + boost::container::flat_set const &t) { + auto count = t.size(); + ar(count); + typename boost::container::flat_set< + Key, Compare, Allocator>::const_iterator it = t.begin(); + while(count-- > 0) { + ar(*it++); + } + } + + template + inline void load(Archive &ar, + boost::container::flat_set &t) { + typedef typename boost::container::flat_set::iterator iterator; + typedef typename boost::container::flat_set::value_type value_type; + t.clear(); + typename boost::container::flat_set::size_type count; + ar(count); + iterator hint = t.begin(); + while(count-- > 0) { + value_type key; + ar(key); + hint = t.insert(hint, key); + } + } +} + #endif #endif diff --git a/modules/kernel/include/utility_macros.h b/modules/kernel/include/utility_macros.h index a8d5edf760..3696af7868 100644 --- a/modules/kernel/include/utility_macros.h +++ b/modules/kernel/include/utility_macros.h @@ -31,20 +31,4 @@ #define IMP_EXPAND_AND_STRINGIFY(x) IMP_STRINGIFY(x) -#ifdef IMP_DOXYGEN -//! Smart pointer to retain sole ownership of an object through a pointer -/** In C++11 mode, this is std::unique_ptr; otherwise, it is std::auto_ptr. - Note that these two classes do not have exactly the same interfaces, so - you must be careful to use IMP_UNIQUE_PTR only in cases where the two - classes behave in the same way (e.g. you cannot copy a unique_ptr, but - you can copy an auto_ptr; unique_ptr works with arrays and can - be stored in STL containers, unlike auto_ptr). - */ -#define IMP_UNIQUE_PTR -#else -#define IMP_UNIQUE_PTR \ - IMPKERNEL_DEPRECATED_MACRO(2.17, "Use std::unique_ptr instead."); \ - std::unique_ptr -#endif - #endif /* IMPKERNEL_UTILITY_MACROS_H */ diff --git a/modules/kernel/pyext/IMP_kernel.dispatcher.i b/modules/kernel/pyext/IMP_kernel.dispatcher.i index 4627ce2668..06878482d9 100644 --- a/modules/kernel/pyext/IMP_kernel.dispatcher.i +++ b/modules/kernel/pyext/IMP_kernel.dispatcher.i @@ -82,12 +82,12 @@ class CommandDispatcher(object): print(self.long_help + """ This program is part of IMP, the Integrative Modeling Platform, -which is Copyright 2007-2022 IMP Inventors. +which is %s. For additional information about IMP, see . Usage: %s [options] [args] -Commands:""" % self._progname) +Commands:""" % (get_copyright(), self._progname)) commands = self._all_commands[:] + ['help'] commands.sort() cmdlen = max([len(c) for c in commands]) diff --git a/modules/kernel/pyext/IMP_kernel.numpy.i b/modules/kernel/pyext/IMP_kernel.numpy.i index a73bea0a04..c8370899d4 100644 --- a/modules/kernel/pyext/IMP_kernel.numpy.i +++ b/modules/kernel/pyext/IMP_kernel.numpy.i @@ -15,7 +15,7 @@ PyObject *_get_floats_data_numpy(PyObject *m_pyobj, unsigned sz, double *data) /* Note that attribute tables are C-style contiguous so no special strides or other flags need to be passed to NumPy */ PyObject *obj = PyArray_New(&PyArray_Type, 1, dims, NPY_DOUBLE, NULL, - data, 0, NPY_WRITEABLE, NULL); + data, 0, NPY_ARRAY_WRITEABLE, NULL); if (!obj) { return NULL; } @@ -23,7 +23,11 @@ PyObject *_get_floats_data_numpy(PyObject *m_pyobj, unsigned sz, double *data) /* Ensure that the Model is kept around as long as the numpy object is alive. */ Py_INCREF(m_pyobj); - PyArray_BASE(obj) = m_pyobj; + if (PyArray_SetBaseObject((PyArrayObject *)obj, m_pyobj) != 0) { + Py_DECREF(m_pyobj); + Py_DECREF(obj); + return NULL; + } return obj; #else @@ -46,7 +50,7 @@ PyObject *_get_ints_data_numpy(PyObject *m_pyobj, unsigned sz, int *data) /* Note that attribute tables are C-style contiguous so no special strides or other flags need to be passed to NumPy */ PyObject *obj = PyArray_New(&PyArray_Type, 1, dims, NPY_INT32, NULL, - data, 0, NPY_WRITEABLE, NULL); + data, 0, NPY_ARRAY_WRITEABLE, NULL); if (!obj) { return NULL; } @@ -54,7 +58,11 @@ PyObject *_get_ints_data_numpy(PyObject *m_pyobj, unsigned sz, int *data) /* Ensure that the Model is kept around as long as the numpy object is alive. */ Py_INCREF(m_pyobj); - PyArray_BASE(obj) = m_pyobj; + if (PyArray_SetBaseObject((PyArrayObject *)obj, m_pyobj) != 0) { + Py_DECREF(m_pyobj); + Py_DECREF(obj); + return NULL; + } return obj; #else @@ -70,7 +78,7 @@ PyObject *_add_spheres_component(void *data, int nd, npy_intp *dims, PyObject *tuple, Py_ssize_t pos) { PyObject *obj = PyArray_New(&PyArray_Type, nd, dims, NPY_DOUBLE, strides, - data, 0, NPY_WRITEABLE, NULL); + data, 0, NPY_ARRAY_WRITEABLE, NULL); if (!obj) { Py_DECREF(tuple); return NULL; @@ -80,7 +88,12 @@ PyObject *_add_spheres_component(void *data, int nd, npy_intp *dims, /* Ensure that the Model is kept around as long as the numpy object is alive. */ Py_INCREF(m_pyobj); - PyArray_BASE(obj) = m_pyobj; + if (PyArray_SetBaseObject((PyArrayObject *)obj, m_pyobj) != 0) { + Py_DECREF(m_pyobj); + Py_DECREF(obj); + Py_DECREF(tuple); + return NULL; + } return obj; } else { Py_DECREF(obj); diff --git a/modules/kernel/pyext/IMP_kernel.random.i b/modules/kernel/pyext/IMP_kernel.random.i index c4ec899dec..b97b82ce61 100644 --- a/modules/kernel/pyext/IMP_kernel.random.i +++ b/modules/kernel/pyext/IMP_kernel.random.i @@ -1,24 +1,10 @@ // Simple wrapper to give read-only access to IMP's random number generator -%{ -#include -// needed to ensure that the swig wrappers work -BOOST_STATIC_ASSERT(sizeof(int) == sizeof(boost::int32_t)); - -%} - - -namespace boost { - typedef int int32_t; - typedef unsigned long int uint64_t; -}; - - namespace IMP { class RandomNumberGenerator { public: //! Set the random number generator seed - void seed(::boost::int32_t x); + void seed(int x); //! Get the next random value from the generator int operator()(); diff --git a/modules/kernel/pyext/include/IMP_kernel.import_numpy.i b/modules/kernel/pyext/include/IMP_kernel.import_numpy.i index 27b1961379..8e9acf1fcc 100644 --- a/modules/kernel/pyext/include/IMP_kernel.import_numpy.i +++ b/modules/kernel/pyext/include/IMP_kernel.import_numpy.i @@ -6,6 +6,8 @@ static int numpy_import_retval; %} %{ +// Silence warnings about old NumPy API +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include %} diff --git a/modules/kernel/pyext/include/IMP_kernel.types.i b/modules/kernel/pyext/include/IMP_kernel.types.i index 217ae6fbba..11afb85cb2 100644 --- a/modules/kernel/pyext/include/IMP_kernel.types.i +++ b/modules/kernel/pyext/include/IMP_kernel.types.i @@ -615,6 +615,8 @@ IMP_SWIG_SHOWABLE_VALUE(Namespace, Name); %define IMP_SWIG_DECORATOR(Namespace, Name, PluralName) IMP_SWIG_DECORATOR_BASE(Namespace, Name, PluralName); +IMP_SWIG_OBJECT_SERIALIZE_IMPL(Namespace, Name); +IMP_SWIG_OBJECT_SERIALIZE_PICKLE(Namespace, Name); %{ BOOST_STATIC_ASSERT(Convert< Namespace::Name >::converter==3); %} @@ -753,8 +755,8 @@ IMP_SWIG_SHOWABLE_VALUE(Namespace, Name); /* Get contents as a binary blob (for serialization) */ PyObject *_get_as_binary() const { std::ostringstream oss; - boost::archive::binary_oarchive ba(oss, boost::archive::no_header); - ba << *self; + cereal::BinaryOutputArchive ba(oss); + ba(*self); std::string s = oss.str(); PyObject *p = PyBytes_FromStringAndSize(s.data(), s.size()); if (p) { @@ -773,8 +775,8 @@ IMP_SWIG_SHOWABLE_VALUE(Namespace, Name); } std::string s(buf, len); std::istringstream iss(s); - boost::archive::binary_iarchive ba(iss, boost::archive::no_header); - ba >> *self; + cereal::BinaryInputArchive ba(iss); + ba(*self); } /* Allow (un-)pickling both C++ and Python contents */ @@ -798,15 +800,74 @@ IMP_SWIG_SHOWABLE_VALUE(Namespace, Name); } %enddef +// Not yet complete for Objects, so don't implement pickle +%define IMP_SWIG_OBJECT_SERIALIZE_IMPL(Namespace, Name) +%extend Namespace::Name { + /* Get contents as a binary blob (for serialization) */ + PyObject *_get_as_binary() const { + std::ostringstream oss; + cereal::BinaryOutputArchive ba(oss); + ba(*self); + std::string s = oss.str(); + PyObject *p = PyBytes_FromStringAndSize(s.data(), s.size()); + if (p) { + return p; + } else { + throw IMP::IndexException("PyBytes_FromStringAndSize failed"); + } + } + + /* Set contents from a binary blob (for unserialization) */ + void _set_from_binary(PyObject *p) { + char *buf; + Py_ssize_t len; + if (PyBytes_AsStringAndSize(p, &buf, &len) < 0) { + throw IMP::IndexException("PyBytes_AsStringAndSize failed"); + } + std::string s(buf, len); + std::istringstream iss(s); + cereal::BinaryInputArchive ba(iss); + ba(*self); + } +} +%enddef + +%define IMP_SWIG_OBJECT_SERIALIZE_PICKLE(Namespace, Name) +%extend Namespace::Name { + /* Allow (un-)pickling both C++ and Python contents */ + %pythoncode %{ + def __getstate__(self): + p = self._get_as_binary() + if len(self.__dict__) > 1: + d = self.__dict__.copy() + del d['this'] + p = (d, p) + return p + + def __setstate__(self, p): + if not hasattr(self, 'this'): + self.__init__() + if isinstance(p, tuple): + d, p = p + self.__dict__.update(d) + return self._set_from_binary(p) + %} +} +%enddef + // A value that is serializable/picklable -// Modules that use these must link against Boost.Serialization and -// include boost/archive/binary_iarchive.hpp and -// boost/archive/binary_oarchive.hpp in their SWIG interface %define IMP_SWIG_VALUE_SERIALIZE(Namespace, Name, PluralName) IMP_SWIG_VALUE(Namespace, Name, PluralName) IMP_SWIG_VALUE_SERIALIZE_IMPL(Namespace, Name) %enddef +// An Object that is serializable/picklable +%define IMP_SWIG_OBJECT_SERIALIZE(Namespace, Name, PluralName) +IMP_SWIG_OBJECT(Namespace, Name, PluralName) +IMP_SWIG_OBJECT_SERIALIZE_IMPL(Namespace, Name) +IMP_SWIG_OBJECT_SERIALIZE_PICKLE(Namespace, Name) +%enddef + %define IMP_SWIG_GENERIC_OBJECT_TEMPLATE(Namespace, Name, lcname, argument) %template(Name) Namespace::Generic##Name; %template(create_##lcname) Namespace::create_##lcname; @@ -1026,3 +1087,15 @@ _value_types.append(#Name) %} %rename(_##Type##VertexIndex) Type##VertexIndex; %enddef + +typedef unsigned int uint32_t; + +%define IMP_NOT_SERIALIZABLE(Name) +%extend Name { + %pythoncode %{ + def __getstate__(self): + raise NotImplementedError(str(self.__class__) + + " does not support serialization") + %} +} +%enddef diff --git a/modules/kernel/pyext/src/_list_util.py b/modules/kernel/pyext/src/_list_util.py index b7f824aef8..043984aefa 100644 --- a/modules/kernel/pyext/src/_list_util.py +++ b/modules/kernel/pyext/src/_list_util.py @@ -62,6 +62,14 @@ def __str__(self): def __repr__(self): return str(self) + def __eq__(self, other): + # e.g. lists compare equal to other lists, but not to tuples + if not isinstance(other, (list, VarList)): + return False + if len(other) != len(self): + return False + return all(a == b for a, b in zip(self, other)) + def __getitem__(self, indx): ret = _handle_seq_indx(self, indx) if isinstance(ret, int): diff --git a/modules/kernel/pyext/swig.i-in b/modules/kernel/pyext/swig.i-in index 811ed74e3c..bc0b6dedea 100644 --- a/modules/kernel/pyext/swig.i-in +++ b/modules/kernel/pyext/swig.i-in @@ -1,12 +1,14 @@ -%{ -#include -#include -%} - %pythoncode %{ from . import _list_util %} +// Provide catch-all implementations in base classes so +// that pickle fails with a more informative error than +// "TypeError: cannot pickle 'SwigPyObject' object" +IMP_NOT_SERIALIZABLE(IMP::Object); +IMP_NOT_SERIALIZABLE(IMP::Value); +IMP_NOT_SERIALIZABLE(IMP::InputAdaptor); + %extend IMP::Object { bool __eq__(const Object *o) const { return self ==o; @@ -28,6 +30,37 @@ from . import _list_util } } +// Make sure that ModelObject::get_model() returns the same Model object +%pythoncode %{ +_models_set = weakref.WeakSet() + +def _models_set_get(m): + for x in _models_set: + if x == m: + return x +%} + +namespace IMP { + %feature("pythonappend") Model::Model %{ + if self not in _models_set: + _models_set.add(self) + %} + %feature("shadow") ModelObject::get_model %{ + def get_model(self): + m = $action(self) + if m in _models_set: + m = _models_set_get(m) + return m + %} + %feature("shadow") Decorator::get_model %{ + def get_model(self): + m = $action(self) + if m in _models_set: + m = _models_set_get(m) + return m + %} +} + %feature("ref") IMP::Object "if ($this) $this->ref();" %feature("unref") IMP::Object "if ($this) $this->unref();" @@ -262,13 +295,16 @@ IMP_SWIG_BASE_OBJECT(IMP,UnaryFunction, UnaryFunctions); IMP_SWIG_OBJECT(IMP, RestraintInfo, RestraintInfos); IMP_SWIG_OBJECT(IMP,ConfigurationSet, ConfigurationSets); IMP_SWIG_OBJECT(IMP,Configuration, Configurations); -IMP_SWIG_OBJECT(IMP,Model, Models); -IMP_SWIG_OBJECT(IMP,Particle, Particles); +IMP_SWIG_OBJECT_SERIALIZE(IMP,Model, Models); +IMP_SWIG_OBJECT_SERIALIZE(IMP,Particle, Particles); IMP_SWIG_NESTED_SEQUENCE_TYPEMAP(IMP::Particle, IMP::ParticlesTemp, IMP::ParticlesTemps, const&); IMP_SWIG_NESTED_SEQUENCE_TYPEMAP(IMP::Particle, IMP::ParticlesTemp, IMP::ParticlesTemps,); IMP_SWIG_BASE_OBJECT(IMP,RestraintSet, RestraintSets); +IMP_SWIG_OBJECT_SERIALIZE_IMPL(IMP, RestraintSet) +IMP_SWIG_OBJECT_SERIALIZE_PICKLE(IMP, RestraintSet) + IMP_SWIG_ARRAY(IMP, ParticlePair, ParticlePairsTemp, IMP::Particle); IMP_SWIG_ARRAY(IMP, ParticleTriplet, ParticleTripletsTemp, IMP::Particle); IMP_SWIG_ARRAY(IMP, ParticleQuad, ParticleQuadsTemp, IMP::Particle); @@ -309,8 +345,10 @@ IMP_SWIG_BASE_OBJECT(IMP, ModelObject, ModelObjects); IMP_SWIG_DECORATOR(IMP::internal, _TrivialDecorator, _TrivialDecorators); IMP_SWIG_DECORATOR(IMP::internal, _TrivialDerivedDecorator, _TrivialDerivedDecorators); IMP_SWIG_DECORATOR_WITH_TRAITS(IMP::internal, _TrivialTraitsDecorator, _TrivialTraitsDecorators); -IMP_SWIG_OBJECT(IMP::internal, _ConstRestraint, _ConstRestraints); -IMP_SWIG_OBJECT(IMP::internal, _ConstOptimizer, _ConstOptimizers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::internal, _ConstRestraint, _ConstRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::internal, _ConstOptimizer, _ConstOptimizers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::internal, _ConstSingletonScore, _ConstSingletonScores); +IMP_SWIG_OBJECT_SERIALIZE(IMP::internal, _ConstPairScore, _ConstPairScores); IMP_SWIG_GRAPH(IMP, DependencyGraph, DependencyGraph, IMP::ModelObject*); diff --git a/modules/kernel/src/Decorator.cpp b/modules/kernel/src/Decorator.cpp index 862126961d..d51b75ed84 100644 --- a/modules/kernel/src/Decorator.cpp +++ b/modules/kernel/src/Decorator.cpp @@ -25,6 +25,20 @@ IMPKERNEL_BEGIN_NAMESPACE Decorator::Decorator(ParticleAdaptor p) : model_(p.get_model()), pi_(p.get_particle_index()), is_valid_(true) {} +uint32_t Decorator::get_model_id() const { + return model_->get_unique_id(); +} + +void Decorator::set_model_from_id(uint32_t model_id) { + Model *m = Model::get_by_unique_id(model_id); + if (!m) { + IMP_THROW("Cannot unserialize Decorator as it refers to a " + "Model that does not exist", ValueException); + } else { + model_ = m; + } +} + void check_particle(Model *m, ParticleIndex pi) { for (unsigned int i = 0; i < internal::particle_validators.size(); ++i) { if (internal::particle_validators[i].first(m, pi)) { diff --git a/modules/kernel/src/Model.cpp b/modules/kernel/src/Model.cpp index f022dd2a64..d77c248e34 100644 --- a/modules/kernel/src/Model.cpp +++ b/modules/kernel/src/Model.cpp @@ -24,6 +24,7 @@ Model::Model(std::string name) saved_dependencies_age_ = 0; dependencies_saved_ = false; moved_particles_cache_age_ = 0; + unique_id_ = model_map_.add_new_model(this); #if IMP_HAS_CHECKS >= IMP_INTERNAL internal::FloatAttributeTable::set_masks( &this->Masks::read_mask_, &this->Masks::write_mask_, @@ -56,6 +57,46 @@ Model::Model(std::string name) #endif } +void Model::register_unique_id() { + model_map_.add_model_with_id(this, unique_id_); +} + +Model::ModelMap Model::model_map_; + +uint32_t Model::ModelMap::add_new_model(Model *m) { + uint32_t id; + // Chance of collision is very small, but not zero + do { + id = id_gen_(); + } while (map_.find(id) != map_.end()); + map_[id] = m; + return id; +} + +void Model::ModelMap::add_model_with_id(Model *m, uint32_t id) { + // If an old model exists with this ID already (e.g. we picked a model + // and then unpickled it, duplicating the model) then give it a new ID. + // We don't want to change the ID of the *new* model, because we want + // any ModelObjects referenced by it to get pointers back to the new model. + Model *oldmodel = get(id); + if (oldmodel) { + oldmodel->unique_id_ = add_new_model(oldmodel); + } + map_[id] = m; +} + +void Model::ModelMap::remove_model(Model *m) { + map_.erase(m->get_unique_id()); +} + +Model* Model::ModelMap::get(uint32_t id) const { + auto p = map_.find(id); + if (p == map_.end()) { + return nullptr; + } else { + return p->second; + } +} IMP_LIST_ACTION_IMPL(Model, ScoreState, ScoreStates, score_state, score_states, ScoreState *, ScoreStates); @@ -212,6 +253,7 @@ void Model::do_destroy() { IMP_CHECK_OBJECT(mo); mo->set_model(nullptr); } + model_map_.remove_model(this); } IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/src/ModelObject.cpp b/modules/kernel/src/ModelObject.cpp index d8d79eaa70..76f2ddfd1c 100644 --- a/modules/kernel/src/ModelObject.cpp +++ b/modules/kernel/src/ModelObject.cpp @@ -21,6 +21,24 @@ ModelObject::ModelObject(Model *m, std::string name) m->do_add_model_object(this); } +ModelObject::ModelObject() : Object("") { +} + +uint32_t ModelObject::get_model_id() const { + return model_->get_unique_id(); +} + +void ModelObject::set_model_from_id(uint32_t model_id) { + Model *m = Model::get_by_unique_id(model_id); + if (!m) { + IMP_THROW("Cannot unserialize ModelObject as it refers to a " + "Model that does not exist", ValueException); + } else { + model_ = m; + m->do_add_model_object(this); + } +} + ModelObject::~ModelObject() { if (get_model()) get_model()->do_remove_model_object(this); } diff --git a/modules/kernel/src/Model_dependencies.cpp b/modules/kernel/src/Model_dependencies.cpp index 3b54aeb261..391f3fdde9 100644 --- a/modules/kernel/src/Model_dependencies.cpp +++ b/modules/kernel/src/Model_dependencies.cpp @@ -20,19 +20,20 @@ #include "IMP/internal/graph_utility.h" #include #include "boost/unordered_map.hpp" +#include #include "IMP/log.h" #include "boost/unordered_set.hpp" IMPKERNEL_BEGIN_NAMESPACE ScoreStatesTemp Model::get_ancestor_score_states(const ModelObject *mo) const { - ModelObjectsTemp all_in = dependency_graph_.find(mo)->second.get_inputs() + - dependency_graph_.find(mo)->second.get_writers(); ScoreStatesTemp ret; - for (unsigned int i = 0; i < all_in.size(); ++i) { - ScoreState *ss = dynamic_cast(all_in[i].get()); + const auto &dg = dependency_graph_.find(mo); + for (ModelObject *in : boost::join(dg->second.get_inputs(), + dg->second.get_writers())) { + ScoreState *ss = dynamic_cast(in); if (ss) ret.push_back(ss); - ret += get_ancestor_score_states(all_in[i]); + ret += get_ancestor_score_states(in); } std::sort(ret.begin(), ret.end()); ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); @@ -41,73 +42,80 @@ ScoreStatesTemp Model::get_ancestor_score_states(const ModelObject *mo) const { ScoreStatesTemp Model::get_descendent_score_states(const ModelObject *mo) const { - ModelObjectsTemp all_out = dependency_graph_.find(mo)->second.get_outputs() + - dependency_graph_.find(mo)->second.get_readers(); ScoreStatesTemp ret; - for (unsigned int i = 0; i < all_out.size(); ++i) { - ScoreState *ss = dynamic_cast(all_out[i].get()); + const auto &dg = dependency_graph_.find(mo); + for (ModelObject *out : boost::join(dg->second.get_outputs(), + dg->second.get_readers())) { + ScoreState *ss = dynamic_cast(out); if (ss) ret.push_back(ss); - ret += get_descendent_score_states(all_out[i]); + ret += get_descendent_score_states(out); } std::sort(ret.begin(), ret.end()); ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); return ret; } -void Model::do_check_inputs_and_outputs(const ModelObject *mo) const { - { +void Model::do_check_inputs_and_outputs(const ModelObject *cmo) const { + ModelObject *mo = const_cast(cmo); + IMP_UNUSED(mo); // for fast builds + IMP_UNUSED(cmo); // for fast builds + IMP_IF_CHECK(USAGE_AND_INTERNAL) { for(ModelObject * i : dependency_graph_.find(mo)->second.get_inputs()) { - ModelObjectsTemp readers = + const std::set &readers = dependency_graph_.find(i)->second.get_readers(); + IMP_INTERNAL_CHECK_VARIABLE(readers); IMP_INTERNAL_CHECK( - std::find(readers.begin(), readers.end(), mo) != readers.end(), + readers.find(mo) != readers.end(), "Input not found in readers for " << mo->get_name() << " and " << i->get_name()); } } - { + IMP_IF_CHECK(USAGE_AND_INTERNAL) { for(ModelObject * o : dependency_graph_.find(mo)->second.get_outputs()) { - ModelObjectsTemp writers = + const std::set &writers = dependency_graph_.find(o)->second.get_writers(); + IMP_INTERNAL_CHECK_VARIABLE(writers); IMP_INTERNAL_CHECK( - std::find(writers.begin(), writers.end(), mo) != writers.end(), + writers.find(mo) != writers.end(), "Input not found in writers for " << (mo)->get_name() << " and " << o->get_name()); } } } -void Model::do_check_readers_and_writers(const ModelObject *mo) const { +void Model::do_check_readers_and_writers(const ModelObject *cmo) const { + ModelObject *mo = const_cast(cmo); { - ModelObjectsTemp readers = dependency_graph_.find(mo)->second.get_readers(); + const std::set &readers + = dependency_graph_.find(mo)->second.get_readers(); for(ModelObject * r : readers) { IMP_INTERNAL_CHECK(dependency_graph_.find(r) != dependency_graph_.end(), "Reader " << r->get_name() << " of " << mo->get_name() << " not in graph" << std::endl); - const ModelObjectsTemp &inputs = + const std::set &inputs = dependency_graph_.find(r)->second.get_inputs(); IMP_UNUSED(inputs); IMP_INTERNAL_CHECK( - std::find(inputs.begin(), inputs.end(), mo) != inputs.end(), + inputs.find(mo) != inputs.end(), "Reader not found in inputs for " << mo->get_name() << " and " << r->get_name()); } } { - const ModelObjectsTemp &writers = + const std::set &writers = dependency_graph_.find(mo)->second.get_writers(); IMP_UNUSED(writers); for(ModelObject * w : writers) { IMP_INTERNAL_CHECK(dependency_graph_.find(w) != dependency_graph_.end(), "Reader " << w->get_name() << " of " << mo->get_name() << " not in graph" << std::endl); - const ModelObjectsTemp &outputs = + const std::set &outputs = dependency_graph_.find(w)->second.get_outputs(); IMP_UNUSED(outputs); IMP_INTERNAL_CHECK( - std::find(outputs.begin(), outputs.end(), mo) != outputs.end(), + outputs.find(mo) != outputs.end(), "Writer not found in outputs for " << (mo)->get_name() << " and " << w->get_name()); } @@ -139,21 +147,27 @@ void Model::do_check_update_order(const ScoreState *ss) const { } } -void Model::do_check_not_in_readers_and_writers(const ModelObject *mo) const { +void Model::do_check_not_in_readers_and_writers(const ModelObject *cmo) const { + ModelObject *mo = const_cast(cmo); IMP_UNUSED(mo); // for fast builds - for(DependencyGraph::value_type vt : dependency_graph_) { - ModelObjectsTemp readers = vt.second.get_readers(); - IMP_INTERNAL_CHECK( - std::find(readers.begin(), readers.end(), mo) == readers.end(), - "ModelObject " << (mo)->get_name() - << " has no dependencies but is in readers list for " - << (vt.first)->get_name()); - ModelObjectsTemp writers = vt.second.get_writers(); - IMP_INTERNAL_CHECK( - std::find(writers.begin(), writers.end(), mo) == writers.end(), - "ModelObject " << (mo)->get_name() - << " has no dependencies but is in writers list for " - << (vt.first)->get_name()); + IMP_UNUSED(cmo); // for fast builds + IMP_IF_CHECK(USAGE_AND_INTERNAL) { + for(DependencyGraph::value_type vt : dependency_graph_) { + const std::set &readers = vt.second.get_readers(); + IMP_INTERNAL_CHECK_VARIABLE(readers); + IMP_INTERNAL_CHECK( + readers.find(mo) == readers.end(), + "ModelObject " << (mo)->get_name() + << " has no dependencies but is in readers list for " + << (vt.first)->get_name()); + const std::set &writers = vt.second.get_writers(); + IMP_INTERNAL_CHECK_VARIABLE(writers); + IMP_INTERNAL_CHECK( + writers.find(mo) == writers.end(), + "ModelObject " << (mo)->get_name() + << " has no dependencies but is in writers list for " + << (vt.first)->get_name()); + } } } @@ -285,32 +299,30 @@ void Model::do_add_dependencies(const ModelObject *cmo) { IMP_INTERNAL_CHECK(no_dependencies_.find(cmo) != no_dependencies_.end(), "Already has dependencies"); ModelObject *mo = const_cast(cmo); - ModelObjectsTemp outputs = mo->get_outputs(); + ModelObjectsTemp outputs_vec = mo->get_outputs(); + std::set outputs(outputs_vec.begin(), outputs_vec.end()); { - std::sort(outputs.begin(), outputs.end()); - outputs.erase(std::unique(outputs.begin(), outputs.end()), outputs.end()); for(ModelObject * out : outputs) { - dependency_graph_[out].access_writers().push_back(mo); + dependency_graph_[out].access_writers().insert(mo); do_clear_required_score_states(out); } dependency_graph_[mo].set_outputs(outputs); } { - ModelObjectsTemp inputs = mo->get_inputs(); - std::sort(inputs.begin(), inputs.end()); - inputs.erase(std::unique(inputs.begin(), inputs.end()), inputs.end()); - ModelObjectsTemp filtered_inputs; + ModelObjectsTemp inputs_vec = mo->get_inputs(); + std::set inputs(inputs_vec.begin(), inputs_vec.end()); + std::set filtered_inputs; std::set_difference(inputs.begin(), inputs.end(), outputs.begin(), - outputs.end(), std::back_inserter(filtered_inputs)); - ModelObjectsTemp input_outputs; + outputs.end(), std::inserter(filtered_inputs, filtered_inputs.end())); + std::set input_outputs; std::set_difference(inputs.begin(), inputs.end(), filtered_inputs.begin(), filtered_inputs.end(), - std::back_inserter(input_outputs)); + std::inserter(input_outputs, input_outputs.end())); IMP_INTERNAL_CHECK( filtered_inputs.size() + input_outputs.size() == inputs.size(), "Sizes don't add up"); for(ModelObject * in : filtered_inputs) { - dependency_graph_[in].access_readers().push_back(mo); + dependency_graph_[in].access_readers().insert(mo); } dependency_graph_[mo].set_inputs(filtered_inputs); dependency_graph_[mo].set_input_outputs(input_outputs); @@ -346,27 +358,25 @@ void Model::do_clear_dependencies(const ModelObject *cmo) { for(ModelObject * in : ni.get_inputs()) { // for teardown if (dependency_graph_.find(in) == dependency_graph_.end()) continue; - Vector &cur = + std::set &cur = dependency_graph_.find(in)->second.access_readers(); - IMP_INTERNAL_CHECK(std::find(cur.begin(), cur.end(), mo) != cur.end(), - "Not in list"); - std::swap(*std::find(cur.begin(), cur.end(), mo), cur.back()); - cur.pop_back(); - IMP_INTERNAL_CHECK(std::find(cur.begin(), cur.end(), mo) == cur.end(), - "in list"); + IMP_INTERNAL_CHECK(cur.find(mo) != cur.end(), + "Not in set"); + cur.erase(mo); + IMP_INTERNAL_CHECK(cur.find(mo) == cur.end(), + "in set"); } ni.set_inputs(Edges()); for(ModelObject * out : ni.get_outputs()) { if (dependency_graph_.find(out) == dependency_graph_.end()) continue; - Vector &cur = + std::set &cur = dependency_graph_.find(out)->second.access_writers(); - IMP_INTERNAL_CHECK(std::find(cur.begin(), cur.end(), mo) != cur.end(), - "Not in list"); - std::swap(*std::find(cur.begin(), cur.end(), mo), cur.back()); - cur.pop_back(); - IMP_INTERNAL_CHECK(std::find(cur.begin(), cur.end(), mo) == cur.end(), - " in list"); + IMP_INTERNAL_CHECK(cur.find(mo) != cur.end(), + "Not in set"); + cur.erase(mo); + IMP_INTERNAL_CHECK(cur.find(mo) == cur.end(), + " in set"); } ni.set_outputs(Edges()); ni.set_input_outputs(Edges()); @@ -387,8 +397,11 @@ ModelObjectsTemp Model::get_dependency_graph_inputs(const ModelObject *mo) << " does not have dependencies."); IMP_INTERNAL_CHECK(dependency_graph_.find(mo) != dependency_graph_.end(), "Node not in dependency_graph."); - return dependency_graph_.find(mo)->second.get_inputs() + - dependency_graph_.find(mo)->second.get_writers(); + const auto &inputs = dependency_graph_.find(mo)->second.get_inputs(); + const auto &writers = dependency_graph_.find(mo)->second.get_writers(); + ModelObjectsTemp ret(inputs.begin(), inputs.end()); + std::copy(writers.begin(), writers.end(), std::back_inserter(ret)); + return ret; } ModelObjectsTemp Model::get_dependency_graph_outputs(const ModelObject *mo) @@ -398,8 +411,11 @@ ModelObjectsTemp Model::get_dependency_graph_outputs(const ModelObject *mo) << " does not have dependencies."); IMP_INTERNAL_CHECK(dependency_graph_.find(mo) != dependency_graph_.end(), "Node not in dependency_graph."); - return dependency_graph_.find(mo)->second.get_outputs() + - dependency_graph_.find(mo)->second.get_readers(); + const auto &outputs = dependency_graph_.find(mo)->second.get_outputs(); + const auto &readers = dependency_graph_.find(mo)->second.get_readers(); + ModelObjectsTemp ret(outputs.begin(), outputs.end()); + std::copy(readers.begin(), readers.end(), std::back_inserter(ret)); + return ret; } RestraintsTemp Model::get_dependent_restraints_uncached(ParticleIndex pi) { @@ -443,19 +459,21 @@ void Model::do_set_has_required_score_states(ModelObject *mo, bool tf) { computed.insert(mo); IMP_OBJECT_LOG; if (tf) { - ScoreStates all; + std::set all; for(ModelObject * input : dependency_graph_.find(mo)->second.get_inputs()) { do_set_has_required_score_states(input, true); - all += required_score_states_.find(input)->second; + const auto &childss = required_score_states_.find(input)->second; + all.insert(childss.begin(), childss.end()); ScoreState *ss = dynamic_cast(input); - if (ss) all.push_back(ss); + if (ss) all.insert(ss); } for(ModelObject * input : dependency_graph_.find(mo)->second.get_writers()) { do_set_has_required_score_states(input, true); - all += required_score_states_.find(input)->second; + const auto &childss = required_score_states_.find(input)->second; + all.insert(childss.begin(), childss.end()); ScoreState *ss = dynamic_cast(input); - if (ss) all.push_back(ss); + if (ss) all.insert(ss); } required_score_states_[mo] = get_update_order(all); IMP_LOG_VERBOSE("Score states for " << get_name() << " are " @@ -506,10 +524,10 @@ void Model::do_remove_model_object(ModelObject *mo) { { NodeInfo &ni = dependency_graph_.find(mo)->second; while (!ni.get_readers().empty()) { - do_clear_dependencies(ni.get_readers().back()); + do_clear_dependencies(*ni.get_readers().begin()); } while (!ni.get_writers().empty()) { - do_clear_dependencies(ni.get_writers().back()); + do_clear_dependencies(*ni.get_writers().begin()); } } no_dependencies_.erase(mo); diff --git a/modules/kernel/src/Model_evaluate.cpp b/modules/kernel/src/Model_evaluate.cpp index 9e9dea8bd8..4b53e4290e 100644 --- a/modules/kernel/src/Model_evaluate.cpp +++ b/modules/kernel/src/Model_evaluate.cpp @@ -18,7 +18,6 @@ #include "IMP/internal/evaluate_utility.h" #include #include -#include #include #include diff --git a/modules/kernel/src/Object.cpp b/modules/kernel/src/Object.cpp index 3b0efc2354..95afe22602 100644 --- a/modules/kernel/src/Object.cpp +++ b/modules/kernel/src/Object.cpp @@ -11,6 +11,8 @@ #include "IMP/log_macros.h" #include "IMP/exception.h" #include "IMP/base_utility.h" +#include "IMP/internal/utility.h" +#include #include IMPKERNEL_BEGIN_NAMESPACE @@ -103,7 +105,11 @@ void Object::set_log_level(LogLevel l) { } void Object::set_name(std::string in_name) { - name_ = get_unique_name(in_name); + set_name_internal(get_unique_name(in_name)); +} + +void Object::set_name_internal(std::string in_name) { + name_ = in_name; quoted_name_.reset(new char[name_.size() + 3]); quoted_name_[0] = '"'; std::copy(name_.begin(), name_.end(), quoted_name_.get() + 1); @@ -132,4 +138,61 @@ void Object::release() const { << ") {" << this << "}" << std::endl); } +std::map & +Object::get_output_serializers() { + static std::map m; + return m; +} + +std::map & +Object::get_input_serializers() { + static std::map m; + return m; +} + +bool Object::register_serialize(const std::type_info &t, std::string name, + SaveFunc save_func, LoadFunc load_func) { + if (name.substr(0, 5) != "IMP::") { + IMP_THROW("Class name for register_serialize is not fully qualified (" + << name << "); should start with IMP::", ValueException); + } + OutputSerializer os; + os.class_name = name; + os.save_func = save_func; + get_output_serializers()[t.name()] = os; + get_input_serializers()[name] = load_func; + return true; +} + +void Object::poly_serialize(cereal::BinaryOutputArchive &ar) { + const std::type_info &oi = typeid(*this); + std::map + &ti_to_name = get_output_serializers(); + auto f = ti_to_name.find(oi.name()); + if (f == ti_to_name.end()) { + IMP_THROW("Trying to save an unregistered polymorphic type (" + << internal::demangle_cxx(oi.name()) + << "), probably a missing IMP_OBJECT_SERIALIZE_IMPL.", + TypeException); + } else { + ar(f->second.class_name); + f->second.save_func(this, ar); + } +} + +Object *Object::poly_unserialize(cereal::BinaryInputArchive &ar) { + std::string class_name; + ar(class_name); + std::map &ti_to_f = get_input_serializers(); + auto f = ti_to_f.find(class_name); + if (f == ti_to_f.end()) { + IMP_THROW("Trying to load an unregistered polymorphic type (" + << class_name << + "), perhaps because its module has not been loaded yet.", + TypeException); + } else { + return f->second(ar); + } +} + IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/src/OptimizerState.cpp b/modules/kernel/src/OptimizerState.cpp index 28fade0b83..d3a1fd1a6e 100644 --- a/modules/kernel/src/OptimizerState.cpp +++ b/modules/kernel/src/OptimizerState.cpp @@ -18,6 +18,12 @@ OptimizerState::OptimizerState(Model* m, std::string name) set_period(1); } +OptimizerState::OptimizerState() { + is_optimizing_ = false; + reset(); + set_period(1); +} + void OptimizerState::set_optimizer(Optimizer* optimizer) { optimizer_ = optimizer; } diff --git a/modules/kernel/src/Restraint.cpp b/modules/kernel/src/Restraint.cpp index 31f57d3b06..e5d74e7437 100644 --- a/modules/kernel/src/Restraint.cpp +++ b/modules/kernel/src/Restraint.cpp @@ -30,6 +30,10 @@ Restraint::Restraint(Model *m, std::string name) : ModelObject(m, name), is_aggregate_(false), weight_(1), max_(NO_MAX), last_score_(BAD_SCORE), last_last_score_(BAD_SCORE) {} +Restraint::Restraint() + : ModelObject(), is_aggregate_(false), weight_(1), max_(NO_MAX), + last_score_(BAD_SCORE), last_last_score_(BAD_SCORE) {} + double Restraint::evaluate(bool calc_derivs) const { IMP_OBJECT_LOG; Pointer sf = create_internal_scoring_function(); @@ -200,6 +204,7 @@ ScoringFunction *Restraint::create_scoring_function(double weight, } ScoringFunction *Restraint::create_internal_scoring_function() const { + IMP_USAGE_CHECK(get_model(), "No Model set"); if (!cached_internal_scoring_function_) { Restraint *ncthis = const_cast(this); IMP_NEW(internal::GenericRestraintsScoringFunction, ret, diff --git a/modules/kernel/src/RestraintInfo.cpp b/modules/kernel/src/RestraintInfo.cpp index c0e757b6e7..c0e2b50f32 100644 --- a/modules/kernel/src/RestraintInfo.cpp +++ b/modules/kernel/src/RestraintInfo.cpp @@ -2,14 +2,25 @@ * \file RestraintInfo.cpp * \brief Report key:value information on restraints * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ #include +#include IMPKERNEL_BEGIN_NAMESPACE +namespace { +bool is_string_key_path(std::string name) { + return boost::algorithm::ends_with(name, "filename") || + boost::algorithm::ends_with(name, "filenames") || + name == "cluster density" || + name == "image files" || + name == "path"; +} +} + void RestraintInfo::add_int(std::string key, int value) { int_.push_back(IntData(key, value)); } @@ -19,10 +30,14 @@ void RestraintInfo::add_float(std::string key, double value) { } void RestraintInfo::add_string(std::string key, std::string value) { + IMP_USAGE_CHECK(!is_string_key_path(key), + "Keys used for strings must not end in 'filename' or 'filenames'"); string_.push_back(StringData(key, value)); } void RestraintInfo::add_filename(std::string key, std::string value) { + IMP_USAGE_CHECK(is_string_key_path(key), + "Keys used for filenames must end in 'filename' or 'filenames'"); filename_.push_back(StringData(key, value)); } @@ -35,10 +50,14 @@ void RestraintInfo::add_ints(std::string key, Ints value) { } void RestraintInfo::add_strings(std::string key, Strings value) { + IMP_USAGE_CHECK(!is_string_key_path(key), + "Keys used for strings must not end in 'filename' or 'filenames'"); strings_.push_back(StringsData(key, value)); } void RestraintInfo::add_filenames(std::string key, Strings value) { + IMP_USAGE_CHECK(is_string_key_path(key), + "Keys used for filenames must end in 'filename' or 'filenames'"); filenames_.push_back(StringsData(key, value)); } diff --git a/modules/kernel/src/RestraintSet.cpp b/modules/kernel/src/RestraintSet.cpp index 960421d10c..f6ecb359da 100644 --- a/modules/kernel/src/RestraintSet.cpp +++ b/modules/kernel/src/RestraintSet.cpp @@ -245,4 +245,6 @@ RestraintsTemp get_restraints(const RestraintsTemp &rs) { return get_restraints(rs.begin(), rs.end()); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::RestraintSet); + IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/src/ScoreState.cpp b/modules/kernel/src/ScoreState.cpp index f413bb4ad1..2e366bb0f4 100644 --- a/modules/kernel/src/ScoreState.cpp +++ b/modules/kernel/src/ScoreState.cpp @@ -55,6 +55,15 @@ ScoreStatesTemp get_update_order(ScoreStatesTemp in) { return in; } +ScoreStatesTemp get_update_order(std::set in) { + IMP_FUNCTION_LOG; + ScoreStatesTemp ret(in.begin(), in.end()); + if (ret.empty()) return ret; + std::sort(ret.begin(), ret.end(), CompOrder()); + IMP_LOG_TERSE("Order: " << ret << std::endl); + return ret; +} + void ScoreState::handle_set_has_required_score_states(bool tf) { if (tf) { IMP_USAGE_CHECK(update_order_ == -1, "Already had update order"); diff --git a/modules/kernel/src/ScoringFunction.cpp b/modules/kernel/src/ScoringFunction.cpp index 6ccb7b9654..6637e96312 100644 --- a/modules/kernel/src/ScoringFunction.cpp +++ b/modules/kernel/src/ScoringFunction.cpp @@ -46,6 +46,10 @@ ScoringFunction::ScoringFunction(Model *m, std::string name) moved_particles_cache_age_ = 0; } +ScoringFunction::ScoringFunction() : moved_particles_cache_(nullptr) { + moved_particles_cache_age_ = 0; +} + double ScoringFunction::evaluate_if_good(bool derivatives) { IMP_OBJECT_LOG; set_was_used(true); diff --git a/modules/kernel/src/WarningContext.cpp b/modules/kernel/src/WarningContext.cpp index 6b160f04ba..e219300c6e 100644 --- a/modules/kernel/src/WarningContext.cpp +++ b/modules/kernel/src/WarningContext.cpp @@ -12,7 +12,7 @@ IMPKERNEL_BEGIN_NAMESPACE #if IMP_HAS_LOG void WarningContext::add_warning(std::string key, std::string warning) const { if (warning.empty()) return; -#if IMP_HAS_LOG >= IMP_WARN +#if IMP_HAS_LOG > IMP_SILENT if (data_.find(key) == data_.end()) { data_.insert(key); IMP_WARN(warning); diff --git a/modules/kernel/src/base_utility.cpp b/modules/kernel/src/base_utility.cpp index a245051a76..a25b0c497b 100644 --- a/modules/kernel/src/base_utility.cpp +++ b/modules/kernel/src/base_utility.cpp @@ -33,4 +33,8 @@ std::string get_unique_name(std::string name) { } } +std::string get_copyright() { + return "Copyright 2007-2023 IMP Inventors"; +} + IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/src/dependency_graph.cpp b/modules/kernel/src/dependency_graph.cpp index a89ea5d8ac..2e701332d5 100644 --- a/modules/kernel/src/dependency_graph.cpp +++ b/modules/kernel/src/dependency_graph.cpp @@ -354,28 +354,10 @@ MOVector do_get_dependent(ModelObject *mo) { } } -RestraintsTemp get_dependent_restraints(Model *m, ParticleIndex pi) { - IMPKERNEL_DEPRECATED_FUNCTION_DEF( - 2.17, "Use Model::get_dependent_restraints_uncached() instead.") - return m->get_dependent_restraints_uncached(pi); -} - -ScoreStatesTemp get_dependent_score_states(Model *m, ParticleIndex pi) { - IMPKERNEL_DEPRECATED_FUNCTION_DEF( - 2.17, "Use Model::get_dependent_score_states_uncached() instead.") - return m->get_dependent_score_states_uncached(pi); -} - ScoreStatesTemp get_required_score_states(Model *m, ParticleIndex pi) { Particle *p = m->get_particle(pi); p->set_has_required_score_states(true); return p->get_required_score_states(); } -ParticlesTemp get_dependent_particles(Model *m, ParticleIndex pi) { - IMPKERNEL_DEPRECATED_FUNCTION_DEF( - 2.17, "Use Model::get_dependent_particles_uncached() instead.") - return m->get_dependent_particles_uncached(pi); -} - IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/src/exception.cpp b/modules/kernel/src/exception.cpp index 9c7e6d4407..22a5d9a2d1 100644 --- a/modules/kernel/src/exception.cpp +++ b/modules/kernel/src/exception.cpp @@ -14,24 +14,24 @@ void handle_error(const char *message) { // this method is just here to provide a place to break in the debugger } -Exception::~Exception() IMP_NOEXCEPT {} +Exception::~Exception() noexcept {} Exception::Exception(const char *message) : std::runtime_error(message) {} -InternalException::~InternalException() IMP_NOEXCEPT {} +InternalException::~InternalException() noexcept {} -UsageException::~UsageException() IMP_NOEXCEPT {} +UsageException::~UsageException() noexcept {} -IndexException::~IndexException() IMP_NOEXCEPT {} +IndexException::~IndexException() noexcept {} -ValueException::~ValueException() IMP_NOEXCEPT {} +ValueException::~ValueException() noexcept {} -ModelException::~ModelException() IMP_NOEXCEPT {} +ModelException::~ModelException() noexcept {} -EventException::~EventException() IMP_NOEXCEPT {} +EventException::~EventException() noexcept {} -IOException::~IOException() IMP_NOEXCEPT {} +IOException::~IOException() noexcept {} -TypeException::~TypeException() IMP_NOEXCEPT {} +TypeException::~TypeException() noexcept {} IMPKERNEL_END_NAMESPACE diff --git a/modules/kernel/src/flags.cpp b/modules/kernel/src/flags.cpp index 4b50fa7f7b..3c0c45359f 100644 --- a/modules/kernel/src/flags.cpp +++ b/modules/kernel/src/flags.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -152,7 +153,7 @@ void write_help(std::ostream &out) { } out << "This program is part of IMP, the Integrative Modeling Platform," << std::endl; - out << "which is Copyright 2007-2022 IMP Inventors." << std::endl; + out << "which is " << get_copyright() << "." << std::endl; out << "For additional information about IMP, " << "see ." << std::endl; } diff --git a/modules/kernel/src/internal/base_static.cpp b/modules/kernel/src/internal/base_static.cpp index 8196ab92e0..537e9837c4 100644 --- a/modules/kernel/src/internal/base_static.cpp +++ b/modules/kernel/src/internal/base_static.cpp @@ -16,12 +16,12 @@ #include "IMP/base_macros.h" #include "IMP/flags.h" #include "IMP/live_objects.h" +#include "IMP/internal/SimpleTimer.h" #include "boost/unordered_map.hpp" #include "IMP/types.h" #include #include #include -#include #include #include #if IMP_KERNEL_HAS_BOOST_RANDOM @@ -52,7 +52,7 @@ IMPKERNEL_BEGIN_INTERNAL_NAMESPACE // logging bool print_time; -boost::timer log_timer; +SimpleTimer log_timer; #if !IMP_KERNEL_HAS_LOG4CXX Vector > log_contexts; int log_context_initializeds = -1; @@ -91,7 +91,7 @@ void init_logger() { #endif -boost::scoped_ptr progress; +boost::scoped_ptr progress; IMPKERNEL_END_INTERNAL_NAMESPACE IMPKERNEL_BEGIN_NAMESPACE diff --git a/modules/kernel/src/internal/base_static.h b/modules/kernel/src/internal/base_static.h index 5bc6cad776..119ca2acda 100644 --- a/modules/kernel/src/internal/base_static.h +++ b/modules/kernel/src/internal/base_static.h @@ -10,13 +10,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include IMPKERNEL_BEGIN_INTERNAL_NAMESPACE @@ -61,7 +61,8 @@ extern IMPKERNELEXPORT std::string exe_description; extern IMPKERNELEXPORT AdvancedFlag number_of_threads; -extern IMPKERNELEXPORT boost::scoped_ptr progress; +extern IMPKERNELEXPORT boost::scoped_ptr< + IMP::internal::BoostProgressDisplay> progress; extern IMPKERNELEXPORT AdvancedFlag no_print_deprecation_messages; extern IMPKERNELEXPORT AdvancedFlag exceptions_on_deprecation; diff --git a/modules/kernel/src/internal/input_output_exception.cpp b/modules/kernel/src/internal/input_output_exception.cpp index 144be7ae5b..19c498a75f 100644 --- a/modules/kernel/src/internal/input_output_exception.cpp +++ b/modules/kernel/src/internal/input_output_exception.cpp @@ -27,7 +27,7 @@ InputOutputException::InputOutputException(std::string container_name, operation_(operation), entity_(NO_ENTITY) {} -InputOutputException::~InputOutputException() IMP_NOEXCEPT {} +InputOutputException::~InputOutputException() noexcept {} std::string InputOutputException::get_message(ModelObject *o) const { std::ostringstream oss; diff --git a/modules/kernel/src/internal/moved_particles_cache.cpp b/modules/kernel/src/internal/moved_particles_cache.cpp index 88c0e539a3..24eda37ff3 100644 --- a/modules/kernel/src/internal/moved_particles_cache.cpp +++ b/modules/kernel/src/internal/moved_particles_cache.cpp @@ -31,8 +31,9 @@ MovedParticlesParticleCache::get_dependent_particles(ParticleIndex pi) { if (it == cache_.end()) { ParticlesTemp ps = m_->get_dependent_particles_uncached(pi); ParticleIndexes pis; - for (ParticlesTemp::const_iterator pi = ps.begin(); pi != ps.end(); ++pi) { - pis.push_back((*pi)->get_index()); + for (ParticlesTemp::const_iterator pit = ps.begin(); + pit != ps.end(); ++pit) { + pis.push_back((*pit)->get_index()); } cache_[pi] = pis; it = cache_.find(pi); diff --git a/modules/kernel/src/internal/restraint_evaluation.cpp b/modules/kernel/src/internal/restraint_evaluation.cpp index 948af1c0d0..0f1b88efe9 100644 --- a/modules/kernel/src/internal/restraint_evaluation.cpp +++ b/modules/kernel/src/internal/restraint_evaluation.cpp @@ -13,7 +13,6 @@ #include "IMP/ScoreAccumulator.h" #include "IMP/internal/input_output_exception.h" #include -#include #include #include "IMP/ModelObject.h" diff --git a/modules/kernel/src/internal/swig.cpp b/modules/kernel/src/internal/swig.cpp index df5319174a..eb6837113b 100644 --- a/modules/kernel/src/internal/swig.cpp +++ b/modules/kernel/src/internal/swig.cpp @@ -14,15 +14,16 @@ double _ConstRestraint::unprotected_evaluate(DerivativeAccumulator *) const { } ModelObjectsTemp _ConstRestraint::do_get_inputs() const { - return ModelObjectsTemp(ps_.begin(), ps_.end()); + return get_particles(get_model(), pis_); } Restraints _ConstRestraint::do_create_decomposition() const { Restraints ret; - for (unsigned int i = 0; i < ps_.size(); ++i) { + Model *m = get_model(); + for (unsigned int i = 0; i < pis_.size(); ++i) { ret.push_back( - new _ConstRestraint(v_ / ps_.size(), ParticlesTemp(1, ps_[i]))); - ret.back()->set_last_score(v_ / ps_.size()); + new _ConstRestraint(m, ParticleIndexes(1, pis_[i]), v_ / pis_.size())); + ret.back()->set_last_score(v_ / pis_.size()); } return ret; } @@ -190,4 +191,8 @@ void _TrivialDecorator::do_setup_particle(Model *m, ParticleIndex pi) { m->add_attribute(IntKey("trivial_attribute"), pi, 1); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::internal::_ConstRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::internal::_ConstSingletonScore); +IMP_OBJECT_SERIALIZE_IMPL(IMP::internal::_ConstPairScore); + IMPKERNEL_END_INTERNAL_NAMESPACE diff --git a/modules/kernel/src/internal/swig_base.cpp b/modules/kernel/src/internal/swig_base.cpp index 163755a336..7dbc9299c6 100644 --- a/modules/kernel/src/internal/swig_base.cpp +++ b/modules/kernel/src/internal/swig_base.cpp @@ -96,4 +96,6 @@ IntRange _test_intrange() { return IntRange(-1, -1); } Strings _pass_overloaded_strings(const Strings &a, int) { return a; } Strings _pass_overloaded_strings(const Strings &a) { return a; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::internal::_TestObject); + IMPKERNEL_END_INTERNAL_NAMESPACE diff --git a/modules/kernel/src/log.cpp b/modules/kernel/src/log.cpp index fd5dcf6e45..0ac6dd554f 100644 --- a/modules/kernel/src/log.cpp +++ b/modules/kernel/src/log.cpp @@ -10,6 +10,7 @@ #include "IMP/file.h" #include "IMP/Object.h" #include "internal/base_static.h" +#include #include "IMP/thread_macros.h" #ifdef _OPENMP #include @@ -138,7 +139,7 @@ void reset_log_timer() { #if IMP_KERNEL_HAS_LOG4CXX #else - internal::log_timer = boost::timer(); + internal::log_timer = internal::SimpleTimer(); #endif } @@ -209,7 +210,7 @@ void set_progress_display(std::string description, unsigned int steps) { if (get_log_level() == PROGRESS) { IMP_USAGE_CHECK(!internal::progress, "There is already a progress bar."); std::cout << description << std::endl; - internal::progress.reset(new boost::progress_display(steps)); + internal::progress.reset(new IMP::internal::BoostProgressDisplay(steps)); } } diff --git a/modules/kernel/test/test_const_optimizer.py b/modules/kernel/test/test_const_optimizer.py new file mode 100644 index 0000000000..df52c00296 --- /dev/null +++ b/modules/kernel/test/test_const_optimizer.py @@ -0,0 +1,24 @@ +from __future__ import print_function +import IMP +import IMP.test +import pickle + + +class Tests(IMP.test.TestCase): + """Test ConstOptimizer""" + + def test_pickle(self): + """Test (un-)pickle of ConstOptimizer""" + m = IMP.Model() + opt = IMP._ConstOptimizer(m) + opt.set_name("foo") + opt.set_stop_on_good_score(True) + dump = pickle.dumps(opt) + + newopt = pickle.loads(dump) + self.assertEqual(newopt.get_name(), "foo") + self.assertEqual(newopt.get_stop_on_good_score(), True) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/kernel/test/test_const_restraint.py b/modules/kernel/test/test_const_restraint.py new file mode 100644 index 0000000000..593e9e6558 --- /dev/null +++ b/modules/kernel/test/test_const_restraint.py @@ -0,0 +1,25 @@ +from __future__ import print_function +import IMP +import IMP.test +import pickle + + +class Tests(IMP.test.TestCase): + """Test ConstRestraint""" + + def test_pickle(self): + """Test (un-)pickle of ConstRestraint""" + m = IMP.Model() + p1 = IMP.Particle(m) + p2 = IMP.Particle(m) + r = IMP._ConstRestraint(m, [p1, p2], 42.0) + r.set_name("foo") + dump = pickle.dumps(r) + + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.get_value(), 42.0, delta=1e-3) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/kernel/test/test_model.py b/modules/kernel/test/test_model.py index 28c07f8ec7..16ee62cea7 100644 --- a/modules/kernel/test/test_model.py +++ b/modules/kernel/test/test_model.py @@ -3,6 +3,8 @@ import IMP.test import io import random +import IMP.core +import pickle class DummyRestraint(IMP.Restraint): @@ -306,6 +308,264 @@ def test_save_restore_dependencies_bad(self): # (as p2 was added) self.assertRaisesInternalException(m.restore_dependencies) + def test_unique_id(self): + """Each Model should get a unique ID""" + m1 = IMP.Model() + m2 = IMP.Model() + self.assertNotEqual(m1.get_unique_id(), m2.get_unique_id()) + self.assertIsInstance(m1.get_unique_id(), int) + + m1id = m1.get_unique_id() + self.assertEqual(IMP.Model.get_by_unique_id(m1id), m1) + del m1 + self.assertIsNone(IMP.Model.get_by_unique_id(m1id)) + + def test_unique_id_duplication(self): + """Duplicating a Model should not duplicate the unique ID""" + m1 = IMP.Model() + m1_orig_id = m1.get_unique_id() + # Duplicate m1 via pickle + dump = pickle.dumps(m1) + m2 = pickle.loads(dump) + + # New model (m2) should keep the ID; old model should get a new one + self.assertEqual(m2.get_unique_id(), m1_orig_id) + self.assertNotEqual(m1.get_unique_id(), m1_orig_id) + + def test_serialize_object(self): + """Check that Object properties are (de-)serialized""" + m = IMP.Model("test model") + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(m2.get_name(), "test model") + + def test_serialize_int_attributes(self): + """Check that Model int attributes are (de-)serialized""" + m = IMP.Model() + ik = IMP.IntKey("hi") + p = IMP.Particle(m) + m.add_attribute(ik, p.get_index(), 42) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(m2.get_attribute(ik, p.get_index()), 42) + + def test_serialize_ints_attributes(self): + """Check that Model ints attributes are (de-)serialized""" + m = IMP.Model() + ik = IMP.IntsKey("hi") + p = IMP.Particle(m) + m.add_attribute(ik, p.get_index(), [1, 2, 42]) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(list(m2.get_attribute(ik, p.get_index())), [1, 2, 42]) + + def test_serialize_cache_int_attributes(self): + """Check that Model cache int attributes are (de-)serialized""" + m = IMP.Model() + ik = IMP.IntKey("hi") + p = IMP.Particle(m) + m.add_cache_attribute(ik, p.get_index(), 42) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(m2.get_attribute(ik, p.get_index()), 42) + + def test_serialize_float_attributes(self): + """Check that Model float attributes are (de-)serialized""" + m = IMP.Model() + fk = IMP.FloatKey("hi") + p = IMP.Particle(m) + m.add_attribute(fk, p.get_index(), 5.4) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertAlmostEqual(m2.get_attribute(fk, p.get_index()), 5.4, + delta=0.1) + + def test_serialize_floats_attributes(self): + """Check that Model floats attributes are (de-)serialized""" + m = IMP.Model() + fk = IMP.FloatsKey("hi") + p = IMP.Particle(m) + m.add_attribute(fk, p.get_index(), [1.0, 3.2, 5.4]) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + att = list(m2.get_attribute(fk, p.get_index())) + self.assertEqual(len(att), 3) + self.assertAlmostEqual(att[0], 1.0, delta=0.1) + self.assertAlmostEqual(att[1], 3.2, delta=0.1) + self.assertAlmostEqual(att[2], 5.4, delta=0.1) + + def test_serialize_string_attributes(self): + """Check that Model string attributes are (de-)serialized""" + m = IMP.Model() + sk = IMP.StringKey("hi") + p = IMP.Particle(m) + m.add_attribute(sk, p.get_index(), "test attribute") + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(m2.get_attribute(sk, p.get_index()), "test attribute") + + def test_serialize_object_attributes(self): + """Check that Model object attributes are (de-)serialized""" + m = IMP.Model() + ok = IMP.ObjectKey("hi") + p = IMP.Particle(m) + t = IMP._TestObject() + t.set_name("testobj") + m.add_attribute(ok, p.get_index(), t) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + newt = m2.get_attribute(ok, p.get_index()) + self.assertEqual(newt.get_name(), "testobj") + + def test_serialize_particle_attributes(self): + """Check that Model particle attributes are (de-)serialized""" + m = IMP.Model() + pk = IMP.ParticleIndexKey("hi") + p = IMP.Particle(m) + p2 = IMP.Particle(m) + m.add_attribute(pk, p.get_index(), p2) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + newp2 = m2.get_attribute(pk, p.get_index()) + self.assertEqual(newp2, p2.get_index()) + + def test_serialize_particles_attributes(self): + """Check that Model particles attributes are (de-)serialized""" + m = IMP.Model() + pk = IMP.ParticleIndexesKey("hi") + p = IMP.Particle(m) + p2 = IMP.Particle(m) + p3 = IMP.Particle(m) + m.add_attribute(pk, p.get_index(), [p2, p3]) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + newp2, newp3 = m2.get_attribute(pk, p.get_index()) + self.assertEqual(newp2, p2.get_index()) + self.assertEqual(newp3, p3.get_index()) + + def test_serialize_particles(self): + """Check that Model particles are (de-)serialized""" + m = IMP.Model() + p1 = m.add_particle("first") + p2 = m.add_particle("second") + p3 = m.add_particle("third") + m.remove_particle(p2) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(m2.get_particle_name(IMP.ParticleIndex(0)), "first") + self.assertEqual(m2.get_particle_name(IMP.ParticleIndex(2)), "third") + self.assertFalse(m2.get_has_particle(IMP.ParticleIndex(1))) + p4 = m2.add_particle("fourth") + # p2 was deleted, so new particle should use this index + self.assertEqual(p4, p2) + + def test_serialize_triggers(self): + """Check that Model triggers are correctly handled by serialization""" + m = IMP.Model() + tk = IMP.TriggerKey("test_trigger") + self.assertEqual(m.get_age(), 1) + m.update() + m.set_trigger_updated(tk) + self.assertEqual(m.get_age(), 2) + self.assertEqual(m.get_trigger_last_updated(tk), 2) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + # Model age should be reset + self.assertEqual(m2.get_age(), 1) + # All triggers should be reset + self.assertEqual(m2.get_trigger_last_updated(tk), 0) + + def test_serialize_data(self): + """Check that Model data are (de-)serialized""" + m = IMP.Model() + mk = IMP.ModelKey("data_key") + t = IMP._TestObject() + t.set_name("testobj") + m.add_data(mk, t) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertTrue(m2.get_has_data(mk)) + newt = m2.get_data(mk) + self.assertEqual(newt.get_name(), "testobj") + + def test_serialize_track_polymorphic(self): + """Check that serialization tracks polymorphic pointers""" + m = IMP.Model() + mk = IMP.ModelKey("data_key1") + mk2 = IMP.ModelKey("data_key2") + mk3 = IMP.ModelKey("data_key3") + t = IMP._TestObject() + t.set_name("testobj") + m.add_data(mk, t) + m.add_data(mk2, t) + t3 = IMP._TestObject() + t3.set_name("testobj3") + m.add_data(mk3, t3) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertTrue(m2.get_has_data(mk)) + self.assertTrue(m2.get_has_data(mk2)) + newt = m2.get_data(mk) + self.assertEqual(newt.get_name(), "testobj") + newt2 = m2.get_data(mk2) + self.assertEqual(newt2.get_name(), "testobj") + newt3 = m2.get_data(mk3) + self.assertEqual(newt3.get_name(), "testobj3") + # newt and newt2 should point to the same underlying C++ object + self.assertEqual(newt, newt2) + # They should be distinct from the objects in the original model though + self.assertNotEqual(t, newt) + + def test_serialize_score_states(self): + """Check that Model ScoreStates are (de-)serialized""" + m = IMP.Model() + m.score_states.append(IMP.core.ChecksScoreState(m, 0.0)) + + dump = pickle.dumps(m) + m2 = pickle.loads(dump) + self.assertEqual(len(m2.score_states), 1) + + def test_serialize_score_states_deleted(self): + """Check that Model ScoreState serialization survives model deletion""" + m = IMP.Model() + m.score_states.append(IMP.core.ChecksScoreState(m, 0.0)) + + dump = pickle.dumps(m) + # Make sure that the new ScoreState does not require (or get + # a pointer to) the old model + del m + m2 = pickle.loads(dump) + self.assertEqual(len(m2.score_states), 1) + + def test_model_object_same_model_python(self): + "ModelObject.get_model() should return the same Python Model object" + m = IMP.Model() + r = IMP._ConstRestraint(m, [], 1) + newm = r.get_model() + self.assertEqual(id(newm), id(m)) + + def test_decorator_same_model_python(self): + "Decorator.get_model() should return the same Python Model object" + m = IMP.Model() + p = IMP.Particle(m) + td = IMP._TrivialDecorator.setup_particle(p) + newm = td.get_model() + self.assertEqual(id(newm), id(m)) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/kernel/test/test_particles.py b/modules/kernel/test/test_particles.py index 34a1f1c0a8..68ce5919bb 100644 --- a/modules/kernel/test/test_particles.py +++ b/modules/kernel/test/test_particles.py @@ -1,6 +1,7 @@ from __future__ import print_function import IMP import IMP.test +import pickle xkey = IMP.FloatKey("x") @@ -37,7 +38,7 @@ def setup(self): p1.add_attribute(IMP.FloatKey("attr_" + str(i)), 3.5 * i, False) # clear derivatives print(model.get_ref_count()) - r = IMP._ConstRestraint(1, particles) + r = IMP._ConstRestraint(model, particles, 1) r.evaluate(True) print(model.get_ref_count()) return (model, particles) @@ -218,5 +219,28 @@ def test_many_particle(self): if i % 10000 == 0: print(i) + def test_pickle(self): + """Test that Particle can be (un-)pickled""" + m = IMP.Model() + p = IMP.Particle(m) + p.set_name("foo") + dump = pickle.dumps(p) + newp = pickle.loads(dump) + self.assertEqual(newp.get_name(), "foo") + self.assertEqual(newp.get_index(), p.get_index()) + + def test_decorator_pickle(self): + """Test that Decorators can be (un-)pickled""" + m = IMP.Model() + p = IMP.Particle(m) + p.set_name("foo") + td = IMP._TrivialDecorator.setup_particle(p) + dump = pickle.dumps(td) + newtd = pickle.loads(dump) + newp = newtd.get_particle() + self.assertEqual(newp.get_name(), "foo") + self.assertEqual(newp.get_index(), p.get_index()) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/kernel/test/test_restraint_info.py b/modules/kernel/test/test_restraint_info.py index 44d8f57a23..1ea38e99f1 100644 --- a/modules/kernel/test/test_restraint_info.py +++ b/modules/kernel/test/test_restraint_info.py @@ -47,6 +47,15 @@ def test_filename(self): self.assertEqual(ri.get_filename_key(0), "test filename") self.assertEqual(ri.get_filename_value(0), "foo") + def test_filename_string_naming(self): + """Test checks of suitable names for string or filename info""" + ri = IMP.RestraintInfo() + ri.set_was_used(True) + self.assertRaisesUsageException(ri.add_string, "test filename", "foo") + self.assertRaisesUsageException(ri.add_strings, "test filename", "foo") + self.assertRaisesUsageException(ri.add_filename, "test string", "foo") + self.assertRaisesUsageException(ri.add_filenames, "test string", "foo") + def test_floats(self): """Test get/set of floats RestraintInfo""" ri = IMP.RestraintInfo() diff --git a/modules/kernel/test/test_restraint_sets.py b/modules/kernel/test/test_restraint_sets.py index 487af841f1..1d07e438b2 100644 --- a/modules/kernel/test/test_restraint_sets.py +++ b/modules/kernel/test/test_restraint_sets.py @@ -2,6 +2,7 @@ import IMP import IMP.core import IMP.test +import pickle class LinkScoreState(IMP.ScoreState): """ScoreState that links one particle to another""" @@ -71,6 +72,32 @@ def test_aggregate(self): self.assertFalse(r1.get_is_aggregate()) self.assertTrue(rs.get_is_aggregate()) + def test_pickle(self): + """Test that RestraintSet can be (un-)pickled""" + m, rs, r0, r1, r2 = self._make_stuff() + rs.set_name("foo") + r0.set_name("bar") + r1.set_name("baz") + self.assertEqual(rs.evaluate(False), 1) + dump = pickle.dumps(rs) + newrs = pickle.loads(dump) + self.assertEqual(newrs.get_name(), "foo") + self.assertEqual([r.get_name() for r in newrs.restraints], + ["bar", "baz"]) + self.assertEqual(newrs.evaluate(False), 1) + + def test_pickle_polymorphic(self): + """Test that RestraintSet can be (un-)pickled via polymorphic pointer""" + m = IMP.Model() + rs1 = IMP.RestraintSet(m, 2.0) + rs1.restraints.append(IMP._ConstRestraint(m, [], 1)) + rs2 = IMP.RestraintSet(m, 12.0) + rs2.restraints.append(rs1) + self.assertEqual(rs2.evaluate(False), 24.) + dump = pickle.dumps(rs2) + newrs2 = pickle.loads(dump) + self.assertEqual(newrs2.evaluate(False), 24.) + def test_restraints(self): """Check access to RestraintSet's restraints""" (m, rs, r0, r1, r2) = self._make_stuff() diff --git a/modules/kernel/test/test_scoring_function.py b/modules/kernel/test/test_scoring_function.py index e060992bd4..753ca221ed 100644 --- a/modules/kernel/test/test_scoring_function.py +++ b/modules/kernel/test/test_scoring_function.py @@ -11,7 +11,7 @@ def test_score_state_show(self): """Test scoring function linkage""" m = IMP.Model("scoring function linkage") ps = [IMP.Particle(m) for i in range(0, 10)] - r = IMP._ConstRestraint(1, ps) + r = IMP._ConstRestraint(m, ps, 1) r.create_scoring_function() self.assertEqual(r.evaluate(False), 1) @@ -19,7 +19,7 @@ def test_reweighting(self): """Test scoring function reweighting""" m = IMP.Model("scoring function linkage") ps = [IMP.Particle(m) for i in range(0, 10)] - r = IMP._ConstRestraint(1, ps) + r = IMP._ConstRestraint(m, ps, 1) rs = IMP.RestraintSet(m, 1.0, "rs") rs.add_restraint(r) rsf = rs.create_scoring_function() diff --git a/modules/kernel/test/test_utility.py b/modules/kernel/test/test_utility.py index 7863e956c4..e430a2b858 100644 --- a/modules/kernel/test/test_utility.py +++ b/modules/kernel/test/test_utility.py @@ -1,5 +1,6 @@ import IMP.test + class Tests(IMP.test.TestCase): def test_unique_name(self): @@ -8,5 +9,12 @@ def test_unique_name(self): self.assertEqual(IMP.get_unique_name("test%1%"), "test1") self.assertRaises(ValueError, IMP.get_unique_name, "test%2%") + def test_copyright(self): + """Test get_copyright()""" + c = IMP.get_copyright() + self.assertIn('Copyright', c) + self.assertIn('IMP Inventors', c) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/kinematics/bin/rrt_ccd.cpp b/modules/kinematics/bin/rrt_ccd.cpp index d4bcaf4e27..336d7aeccb 100644 --- a/modules/kinematics/bin/rrt_ccd.cpp +++ b/modules/kinematics/bin/rrt_ccd.cpp @@ -51,11 +51,12 @@ int main(int argc, char **argv) float radii_scaling = 0.5; bool reset_angles = false; std::string connect_chains_file; - po::options_description desc( + std::string desc_prefix( "Usage: \n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/kinematics/bin/rrt_sample.cpp b/modules/kinematics/bin/rrt_sample.cpp index 3efc83ee29..1bd11de5fe 100644 --- a/modules/kinematics/bin/rrt_sample.cpp +++ b/modules/kinematics/bin/rrt_sample.cpp @@ -50,11 +50,12 @@ int rrt_sample(int argc, char **argv) float radii_scaling = 0.5; bool reset_angles = false; std::string connect_chains_file; - po::options_description desc( + std::string desc_prefix( "Usage: \n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/kinematics/include/DOFValues.h b/modules/kinematics/include/DOFValues.h index 6ae0b88fd5..e7e76ee5c1 100644 --- a/modules/kinematics/include/DOFValues.h +++ b/modules/kinematics/include/DOFValues.h @@ -13,9 +13,9 @@ #include "DOF.h" #include -#include -#include -#include +#include +#include +#include IMPKINEMATICS_BEGIN_NAMESPACE @@ -85,10 +85,10 @@ class IMPKINEMATICSEXPORT DOFValues : public std::vector { }); private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & boost::serialization::base_object >(*this); + template void serialize(Archive &ar) { + ar(cereal::base_class >(this)); } }; @@ -96,4 +96,9 @@ IMP_VALUES(DOFValues, DOFValuesList); IMPKINEMATICS_END_NAMESPACE +// std::vector may serialize with load/save methods instead; force +// cereal to use our 'serialize' method +CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( + IMP::kinematics::DOFValues, cereal::specialization::member_serialize); + #endif /* IMPKINEMATICS_DOF_VALUES_H */ diff --git a/modules/kinematics/include/RRT.h b/modules/kinematics/include/RRT.h index c055c55526..8dec5d14db 100644 --- a/modules/kinematics/include/RRT.h +++ b/modules/kinematics/include/RRT.h @@ -19,7 +19,7 @@ #include #include -#include +#include IMPKINEMATICS_BEGIN_NAMESPACE @@ -173,7 +173,7 @@ class IMPKINEMATICSEXPORT RRT : public IMP::Sampler { private: PointerMember dofs_sampler_; PointerMember local_planner_; - typedef boost::shared_ptr RRTNodePtr; + typedef std::shared_ptr RRTNodePtr; typedef std::vector RRTTree; RRTTree tree_; DOFs cspace_dofs_; // configuration space dofs diff --git a/modules/kinematics/pyext/swig.i-in b/modules/kinematics/pyext/swig.i-in index a20488d727..1ff7cdc0b5 100644 --- a/modules/kinematics/pyext/swig.i-in +++ b/modules/kinematics/pyext/swig.i-in @@ -1,8 +1,3 @@ -%{ -#include -#include -%} - /* Tell swig how to treat various types when moving them to and from python. Among other things, they tell swig how to convert collections of C++ objects (eg ExampleRestraints) into python lists and back. diff --git a/modules/kinematics/src/FibrilSampler.cpp b/modules/kinematics/src/FibrilSampler.cpp index 34ea52b2d2..d4d9043519 100644 --- a/modules/kinematics/src/FibrilSampler.cpp +++ b/modules/kinematics/src/FibrilSampler.cpp @@ -15,7 +15,7 @@ IMPKINEMATICS_BEGIN_NAMESPACE FibrilSampler::FibrilSampler( TransformationJoints trans_joint, DihedralAngleRevoluteJoints joints, DOFs dofs) - : trans_joint_(trans_joint), dihedral_joints_(joints), DOFsSampler(dofs) { + : DOFsSampler(dofs), dihedral_joints_(joints), trans_joint_(trans_joint) { IMP_USAGE_CHECK(dihedral_joints_.size() == get_number_of_dofs() + -6, "FibrilSampler: number of joints should be equal to the number " << "of degrees of freedom minus 5"); diff --git a/modules/kinematics/src/ProteinKinematics.cpp b/modules/kinematics/src/ProteinKinematics.cpp index bfa5907261..b3b02a13ee 100644 --- a/modules/kinematics/src/ProteinKinematics.cpp +++ b/modules/kinematics/src/ProteinKinematics.cpp @@ -295,7 +295,7 @@ void ProteinKinematics::build_topology_graph() { // TODO: add IMP_CHECK on this code std::vector component(boost::num_vertices(graph_)); - unsigned int num = boost::connected_components(graph_, &component[0]); + // unsigned int num = boost::connected_components(graph_, &component[0]); //std::cout << "Num Connected Components = " << num << std::endl; } @@ -327,7 +327,7 @@ void ProteinKinematics::mark_rotatable_angle( IMP_THROW("cannot find node index for angle", ValueException); } std::vector component(boost::num_vertices(graph_)); - unsigned int num = boost::connected_components(graph_, &component[0]); + // unsigned int num = boost::connected_components(graph_, &component[0]); //std::cerr << "CC NUM before removal of rotatable bonds = " << component[0] // << std::endl; //std::cerr << "REMOVE EDGE = " << atom_index1 << atom_index2 << std::endl; diff --git a/modules/kinematics/test/test_kinematic_pdb.cpp b/modules/kinematics/test/test_kinematic_pdb.cpp index 0e7d537431..2d6ed203ed 100644 --- a/modules/kinematics/test/test_kinematic_pdb.cpp +++ b/modules/kinematics/test/test_kinematic_pdb.cpp @@ -31,22 +31,12 @@ IMP::Pointer build_model_pdb( std::string pdb_fname, IMP::core::RigidBodies& rbs, IMP::atom::Hierarchy& mhd); -void test_pdb_model(IMP::Model* model, IMP::core::RigidBodies& rbs, - bool print_hierarchy, - IMP::atom::Hierarchy mhd = IMP::atom::Hierarchy()); +void test_pdb_model(IMP::Model* model, IMP::core::RigidBodies& rbs); void test_model_with_rbs(IMP::Model* model, IMP::core::RigidBodies& rbs, bool print_hierarchy, IMP::atom::Hierarchy mhd = IMP::atom::Hierarchy()); -void print_transformation(IMP::algebra::Transformation3D T, - std::string description); - -void print_info(KinematicForest* kf, IMP::core::RigidBodies& rbs, - PrismaticJoint* pj0, DihedralAngleRevoluteJoint* dj1, - DihedralAngleRevoluteJoint* dj2, PrismaticJoint* pj3, - std::string action_desc); - void test_dihedral(IMP::Model* model, IMP::core::RigidBodies& rbs); /********** implementation ***********/ @@ -109,8 +99,7 @@ IMP::Pointer build_model_pdb( return m; } -void test_pdb_model(IMP::Model* model, IMP::core::RigidBodies& rbs, - bool /*print_hierarchy*/, IMP::atom::Hierarchy mhd) { +void test_pdb_model(IMP::Model* model, IMP::core::RigidBodies& rbs) { IMP_ALWAYS_CHECK(rbs.size() >= 5, "Must have at least 5 rigid bodies but only got " << rbs.size(), @@ -318,54 +307,6 @@ void test_model_with_rbs(IMP::Model* model, IMP::core::RigidBodies& rbs, << std::endl;*/ } -void print_transformation(IMP::algebra::Transformation3D T, - std::string description) { - std::pair aa = - IMP::algebra::get_axis_and_angle(T.get_rotation()); -/*std::cout << "trans " << description << ": " - << "axis = " << aa.first - << "; angle = " << aa.second * 180.0 / 3.141256 << " deg" - << "; translation = " << T.get_translation() << std::endl;*/ -} - -void print_info(KinematicForest* kf, IMP::core::RigidBodies& rbs, - PrismaticJoint* pj0, DihedralAngleRevoluteJoint* dj1, - DihedralAngleRevoluteJoint* dj2, PrismaticJoint* pj3, - std::string action_desc) { -/*std::cout << std::endl << "******** After " << action_desc << " ********" - << std::endl; - - std::cout << "Coords: " << kf->get_coordinates_safe(rbs[0]) << ", " - << kf->get_coordinates_safe(rbs[1]) << ", " - << kf->get_coordinates_safe(rbs[2]) << ", " - << kf->get_coordinates_safe(rbs[3]) << ", " - << kf->get_coordinates_safe(rbs[4]) << std::endl; - std::cout << "Distance 0-1: " - << IMP::algebra::get_distance(kf->get_coordinates_safe(rbs[0]), - kf->get_coordinates_safe(rbs[1])) - << std::endl; - std::cout << "Distance 1-2: " - << IMP::algebra::get_distance(kf->get_coordinates_safe(rbs[1]), - kf->get_coordinates_safe(rbs[2])) - << std::endl; - std::cout << "Distance 2-3: " - << IMP::algebra::get_distance(kf->get_coordinates_safe(rbs[2]), - kf->get_coordinates_safe(rbs[3])) - << std::endl; - std::cout << "Distance 3-4: " - << IMP::algebra::get_distance(kf->get_coordinates_safe(rbs[3]), - kf->get_coordinates_safe(rbs[4])) - << std::endl; - std::cout << "length 0-1 = " << pj0->get_length() << std::endl; - print_transformation(pj0->get_transformation_child_to_parent(), "0-1"); - std::cout << "angle 1-2 = " << dj1->get_angle() * 180 / 3.141256 << std::endl; - print_transformation(dj1->get_transformation_child_to_parent(), "1-2"); - std::cout << "angle 2-3 = " << dj2->get_angle() * 180 / 3.141256 << std::endl; - print_transformation(dj2->get_transformation_child_to_parent(), "2-3"); - std::cout << "length 3-4 = " << pj3->get_length() << std::endl; - print_transformation(pj3->get_transformation_child_to_parent(), "3-4");*/ -} - void test_dihedral(IMP::Model* model, IMP::core::RigidBodies& rbs) { IMP_ALWAYS_CHECK(rbs.size() >= 5, "Must have at least 5 rigid bodies but only got " @@ -386,23 +327,15 @@ void test_dihedral(IMP::Model* model, IMP::core::RigidBodies& rbs) { kf->add_edge(dj2); kf->add_edge(pj3); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "KinematicForest ctr"); dj1->set_angle(0.0 * 3.141259265358973 / 180); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle dj1 0 deg"); // dj1->set_angle(45.0 * 3.141259265358973/180); // print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle 45 deg"); dj1->set_angle(180.0 * 3.141259265358973 / 180); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle dj1 180 deg"); dj2->set_angle(0.0 * 3.141259265358973 / 180); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle dj2 0 deg"); dj1->set_angle(0.0 * 3.141259265358973 / 180); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle dj1 0 deg"); kf->set_coordinates_safe(rbs[1], IMP::algebra::Vector3D(0, 0, 1)); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle set_rbs[1] = 0,0,1"); dj1->set_angle(0.0 * 3.141259265358973 / 180); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle 0 deg"); dj1->set_angle(180.0 * 3.141259265358973 / 180); - print_info(kf, rbs, pj0, dj1, dj2, pj3, "set_angle 180 deg"); } int main(int argc, char *argv[]) { @@ -419,7 +352,7 @@ int main(int argc, char *argv[]) { IMP::atom::Hierarchy mhd2; IMP::Pointer m2 = build_model_pdb(fname, rbs2, mhd2); - test_pdb_model(m2, rbs2, true, mhd2); + test_pdb_model(m2, rbs2); // test_model_with_rbs(m2, rbs2, true, mhd); // test_dihedral(m2, rbs2); } diff --git a/modules/mmcif/pyext/src/data.py b/modules/mmcif/pyext/src/data.py index e5a733947c..e3efa1b56f 100644 --- a/modules/mmcif/pyext/src/data.py +++ b/modules/mmcif/pyext/src/data.py @@ -10,6 +10,7 @@ import ihm.analysis import ihm.protocol import ihm.model +import ihm.citations def get_molecule(h): @@ -426,20 +427,44 @@ def get_all(self): class _AllSoftware(object): """Keep track of all Software objects.""" + + # IMP/RMF doesn't store citation info for software, so provide it + # for known software packages + cites = {'Integrative Modeling Platform (IMP)': ihm.citations.imp, + 'IMP PMI module': ihm.citations.pmi} + def __init__(self, system): self.system = system + self._by_namever = {} super(_AllSoftware, self).__init__() def add_hierarchy(self, h): # todo: if no SoftwareProvenance available, use RMF producer field for p in IMP.core.get_all_provenance( h, types=[IMP.core.SoftwareProvenance]): - self.system.software.append( - ihm.Software(name=p.get_software_name(), - classification='integrative model building', - description=None, - version=p.get_version(), - location=p.get_location())) + self._add_provenance(p) + + def _add_provenance(self, p): + """Add Software from SoftwareProvenance""" + # Only reference the same version of a given software package once + name = p.get_software_name() + version = p.get_version() + if (name, version) not in self._by_namever: + s = ihm.Software(name=name, + classification='integrative model building', + description=None, version=version, + location=p.get_location(), + citation=self.cites.get(name)) + self.system.software.append(s) + self._by_namever[name, version] = s + return self._by_namever[name, version] + + def _add_previous_provenance(self, prov): + """Add Software from a previous SoftwareProvenance, if any""" + while prov: + if IMP.core.SoftwareProvenance.get_is_setup(prov): + return self._add_provenance(IMP.core.SoftwareProvenance(prov)) + prov = prov.get_previous() class _ExternalFiles(object): @@ -467,7 +492,7 @@ def add_hierarchy(self, h): class _ProtocolStep(ihm.protocol.Step): """A single step (e.g. sampling, refinement) in a protocol.""" - def __init__(self, prov, num_models_begin, assembly): + def __init__(self, prov, num_models_begin, assembly, all_software): method = prov.get_method() if prov.get_number_of_replicas() > 1: method = "Replica exchange " + method @@ -481,7 +506,8 @@ def __init__(self, prov, num_models_begin, assembly): # todo: support multiple states, time ordered multi_state=False, ordered=False, # todo: revisit assumption all models are multiscale - multi_scale=True) + multi_scale=True, + software=all_software._add_previous_provenance(prov)) def add_combine(self, prov): self.num_models_end = prov.get_number_of_frames() @@ -494,14 +520,14 @@ class _Protocol(ihm.protocol.Protocol): refinement) followed by a number of postprocessing steps (e.g. filtering, rescoring, clustering)""" - def add_step(self, prov, num_models, assembly): + def add_step(self, prov, num_models, assembly, all_software): if isinstance(prov, IMP.core.CombineProvenance): # Fold CombineProvenance into a previous sampling step if len(self.steps) == 0: raise ValueError("CombineProvenance with no previous sampling") return self.steps[-1].add_combine(prov) else: - ps = _ProtocolStep(prov, num_models, assembly) + ps = _ProtocolStep(prov, num_models, assembly, all_software) self.steps.append(ps) return ps.num_models_end @@ -532,7 +558,7 @@ def __init__(self, system): def _add_protocol(self, prot): self.system.orphan_protocols.append(prot) - def _add_hierarchy(self, h, modeled_assembly): + def _add_hierarchy(self, h, modeled_assembly, all_software): num_models = 0 # assume we always start with no models prot_types = (IMP.core.SampleProvenance, IMP.core.CombineProvenance) pp_types = (IMP.core.FilterProvenance, IMP.core.ClusterProvenance) @@ -548,7 +574,8 @@ def _add_hierarchy(self, h, modeled_assembly): # Start a new protocol self._add_protocol(prot) prot = _Protocol() - num_models = prot.add_step(p, num_models, modeled_assembly) + num_models = prot.add_step(p, num_models, modeled_assembly, + all_software) in_postproc = False if len(prot.steps) > 0: self._add_protocol(prot) diff --git a/modules/mmcif/pyext/src/restraint.py b/modules/mmcif/pyext/src/restraint.py index ca0ab228b8..71cd48c5a7 100644 --- a/modules/mmcif/pyext/src/restraint.py +++ b/modules/mmcif/pyext/src/restraint.py @@ -6,13 +6,93 @@ import ihm.restraint +def _get_input_pis(r): + """Yield all input ParticleIndexes for a given Restraint""" + for inp in r.get_inputs(): + try: + p = IMP.Particle.get_from(inp) + yield p.get_index() + except ValueError: + pass + + +def _get_by_residue(m, p): + """Determine whether the given particle represents a specific residue + or a more coarse-grained object.""" + return (IMP.atom.Residue.get_is_setup(m, p) + or IMP.atom.Atom.get_is_setup(m, p)) + + +def _get_scale(m, p): + """Get the numerical value of the Scale particle""" + if not IMP.isd.Scale.get_is_setup(m, p): + raise ValueError("not scale particle") + return IMP.isd.Scale(m, p).get_scale() + + +class _AsymMapper(object): + """Map ParticleIndexes to ihm.AsymUnit""" + def __init__(self, m, system): + self.m = m + self.components = system.components + self._seen_ranges = {} + + def __getitem__(self, pi): + m = self.m + # Walk up the hierarchy until we find the Chain, + # then map that to AsymUnit + if IMP.atom.Hierarchy.get_is_setup(m, pi): + h = IMP.atom.Hierarchy(m, pi) + while h: + if IMP.atom.Chain.get_is_setup(m, h): + return self.components[IMP.atom.Chain(h)].asym_unit + h = h.get_parent() + raise KeyError("Could not find top-level Chain for " + + m.get_particle_name(pi)) + + def get_feature(self, ps): + """Get an ihm.restraint.Feature that covers the given particles""" + # todo: handle things other than residues + m = self.m + rngs = [] + for p in ps: + asym = self[p] + # todo: handle overlapping ranges + if IMP.atom.Residue.get_is_setup(m, p): + rind = IMP.atom.Residue(m, p).get_index() + rng = asym(rind, rind) + elif IMP.atom.Fragment.get_is_setup(m, p): + # PMI Fragments always contain contiguous residues + rinds = IMP.atom.Fragment(m, p).get_residue_indexes() + rng = asym(rinds[0], rinds[-1]) + else: + raise ValueError("Unsupported particle type %s" % str(p)) + # Join contiguous ranges + if len(rngs) > 0 and rngs[-1].asym == asym \ + and rngs[-1].seq_id_range[1] == rng.seq_id_range[0] - 1: + rngs[-1].seq_id_range = (rngs[-1].seq_id_range[0], + rng.seq_id_range[1]) + else: + rngs.append(rng) + # If an identical feature already exists, return that + # todo: python-ihm should handle this automatically for us + hrngs = tuple(rngs) + if hrngs in self._seen_ranges: + return self._seen_ranges[hrngs] + else: + feat = ihm.restraint.ResidueFeature(rngs) + self._seen_ranges[hrngs] = feat + return feat + + def _parse_restraint_info(info): """Convert RestraintInfo object to Python dict""" d = {} if info is None: return d info.set_was_used(True) - for typ in ('int', 'float', 'string', 'filename', 'floats', 'filenames'): + for typ in ('int', 'float', 'string', 'filename', 'floats', 'filenames', + 'particle_indexes'): for i in range(getattr(info, 'get_number_of_' + typ)()): key = getattr(info, 'get_%s_key' % typ)(i) value = getattr(info, 'get_%s_value' % typ)(i) @@ -23,7 +103,7 @@ def _parse_restraint_info(info): class _GaussianEMRestraint(ihm.restraint.EM3DRestraint): """Handle an IMP.isd.GaussianEMRestraint""" - def __init__(self, imp_restraint, info, modeled_assembly): + def __init__(self, imp_restraint, info, modeled_assembly, system): self._imp_restraint = imp_restraint p = IMP.mmcif.metadata._GMMParser() r = p.parse_file(info['filename']) @@ -39,10 +119,166 @@ def add_model_fit(self, model): cross_correlation_coefficient=info['cross correlation']) +class _CrossLinkRestraint(ihm.restraint.CrossLinkRestraint): + def __init__(self, imp_restraint, info, modeled_assembly, system): + self._imp_restraint = imp_restraint + loc = ihm.location.InputFileLocation( + info['filename'], details='Crosslinks') + dataset = ihm.dataset.CXMSDataset(loc) + linker = ihm.ChemDescriptor( + auth_name=info['linker author name'], + chemical_name=info.get('linker chemical name'), + smiles=info.get('linker smiles'), + smiles_canonical=info.get('linker smiles canonical'), + inchi=info.get('linker inchi'), + inchi_key=info.get('linker inchi key')) + super(_CrossLinkRestraint, self).__init__( + dataset=dataset, linker=linker) + # Map from IMP/RMF chain names to ihm.Entity + cmap = dict((e.description, e) for e in system.entities.get_all()) + dist = ihm.restraint.UpperBoundDistanceRestraint(info['linker length']) + asym = _AsymMapper(imp_restraint.get_model(), system) + self._add_all_links(IMP.RestraintSet.get_from(imp_restraint), cmap, + asym, dist) + + def _add_all_links(self, rset, cmap, asym, dist): + """Add info for each cross-link in the given RestraintSet""" + for link in rset.restraints: + # Recurse into any child RestraintSets + try: + child_rs = IMP.RestraintSet.get_from(link) + except ValueError: + child_rs = None + if child_rs: + self._add_all_links(child_rs, cmap, asym, dist) + else: + info = _parse_restraint_info(link.get_static_info()) + # todo: handle ambiguous cross-links, fix residue numbering + r1 = cmap[info['protein1']].residue(info['residue1']) + r2 = cmap[info['protein2']].residue(info['residue2']) + ex_xl = ihm.restraint.ExperimentalCrossLink(residue1=r1, + residue2=r2) + self.experimental_cross_links.append([ex_xl]) + # todo: handle multiple contributions + m = link.get_model() + endp1, endp2 = info['endpoints'] + asym1 = asym[endp1] + asym2 = asym[endp2] + if _get_by_residue(m, endp1) and _get_by_residue(m, endp2): + cls = ihm.restraint.ResidueCrossLink + else: + cls = ihm.restraint.FeatureCrossLink + xl = cls(ex_xl, asym1=asym1, asym2=asym2, distance=dist, + restrain_all=False, + psi=_get_scale(m, info['psis'][0]), + sigma1=_get_scale(m, info['sigmas'][0]), + sigma2=_get_scale(m, info['sigmas'][1])) + self.cross_links.append(xl) + + def add_model_fit(self, model): + pass # todo + + +class _EM2DRestraint(ihm.restraint.EM2DRestraint): + """Handle an IMP.em2d.PCAFitRestraint""" + + def __init__(self, imp_restraint, info, modeled_assembly, system): + # todo: handle more than one image + self._imp_restraint = imp_restraint + loc = ihm.location.InputFileLocation( + info['image files'][0], + details="Electron microscopy class average") + dataset = ihm.dataset.EM2DClassDataset(loc) + super(_EM2DRestraint, self).__init__( + dataset=dataset, + assembly=modeled_assembly, # todo: fill in correct assembly + segment=False, + number_raw_micrographs=info['micrographs number'] or None, + pixel_size_width=info['pixel size'], + pixel_size_height=info['pixel size'], + image_resolution=info['resolution'], + number_of_projections=info['projection number']) + + def add_model_fit(self, model): + # todo: handle multiple images + nimage = 0 + info = _parse_restraint_info(self._imp_restraint.get_dynamic_info()) + ccc = info['cross correlation'][nimage] + transform = self._get_transformation(model, info, nimage) + rot = transform.get_rotation() + rm = [[e for e in rot.get_rotation_matrix_row(i)] for i in range(3)] + self.fits[model] = ihm.restraint.EM2DRestraintFit( + cross_correlation_coefficient=ccc, rot_matrix=rm, + tr_vector=transform.get_translation()) + + def _get_transformation(self, model, info, nimage): + """Get the transformation that places the model on image nimage""" + r = info['rotation'][nimage * 4: nimage * 4 + 4] + t = info['translation'][nimage * 3: nimage * 3 + 3] + return IMP.algebra.Transformation3D(IMP.algebra.Rotation3D(*r), + IMP.algebra.Vector3D(*t)) + + +class _GeometricRestraint(ihm.restraint.GeometricRestraint): + """Base for all geometric restraints""" + + def __init__(self, imp_restraint, info, modeled_assembly, system): + self._imp_restraint = imp_restraint + asym = _AsymMapper(imp_restraint.get_model(), system) + super(_GeometricRestraint, self).__init__( + dataset=None, + geometric_object=self._geom_object, + feature=asym.get_feature(_get_input_pis(imp_restraint)), + distance=self._get_distance(info), + harmonic_force_constant=1. / info['sigma'], + restrain_all=True) + + def _get_distance(self, info): + pass + + def add_model_fit(self, model): + pass + + +class _ZAxialRestraint(_GeometricRestraint): + """Handle an IMP.npc.ZAxialRestraint""" + _geom_object = ihm.geometry.XYPlane() + + def _get_distance(self, info): + return ihm.restraint.LowerUpperBoundDistanceRestraint( + info['lower bound'], info['upper bound']) + + +class _SAXSRestraint(ihm.restraint.SASRestraint): + """Handle an IMP.saxs.Restraint""" + + def __init__(self, imp_restraint, info, modeled_assembly, system): + self._imp_restraint = imp_restraint + loc = ihm.location.InputFileLocation( + info['filename'], details='SAXS profile') + dataset = ihm.dataset.SASDataset(loc) + super(_SAXSRestraint, self).__init__( + dataset=dataset, + assembly=modeled_assembly, # todo: fill in correct assembly + segment=False, fitting_method='IMP SAXS restraint', + fitting_atom_type=info['form factor type'], + multi_state=False) + + def add_model_fit(self, model): + # We don't know the chi value; we only report a score + self.fits[model] = ihm.restraint.SASRestraintFit(chi_value=None) + + class _RestraintMapper(object): """Map IMP restraints to mmCIF objects""" def __init__(self, system): - self._typemap = {"IMP.isd.GaussianEMRestraint": _GaussianEMRestraint} + self._typemap = { + "IMP.isd.GaussianEMRestraint": _GaussianEMRestraint, + "IMP.pmi.CrossLinkingMassSpectrometryRestraint": + _CrossLinkRestraint, + "IMP.em2d.PCAFitRestraint": _EM2DRestraint, + "IMP.npc.ZAxialPositionRestraint": _ZAxialRestraint, + "IMP.saxs.Restraint": _SAXSRestraint} self._system = system def handle(self, r, model, modeled_assembly): @@ -51,6 +287,7 @@ def handle(self, r, model, modeled_assembly): mmCIF, otherwise None.""" info = _parse_restraint_info(r.get_static_info()) if 'type' in info and info['type'] in self._typemap: - r = self._typemap[info['type']](r, info, modeled_assembly) + r = self._typemap[info['type']](r, info, modeled_assembly, + self._system) r.add_model_fit(model) return r diff --git a/modules/mmcif/pyext/src/util.py b/modules/mmcif/pyext/src/util.py index 54d1de7b55..4fc1c039f0 100644 --- a/modules/mmcif/pyext/src/util.py +++ b/modules/mmcif/pyext/src/util.py @@ -126,6 +126,8 @@ def _add_frame(self, frame): frame.id = len(self._frames) def _add_hierarchy(self, h, state): + if self.system.title is None: + self.system.title = h.get_name() chains = [IMP.atom.Chain(c) for c in IMP.atom.get_by_type(h, IMP.atom.CHAIN_TYPE)] if len(chains) == 0: @@ -148,9 +150,10 @@ def _add_hierarchy(self, h, state): # states, so we only need one copy of it in the mmCIF file if num_state_reps == 1: self.representation.extend(state.repsegments[component]) - self.protocols._add_hierarchy(h, state.modeled_assembly) - self._external_files.add_hierarchy(h) self._software.add_hierarchy(h) + self.protocols._add_hierarchy(h, state.modeled_assembly, + self._software) + self._external_files.add_hierarchy(h) def _get_all_starting_models(self, comp): """Get all starting models (in all states) for the given component""" @@ -281,12 +284,23 @@ def _add_hierarchy(self, h): self.system._add_hierarchy(h, self) def _add_restraints(self, rs, model): - m = IMP.mmcif.restraint._RestraintMapper(self.system) + mapper = IMP.mmcif.restraint._RestraintMapper(self.system) for r in rs: - rw = m.handle(r, model, self.modeled_assembly) - if rw: - self._wrapped_restraints.append(rw) - self.system.system.restraints.append(rw) + self._handle_restraint(mapper, r, model) + + def _handle_restraint(self, mapper, r, model): + rw = mapper.handle(r, model, self.modeled_assembly) + if rw: + self._wrapped_restraints.append(rw) + self.system.system.restraints.append(rw) + else: + try: + rs = IMP.RestraintSet.get_from(r) + except ValueError: + rs = None + if rs: + for child in rs.restraints: + self._handle_restraint(mapper, child, model) def _update_restraints(self, model): for rw in self._wrapped_restraints: diff --git a/modules/mmcif/test/input/6lyz.pdb.dat b/modules/mmcif/test/input/6lyz.pdb.dat new file mode 100644 index 0000000000..beebc08659 --- /dev/null +++ b/modules/mmcif/test/input/6lyz.pdb.dat @@ -0,0 +1,502 @@ +# SAXS profile: number of points = 500, q_min = 0, q_max = 0.5, delta_q = 0.001 +# q intensity +0.00000 3280254.92988282 +0.00100 3280024.02539636 +0.00200 3279331.33019150 +0.00300 3278177.29448420 +0.00400 3276561.94535789 +0.00500 3274486.48422156 +0.00600 3271951.25426406 +0.00700 3268957.77694140 +0.00800 3265506.31210441 +0.00900 3261599.97491119 +0.01000 3257238.07201537 +0.01100 3252424.32151185 +0.01200 3247159.23773709 +0.01300 3241446.13381289 +0.01400 3235286.07993632 +0.01500 3228682.87074482 +0.01600 3221636.93886111 +0.01700 3214154.03517394 +0.01800 3206235.02838116 +0.01900 3197883.50261112 +0.02000 3189102.62614794 +0.02100 3179897.81937419 +0.02200 3170268.46581922 +0.02300 3160222.20535305 +0.02400 3149760.87273025 +0.02500 3138890.87834558 +0.02600 3127614.17196423 +0.02700 3115936.50361947 +0.02800 3103860.13522221 +0.02900 3091393.17534814 +0.03000 3078538.56801494 +0.03100 3065301.26776359 +0.03200 3051685.37253554 +0.03300 3037700.41566996 +0.03400 3023346.22170991 +0.03500 3008631.90276465 +0.03600 2993561.05668122 +0.03700 2978141.13008535 +0.03800 2962376.65426387 +0.03900 2946275.93540863 +0.04000 2929840.33224233 +0.04100 2913080.84318972 +0.04200 2896001.95402497 +0.04300 2878608.59468399 +0.04400 2860910.08152620 +0.04500 2842912.02761757 +0.04600 2824618.56762149 +0.04700 2806039.70784615 +0.04800 2787180.13288729 +0.04900 2768049.62910473 +0.05000 2748651.54070352 +0.05100 2728996.23532779 +0.05200 2709086.29629811 +0.05300 2688933.12791364 +0.05400 2668542.50705235 +0.05500 2647921.80219907 +0.05600 2627076.98963802 +0.05700 2606019.09443363 +0.05800 2584750.90610143 +0.05900 2563281.06255616 +0.06000 2541619.28608073 +0.06100 2519772.05849947 +0.06200 2497746.25410273 +0.06300 2475551.26329993 +0.06400 2453188.83381564 +0.06500 2430673.03805581 +0.06600 2408008.82454011 +0.06700 2385202.72287712 +0.06800 2362264.79606745 +0.06900 2339201.76809060 +0.07000 2316018.85016657 +0.07100 2292725.45201791 +0.07200 2269328.65484997 +0.07300 2245837.89063716 +0.07400 2222258.90995719 +0.07500 2198599.11855814 +0.07600 2174862.68620049 +0.07700 2151063.89809256 +0.07800 2127204.53938661 +0.07900 2103293.19852385 +0.08000 2079338.56571995 +0.08100 2055348.35132046 +0.08200 2031325.46490373 +0.08300 2007280.25624245 +0.08400 1983219.09804813 +0.08500 1959149.44334486 +0.08600 1935077.30513102 +0.08700 1911010.97682428 +0.08800 1886953.30163515 +0.08900 1862915.13076270 +0.09000 1838902.40656517 +0.09100 1814919.53451826 +0.09200 1790973.45692422 +0.09300 1767074.82449142 +0.09400 1743220.20164103 +0.09500 1719423.63827589 +0.09600 1695689.40448105 +0.09700 1672025.01740454 +0.09800 1648434.84530528 +0.09900 1624925.05364691 +0.10000 1601498.27752496 +0.10100 1578162.51842657 +0.10200 1554924.43189384 +0.10300 1531787.03714844 +0.10400 1508756.44972394 +0.10500 1485842.30271947 +0.10600 1463038.48218685 +0.10700 1440361.30165183 +0.10800 1417808.94960433 +0.10900 1395388.51397021 +0.11000 1373104.59352844 +0.11100 1350961.23422564 +0.11200 1328961.48989701 +0.11300 1307111.27618922 +0.11400 1285415.01325822 +0.11500 1263875.79482966 +0.11600 1242497.72169436 +0.11700 1221285.50462589 +0.11800 1200237.65714681 +0.11900 1179362.45398274 +0.12000 1158661.48960958 +0.12100 1138142.73229072 +0.12200 1117802.94442110 +0.12300 1097648.08002575 +0.12400 1077679.99413481 +0.12500 1057899.95196416 +0.12600 1038317.14374196 +0.12700 1018926.88030237 +0.12800 999733.92857949 +0.12900 980742.31237098 +0.13000 961952.35682074 +0.13100 943363.92480993 +0.13200 924982.90789094 +0.13300 906810.57807728 +0.13400 888846.27369320 +0.13500 871093.93237347 +0.13600 853552.91031660 +0.13700 836225.91778608 +0.13800 819113.00710389 +0.13900 802217.27705542 +0.14000 785538.66759826 +0.14100 769077.61422500 +0.14200 752834.90096552 +0.14300 736812.26739805 +0.14400 721006.32275618 +0.14500 705424.68158955 +0.14600 690063.08083815 +0.14700 674923.28704517 +0.14800 660002.08301632 +0.14900 645302.96558055 +0.15000 630824.80126119 +0.15100 616568.04871227 +0.15200 602533.76729527 +0.15300 588719.69557113 +0.15400 575123.06874242 +0.15500 561748.09667468 +0.15600 548590.52497930 +0.15700 535654.84234235 +0.15800 522932.53912934 +0.15900 510430.06404964 +0.16000 498140.36355006 +0.16100 486070.59807573 +0.16200 474211.65070602 +0.16300 462566.80805070 +0.16400 451133.42387741 +0.16500 439910.68714210 +0.16600 428897.34730922 +0.16700 418090.64909937 +0.16800 407489.51746055 +0.16900 397096.50015184 +0.17000 386905.01620117 +0.17100 376915.66818048 +0.17200 367125.60943277 +0.17300 357534.92201960 +0.17400 348141.58300863 +0.17500 338942.43802568 +0.17600 329934.23546489 +0.17700 321120.17403516 +0.17800 312493.46191568 +0.17900 304054.57045743 +0.18000 295801.61482087 +0.18100 287733.70046648 +0.18200 279843.13406232 +0.18300 272133.18986175 +0.18400 264599.83930793 +0.18500 257242.85818992 +0.18600 250057.17362134 +0.18700 243041.68725710 +0.18800 236194.03461848 +0.18900 229514.69428117 +0.19000 222994.35669747 +0.19100 216641.08371512 +0.19200 210442.44031631 +0.19300 204404.26286928 +0.19400 198517.79162231 +0.19500 192784.68203504 +0.19600 187200.70252411 +0.19700 181764.85916614 +0.19800 176473.75213449 +0.19900 171326.29745468 +0.20000 166317.27601616 +0.20100 161448.53235683 +0.20200 156713.78043868 +0.20300 152113.97847878 +0.20400 147644.31048565 +0.20500 143303.30151369 +0.20600 139088.00342907 +0.20700 134997.65898161 +0.20800 131027.88852985 +0.20900 127181.12438149 +0.21000 123447.54642905 +0.21100 119830.05309311 +0.21200 116324.93586843 +0.21300 112929.23666369 +0.21400 109642.82439085 +0.21500 106462.95835272 +0.21600 103384.73255629 +0.21700 100409.22878340 +0.21800 97532.21525385 +0.21900 94750.80424744 +0.22000 92065.40469600 +0.22100 89473.95373156 +0.22200 86972.29813040 +0.22300 84558.58308334 +0.22400 82230.71647942 +0.22500 79989.97012435 +0.22600 77828.67584314 +0.22700 75749.91810724 +0.22800 73748.98107473 +0.22900 71823.58720953 +0.23000 69973.89531021 +0.23100 68197.22357251 +0.23200 66489.91591842 +0.23300 64852.88221984 +0.23400 63282.94429015 +0.23500 61776.16746747 +0.23600 60335.23308139 +0.23700 58955.62823521 +0.23800 57636.35898099 +0.23900 56374.53443757 +0.24000 55169.59794555 +0.24100 54021.49825367 +0.24200 52926.07450847 +0.24300 51882.29073233 +0.24400 50889.33003004 +0.24500 49944.79947008 +0.24600 49048.52337404 +0.24700 48197.51180485 +0.24800 47391.33093182 +0.24900 46627.71705109 +0.25000 45906.27131966 +0.25100 45224.09085676 +0.25200 44583.10514465 +0.25300 43978.83087583 +0.25400 43411.13369852 +0.25500 42877.90797419 +0.25600 42379.44350667 +0.25700 41912.97101055 +0.25800 41478.73224693 +0.25900 41074.73705646 +0.26000 40700.79972786 +0.26100 40353.33396759 +0.26200 40034.80105093 +0.26300 39740.56032382 +0.26400 39472.38438675 +0.26500 39228.25266006 +0.26600 39007.12165180 +0.26700 38808.50065206 +0.26800 38631.27058939 +0.26900 38473.13468956 +0.27000 38335.73132883 +0.27100 38215.96209974 +0.27200 38115.73268633 +0.27300 38030.44391340 +0.27400 37959.96664901 +0.27500 37907.83562833 +0.27600 37867.63571961 +0.27700 37842.98635127 +0.27800 37830.73757488 +0.27900 37830.84085513 +0.28000 37842.84332605 +0.28100 37865.30303690 +0.28200 37899.16571700 +0.28300 37942.25909057 +0.28400 37994.17245938 +0.28500 38055.45963586 +0.28600 38123.65559252 +0.28700 38199.81035387 +0.28800 38282.65644557 +0.28900 38372.37706561 +0.29000 38467.17696299 +0.29100 38568.55218834 +0.29200 38674.12939828 +0.29300 38784.24143619 +0.29400 38897.49396665 +0.29500 39015.52424799 +0.29600 39135.96503573 +0.29700 39258.66549479 +0.29800 39384.49605114 +0.29900 39512.42087566 +0.30000 39641.20574391 +0.30100 39771.80387697 +0.30200 39902.41340634 +0.30300 40034.43836451 +0.30400 40166.48254224 +0.30500 40297.92104785 +0.30600 40428.75725046 +0.30700 40559.99489442 +0.30800 40689.26436766 +0.30900 40818.10929764 +0.31000 40945.07755199 +0.31100 41069.94171304 +0.31200 41193.36906077 +0.31300 41314.54587008 +0.31400 41433.63306814 +0.31500 41549.08657413 +0.31600 41662.59820624 +0.31700 41773.18224375 +0.31800 41879.77059808 +0.31900 41984.20580028 +0.32000 42084.59521963 +0.32100 42181.19365171 +0.32200 42274.57961334 +0.32300 42362.86765500 +0.32400 42447.69856998 +0.32500 42528.40172834 +0.32600 42604.37452590 +0.32700 42676.19794223 +0.32800 42744.21295185 +0.32900 42806.39669438 +0.33000 42865.34740206 +0.33100 42917.36807933 +0.33200 42966.43753237 +0.33300 43009.84601722 +0.33400 43048.39380269 +0.33500 43081.59548677 +0.33600 43110.04762923 +0.33700 43132.42319627 +0.33800 43151.05201194 +0.33900 43163.31660716 +0.34000 43170.09674931 +0.34100 43171.91238405 +0.34200 43169.56481003 +0.34300 43160.36041916 +0.34400 43147.44475385 +0.34500 43128.15000681 +0.34600 43104.16935336 +0.34700 43073.98810117 +0.34800 43038.82711755 +0.34900 42998.81826930 +0.35000 42953.21974067 +0.35100 42902.99140903 +0.35200 42846.25374684 +0.35300 42784.87877366 +0.35400 42718.35044035 +0.35500 42647.33541031 +0.35600 42570.47400991 +0.35700 42488.91435894 +0.35800 42402.35553729 +0.35900 42310.91811664 +0.36000 42215.11072273 +0.36100 42114.04507204 +0.36200 42009.11702612 +0.36300 41898.60555028 +0.36400 41783.02651333 +0.36500 41663.24937885 +0.36600 41539.85994282 +0.36700 41411.27352446 +0.36800 41279.68838647 +0.36900 41143.65533812 +0.37000 41002.09949564 +0.37100 40856.71307463 +0.37200 40708.76245771 +0.37300 40556.15160229 +0.37400 40400.24708446 +0.37500 40240.92014091 +0.37600 40077.64627036 +0.37700 39910.89023691 +0.37800 39741.34844506 +0.37900 39568.90097510 +0.38000 39392.43818578 +0.38100 39213.40930050 +0.38200 39031.21976678 +0.38300 38846.29570411 +0.38400 38659.47110869 +0.38500 38468.98893063 +0.38600 38277.52744089 +0.38700 38082.34331328 +0.38800 37885.07285674 +0.38900 37686.02737754 +0.39000 37485.41529428 +0.39100 37282.62509871 +0.39200 37078.68010247 +0.39300 36871.69551860 +0.39400 36665.30177336 +0.39500 36455.96230937 +0.39600 36245.47377245 +0.39700 36033.98087487 +0.39800 35821.73847989 +0.39900 35608.48516621 +0.40000 35394.08769111 +0.40100 35178.76801127 +0.40200 34963.78992297 +0.40300 34747.37722697 +0.40400 34530.98602403 +0.40500 34314.34131026 +0.40600 34098.08463941 +0.40700 33880.96976797 +0.40800 33664.08665319 +0.40900 33447.25134995 +0.41000 33231.64608503 +0.41100 33015.29662549 +0.41200 32799.59168394 +0.41300 32585.14889165 +0.41400 32370.99571602 +0.41500 32157.42288715 +0.41600 31944.09160879 +0.41700 31732.71269763 +0.41800 31522.95549569 +0.41900 31312.06548783 +0.42000 31104.25781927 +0.42100 30897.28131167 +0.42200 30692.04475600 +0.42300 30487.50496976 +0.42400 30284.68312112 +0.42500 30083.82641605 +0.42600 29883.93820174 +0.42700 29686.64982327 +0.42800 29490.70954472 +0.42900 29297.31567588 +0.43000 29105.50632450 +0.43100 28914.86311968 +0.43200 28727.31586198 +0.43300 28541.25102757 +0.43400 28357.72762375 +0.43500 28176.17769128 +0.43600 27998.40692630 +0.43700 27820.93867483 +0.43800 27646.00162825 +0.43900 27474.47890579 +0.44000 27304.99780054 +0.44100 27138.16914843 +0.44200 26974.01832157 +0.44300 26811.81315350 +0.44400 26652.99204080 +0.44500 26495.32046738 +0.44600 26341.09137750 +0.44700 26190.23651471 +0.44800 26041.17775957 +0.44900 25895.56608561 +0.45000 25752.91752149 +0.45100 25611.58487659 +0.45200 25474.04880944 +0.45300 25338.92260463 +0.45400 25206.74498131 +0.45500 25077.31204647 +0.45600 24950.50641935 +0.45700 24826.61045831 +0.45800 24705.22981986 +0.45900 24586.51877110 +0.46000 24471.70168670 +0.46100 24357.97334007 +0.46200 24248.39779903 +0.46300 24140.71052576 +0.46400 24035.83881965 +0.46500 23934.09418166 +0.46600 23834.89565701 +0.46700 23737.64420996 +0.46800 23644.58215122 +0.46900 23552.62384882 +0.47000 23463.71250822 +0.47100 23377.74508812 +0.47200 23294.40007673 +0.47300 23213.57207565 +0.47400 23134.52173854 +0.47500 23058.75019085 +0.47600 22985.91518470 +0.47700 22913.85588556 +0.47800 22845.19292237 +0.47900 22779.30171780 +0.48000 22714.85698893 +0.48100 22654.12458322 +0.48200 22593.53869803 +0.48300 22536.16585472 +0.48400 22481.41290196 +0.48500 22428.43178618 +0.48600 22378.10409173 +0.48700 22329.26556891 +0.48800 22282.25241352 +0.48900 22237.39132211 +0.49000 22194.76176468 +0.49100 22154.33005609 +0.49200 22115.07899944 +0.49300 22078.18696752 +0.49400 22042.81127544 +0.49500 22009.09587115 +0.49600 21977.48937236 +0.49700 21947.33011934 +0.49800 21919.03032678 +0.49900 21892.04116712 diff --git a/modules/mmcif/test/input/image_2.pgm b/modules/mmcif/test/input/image_2.pgm new file mode 100644 index 0000000000..31c0bd6fc4 --- /dev/null +++ b/modules/mmcif/test/input/image_2.pgm @@ -0,0 +1,1103 @@ +P2 +110 110 +255 +85 89 93 93 89 93 89 85 89 85 85 85 89 +89 89 85 81 81 81 85 89 89 89 85 85 +85 89 89 85 89 93 93 89 89 93 93 93 +89 85 85 85 89 89 89 85 85 89 89 89 +93 97 97 93 89 93 97 97 93 89 85 85 +85 81 81 81 85 85 81 85 89 89 97 97 +93 93 85 89 93 89 89 85 85 89 93 89 +85 81 85 85 85 85 85 89 89 85 89 93 +93 93 89 89 85 81 85 89 89 93 93 89 +85 +85 89 89 81 81 81 81 85 89 93 93 93 93 +85 89 85 81 77 77 81 81 85 85 89 89 +93 89 93 97 93 93 93 89 93 93 89 89 +89 85 85 85 93 93 89 85 89 89 89 93 +93 93 93 93 89 93 97 93 89 85 81 85 +85 81 81 85 85 85 85 85 93 93 101 101 +97 97 89 89 89 89 81 81 81 85 85 85 +85 81 81 81 85 85 85 81 85 89 89 89 +93 97 93 93 93 93 89 97 93 93 93 89 +85 +85 85 89 85 85 81 81 81 81 89 89 93 89 +85 85 81 85 85 85 85 89 89 93 93 85 +85 89 93 97 93 93 89 93 93 97 89 93 +93 89 89 89 93 93 93 93 93 93 97 101 +97 93 93 85 85 85 93 93 89 89 89 89 +89 85 85 81 85 85 85 89 89 93 93 93 +93 93 89 89 85 85 81 81 85 85 89 89 +89 85 85 85 89 85 81 81 85 89 89 89 +89 89 89 93 93 89 93 93 93 93 93 89 +85 +85 85 85 89 89 85 85 81 81 81 85 85 85 +85 85 85 89 89 85 85 89 93 89 89 85 +85 85 85 89 85 85 89 89 97 101 93 89 +93 93 93 93 97 93 93 97 97 93 97 97 +97 89 89 85 81 85 89 89 89 89 89 89 +89 85 85 89 85 89 89 93 93 85 85 89 +93 93 89 85 89 81 77 81 81 81 85 89 +89 89 89 93 93 93 89 81 85 85 81 85 +85 85 85 89 89 85 89 93 97 93 97 93 +89 +89 85 85 81 85 89 81 81 81 81 81 81 81 +85 85 89 93 93 93 93 93 89 89 89 89 +85 81 81 85 89 89 93 97 97 97 93 89 +89 89 89 89 89 93 93 97 101 97 93 97 +97 89 89 85 81 85 81 85 85 89 93 89 +89 85 89 89 85 85 89 93 93 85 81 85 +89 89 89 85 81 77 77 77 81 77 85 85 +89 89 93 97 97 97 93 89 85 85 85 85 +81 81 85 89 85 85 85 89 97 97 97 93 +85 +89 85 81 81 81 85 81 81 85 85 85 81 89 +89 89 93 93 93 93 97 97 97 93 93 89 +85 81 81 85 89 93 101 101 97 93 93 93 +89 89 85 89 89 89 93 93 97 97 97 93 +93 89 89 81 81 85 81 81 85 85 89 85 +85 85 89 89 89 85 85 85 85 85 81 85 +85 89 89 89 85 81 77 81 77 85 85 85 +89 89 93 97 97 101 101 93 89 85 89 89 +85 85 89 89 85 85 85 89 93 97 97 93 +85 +89 89 85 85 81 85 85 81 85 81 85 85 89 +89 89 97 93 97 97 101 97 97 97 93 89 +85 85 85 89 93 93 101 101 97 97 97 93 +89 89 85 85 89 93 97 93 97 97 97 97 +93 89 85 85 81 85 85 81 81 85 89 85 +85 85 85 89 89 89 85 81 77 85 85 89 +89 89 89 85 85 81 85 81 81 89 89 89 +85 93 93 93 93 97 97 97 93 89 85 89 +89 85 85 85 85 81 81 85 89 93 97 93 +89 +85 85 85 85 85 85 89 85 81 85 85 85 85 +89 93 97 97 97 101 101 97 101 101 97 89 +89 89 89 93 97 97 101 105 101 97 97 93 +89 85 85 81 85 89 93 93 93 93 89 89 +89 85 85 81 81 85 81 77 81 85 89 85 +85 89 85 81 85 85 81 77 81 85 89 89 +89 89 89 89 89 85 85 85 85 89 93 93 +89 93 97 101 101 101 97 97 93 89 89 89 +89 85 85 89 85 85 89 89 85 89 93 89 +85 +85 85 81 85 89 85 85 85 81 81 81 85 85 +89 89 93 97 93 97 97 101 97 97 93 97 +93 89 93 97 97 97 97 105 105 97 93 89 +85 81 77 77 81 85 89 89 93 93 85 85 +81 81 81 81 81 81 77 81 85 89 85 85 +85 85 85 85 85 81 77 81 89 89 89 85 +89 89 89 89 85 81 85 85 85 85 89 97 +97 97 101 101 101 101 101 93 93 93 93 93 +89 89 85 85 85 85 89 89 85 89 93 89 +89 +85 85 85 85 85 85 85 85 81 85 85 85 85 +85 85 89 89 93 97 97 101 101 93 93 93 +89 89 93 93 93 97 97 101 97 93 89 93 +89 81 77 73 77 85 89 93 89 85 81 81 +81 81 81 81 77 77 77 81 85 85 85 85 +81 81 85 89 85 85 77 81 89 93 93 89 +89 89 89 89 85 85 85 85 85 85 93 93 +97 97 97 93 97 101 97 93 93 93 97 97 +89 85 85 85 85 85 85 85 89 93 93 89 +89 +85 85 85 85 85 81 85 81 85 89 85 81 77 +77 85 93 97 93 97 97 97 97 93 93 93 +89 89 93 89 89 93 101 101 97 97 89 85 +81 77 73 69 73 77 81 85 85 81 81 85 +85 81 85 85 81 77 77 81 85 77 85 81 +81 77 77 85 85 81 77 77 89 97 97 97 +97 93 93 93 89 89 85 89 85 85 85 93 +93 93 93 93 93 97 93 93 93 89 93 93 +85 85 85 85 85 81 89 89 85 93 97 89 +89 +85 85 85 85 85 81 81 81 85 85 85 81 77 +81 85 89 97 97 97 97 97 89 89 89 93 +89 89 89 93 85 89 93 97 93 89 85 77 +73 69 65 69 69 73 73 77 85 85 85 89 +85 85 89 89 85 81 81 89 89 81 81 81 +81 77 81 81 85 81 77 77 85 93 93 97 +97 93 93 97 93 89 89 89 89 89 85 89 +93 93 89 93 97 93 93 93 93 89 89 93 +89 89 85 85 85 85 93 89 89 89 93 85 +85 +85 85 85 85 85 81 81 81 85 85 85 81 77 +85 89 89 93 97 97 101 97 93 89 89 89 +89 89 89 89 85 81 89 93 89 81 77 73 +73 69 65 65 65 65 73 73 81 85 85 85 +85 89 89 89 81 85 85 85 85 81 81 81 +81 81 81 85 89 85 81 77 85 93 97 97 +93 93 93 93 89 93 97 93 85 85 85 85 +89 93 89 93 97 93 89 89 93 85 85 89 +89 93 89 89 89 89 93 93 93 89 89 85 +85 +89 89 89 85 85 85 81 85 89 89 81 81 81 +89 89 89 93 93 93 97 97 93 89 85 85 +89 89 85 85 85 85 81 85 81 77 73 73 +73 73 69 69 65 69 73 77 85 89 89 85 +85 89 89 85 85 85 85 81 81 77 77 81 +77 85 89 89 89 85 81 81 85 93 97 101 +97 97 93 93 89 93 97 93 85 89 85 85 +89 89 89 89 89 93 89 89 89 85 85 89 +93 93 93 89 89 89 89 89 89 89 93 89 +89 +89 89 93 89 85 85 85 81 85 89 89 85 81 +85 85 81 85 89 89 89 93 89 81 81 85 +89 89 85 85 85 85 81 85 81 77 81 77 +73 73 73 73 73 77 81 85 85 89 93 89 +85 89 85 85 85 81 85 85 81 77 73 77 +81 85 89 93 89 85 89 85 85 93 97 97 +97 97 97 93 93 93 93 93 89 89 89 81 +85 89 89 85 85 89 89 85 85 85 85 85 +89 89 89 89 85 89 89 89 89 85 89 85 +93 +89 89 89 89 89 89 89 89 89 89 89 85 81 +77 81 85 85 85 89 89 89 89 85 81 85 +85 81 77 77 81 81 81 81 81 77 81 77 +77 77 77 81 81 81 81 85 89 89 89 93 +85 85 85 89 89 85 81 85 81 77 77 81 +89 89 89 89 89 89 89 85 85 85 89 97 +97 97 101 97 93 93 93 93 89 85 85 85 +85 81 85 85 81 85 89 85 81 85 85 85 +85 89 89 89 89 85 85 85 85 85 85 81 +89 +89 89 89 89 89 93 93 93 93 89 89 89 81 +81 85 81 85 85 85 89 89 89 85 85 81 +77 77 73 77 77 77 81 81 77 77 77 73 +73 73 77 81 85 85 89 89 89 89 89 89 +89 89 89 89 89 81 81 85 81 81 81 81 +89 85 89 89 89 89 93 85 85 85 89 93 +93 93 93 93 93 93 89 89 89 89 89 85 +81 81 85 85 81 81 85 85 81 81 85 85 +85 85 85 85 89 85 85 85 85 85 85 85 +93 +93 93 89 89 89 93 89 93 93 93 89 89 85 +85 85 85 85 85 85 85 93 93 85 85 81 +77 73 69 73 73 73 81 77 77 77 81 77 +77 73 77 85 89 89 85 85 89 89 89 89 +89 93 89 85 85 85 85 85 85 81 85 85 +85 85 81 85 89 89 89 89 85 85 89 93 +89 89 93 93 93 89 89 85 89 89 89 85 +81 81 85 85 81 81 81 85 85 81 81 85 +81 85 85 85 89 85 85 85 89 89 85 85 +93 +89 93 93 93 89 89 93 93 97 93 93 93 89 +89 89 85 85 85 85 85 93 89 85 81 81 +77 73 69 73 73 73 77 81 77 77 77 77 +77 77 81 85 85 85 89 89 89 89 89 89 +89 89 89 85 89 89 85 81 81 81 81 81 +81 85 89 85 85 89 89 85 81 85 89 89 +89 89 93 93 93 89 85 85 89 85 85 85 +81 81 85 85 85 85 89 89 85 81 81 81 +85 81 85 85 89 89 85 89 89 85 81 85 +89 +89 93 97 97 93 93 93 97 93 89 93 89 89 +93 89 93 89 89 85 85 85 89 85 85 81 +73 77 73 81 81 77 77 77 77 81 77 81 +81 81 85 85 85 85 85 89 93 89 89 89 +85 85 85 85 85 85 81 77 81 81 77 77 +77 85 85 85 85 89 89 85 85 85 85 89 +93 93 93 93 89 85 85 85 89 89 89 85 +81 85 85 85 85 89 93 93 89 81 81 81 +89 89 89 89 93 89 85 85 93 89 85 89 +89 +93 93 97 97 93 93 97 97 93 93 93 93 89 +93 93 93 93 89 85 85 85 89 89 85 85 +81 77 81 85 85 81 81 81 81 77 77 81 +81 81 85 85 89 85 85 89 89 85 85 85 +81 81 81 81 81 85 85 81 77 73 77 77 +77 81 81 85 85 89 89 93 89 85 85 89 +93 93 93 93 93 93 89 89 85 85 89 81 +81 81 81 85 89 85 89 89 89 89 85 85 +85 89 89 89 93 89 89 85 89 89 85 89 +89 +93 93 97 93 93 93 101 93 93 93 97 93 89 +93 97 97 93 89 85 85 89 89 89 85 89 +89 85 89 85 85 81 81 85 85 85 85 81 +85 81 81 81 85 85 85 85 85 81 81 85 +81 81 81 85 85 81 81 81 73 73 73 73 +77 81 81 85 89 89 89 89 85 85 85 89 +93 89 89 89 97 93 89 85 85 85 85 81 +81 77 77 89 93 93 93 93 89 89 89 89 +93 93 93 93 93 89 89 89 89 93 89 93 +89 +93 89 89 93 93 93 97 93 93 89 89 93 89 +89 93 89 89 85 85 85 89 93 89 85 85 +85 85 89 89 89 81 85 85 89 89 93 85 +81 89 89 85 81 81 81 81 85 81 81 81 +81 77 81 81 81 85 85 81 77 73 77 77 +77 77 81 85 89 89 89 85 85 81 85 89 +89 93 89 89 93 89 85 85 81 85 81 81 +81 81 81 89 93 97 97 93 89 89 89 93 +89 97 101 93 89 85 85 89 89 89 85 93 +89 +89 89 89 89 89 89 93 93 89 85 89 89 89 +89 89 89 89 89 85 85 85 89 85 85 89 +89 85 89 93 93 89 89 89 89 89 89 85 +85 85 85 85 85 77 77 77 81 81 77 81 +77 77 77 77 81 89 85 81 73 73 77 77 +77 81 81 85 89 89 89 85 77 77 77 81 +81 85 89 85 85 85 81 85 85 85 81 81 +81 85 89 85 93 97 93 89 89 89 93 93 +89 93 93 89 89 89 85 85 93 89 85 89 +85 +85 85 85 89 89 89 89 89 89 85 85 85 85 +89 89 89 89 89 85 85 85 81 85 89 89 +89 85 89 93 93 93 93 93 89 89 85 85 +81 81 85 85 81 77 73 77 73 73 73 73 +73 77 81 81 81 85 85 81 77 73 73 77 +77 77 73 77 81 81 77 73 69 73 73 69 +73 77 77 77 73 73 73 77 77 81 81 81 +85 85 85 89 93 93 85 85 85 89 93 89 +89 89 89 89 93 93 89 89 93 93 89 89 +81 +81 81 85 85 85 85 85 89 85 89 89 85 89 +89 93 89 85 85 85 85 85 81 81 81 81 +85 85 89 93 89 93 89 89 89 85 85 85 +85 85 85 85 81 73 73 77 73 69 69 73 +77 81 81 81 81 85 81 81 77 73 73 73 +73 73 69 65 69 69 65 60 56 60 60 60 +65 69 65 65 65 65 65 69 69 73 77 81 +85 85 85 85 89 85 85 77 77 85 93 89 +89 85 89 89 89 89 93 93 97 93 85 85 +81 +81 81 81 85 81 81 85 85 81 85 85 85 89 +85 89 89 85 81 81 81 81 77 81 81 81 +81 85 89 89 85 85 89 89 85 85 89 85 +89 85 81 81 81 77 77 77 73 77 77 77 +81 81 77 77 81 81 81 81 73 65 65 69 +65 60 65 60 56 52 48 48 48 44 48 48 +52 56 52 52 56 56 56 60 60 65 73 81 +81 81 81 85 85 81 81 77 77 85 89 85 +85 85 85 81 89 93 97 97 93 89 85 85 +85 +81 81 81 81 81 81 81 81 81 81 81 85 85 +85 85 85 85 85 81 85 81 81 81 85 85 +81 85 85 85 85 85 89 89 89 89 89 85 +89 85 85 77 77 77 77 77 81 81 81 77 +77 81 81 81 85 81 73 73 65 60 56 60 +56 56 52 44 44 44 36 40 36 40 40 40 +44 44 44 48 48 48 48 56 56 60 65 73 +73 73 77 85 81 81 77 81 77 81 85 85 +85 81 81 81 89 93 93 97 93 93 89 89 +89 +81 85 81 81 85 81 85 85 85 85 85 89 85 +85 85 85 81 81 85 85 89 85 85 89 89 +89 89 89 85 85 85 89 93 89 89 89 89 +89 85 85 77 77 77 81 81 85 85 85 81 +81 85 77 81 81 73 69 60 60 60 52 48 +48 48 44 32 36 36 32 32 32 32 36 36 +40 40 44 48 48 44 48 52 52 56 60 65 +65 69 73 81 77 81 81 77 77 77 81 81 +81 81 81 81 85 89 93 97 97 93 93 93 +85 +85 89 81 81 85 77 85 89 89 85 89 93 89 +89 85 81 81 81 81 85 89 89 89 89 93 +93 89 93 93 89 85 89 89 89 89 89 93 +89 89 81 73 73 77 81 81 85 85 85 85 +85 81 77 73 69 60 52 56 52 52 48 52 +48 44 44 36 32 36 36 32 28 28 36 44 +44 48 52 56 52 48 52 52 52 52 56 56 +60 65 69 81 77 77 77 77 77 73 73 73 +77 81 81 85 81 89 89 93 93 89 93 89 +85 +85 85 81 81 77 81 85 89 89 89 89 85 89 +89 85 85 85 85 81 85 85 85 89 93 93 +89 89 93 101 93 85 81 85 85 85 89 89 +89 85 81 77 77 81 85 85 85 85 81 81 +81 81 69 65 56 48 44 44 44 48 48 52 +48 44 44 48 40 44 40 36 32 36 44 52 +56 60 60 65 65 56 56 56 48 48 48 52 +52 56 65 73 73 73 77 73 69 73 73 69 +73 77 85 85 85 85 89 89 89 89 89 85 +85 +89 89 89 85 85 85 85 89 85 85 85 85 89 +89 85 85 85 85 85 89 85 85 89 89 93 +89 89 93 93 89 85 81 85 81 77 81 85 +89 85 85 85 85 85 85 81 81 81 77 73 +73 69 60 52 48 40 40 44 44 44 56 60 +52 52 52 52 56 56 52 44 48 56 60 69 +73 77 77 77 77 73 65 56 52 52 44 48 +48 52 60 69 77 73 73 73 73 69 69 73 +73 77 89 89 89 89 89 93 89 89 85 81 +89 +89 89 89 85 81 85 85 85 85 89 89 85 85 +85 81 81 85 85 85 93 93 85 85 89 89 +89 85 85 85 81 77 77 77 73 73 77 81 +85 85 85 85 85 89 89 85 81 77 73 65 +65 65 52 48 44 40 36 40 40 48 60 65 +69 69 73 77 81 77 73 69 73 77 81 85 +93 97 97 97 93 89 81 73 65 56 52 48 +48 48 56 65 69 77 73 77 77 73 73 77 +81 85 85 89 89 89 89 93 93 89 85 81 +85 +85 85 85 85 89 89 89 89 93 93 93 85 85 +81 81 81 81 81 85 85 89 85 85 89 89 +89 85 81 77 77 69 65 65 69 73 77 81 +85 81 81 81 85 89 85 85 77 73 69 56 +52 52 48 44 44 40 40 44 48 52 65 81 +89 93 101 105 105 101 101 97 97 97 105 113 +113 117 117 117 117 109 97 89 73 65 56 52 +48 48 56 60 65 69 73 73 77 77 77 81 +89 89 89 89 89 89 93 89 93 93 93 85 +85 +85 85 85 89 89 89 89 93 97 93 93 89 85 +81 81 77 77 81 77 81 85 85 85 85 85 +85 81 81 81 73 65 56 56 65 65 69 77 +77 81 77 81 81 85 81 81 69 69 65 56 +48 48 44 40 40 40 44 48 56 69 81 97 +109 121 125 130 134 130 125 130 125 125 125 130 +138 146 146 142 138 125 113 101 85 73 60 56 +56 52 48 56 60 73 77 81 85 81 81 85 +89 93 93 93 93 93 93 93 89 93 93 85 +81 +89 89 89 89 93 89 93 93 97 93 89 85 85 +81 77 77 77 73 73 81 89 89 85 85 85 +85 81 85 77 73 65 65 65 60 65 65 73 +73 77 81 77 81 85 81 73 65 60 60 52 +48 40 40 36 40 44 48 56 69 85 101 117 +134 142 150 158 162 166 162 162 154 146 150 154 +162 174 174 170 162 146 130 109 93 77 65 56 +52 48 48 52 60 73 81 81 89 89 89 89 +97 101 97 97 101 97 97 97 89 89 93 89 +85 +93 93 93 93 97 93 97 93 97 93 89 85 85 +81 81 77 81 81 81 81 89 89 89 85 85 +85 85 81 77 77 69 65 65 65 65 69 69 +77 81 81 77 81 81 77 69 60 56 48 48 +44 40 36 40 44 48 56 69 85 101 121 138 +154 166 174 178 195 195 190 186 182 170 170 174 +182 195 195 190 178 158 142 121 101 85 69 60 +48 44 44 52 60 77 85 89 89 93 89 89 +97 101 101 97 97 97 97 97 93 93 89 89 +85 +93 93 93 97 97 93 93 93 97 93 85 85 85 +85 85 81 81 81 81 85 85 89 93 93 93 +93 89 85 81 77 73 69 69 69 65 69 73 +77 85 81 81 85 81 69 65 56 48 44 40 +40 40 40 44 52 56 69 81 97 117 138 154 +170 186 195 207 219 219 215 211 203 190 186 190 +203 211 211 207 195 174 154 134 109 89 73 60 +48 44 44 52 60 73 85 93 97 93 89 93 +93 97 101 97 97 97 93 93 93 89 89 89 +89 +93 93 93 97 97 97 93 89 93 89 85 89 89 +85 85 81 77 77 77 77 85 89 93 97 93 +89 89 85 85 81 77 73 73 73 69 69 73 +77 85 85 81 81 77 65 56 52 48 36 40 +40 44 48 52 60 73 85 101 109 125 146 166 +186 199 215 223 231 235 231 223 219 203 199 203 +211 223 223 219 207 186 166 138 117 93 73 56 +44 40 44 44 56 69 81 93 97 93 93 93 +93 93 97 101 97 93 93 93 89 85 89 89 +97 +97 93 89 93 97 97 97 89 89 85 85 89 93 +85 81 81 77 77 73 73 81 89 93 97 93 +85 85 85 85 85 81 77 77 73 69 73 77 +81 89 85 81 77 69 60 52 52 44 36 36 +36 48 56 60 73 85 101 113 125 138 158 174 +190 207 223 231 235 231 235 231 223 211 203 207 +219 227 231 227 215 195 170 146 117 93 73 56 +40 36 40 40 52 65 81 93 97 97 93 97 +97 93 93 101 97 89 93 93 85 85 89 89 +93 +89 93 93 93 89 93 97 89 89 85 89 93 93 +89 85 85 81 77 77 77 81 85 89 93 93 +85 85 81 81 81 81 81 77 77 69 73 77 +81 85 85 81 73 65 56 48 44 40 32 36 +44 56 65 77 85 101 117 130 138 150 162 178 +186 207 215 223 223 223 227 223 223 215 203 203 +215 223 231 231 219 199 174 146 125 101 73 52 +40 32 32 40 52 65 77 93 97 97 97 97 +93 89 93 97 93 89 89 85 85 85 85 89 +89 +85 89 89 93 89 89 93 93 85 81 89 89 93 +93 89 89 89 81 81 81 81 85 85 89 89 +85 81 77 81 81 81 81 77 77 73 77 81 +81 81 81 73 69 65 52 40 40 32 32 40 +48 65 81 93 109 121 138 146 150 158 166 174 +182 195 203 211 211 215 215 215 211 207 203 203 +207 219 227 227 219 195 174 146 117 97 73 48 +36 28 32 44 52 69 85 93 93 93 97 93 +89 89 89 93 93 89 85 85 89 81 85 89 +93 +85 85 89 93 89 85 85 85 81 85 85 89 89 +93 93 93 93 89 85 81 81 81 81 81 81 +81 81 81 77 77 77 77 73 73 77 81 77 +77 77 73 65 56 48 40 28 28 24 24 36 +52 73 89 109 125 142 154 162 162 162 162 166 +170 178 190 195 199 199 199 203 203 203 203 203 +207 215 223 219 207 190 170 142 117 93 69 48 +36 36 32 44 52 69 85 85 85 89 93 89 +85 85 89 89 85 85 85 89 93 93 89 89 +89 +85 85 85 89 89 85 85 85 81 81 85 93 93 +93 93 97 93 89 85 81 77 77 77 77 77 +81 81 81 77 77 77 81 81 77 81 81 77 +73 73 65 56 48 40 28 24 20 20 24 36 +56 73 97 117 138 154 166 166 166 162 154 158 +158 166 174 178 182 186 186 190 195 199 203 207 +211 215 215 211 195 178 162 138 113 85 65 48 +40 36 36 48 60 69 81 85 81 81 85 81 +81 81 85 85 81 85 85 89 93 89 89 89 +89 +85 85 85 81 81 81 85 81 81 81 89 97 97 +97 93 97 97 85 85 81 77 77 77 77 77 +77 77 77 77 73 77 77 77 77 73 73 69 +65 65 60 48 40 32 20 16 12 12 20 32 +52 77 101 125 150 166 174 174 170 162 154 150 +154 154 158 162 166 170 182 190 195 199 203 203 +207 207 207 195 182 170 150 125 101 81 60 48 +40 36 40 52 65 73 81 77 77 77 77 81 +77 81 85 85 85 85 85 89 85 89 85 89 +93 +85 81 85 81 81 77 77 77 81 85 89 97 101 +97 101 97 93 89 85 81 81 81 77 73 73 +77 77 77 77 77 77 77 77 73 69 65 56 +52 52 48 40 32 28 16 12 12 12 20 32 +52 73 97 125 150 166 178 178 170 162 150 146 +142 142 142 146 154 162 174 186 190 199 203 203 +199 199 195 186 170 154 130 109 93 73 56 48 +36 40 40 52 65 77 81 77 77 77 73 77 +81 81 85 85 85 85 85 85 89 85 85 89 +89 +89 85 85 81 77 77 81 77 81 89 89 93 101 +101 97 93 93 89 85 85 85 81 77 73 77 +77 77 77 77 77 73 73 73 69 65 56 48 +44 44 36 32 28 24 16 12 12 12 20 36 +52 73 101 125 150 170 178 178 166 158 150 138 +130 130 130 138 146 154 170 182 186 195 199 199 +199 190 178 166 154 138 117 101 81 65 48 44 +40 40 44 56 69 77 81 81 77 73 73 73 +77 77 81 81 81 81 81 85 85 85 89 89 +89 +89 85 85 85 81 81 81 81 85 89 89 97 101 +101 97 93 93 89 89 85 85 81 77 77 77 +77 77 77 77 77 73 73 69 65 56 44 40 +36 36 32 24 28 24 20 16 16 20 24 40 +60 77 101 130 150 166 174 170 162 150 142 130 +121 121 125 134 142 150 166 178 186 190 199 195 +190 178 162 146 134 117 101 85 69 56 48 44 +44 48 56 65 73 77 81 81 81 77 73 73 +73 77 81 81 81 81 81 85 85 85 85 89 +89 +89 85 81 85 85 85 81 85 89 93 93 97 97 +97 97 93 93 89 89 85 85 81 73 73 77 +77 77 77 73 77 77 69 60 52 44 36 36 +28 32 32 32 32 28 28 24 28 32 40 56 +69 89 109 130 150 158 166 166 158 150 142 130 +121 121 125 134 142 154 166 178 186 186 186 178 +174 162 142 125 109 97 89 77 65 56 48 44 +52 56 65 77 77 77 81 81 77 81 77 73 +77 81 85 85 85 89 89 93 89 85 89 93 +89 +89 85 85 85 85 85 85 85 89 93 97 97 97 +93 93 93 89 85 85 85 81 77 73 69 77 +77 77 77 73 73 69 60 56 48 40 32 32 +32 36 36 40 44 44 48 44 48 56 60 69 +77 93 113 130 142 154 158 158 154 150 142 130 +125 125 130 142 146 158 174 182 182 182 174 166 +154 138 117 97 89 81 73 60 52 48 48 52 +56 60 73 81 81 85 85 81 81 77 77 77 +81 81 85 85 89 89 97 97 93 93 93 93 +89 +89 89 85 89 89 85 85 89 93 97 97 93 93 +93 89 89 85 85 85 85 85 81 77 73 73 +73 73 73 73 69 65 56 56 48 36 32 32 +36 40 44 52 60 65 69 69 69 77 81 85 +93 101 113 125 138 146 150 150 154 150 142 138 +134 134 138 146 154 166 174 182 178 174 162 150 +134 113 93 77 65 60 52 48 48 48 52 60 +69 77 81 85 85 89 89 81 77 77 77 81 +81 85 85 85 85 89 93 93 97 97 93 93 +89 +93 97 89 89 89 89 89 93 93 93 93 93 93 +93 89 85 85 85 85 85 81 77 77 77 73 +73 69 69 73 69 60 56 48 44 36 32 32 +36 48 60 73 85 89 97 101 105 105 105 105 +109 113 117 125 134 146 150 154 154 150 146 142 +138 146 150 158 170 178 182 186 178 166 150 134 +109 93 73 56 48 44 40 40 44 48 52 65 +77 85 85 85 85 89 85 85 81 81 77 81 +89 89 89 89 89 89 89 93 93 93 93 93 +89 +101 101 93 89 89 89 93 93 93 89 93 93 89 +93 89 85 89 89 85 81 77 77 73 73 73 +77 77 73 73 69 60 52 44 40 36 36 36 +48 65 81 97 109 125 134 138 138 134 130 130 +130 130 130 130 134 142 146 146 146 146 146 146 +142 150 158 170 182 186 186 186 174 158 138 113 +89 69 52 40 36 32 32 36 40 48 56 60 +69 81 89 89 89 89 81 81 81 81 85 89 +85 89 89 89 89 93 93 89 89 93 89 93 +93 +101 101 93 89 85 89 89 93 93 93 89 93 89 +89 85 89 85 81 81 77 77 73 73 73 77 +77 77 81 77 69 65 56 48 44 40 44 48 +60 77 97 113 138 154 162 170 170 166 158 154 +146 142 138 138 134 134 138 142 146 142 146 146 +146 150 162 174 182 182 178 178 166 146 125 97 +77 52 36 28 24 24 24 36 40 48 56 65 +73 85 89 89 89 85 85 81 77 81 81 85 +89 93 93 89 93 93 93 89 85 89 89 89 +93 +97 97 97 89 85 85 85 89 89 89 89 89 93 +89 89 85 81 81 77 77 77 69 73 77 77 +73 77 77 77 69 60 56 48 44 44 48 60 +73 93 113 142 162 178 190 199 195 190 186 174 +162 154 146 142 138 134 138 138 134 134 138 138 +142 146 158 174 178 178 170 166 154 130 109 89 +69 44 28 20 24 20 28 32 44 52 69 77 +85 85 89 93 89 89 85 77 73 77 81 81 +85 89 89 89 97 93 93 93 85 81 85 89 +93 +97 97 97 89 81 81 85 85 89 93 89 89 89 +89 89 89 81 77 77 77 77 69 73 73 73 +77 77 77 81 69 60 56 48 48 48 56 69 +89 105 130 162 182 203 215 219 215 207 203 190 +174 158 146 142 142 134 134 134 130 130 130 130 +134 138 154 162 162 162 154 146 138 117 93 73 +56 40 28 20 24 24 32 40 48 56 73 81 +89 93 89 89 85 85 85 77 77 77 77 81 +89 89 85 89 93 93 93 93 89 85 85 89 +93 +93 97 97 85 77 77 85 85 85 89 93 89 89 +89 89 85 81 81 77 77 73 69 69 69 73 +73 81 81 77 69 60 52 48 52 52 60 77 +97 121 150 182 207 223 235 231 227 223 215 199 +178 162 150 142 142 134 130 125 121 117 117 117 +121 130 138 142 146 142 134 125 113 97 77 60 +48 36 32 24 28 32 40 48 56 60 77 81 +89 93 89 85 81 81 81 77 73 77 81 85 +89 89 85 81 85 89 89 89 89 89 85 89 +97 +93 93 97 85 77 77 81 81 85 93 93 89 85 +85 89 85 81 81 77 77 73 69 69 69 73 +77 81 81 77 69 60 52 48 52 56 69 85 +109 138 166 195 223 235 247 247 239 231 215 203 +182 166 150 146 138 134 125 121 117 109 105 105 +105 109 109 113 117 125 113 105 97 81 69 56 +44 36 28 24 28 40 48 56 65 69 81 89 +93 93 85 81 81 81 77 77 73 77 81 85 +89 85 81 81 81 85 89 93 93 89 93 97 +97 +93 93 89 85 81 77 81 89 93 97 97 93 81 +81 81 81 81 81 81 77 73 69 69 69 77 +77 81 77 73 69 60 48 48 56 69 81 97 +121 150 178 203 231 243 251 251 243 227 215 199 +182 170 158 150 142 134 125 113 105 97 89 89 +85 81 85 85 93 101 97 89 81 69 52 44 +40 36 32 32 36 44 56 69 73 77 85 93 +93 93 89 85 77 77 81 77 77 77 81 85 +85 85 81 81 81 81 85 89 93 89 93 93 +97 +93 97 89 85 81 81 85 89 97 97 97 93 85 +81 77 81 81 81 81 81 73 69 69 69 73 +77 73 73 69 65 60 48 52 60 77 93 109 +138 162 182 203 231 251 255 251 239 223 207 190 +182 178 170 158 146 134 121 109 97 85 73 69 +60 60 65 60 69 77 77 69 65 56 44 40 +36 36 36 36 44 52 65 73 77 85 85 93 +89 85 89 89 85 73 77 77 81 77 81 81 +81 85 81 81 81 81 85 89 93 93 97 97 +97 +93 93 89 85 85 85 89 85 93 97 97 93 85 +81 81 77 81 81 81 81 73 73 73 73 73 +69 69 69 60 60 56 52 56 65 81 101 121 +142 166 186 207 231 247 251 247 239 219 203 186 +186 182 178 166 150 134 121 105 89 73 56 48 +44 36 40 44 48 52 56 56 56 48 44 36 +40 36 36 44 52 60 73 77 81 85 89 89 +89 81 81 81 81 77 77 77 81 81 81 81 +85 81 81 85 81 81 85 85 89 89 93 97 +97 +93 89 85 81 81 89 93 89 93 97 97 97 89 +85 85 81 81 81 81 85 81 81 81 77 73 +73 65 65 56 56 60 56 60 73 89 105 125 +150 170 195 215 231 239 243 243 231 215 203 186 +182 186 186 170 154 146 125 105 85 65 44 36 +32 24 24 28 32 36 40 44 44 40 40 40 +40 40 44 52 56 65 77 77 81 85 89 89 +85 81 77 81 81 77 77 81 81 81 81 81 +85 85 85 85 81 81 85 85 85 89 89 97 +97 +89 85 85 81 81 89 89 93 97 97 97 93 89 +93 89 81 81 81 85 85 81 81 77 77 77 +73 69 65 56 56 56 60 65 73 89 109 134 +158 178 195 215 231 239 239 235 227 215 203 190 +190 190 190 178 166 150 134 105 89 60 40 32 +24 16 12 12 16 24 32 36 44 44 40 40 +48 48 52 60 65 69 73 77 81 81 85 89 +81 81 81 81 81 81 85 81 85 85 81 81 +85 85 85 85 85 85 81 81 85 85 85 89 +93 +85 85 85 81 81 85 85 89 93 89 89 89 93 +93 85 85 85 85 85 81 81 77 77 73 73 +69 65 60 52 48 48 52 65 77 93 117 142 +162 186 203 223 235 239 239 235 227 219 207 199 +195 199 195 186 174 162 142 113 89 60 40 24 +12 4 0 0 8 16 28 36 44 44 44 48 +60 60 60 69 73 77 77 77 77 81 85 89 +85 81 85 85 85 85 85 85 85 85 85 85 +89 89 89 89 89 85 85 89 85 85 85 89 +89 +93 89 81 85 85 81 81 85 85 89 85 85 85 +85 85 81 85 81 81 77 77 77 73 69 69 +65 60 56 48 48 48 56 65 81 101 125 154 +174 199 219 231 239 239 235 235 227 223 215 211 +207 207 207 203 186 170 146 121 93 65 44 24 +12 0 0 0 8 12 24 36 48 52 52 56 +65 69 69 77 81 77 77 77 77 81 77 81 +81 81 81 85 85 89 81 85 89 89 89 89 +93 93 93 93 89 93 93 89 89 93 89 89 +93 +93 85 85 85 89 81 81 81 81 81 85 85 85 +81 81 81 81 77 77 73 73 73 73 69 69 +65 60 52 48 48 52 56 65 85 105 130 158 +186 211 231 243 247 243 235 231 231 227 227 223 +223 223 219 211 195 174 150 121 93 65 40 24 +12 4 0 8 16 20 36 44 52 56 60 60 +69 73 73 77 77 77 73 73 73 77 77 77 +77 77 81 81 85 85 85 85 89 89 93 93 +93 93 89 93 89 97 97 93 89 89 93 93 +93 +93 89 85 85 81 81 81 77 81 85 81 85 81 +81 77 73 73 77 77 73 73 73 69 69 69 +65 56 48 44 44 48 52 65 85 109 138 166 +190 215 235 247 247 243 235 231 231 227 235 235 +235 231 227 215 199 178 150 121 93 65 44 28 +20 8 8 16 24 36 48 56 56 65 69 69 +73 77 81 81 81 77 73 73 73 77 77 77 +81 81 81 81 85 85 85 85 85 89 93 97 +97 93 89 89 89 89 93 93 89 85 89 89 +93 +89 89 89 81 77 77 81 81 81 85 81 81 81 +81 77 73 73 73 73 69 65 69 69 60 60 +60 52 48 44 44 44 56 69 85 113 142 174 +199 219 239 247 247 243 239 239 235 235 239 239 +239 235 227 211 190 170 146 117 93 65 44 28 +24 16 16 28 36 48 60 65 69 73 77 77 +77 77 81 81 77 77 73 73 73 77 77 85 +85 85 81 81 85 89 89 85 85 89 93 93 +93 93 89 89 89 89 89 93 89 89 89 85 +89 +89 89 89 77 77 81 81 81 81 85 85 81 85 +85 81 73 73 73 73 69 69 69 69 60 60 +56 48 48 40 40 40 52 69 89 113 142 174 +203 227 239 247 251 247 239 239 235 235 239 239 +239 231 215 203 178 154 130 105 85 56 40 28 +28 24 28 40 56 69 73 77 81 85 77 77 +81 77 77 77 77 73 73 73 73 77 73 77 +81 85 81 81 81 89 89 85 89 89 93 93 +93 97 93 93 93 89 89 93 93 93 89 93 +93 +85 89 85 81 81 81 81 81 85 85 85 81 85 +81 77 77 77 73 73 73 69 69 69 65 60 +52 44 40 36 32 40 52 69 85 109 138 174 +203 223 239 247 251 247 243 239 239 239 235 235 +231 219 207 186 166 142 113 89 69 48 36 32 +28 28 36 52 69 77 85 85 89 89 85 77 +81 81 77 77 77 73 73 69 73 73 73 73 +81 81 85 81 85 85 81 85 93 93 89 93 +93 97 97 97 93 89 89 93 93 93 89 89 +89 +89 89 89 85 81 81 85 89 85 89 85 81 85 +85 81 81 77 77 77 73 69 65 65 60 56 +52 44 36 32 28 32 48 65 81 105 134 166 +199 219 239 247 251 247 243 239 235 235 235 231 +219 203 190 166 146 121 97 73 56 40 32 32 +32 36 48 60 73 81 89 93 89 89 85 81 +77 77 77 77 73 73 73 73 73 69 73 77 +77 81 85 89 89 85 81 85 89 93 93 93 +93 93 97 97 93 93 89 93 93 89 89 89 +89 +89 85 89 85 85 85 89 89 89 93 89 85 85 +85 89 89 81 81 77 73 69 69 65 65 60 +52 48 40 28 24 28 40 60 77 101 125 154 +186 215 239 247 251 251 247 239 235 231 227 215 +207 190 170 146 125 105 81 56 40 32 28 32 +32 40 52 60 77 85 89 93 89 85 81 77 +77 81 77 77 77 77 77 77 77 69 73 73 +73 73 85 89 85 81 81 85 89 93 97 93 +93 89 93 97 93 93 93 93 93 89 93 93 +93 +85 85 89 85 89 85 89 89 89 93 89 89 89 +89 89 89 89 81 77 73 73 73 69 65 65 +60 52 44 32 24 28 40 56 69 89 113 142 +174 203 227 243 247 247 243 235 231 231 219 203 +190 174 150 125 109 85 60 44 32 24 24 24 +32 40 52 60 77 85 85 85 85 85 81 81 +81 81 81 81 81 77 81 77 77 73 77 77 +73 77 81 85 85 85 81 81 85 89 93 93 +89 89 97 101 97 97 93 93 93 89 93 93 +85 +85 85 85 89 93 93 89 89 93 93 93 93 93 +93 93 97 93 85 77 73 73 77 73 73 73 +69 60 48 32 24 24 36 48 65 81 101 125 +158 190 211 227 235 239 235 235 227 219 207 186 +174 158 134 113 93 65 44 32 24 20 24 28 +32 36 52 60 73 81 81 81 81 77 81 85 +81 85 85 85 85 81 81 77 77 77 81 77 +81 85 85 89 89 85 89 85 89 89 93 89 +93 93 97 93 93 97 93 93 93 89 93 93 +85 +85 85 89 89 93 93 89 89 93 89 93 97 97 +89 89 93 93 85 81 77 73 73 69 73 77 +73 65 52 40 28 28 28 40 52 69 89 117 +142 174 190 211 223 231 231 227 219 207 195 174 +154 138 117 97 77 48 28 16 12 12 20 28 +32 44 56 65 73 81 81 81 77 77 81 85 +85 85 89 85 81 81 81 81 77 77 81 77 +81 85 85 89 89 89 89 89 89 85 89 89 +89 93 93 93 93 93 93 93 89 93 93 93 +85 +85 85 85 89 89 89 85 85 93 93 97 93 93 +89 85 89 89 85 81 81 73 73 73 77 81 +81 73 60 48 36 32 28 28 36 56 73 101 +125 150 170 190 203 215 211 207 203 195 174 158 +138 117 97 81 56 36 20 16 12 12 20 28 +36 52 60 69 77 81 85 81 81 77 77 81 +77 81 85 89 81 81 81 81 81 73 77 77 +81 81 89 89 93 89 89 93 89 85 89 89 +89 89 89 89 89 89 93 93 89 93 93 89 +89 +85 85 85 89 89 93 89 85 93 93 93 89 89 +89 85 81 81 81 77 77 73 73 77 81 85 +85 77 69 56 40 32 28 20 28 44 56 77 +101 125 150 166 182 190 190 186 182 174 158 142 +121 105 85 65 48 28 20 16 12 12 24 32 +44 56 69 73 77 81 77 77 77 77 77 77 +77 77 81 85 85 77 81 81 81 77 77 81 +81 81 89 89 93 89 89 93 89 89 89 89 +93 97 93 93 93 93 89 93 93 97 97 93 +85 +85 89 85 89 89 89 89 85 89 89 89 89 89 +85 85 77 77 77 73 77 73 77 77 81 85 +85 81 73 60 48 36 28 20 24 32 44 56 +81 105 125 146 162 170 170 166 158 150 142 130 +113 97 77 60 44 28 24 20 20 24 32 40 +48 65 73 73 77 77 77 73 73 73 73 73 +77 81 81 85 81 77 77 81 81 81 77 77 +77 77 85 85 89 89 89 89 89 89 89 93 +93 97 93 93 97 93 89 89 93 97 97 93 +89 +85 89 89 89 89 85 85 81 85 81 81 81 85 +81 81 81 77 77 73 77 77 77 77 85 85 +81 81 81 69 52 40 28 20 20 24 32 44 +65 81 105 121 134 146 146 142 134 125 117 113 +101 85 69 52 44 36 32 28 32 36 48 52 +60 73 81 81 73 77 73 73 69 69 73 73 +77 77 81 85 85 77 77 77 81 81 81 73 +73 77 81 81 85 89 85 89 85 85 89 93 +93 93 93 89 93 93 89 85 93 93 93 93 +93 +85 85 93 93 89 85 89 85 81 81 81 85 81 +77 77 77 77 81 81 81 81 77 73 81 85 +85 85 81 73 56 44 28 20 20 20 24 36 +52 73 85 101 109 113 117 117 113 105 101 93 +81 69 56 44 44 40 36 40 44 48 56 65 +69 77 81 77 73 73 73 69 65 60 69 69 +73 77 81 81 85 77 77 77 77 81 81 81 +81 81 81 81 85 85 85 89 89 89 89 89 +89 89 89 89 89 93 89 85 89 97 93 89 +89 +85 85 93 89 89 89 85 85 85 81 81 81 81 +77 77 73 77 85 85 85 81 77 77 81 85 +89 85 81 77 60 48 36 24 24 24 20 28 +44 56 69 81 89 97 97 93 89 89 89 81 +69 56 52 44 40 40 40 48 56 65 69 73 +73 77 81 77 73 73 73 73 65 65 65 69 +77 81 81 81 77 77 77 77 77 77 81 81 +81 81 85 81 85 89 89 89 89 85 89 89 +93 85 89 89 89 89 85 85 89 97 93 89 +89 +89 85 89 89 89 85 85 85 85 85 85 81 81 +77 77 81 81 85 89 85 81 85 85 85 81 +85 85 85 77 65 52 44 36 28 24 24 28 +40 52 60 65 73 81 81 77 73 77 77 73 +56 52 48 44 44 44 48 52 65 73 77 77 +77 73 81 81 73 73 73 69 69 65 65 69 +77 77 81 81 77 77 73 73 73 73 77 77 +81 81 85 81 85 89 89 89 85 85 85 85 +85 85 85 85 89 85 85 89 93 97 93 93 +89 +85 85 89 85 89 85 81 85 89 89 85 85 85 +85 81 81 81 85 85 85 85 85 89 85 85 +93 89 89 81 69 60 52 40 32 32 28 32 +40 48 56 56 56 60 60 65 60 60 60 56 +52 48 44 44 48 48 56 60 69 73 77 81 +81 77 81 81 77 73 73 69 69 65 65 69 +73 73 81 81 81 77 73 73 73 77 77 77 +77 81 85 81 85 89 85 85 89 85 81 81 +81 81 85 89 89 89 89 93 93 93 89 89 +89 +85 81 81 85 89 89 85 85 89 89 89 85 85 +89 85 85 85 89 89 89 93 89 89 89 89 +93 89 89 81 77 69 60 52 48 44 40 40 +44 48 52 48 44 48 48 48 48 52 48 48 +44 44 44 48 52 56 60 65 73 77 77 81 +77 77 81 81 81 77 77 73 73 69 65 65 +73 77 77 81 81 81 81 77 77 81 81 85 +81 81 85 85 89 89 85 85 85 85 81 81 +81 81 81 89 89 97 93 93 89 89 85 85 +85 +85 85 89 89 93 93 89 89 89 93 89 85 85 +85 89 93 93 93 93 89 93 93 93 97 93 +93 89 89 81 73 73 69 65 60 56 48 48 +48 48 52 44 40 44 44 40 40 40 40 40 +40 44 48 52 60 65 65 69 73 73 77 81 +81 85 81 81 81 77 77 77 77 73 73 77 +81 81 77 77 81 81 81 81 81 81 89 89 +85 85 89 89 89 89 89 85 85 81 85 85 +81 85 85 85 85 97 93 93 85 85 85 85 +85 +85 85 89 93 93 93 89 89 93 93 97 89 85 +85 89 93 97 93 93 89 89 93 93 89 89 +89 85 81 77 73 73 73 69 69 65 60 52 +52 56 52 48 44 44 44 40 36 40 36 40 +40 48 56 60 65 69 69 69 69 73 77 77 +81 85 81 81 77 81 77 81 81 77 77 77 +77 81 81 77 81 81 85 85 85 85 93 93 +93 89 89 93 93 89 89 89 85 81 85 85 +85 85 89 89 89 93 93 89 85 89 89 89 +85 +89 85 89 93 93 89 89 89 93 93 93 89 89 +85 89 89 97 97 93 93 93 93 93 89 85 +81 77 77 81 81 81 81 77 77 73 69 65 +65 60 60 56 48 44 44 44 40 40 40 40 +44 52 60 65 69 69 69 73 69 77 77 81 +89 85 85 85 85 85 81 85 81 77 81 77 +81 81 81 81 81 85 89 85 89 93 97 97 +97 93 89 93 93 93 89 89 89 85 89 85 +85 85 89 93 93 93 97 93 89 89 89 85 +85 +89 85 89 89 89 89 89 93 89 89 93 89 85 +85 89 89 97 97 97 93 93 93 93 89 81 +77 77 81 85 81 81 81 85 85 81 77 73 +69 69 69 60 52 48 52 52 48 48 48 48 +48 60 65 69 69 69 73 73 73 77 77 85 +89 89 89 85 85 85 81 81 81 77 81 81 +81 81 85 85 85 93 89 89 89 93 101 101 +97 97 93 93 93 93 89 89 89 89 89 89 +89 89 89 93 89 93 97 93 93 93 93 93 +89 +85 85 89 89 89 89 85 85 89 89 85 89 85 +89 89 89 93 97 97 93 89 89 89 81 81 +77 77 85 85 81 85 89 89 89 89 85 81 +77 73 73 69 60 56 60 60 56 56 56 56 +60 65 69 73 73 73 73 73 73 73 77 81 +85 89 89 85 85 85 81 81 85 81 81 81 +81 81 81 85 89 93 89 89 89 97 97 97 +97 97 97 97 89 89 93 93 93 93 89 93 +89 89 89 93 93 97 97 97 93 89 93 93 +89 +89 85 89 89 93 93 85 85 89 89 85 85 89 +89 85 85 89 93 97 93 89 89 85 81 81 +73 77 85 85 85 89 93 93 89 89 85 85 +81 81 77 73 69 60 65 69 65 69 65 65 +73 77 81 85 77 73 69 73 73 69 73 77 +85 89 85 89 85 85 81 85 85 81 81 81 +77 81 81 85 89 89 89 89 89 93 93 93 +93 97 97 97 93 89 93 93 97 93 93 89 +89 89 89 89 93 93 97 97 93 89 85 89 +89 +89 89 89 89 93 93 85 81 85 81 77 85 85 +89 85 81 85 89 93 93 93 89 85 81 81 +81 81 85 85 85 85 93 93 93 89 81 85 +85 81 81 73 73 69 69 69 73 77 73 77 +81 85 85 81 77 73 73 73 73 73 77 85 +89 89 93 93 89 85 85 85 77 77 85 81 +81 81 81 89 89 89 85 85 89 89 93 93 +93 97 93 93 93 93 93 97 93 93 93 89 +89 85 89 89 89 93 93 93 89 89 89 89 +89 +85 85 85 89 93 93 85 85 85 81 81 81 85 +85 85 85 89 89 85 89 89 89 85 81 81 +85 89 89 85 85 85 89 93 93 89 81 85 +85 85 81 81 77 77 73 73 77 81 81 85 +85 85 85 81 77 73 73 69 73 77 85 85 +89 93 97 97 93 89 89 85 77 81 85 81 +77 81 81 85 93 93 89 89 89 89 93 93 +89 93 93 93 93 93 93 97 93 93 93 89 +89 89 89 89 93 93 97 93 93 93 89 89 +85 +85 85 85 89 93 89 85 85 85 81 81 85 85 +85 89 89 89 85 85 85 85 85 81 85 85 +85 89 89 89 89 89 93 93 89 85 77 81 +81 81 81 77 77 77 77 77 77 81 85 89 +89 89 85 81 81 77 73 73 73 77 85 89 +89 97 101 97 93 89 93 85 81 81 81 81 +81 85 81 85 89 93 93 93 93 89 89 89 +89 93 93 93 93 93 89 89 93 97 93 89 +85 93 93 89 93 97 93 93 93 89 89 89 +85 +85 81 81 89 93 89 93 89 85 81 89 89 85 +85 93 89 89 89 85 85 89 89 89 85 85 +85 89 85 85 89 89 89 89 89 81 77 73 +77 81 77 73 73 77 77 81 81 85 89 93 +93 93 85 85 85 81 77 77 73 81 85 89 +97 101 101 97 97 93 93 89 85 85 85 81 +85 85 81 85 89 89 93 93 89 89 85 89 +89 93 93 93 93 89 85 89 89 93 93 93 +93 89 89 89 89 93 93 93 89 89 89 89 +85 +85 81 85 89 93 89 93 89 89 85 85 85 85 +85 85 89 89 93 89 89 89 89 93 89 85 +85 85 85 85 85 85 85 85 85 81 77 69 +73 77 73 73 77 77 81 81 85 89 93 93 +93 89 85 89 85 81 81 81 77 85 89 93 +97 97 97 97 101 93 93 85 85 81 81 85 +85 89 85 85 89 93 93 89 89 89 85 93 +93 89 85 89 89 85 89 89 89 89 93 97 +93 89 89 93 89 93 93 89 81 85 85 85 +85 +89 85 85 85 89 97 93 93 89 85 85 89 89 +89 89 89 85 89 89 85 89 93 93 89 89 +85 85 89 89 85 89 89 85 81 77 73 73 +73 73 73 77 77 77 77 81 85 93 93 93 +93 93 89 89 89 81 85 81 81 85 93 93 +93 93 93 97 97 93 89 85 81 81 81 85 +89 85 89 89 89 93 93 93 89 85 89 93 +89 89 85 89 89 89 93 93 93 93 97 97 +93 89 89 93 89 93 93 85 81 85 85 81 +85 +93 85 85 89 93 97 97 97 97 93 93 89 89 +93 89 85 85 85 85 89 89 89 93 93 89 +89 89 89 93 89 89 93 89 85 81 77 81 +77 73 73 77 77 77 81 85 89 93 93 89 +93 93 89 85 85 85 85 81 81 81 89 93 +93 89 93 93 93 85 85 81 81 81 85 85 +89 93 89 85 89 89 93 89 89 85 85 93 +89 85 85 85 89 89 93 97 93 97 97 93 +93 85 85 89 89 93 85 81 77 77 81 85 +89 +89 89 89 89 89 93 101 105 97 97 97 97 93 +93 89 85 81 85 85 89 89 89 89 89 89 +89 89 89 93 89 85 89 89 85 85 81 85 +81 77 77 77 81 81 85 85 93 97 97 89 +93 89 89 89 85 81 81 81 81 81 85 89 +89 89 89 89 89 81 81 77 77 85 85 85 +93 93 89 85 89 93 89 89 89 85 85 89 +89 85 85 85 89 93 93 97 93 93 93 97 +97 93 89 89 89 89 81 81 81 81 77 81 +85 +89 89 93 93 89 97 101 105 101 101 101 97 93 +89 89 85 81 81 81 81 89 89 89 89 85 +89 85 89 93 89 89 89 89 89 85 81 81 +77 77 77 81 85 85 89 89 97 97 93 89 +89 89 89 85 85 81 81 81 81 85 81 85 +89 85 85 85 81 85 81 77 81 89 89 89 +93 93 93 93 93 89 89 89 85 85 85 85 +85 85 85 85 89 97 97 97 93 89 93 97 +101 97 93 93 89 89 81 81 85 85 77 81 +81 +93 93 93 93 93 97 105 105 105 101 101 101 93 +89 89 89 85 85 81 81 85 85 85 85 85 +85 89 93 97 93 93 93 89 85 85 81 81 +77 77 81 85 89 93 93 97 97 93 93 89 +89 89 85 85 81 81 81 81 81 81 81 81 +89 85 81 81 81 81 81 85 89 89 93 97 +97 97 97 97 97 89 89 93 89 85 85 89 +89 85 85 85 89 97 97 93 93 93 93 93 +97 97 93 89 85 85 89 89 89 85 81 85 +85 +93 93 89 89 89 101 105 105 101 101 101 97 97 +93 93 93 89 85 89 81 81 89 85 85 89 +89 93 93 97 97 93 97 93 85 85 81 85 +85 81 85 85 89 89 93 93 93 89 85 85 +85 85 85 81 81 85 85 81 85 81 81 81 +81 85 81 81 81 81 81 81 89 93 93 97 +101 97 97 97 97 93 93 93 93 89 89 89 +89 85 85 85 89 89 89 89 89 93 89 89 +89 89 89 93 85 89 89 85 85 85 85 85 +85 +85 89 85 85 85 97 101 101 101 97 97 97 97 +97 93 89 89 85 85 85 81 85 85 85 89 +89 93 93 97 97 97 97 93 93 89 85 85 +89 93 89 89 93 93 97 93 89 89 85 85 +85 81 81 77 77 81 85 85 85 81 81 81 +81 81 85 81 77 81 81 81 85 93 93 97 +97 97 97 97 97 97 97 93 89 85 85 85 +81 85 85 85 89 89 89 89 89 93 89 89 +89 85 89 89 85 85 81 85 85 89 89 89 +85 +89 93 85 85 85 97 97 97 101 101 101 97 93 +93 89 85 85 85 85 85 85 85 81 77 85 +89 93 93 97 97 97 93 93 93 89 89 85 +89 89 89 89 89 89 89 89 85 89 85 85 +85 89 81 77 77 81 85 85 85 81 81 81 +81 85 85 89 81 77 77 77 81 89 93 97 +97 101 101 101 101 97 93 89 89 89 85 81 +81 85 85 85 89 89 85 89 85 85 89 85 +89 89 89 85 85 85 81 85 89 89 89 93 +89 +89 89 89 85 85 93 93 93 97 97 97 93 89 +89 85 85 89 85 81 81 81 81 85 81 85 +89 89 93 93 89 89 89 89 89 89 85 85 +89 89 93 93 89 85 85 85 85 85 81 85 +89 85 77 81 81 81 81 85 85 85 81 85 +81 81 81 81 81 73 73 77 77 85 93 97 +97 101 101 97 97 93 93 89 85 85 85 85 +85 85 85 85 85 85 85 89 89 89 89 89 +89 93 89 85 89 89 89 93 93 89 89 93 +93 +85 85 85 85 81 93 93 93 93 97 97 93 89 +89 85 85 89 85 81 81 81 81 81 81 85 +89 89 89 89 89 89 85 85 85 89 85 85 +85 89 93 89 89 89 85 85 85 85 81 85 +89 85 85 81 85 85 85 85 85 85 85 85 +85 81 81 85 81 81 77 81 85 85 93 97 +97 93 97 93 89 93 93 89 89 89 89 89 +89 85 81 85 85 85 85 85 89 93 93 89 +85 89 85 89 89 89 89 93 89 89 89 93 +89 +85 85 89 85 81 89 89 89 89 93 97 97 89 +85 85 89 93 89 85 85 85 85 85 89 89 +89 85 89 89 85 85 85 89 85 85 89 85 +85 89 89 89 85 85 85 85 85 85 81 81 +85 89 89 89 89 89 85 81 85 85 85 85 +85 85 85 85 81 81 85 93 89 89 89 93 +93 97 93 97 93 93 89 89 89 93 93 93 +85 85 81 85 85 85 81 81 85 89 93 89 +89 85 85 89 93 89 93 93 89 93 93 93 +93 +85 81 85 85 85 89 89 89 89 93 93 93 89 +89 89 89 89 89 89 85 85 85 85 85 85 +85 85 85 85 89 85 85 85 89 85 89 89 +89 89 93 89 85 85 85 85 81 81 77 85 +89 89 93 93 89 89 85 81 85 81 81 85 +85 89 89 85 85 85 85 93 93 93 93 93 +89 93 93 93 89 89 85 85 85 89 93 89 +85 85 85 89 85 85 81 81 81 85 89 89 +85 85 85 85 89 89 93 89 89 89 93 93 +93 +85 81 85 85 85 85 89 89 89 93 89 89 89 +89 89 89 89 89 85 85 89 89 85 85 85 +85 89 85 81 85 89 89 85 89 93 93 97 +93 85 89 89 89 89 89 85 85 89 85 89 +89 85 85 85 89 89 89 85 89 89 85 85 +85 89 85 85 81 81 85 93 89 93 93 97 +97 89 89 93 93 89 89 85 89 93 93 89 +85 81 81 85 85 85 81 85 85 85 85 89 +85 89 89 85 85 85 85 85 85 89 89 89 +89 +85 85 85 93 93 89 89 85 89 89 85 85 81 +89 89 85 85 89 89 89 89 89 89 93 89 +85 85 89 85 85 93 93 85 85 89 89 89 +85 81 85 89 85 85 85 85 85 89 93 93 +89 85 89 89 89 93 97 97 93 89 85 85 +85 85 85 85 81 77 85 89 89 93 97 101 +97 93 89 89 89 89 93 89 93 93 93 93 +89 85 85 85 89 89 89 89 85 85 85 89 +93 89 89 85 85 85 85 89 89 93 89 89 +89 +89 85 93 93 89 93 89 85 89 89 85 85 89 +93 89 89 85 85 85 85 89 89 85 89 85 +85 85 85 85 89 93 93 89 89 89 89 89 +85 81 85 85 89 85 85 85 89 89 89 89 +89 93 93 93 89 93 97 97 93 85 85 89 +85 81 81 81 81 81 85 85 85 93 97 97 +93 89 85 89 89 93 93 93 93 89 93 89 +89 85 85 85 85 85 89 89 85 89 89 89 +89 89 89 85 85 81 85 85 89 89 85 85 +85 diff --git a/modules/mmcif/test/input/test.xlms.csv b/modules/mmcif/test/input/test.xlms.csv new file mode 100644 index 0000000000..d4803aa624 --- /dev/null +++ b/modules/mmcif/test/input/test.xlms.csv @@ -0,0 +1,6 @@ +prot1,res1,prot2,res2 +Rpb1,34,Rpb1,49 +Rpb1,101,Rpb1,143 +Rpb1,101,Rpb1,176 +Rpb1,143,Rpb1,187 +Rpb1,368,Rpb1,461 diff --git a/modules/mmcif/test/test_data.py b/modules/mmcif/test/test_data.py index 0d6b3e460f..ee6ac52c4e 100644 --- a/modules/mmcif/test/test_data.py +++ b/modules/mmcif/test/test_data.py @@ -124,6 +124,67 @@ def test_representation_same_rigid_body(self): self.assertFalse(r._same_rigid_body(None)) self.assertTrue(r._same_rigid_body(rigid1)) + def test_software_add_hierarchy(self): + """Test AllSoftware.add_hierarchy""" + s = ihm.System() + allsoft = IMP.mmcif.data._AllSoftware(s) + m = IMP.Model() + top = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "testname", "testver", "testloc") + IMP.core.add_provenance(m, top, prov) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "testname", "testver", "testloc") + IMP.core.add_provenance(m, top, prov) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "testname", "diffver", "testloc") + IMP.core.add_provenance(m, top, prov) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "diffname", "testver", "testloc") + IMP.core.add_provenance(m, top, prov) + allsoft.add_hierarchy(top) + # Duplicate name-version should be removed + self.assertEqual([(x.name, x.version) for x in s.software], + [('diffname', 'testver'), ('testname', 'diffver'), + ('testname', 'testver')]) + + def test_software_add_hierarchy_citations(self): + """Test that AllSoftware.add_hierarchy adds citations""" + s = ihm.System() + allsoft = IMP.mmcif.data._AllSoftware(s) + m = IMP.Model() + top = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "testname", "testver", "testloc") + IMP.core.add_provenance(m, top, prov) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "IMP PMI module", "testver", "testloc") + IMP.core.add_provenance(m, top, prov) + allsoft.add_hierarchy(top) + pmisoft, testsoft = s.software + self.assertIsNone(testsoft.citation) + self.assertEqual(pmisoft.citation.pmid, '31396911') + + def test_protocols_add_hierarchy(self): + """Test _Protocols.add_hierarchy""" + s = ihm.System() + software = IMP.mmcif.data._AllSoftware(s) + protocols = IMP.mmcif.data._Protocols(s) + m = IMP.Model() + top = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + prov = IMP.core.SoftwareProvenance.setup_particle( + IMP.Particle(m), "testname", "testver", "testloc") + IMP.core.add_provenance(m, top, prov) + prov = IMP.core.SampleProvenance.setup_particle( + IMP.Particle(m), "Monte Carlo", 100, 10, 1) + IMP.core.add_provenance(m, top, prov) + protocols._add_hierarchy(top, None, software) + protocol, = s.orphan_protocols + step, = protocol.steps + self.assertEqual(step.num_models_begin, 0) + self.assertEqual(step.num_models_end, 100) + self.assertEqual(step.software.name, "testname") + if __name__ == '__main__': IMP.test.main() diff --git a/modules/mmcif/test/test_dumper.py b/modules/mmcif/test/test_dumper.py index 4330f8ed3a..e8d0de6e26 100644 --- a/modules/mmcif/test/test_dumper.py +++ b/modules/mmcif/test/test_dumper.py @@ -95,6 +95,10 @@ def test_software_dumper(self): IMP.core.add_imp_provenance(h) IMP.mmcif.Ensemble(state, "cluster 1").add_model([h], [], "model1") + # Assign ID to IMP citation + dumper = ihm.dumper._CitationDumper() + dumper.finalize(system.system) + dumper = ihm.dumper._SoftwareDumper() dumper.finalize(system.system) out = _get_dumper_output(dumper, system.system) @@ -111,7 +115,7 @@ def test_software_dumper(self): _software.location _software.citation_id 1 'Integrative Modeling Platform (IMP)' 'integrative model building' . -%s program https://integrativemodeling.org . +%s program https://integrativemodeling.org 1 # """ % IMP.get_module_version()).replace('\n', ' ')) @@ -571,9 +575,10 @@ def test_ensemble_info(self): _ihm_ensemble_info.ensemble_precision_value _ihm_ensemble_info.ensemble_file_id _ihm_ensemble_info.details +_ihm_ensemble_info.model_group_superimposed_flag _ihm_ensemble_info.sub_sample_flag _ihm_ensemble_info.sub_sampling_type -1 'cluster 1' . 1 . . 1 1 . . . NO . +1 'cluster 1' . 1 . . 1 1 . . . . NO . # """) diff --git a/modules/mmcif/test/test_restraints.py b/modules/mmcif/test/test_restraints.py index e0785ea6ef..fe6159d021 100644 --- a/modules/mmcif/test/test_restraints.py +++ b/modules/mmcif/test/test_restraints.py @@ -3,6 +3,27 @@ import IMP.mmcif.restraint import ihm.dataset + +def make_model(system, chains=None): + if chains is None: + chains = (('foo', 'ACGT', 'A'), ('bar', 'ACGT', 'B'), + ('baz', 'ACC', 'C')) + s = IMP.mmcif.State(system) + m = s.model + top = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + for name, seq, cid in chains: + h = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + mol = IMP.atom.Molecule.setup_particle(h) + mol.set_name(name) + top.add_child(mol) + + h = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + chain = IMP.atom.Chain.setup_particle(h, cid) + chain.set_sequence(seq) + mol.add_child(chain) + return top, s + + class MockGaussianEMRestraint(IMP.Restraint): def __init__(self, m, em_filename): @@ -29,6 +50,107 @@ def get_dynamic_info(self): return i +class MockCrossLinkRestraint(IMP.RestraintSet): + + def __init__(self, m, xlms_filename): + self.xlms_filename = xlms_filename + IMP.RestraintSet.__init__(self, m, "MockRestraint %1%") + def unprotected_evaluate(self, accum): + return 0. + def get_version_info(self): + return IMP.VersionInfo("IMP authors", "0.1") + def do_show(self, fh): + fh.write('MockRestraint') + def do_get_inputs(self): + return [] + + def get_static_info(self): + i = IMP.RestraintInfo() + i.add_string("type", "IMP.pmi.CrossLinkingMassSpectrometryRestraint") + i.add_filename("filename", self.xlms_filename) + i.add_string("linker author name", "DSS") + i.add_float("linker length", 21.0) + return i + + +class MockSAXSRestraint(IMP.Restraint): + + def __init__(self, m, dat_filename): + self.dat_filename = dat_filename + IMP.Restraint.__init__(self, m, "MockRestraint %1%") + def unprotected_evaluate(self, accum): + return 0. + def get_version_info(self): + return IMP.VersionInfo("IMP authors", "0.1") + def do_show(self, fh): + fh.write('MockRestraint') + def do_get_inputs(self): + return [] + + def get_static_info(self): + i = IMP.RestraintInfo() + i.add_string("type", "IMP.saxs.Restraint") + i.add_string("form factor type", "residues") + i.add_filename("filename", self.dat_filename) + i.add_float("min q", 0.0) + i.add_float("max q", 1.0) + i.add_float("delta q", 0.01) + return i + + +class MockZAxialRestraint(IMP.Restraint): + def __init__(self, m): + IMP.Restraint.__init__(self, m, "MockRestraint %1%") + def unprotected_evaluate(self, accum): + return 0. + def get_version_info(self): + return IMP.VersionInfo("IMP authors", "0.1") + def do_show(self, fh): + fh.write('MockRestraint') + def do_get_inputs(self): + return [] + + def get_static_info(self): + i = IMP.RestraintInfo() + i.add_string("type", "IMP.npc.ZAxialPositionRestraint") + i.add_float("lower bound", -10.0) + i.add_float("upper bound", 20.0) + i.add_float("sigma", 4.0) + return i + + +class MockPCAFitRestraint(IMP.Restraint): + + def __init__(self, m, image_filename): + self.image_filename = image_filename + IMP.Restraint.__init__(self, m, "MockRestraint %1%") + def unprotected_evaluate(self, accum): + return 0. + def get_version_info(self): + return IMP.VersionInfo("IMP authors", "0.1") + def do_show(self, fh): + fh.write('MockRestraint') + def do_get_inputs(self): + return [] + + def get_static_info(self): + i = IMP.RestraintInfo() + i.add_string("type", "IMP.em2d.PCAFitRestraint") + i.add_filenames("image files", [self.image_filename]) + i.add_float("pixel size", 2.2) + i.add_float("resolution", 20.) + i.add_int("projection number", 20) + i.add_int("micrographs number", 0) + return i + + def get_dynamic_info(self): + i = IMP.RestraintInfo() + i.add_floats("cross correlation", [0.4]) + i.add_floats("rotation", [0., 0., 1., 0.]) + i.add_floats("translation", [241.8, 17.4, 0.0]) + return i + + class Tests(IMP.test.TestCase): def test_parse_restraint_info_empty(self): """Test _parse_restraint_info() with empty RestraintInfo""" @@ -79,6 +201,82 @@ def test_restraint_mapper_gaussian_em(self): self.assertEqual(type(wr), IMP.mmcif.restraint._GaussianEMRestraint) self.assertEqual(type(wr.dataset), ihm.dataset.EMDensityDataset) + def test_restraint_mapper_cross_link(self): + """Test _RestraintMapper with cross-link restraint""" + system = IMP.mmcif.System() + h, state = make_model(system, chains=[("Rpb1", "AMT", "X"), + ("Rpb2", "ACC", "Z")]) + IMP.mmcif.Ensemble(state, "cluster 1").add_model([h], [], "model1") + m = state.model + + xl_csv = self.get_input_file_name('test.xlms.csv') + r = MockCrossLinkRestraint(m, xl_csv) + r.set_was_used(True) + xl = IMP.isd.CrossLinkMSRestraint(m, 21.0, 0.01) + xl.set_source_protein1('Rpb1') + xl.set_source_residue1(34) + xl.set_source_protein2('Rpb1') + xl.set_source_residue2(49) + rpb1 = IMP.atom.get_by_type(h, IMP.atom.CHAIN_TYPE)[0] + h1 = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + h2 = IMP.atom.Hierarchy.setup_particle(IMP.Particle(m)) + rpb1.add_child(h1) + rpb1.add_child(h2) + s1 = IMP.isd.Scale.setup_particle(IMP.Particle(m), 10.0) + s2 = IMP.isd.Scale.setup_particle(IMP.Particle(m), 10.0) + psi = IMP.isd.Scale.setup_particle(IMP.Particle(m), 0.5) + xl.add_contribution((h1, h2), (s1, s2), psi) + r.restraints.append(xl) + rm = IMP.mmcif.restraint._RestraintMapper(system) + frame = None + assembly = None + wr = rm.handle(r, frame, assembly) + self.assertEqual(type(wr), IMP.mmcif.restraint._CrossLinkRestraint) + self.assertEqual(type(wr.dataset), ihm.dataset.CXMSDataset) + self.assertEqual(len(wr.experimental_cross_links), 1) + self.assertEqual(len(wr.cross_links), 1) + + def test_restraint_mapper_saxs(self): + """Test _RestraintMapper with SAXS restraint""" + s = IMP.mmcif.System() + m = IMP.Model() + dat_filename = self.get_input_file_name('6lyz.pdb.dat') + r = MockSAXSRestraint(m, dat_filename) + r.set_was_used(True) + rm = IMP.mmcif.restraint._RestraintMapper(s) + frame = None + assembly = None + wr = rm.handle(r, frame, assembly) + self.assertEqual(type(wr), IMP.mmcif.restraint._SAXSRestraint) + self.assertEqual(type(wr.dataset), ihm.dataset.SASDataset) + + def test_restraint_mapper_zaxial(self): + """Test _RestraintMapper with ZAxialPositionRestraint""" + s = IMP.mmcif.System() + m = IMP.Model() + r = MockZAxialRestraint(m) + r.set_was_used(True) + rm = IMP.mmcif.restraint._RestraintMapper(s) + frame = None + assembly = None + wr = rm.handle(r, frame, assembly) + self.assertEqual(type(wr), IMP.mmcif.restraint._ZAxialRestraint) + self.assertIsNone(wr.dataset) + + def test_restraint_mapper_em2d_restraint(self): + """Test _RestraintMapper with IMP.em2d.PCAFitRestraint""" + s = IMP.mmcif.System() + m = IMP.Model() + image_filename = self.get_input_file_name('image_2.pgm') + r = MockPCAFitRestraint(m, image_filename) + r.set_was_used(True) + rm = IMP.mmcif.restraint._RestraintMapper(s) + frame = None + assembly = None + wr = rm.handle(r, frame, assembly) + self.assertEqual(type(wr), IMP.mmcif.restraint._EM2DRestraint) + self.assertEqual(type(wr.dataset), ihm.dataset.EM2DClassDataset) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/multi_state/bin/multi_foxs.cpp b/modules/multi_state/bin/multi_foxs.cpp index 999619d7d7..633ac032ed 100644 --- a/modules/multi_state/bin/multi_foxs.cpp +++ b/modules/multi_state/bin/multi_foxs.cpp @@ -166,14 +166,15 @@ int main(int argc, char* argv[]) { bool vr_score = false; bool use_offset = false; - po::options_description desc( + std::string desc_prefix( "Usage: ... or \n\n" "Any number of input profiles is supported.\n" "The weights are computed to minimize the chi between the first profile\n" "and a weighted average of the rest.\n\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/multi_state/bin/multi_foxs_combination.cpp b/modules/multi_state/bin/multi_foxs_combination.cpp index 528dcd7c44..dc9337486f 100644 --- a/modules/multi_state/bin/multi_foxs_combination.cpp +++ b/modules/multi_state/bin/multi_foxs_combination.cpp @@ -129,12 +129,13 @@ int main(int argc, char* argv[]) { int units = 1; // determine automatically bool use_offset = false; - po::options_description desc( + std::string desc_prefix( "Usage: ... or \n\n" "Any number of input pdbs is supported.\n" "This program is part of IMP, the Integrative Modeling Platform,\n" - "which is Copyright 2007-2022 IMP Inventors.\n\n" - "Options"); + "which is "); + po::options_description desc( + desc_prefix + IMP::get_copyright() + ".\n\nOptions"); desc.add_options() ("help", "Show command line arguments and exit.") ("version", "Show version info and exit.") diff --git a/modules/multi_state/include/SAXSMultiCombinationScore.h b/modules/multi_state/include/SAXSMultiCombinationScore.h index 1aa05ed47f..01c6945ee1 100644 --- a/modules/multi_state/include/SAXSMultiCombinationScore.h +++ b/modules/multi_state/include/SAXSMultiCombinationScore.h @@ -39,26 +39,26 @@ class SAXSMultiCombinationScore : public MultiStateModelScore { double min_c2 = -0.5, double max_c2 = 2.0, bool use_offset = false); - double get_score(const MultiStateModel& m) const IMP_OVERRIDE; + double get_score(const MultiStateModel& m) const override; double get_score(const MultiStateModel& m, - Vector& weights) const IMP_OVERRIDE { + Vector& weights) const override { IMP_UNUSED(weights); return get_score(m); } - saxs::WeightedFitParameters get_fit_parameters(MultiStateModel& m) const IMP_OVERRIDE; + saxs::WeightedFitParameters get_fit_parameters(MultiStateModel& m) const override; - saxs::WeightedFitParameters get_fit_parameters() const IMP_OVERRIDE; + saxs::WeightedFitParameters get_fit_parameters() const override; void write_fit_file(MultiStateModel& m, const saxs::WeightedFitParameters& fp, - const std::string fit_file_name) const IMP_OVERRIDE; + const std::string fit_file_name) const override; - std::string get_state_name(unsigned int id) const IMP_OVERRIDE { + std::string get_state_name(unsigned int id) const override { return profiles_[id]->get_name(); } - std::string get_dataset_name() const IMP_OVERRIDE { + std::string get_dataset_name() const override { return exp_profile_->get_name(); } diff --git a/modules/multifit/include/AlignmentParams.h b/modules/multifit/include/AlignmentParams.h index 4f3d39417d..6c22e1abfd 100644 --- a/modules/multifit/include/AlignmentParams.h +++ b/modules/multifit/include/AlignmentParams.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -47,11 +47,11 @@ struct DominoParams { int cache_size_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & max_value_threshold_ & max_num_states_for_subset_ - & max_anchor_penetration_ & heap_size_ & cache_size_; + template void serialize(Archive &ar) { + ar(max_value_threshold_, max_num_states_for_subset_, + max_anchor_penetration_, heap_size_, cache_size_); } }; IMP_VALUES(DominoParams, DominoParamsList); @@ -79,10 +79,10 @@ struct XlinkParams { bool treat_between_residues_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & upper_bound_ & k_ & max_xlink_val_ & treat_between_residues_; + template void serialize(Archive &ar) { + ar(upper_bound_, k_, max_xlink_val_, treat_between_residues_); } }; IMP_VALUES(XlinkParams, XlinkParamsList); @@ -109,10 +109,10 @@ struct ConnectivityParams { float max_conn_rest_val_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & upper_bound_ & k_ & max_conn_rest_val_; + template void serialize(Archive &ar) { + ar(upper_bound_, k_, max_conn_rest_val_); } }; IMP_VALUES(ConnectivityParams, ConnectivityParamsList); @@ -143,10 +143,10 @@ struct FragmentsParams { // true if the subunits are rigid bool subunit_rigid_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & frag_len_ & bead_radius_scale_ & load_atomic_ & subunit_rigid_; + template void serialize(Archive &ar) { + ar(frag_len_, bead_radius_scale_, load_atomic_, subunit_rigid_); } }; IMP_VALUES(FragmentsParams, FragmentsParamsList); @@ -168,10 +168,10 @@ struct RogParams { private: // maximum score float max_score_, scale_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & max_score_ & scale_; + template void serialize(Archive &ar) { + ar(max_score_, scale_); } }; IMP_VALUES(RogParams, RogParamsList); @@ -217,12 +217,12 @@ struct EVParams { // 1 means EV between all pairs is calculated // 2 means EV only between selected pairs is calculated private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & pair_distance_ & pair_slack_ & hlb_mean_ & hlb_k_ - & maximum_ev_score_for_pair_ & allowed_percentage_of_bad_pairs_ - & scoring_mode_; + template void serialize(Archive &ar) { + ar(pair_distance_, pair_slack_, hlb_mean_, hlb_k_, + maximum_ev_score_for_pair_, allowed_percentage_of_bad_pairs_, + scoring_mode_); } }; IMP_VALUES(EVParams, EVParamsList); @@ -248,11 +248,11 @@ struct FiltersParams { int max_num_violated_xlink_, max_num_violated_conn_; int max_num_violated_ev_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & max_num_violated_xlink_ & max_num_violated_conn_ - & max_num_violated_ev_; + template void serialize(Archive &ar) { + ar(max_num_violated_xlink_, max_num_violated_conn_, + max_num_violated_ev_); } }; IMP_VALUES(FiltersParams, FiltersParamsList); @@ -281,11 +281,11 @@ struct FittingParams { float pca_max_angle_diff_, pca_max_size_diff_; float pca_max_cent_dist_diff_, max_asmb_fit_score_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & pca_max_angle_diff_ & pca_max_size_diff_ & pca_max_cent_dist_diff_ - & max_asmb_fit_score_; + template void serialize(Archive &ar) { + ar(pca_max_angle_diff_, pca_max_size_diff_, pca_max_cent_dist_diff_, + max_asmb_fit_score_); } }; IMP_VALUES(FittingParams, FittingParamsList); @@ -322,11 +322,11 @@ struct ComplementarityParams { float interior_layer_thickness_; float boundary_coef_, comp_coef_, penetration_coef_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & max_score_ & max_penetration_ & interior_layer_thickness_ - & boundary_coef_ & comp_coef_ & penetration_coef_; + template void serialize(Archive &ar) { + ar(max_score_, max_penetration_, interior_layer_thickness_, + boundary_coef_, comp_coef_, penetration_coef_); } }; IMP_VALUES(ComplementarityParams, ComplementarityParamsList); @@ -384,12 +384,12 @@ class IMPMULTIFITEXPORT AlignmentParams { FiltersParams filters_params_; EVParams ev_params_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & domino_params_ & fitting_params_ & complementarity_params_ - & xlink_params_ & conn_params_ & fragments_params_ & rog_params_ - & filters_params_ & ev_params_; + template void serialize(Archive &ar) { + ar(domino_params_, fitting_params_, complementarity_params_, + xlink_params_, conn_params_, fragments_params_, rog_params_, + filters_params_, ev_params_); } }; IMP_VALUES(AlignmentParams, AlignmentParamsList); diff --git a/modules/multifit/include/FittingSolutionRecord.h b/modules/multifit/include/FittingSolutionRecord.h index 72924d765f..180806ffa7 100644 --- a/modules/multifit/include/FittingSolutionRecord.h +++ b/modules/multifit/include/FittingSolutionRecord.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include IMPMULTIFIT_BEGIN_NAMESPACE @@ -84,12 +84,12 @@ class IMPMULTIFITEXPORT FittingSolutionRecord { Float rmsd_to_ref_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & index_ & sol_fn_ & fit_transformation_ & dock_transformation_ - & match_size_ & match_avg_dist_ & env_pen_ & fitting_score_ - & rmsd_to_ref_; + template void serialize(Archive &ar) { + ar(index_, sol_fn_, fit_transformation_, dock_transformation_, + match_size_, match_avg_dist_, env_pen_, fitting_score_, + rmsd_to_ref_); } }; IMP_VALUES(FittingSolutionRecord, FittingSolutionRecords); diff --git a/modules/multifit/include/GeometricHash.h b/modules/multifit/include/GeometricHash.h index 5f28960cb7..6bcba76108 100644 --- a/modules/multifit/include/GeometricHash.h +++ b/modules/multifit/include/GeometricHash.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include "IMP/algebra/VectorD.h" @@ -30,7 +30,7 @@ class GeometricHash { EUCLIDEAN }; typedef algebra::VectorD Point; - typedef boost::array Bucket; + typedef std::array Bucket; typedef std::pair ValueType; typedef std::vector PointList; typedef std::map GeomMap; diff --git a/modules/multifit/include/proteomics_reader.h b/modules/multifit/include/proteomics_reader.h index 419d7969bc..21b3484001 100644 --- a/modules/multifit/include/proteomics_reader.h +++ b/modules/multifit/include/proteomics_reader.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include IMPMULTIFIT_BEGIN_NAMESPACE class ProteinRecordData { @@ -67,11 +67,11 @@ class ProteinRecordData { std::string ref_filename_; private: - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & name_ & start_res_ & end_res_ & filename_ & surface_filename_ - & ref_filename_; + template void serialize(Archive &ar) { + ar(name_, start_res_, end_res_, filename_, surface_filename_, + ref_filename_); } }; diff --git a/modules/multifit/pyext/swig.i-in b/modules/multifit/pyext/swig.i-in index 8ca5fe9672..9ca8157fc2 100644 --- a/modules/multifit/pyext/swig.i-in +++ b/modules/multifit/pyext/swig.i-in @@ -1,8 +1,6 @@ %import "RMF.i" %{ #include "RMF.h" -#include -#include %} IMP_SWIG_OBJECT(IMP::multifit, RadiusOfGyrationRestraint, diff --git a/modules/multifit/src/RadiusOfGyrationRestraint.cpp b/modules/multifit/src/RadiusOfGyrationRestraint.cpp index 09c3a56a6f..081e4b270a 100644 --- a/modules/multifit/src/RadiusOfGyrationRestraint.cpp +++ b/modules/multifit/src/RadiusOfGyrationRestraint.cpp @@ -75,7 +75,7 @@ double RadiusOfGyrationRestraint::unprotected_evaluate( IMP_UNUSED(accum); // IMP_USAGE_CHECK(!accum, "No derivatives computed"); if (accum) { - IMP_WARN("Can not calcaulte derivatives\n"); + IMP_WARN("Can not calculate derivatives\n"); } // calculate actual rog float actual_rog = get_actual_radius_of_gyration(get_particles()); diff --git a/modules/multifit/utility/single_prot_fft_fit.cpp b/modules/multifit/utility/single_prot_fft_fit.cpp index d08fe5475f..ef6d6b380b 100644 --- a/modules/multifit/utility/single_prot_fft_fit.cpp +++ b/modules/multifit/utility/single_prot_fft_fit.cpp @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/modules/multifit/utility/single_prot_pca_fit.cpp b/modules/multifit/utility/single_prot_pca_fit.cpp index 2d91be4fb2..eebd77c847 100644 --- a/modules/multifit/utility/single_prot_pca_fit.cpp +++ b/modules/multifit/utility/single_prot_pca_fit.cpp @@ -11,8 +11,6 @@ #include #include #include -#include -#include // imp #include #include diff --git a/modules/npc/include/MinimumSphereDistancePairScore.h b/modules/npc/include/MinimumSphereDistancePairScore.h index b64de9e93e..41191e4154 100644 --- a/modules/npc/include/MinimumSphereDistancePairScore.h +++ b/modules/npc/include/MinimumSphereDistancePairScore.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include IMPNPC_BEGIN_NAMESPACE @@ -30,11 +32,19 @@ class IMPNPCEXPORT MinimumSphereDistancePairScore : public PairScore { IMP::PointerMember f_; algebra::Transformation3Ds transforms_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), f_, transforms_); + } + IMP_OBJECT_SERIALIZE_DECL(MinimumSphereDistancePairScore); + public: MinimumSphereDistancePairScore(UnaryFunction *f, algebra::Transformation3Ds transforms) : f_(f), transforms_(transforms) {} + MinimumSphereDistancePairScore() {} + virtual double evaluate_index(Model *m, const ParticleIndexPair &pi, DerivativeAccumulator *da) const override; virtual ModelObjectsTemp do_get_inputs( diff --git a/modules/npc/include/ProteinLocalizationRestraint.h b/modules/npc/include/ProteinLocalizationRestraint.h index c3eff6f419..1e2e6d711c 100644 --- a/modules/npc/include/ProteinLocalizationRestraint.h +++ b/modules/npc/include/ProteinLocalizationRestraint.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include IMPNPC_BEGIN_NAMESPACE @@ -30,11 +32,20 @@ class IMPNPCEXPORT ZAxialPositionRestraint : public Restraint double upper_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, lower_bound_, upper_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(ZAxialPositionRestraint); + public: ZAxialPositionRestraint(Model *m, SingletonContainerAdaptor sc, double lower_bound, double upper_bound, bool consider_radius, double sigma=1); ZAxialPositionRestraint(Model *m, double lower_bound, double upper_bound, bool consider_radius, double sigma=1); + ZAxialPositionRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -46,6 +57,9 @@ class IMPNPCEXPORT ZAxialPositionRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(ZAxialPositionRestraint);; }; @@ -59,11 +73,20 @@ class IMPNPCEXPORT ZAxialPositionLowerRestraint : public Restraint double lower_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, lower_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(ZAxialPositionLowerRestraint); + public: ZAxialPositionLowerRestraint(Model *m, SingletonContainerAdaptor sc, double lower_bound, bool consider_radius, double sigma=1); ZAxialPositionLowerRestraint(Model *m, double lower_bound, bool consider_radius, double sigma=1); + ZAxialPositionLowerRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -75,6 +98,9 @@ class IMPNPCEXPORT ZAxialPositionLowerRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(ZAxialPositionLowerRestraint);; }; @@ -88,11 +114,20 @@ class IMPNPCEXPORT ZAxialPositionUpperRestraint : public Restraint double upper_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, upper_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(ZAxialPositionUpperRestraint); + public: ZAxialPositionUpperRestraint(Model *m, SingletonContainerAdaptor sc, double upper_bound, bool consider_radius, double sigma=1); ZAxialPositionUpperRestraint(Model *m, double upper_bound, bool consider_radius, double sigma=1); + ZAxialPositionUpperRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -104,6 +139,9 @@ class IMPNPCEXPORT ZAxialPositionUpperRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(ZAxialPositionUpperRestraint);; }; @@ -119,11 +157,20 @@ class IMPNPCEXPORT YAxialPositionRestraint : public Restraint double upper_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, lower_bound_, upper_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(YAxialPositionRestraint); + public: YAxialPositionRestraint(Model *m, SingletonContainerAdaptor sc, double lower_bound, double upper_bound, bool consider_radius, double sigma=1); YAxialPositionRestraint(Model *m, double lower_bound, double upper_bound, bool consider_radius, double sigma=1); + YAxialPositionRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -135,6 +182,9 @@ class IMPNPCEXPORT YAxialPositionRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(YAxialPositionRestraint);; }; @@ -148,11 +198,20 @@ class IMPNPCEXPORT YAxialPositionLowerRestraint : public Restraint double lower_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, lower_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(YAxialPositionLowerRestraint); + public: YAxialPositionLowerRestraint(Model *m, SingletonContainerAdaptor sc, double lower_bound, bool consider_radius, double sigma=1); YAxialPositionLowerRestraint(Model *m, double lower_bound, bool consider_radius, double sigma=1); + YAxialPositionLowerRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -164,6 +223,9 @@ class IMPNPCEXPORT YAxialPositionLowerRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(YAxialPositionLowerRestraint);; }; @@ -177,11 +239,20 @@ class IMPNPCEXPORT YAxialPositionUpperRestraint : public Restraint double upper_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, upper_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(YAxialPositionUpperRestraint); + public: YAxialPositionUpperRestraint(Model *m, SingletonContainerAdaptor sc, double upper_bound, bool consider_radius, double sigma=1); YAxialPositionUpperRestraint(Model *m, double upper_bound, bool consider_radius, double sigma=1); + YAxialPositionUpperRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -193,6 +264,9 @@ class IMPNPCEXPORT YAxialPositionUpperRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(YAxialPositionUpperRestraint);; }; @@ -208,11 +282,20 @@ class IMPNPCEXPORT XYRadialPositionRestraint : public Restraint double upper_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, lower_bound_, upper_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(XYRadialPositionRestraint); + public: XYRadialPositionRestraint(Model *m, SingletonContainerAdaptor sc, double lower_bound, double upper_bound, bool consider_radius, double sigma=1); XYRadialPositionRestraint(Model *m, double lower_bound, double upper_bound, bool consider_radius, double sigma=1); + XYRadialPositionRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -224,6 +307,9 @@ class IMPNPCEXPORT XYRadialPositionRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(XYRadialPositionRestraint);; }; @@ -237,11 +323,20 @@ class IMPNPCEXPORT XYRadialPositionLowerRestraint : public Restraint double lower_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, lower_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(XYRadialPositionLowerRestraint); + public: XYRadialPositionLowerRestraint(Model *m, SingletonContainerAdaptor sc, double lower_bound, bool consider_radius, double sigma=1); XYRadialPositionLowerRestraint(Model *m, double lower_bound, bool consider_radius, double sigma=1); + XYRadialPositionLowerRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -253,6 +348,9 @@ class IMPNPCEXPORT XYRadialPositionLowerRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(XYRadialPositionLowerRestraint);; }; @@ -266,11 +364,20 @@ class IMPNPCEXPORT XYRadialPositionUpperRestraint : public Restraint double upper_bound_; double sigma_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, upper_bound_, sigma_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(XYRadialPositionUpperRestraint); + public: XYRadialPositionUpperRestraint(Model *m, SingletonContainerAdaptor sc, double upper_bound, bool consider_radius, double sigma=1); XYRadialPositionUpperRestraint(Model *m, double upper_bound, bool consider_radius, double sigma=1); + XYRadialPositionUpperRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -282,6 +389,9 @@ class IMPNPCEXPORT XYRadialPositionUpperRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(XYRadialPositionUpperRestraint);; }; @@ -296,11 +406,19 @@ class IMPNPCEXPORT ProteinContactRestraint : public Restraint IMP::PointerMember sc_; double tolerance_factor_; double sigma_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, tolerance_factor_, sigma_); + } + IMP_OBJECT_SERIALIZE_DECL(ProteinContactRestraint); + public: ProteinContactRestraint(Model *m, SingletonContainerAdaptor sc, double tolerance_factor, double sigma=0.1); ProteinContactRestraint(Model *m, double tolerance_factor, double sigma=0.1); + ProteinContactRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -325,11 +443,19 @@ class IMPNPCEXPORT ProteinChainRestraint : public Restraint { IMP::PointerMember sc_; double sigma_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, sigma_); + } + IMP_OBJECT_SERIALIZE_DECL(ProteinChainRestraint); + public: ProteinChainRestraint(Model *m, SingletonContainerAdaptor sc, double sigma=0.1); ProteinChainRestraint(Model *m, double sigma=0.1); + ProteinChainRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -356,11 +482,19 @@ class IMPNPCEXPORT MembraneSurfaceLocationRestraint : public Restraint double r_; double sigma_; double thickness_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, R_, r_, sigma_, thickness_); + } + IMP_OBJECT_SERIALIZE_DECL(MembraneSurfaceLocationRestraint); + public: MembraneSurfaceLocationRestraint(Model *m, SingletonContainerAdaptor sc, double R, double r, double thickness, double sigma=2); MembraneSurfaceLocationRestraint(Model *m, double R, double r, double thickness, double sigma=2); + MembraneSurfaceLocationRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -372,6 +506,9 @@ class IMPNPCEXPORT MembraneSurfaceLocationRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(MembraneSurfaceLocationRestraint);; }; @@ -389,11 +526,20 @@ class IMPNPCEXPORT MembraneSurfaceLocationConditionalRestraint : public Restrain double r_; double sigma_; double thickness_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc1_, sc2_, R_, r_, sigma_, thickness_); + } + IMP_OBJECT_SERIALIZE_DECL(MembraneSurfaceLocationConditionalRestraint); + public: MembraneSurfaceLocationConditionalRestraint(Model *m, SingletonContainerAdaptor sc1, SingletonContainerAdaptor sc2, double R, double r, double thickness, double sigma=2); MembraneSurfaceLocationConditionalRestraint(Model *m, double R, double r, double thickness, double sigma=2); + MembraneSurfaceLocationConditionalRestraint() {} #ifndef IMP_DOXYGEN void add_particle1(Particle *p); @@ -408,6 +554,9 @@ class IMPNPCEXPORT MembraneSurfaceLocationConditionalRestraint : public Restrain IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(MembraneSurfaceLocationConditionalRestraint);; }; @@ -423,11 +572,19 @@ class IMPNPCEXPORT MembraneExclusionRestraint : public Restraint double r_; double sigma_; double thickness_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, R_, r_, sigma_, thickness_); + } + IMP_OBJECT_SERIALIZE_DECL(MembraneExclusionRestraint); + public: MembraneExclusionRestraint(Model *m, SingletonContainerAdaptor sc, double R, double r, double thickness, double sigma=2); MembraneExclusionRestraint(Model *m, double R, double r, double thickness, double sigma=2); + MembraneExclusionRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -439,6 +596,9 @@ class IMPNPCEXPORT MembraneExclusionRestraint : public Restraint IMP::DerivativeAccumulator *accum) const override; ModelObjectsTemp do_get_inputs() const override; + //! \return Information for writing to RMF files + RestraintInfo *get_static_info() const override; + IMP_OBJECT_METHODS(MembraneExclusionRestraint);; }; @@ -455,11 +615,20 @@ class IMPNPCEXPORT PoreSideVolumeLocationRestraint : public Restraint double sigma_; double thickness_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, R_, r_, sigma_, thickness_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(PoreSideVolumeLocationRestraint); + public: PoreSideVolumeLocationRestraint(Model *m, SingletonContainerAdaptor sc, double R, double r, double thickness, bool consider_radius, double sigma=2); PoreSideVolumeLocationRestraint(Model *m, double R, double r, double thickness, bool consider_radius, double sigma=2); + PoreSideVolumeLocationRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -487,11 +656,20 @@ class IMPNPCEXPORT PerinuclearVolumeLocationRestraint : public Restraint double sigma_; double thickness_; bool consider_radius_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + sc_, R_, r_, sigma_, thickness_, consider_radius_); + } + IMP_OBJECT_SERIALIZE_DECL(PerinuclearVolumeLocationRestraint); + public: PerinuclearVolumeLocationRestraint(Model *m, SingletonContainerAdaptor sc, double R, double r, double thickness, bool consider_radius, double sigma=2); PerinuclearVolumeLocationRestraint(Model *m, double R, double r, double thickness, bool consider_radius, double sigma=2); + PerinuclearVolumeLocationRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -517,11 +695,19 @@ class IMPNPCEXPORT AssemblySymmetryByDistanceRestraint : public Restraint { IMP::PointerMember sc_; double sigma_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, sigma_); + } + IMP_OBJECT_SERIALIZE_DECL(AssemblySymmetryByDistanceRestraint); + public: AssemblySymmetryByDistanceRestraint(Model *m, SingletonContainerAdaptor sc, double sigma=4); AssemblySymmetryByDistanceRestraint(Model *m, double sigma=4); + AssemblySymmetryByDistanceRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -548,11 +734,19 @@ class IMPNPCEXPORT AssemblySymmetryByDihedralRestraint { IMP::PointerMember sc_; double sigma_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, sigma_); + } + IMP_OBJECT_SERIALIZE_DECL(AssemblySymmetryByDihedralRestraint); + public: AssemblySymmetryByDihedralRestraint(Model *m, SingletonContainerAdaptor sc, double sigma=0.1); AssemblySymmetryByDihedralRestraint(Model *m, double sigma=0.1); + AssemblySymmetryByDihedralRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); @@ -577,11 +771,19 @@ class IMPNPCEXPORT ProteinProximityRestraint IMP::PointerMember sc_; double sigma_; double max_dist_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), sc_, sigma_, max_dist_); + } + IMP_OBJECT_SERIALIZE_DECL(ProteinProximityRestraint); + public: ProteinProximityRestraint(Model *m, SingletonContainerAdaptor sc, double max_dist, double sigma=0.1); ProteinProximityRestraint(Model *m, double max_dist, double sigma=0.1); + ProteinProximityRestraint() {} #ifndef IMP_DOXYGEN void add_particle(Particle *p); diff --git a/modules/npc/pyext/src/npc_restraints.py b/modules/npc/pyext/src/npc_restraints.py deleted file mode 100644 index 753a1efdcf..0000000000 --- a/modules/npc/pyext/src/npc_restraints.py +++ /dev/null @@ -1,10 +0,0 @@ -import IMP.npc -import IMP.pmi1.restraints.npc - - -IMP.deprecated_module( - "2.18", __name__, - "Use IMP.pmi.restraints.npc or IMP.pmi1.restraints.npc instead") - - -from IMP.pmi1.restraints.npc import * diff --git a/modules/npc/pyext/swig.i-in b/modules/npc/pyext/swig.i-in index bbbe4b718d..e934392a0c 100644 --- a/modules/npc/pyext/swig.i-in +++ b/modules/npc/pyext/swig.i-in @@ -1,24 +1,24 @@ -IMP_SWIG_OBJECT( IMP::npc, ZAxialPositionLowerRestraint, ZAxialPositionLowerRestraints); -IMP_SWIG_OBJECT( IMP::npc, ZAxialPositionUpperRestraint, ZAxialPositionUpperRestraints); -IMP_SWIG_OBJECT( IMP::npc, XYRadialPositionLowerRestraint, XYRadialPositionLowerRestraints); -IMP_SWIG_OBJECT( IMP::npc, XYRadialPositionUpperRestraint, XYRadialPositionUpperRestraints); -IMP_SWIG_OBJECT( IMP::npc, ProteinContactRestraint, ProteinContactRestraints); -IMP_SWIG_OBJECT( IMP::npc, ProteinChainRestraint, ProteinChainRestraints); -IMP_SWIG_OBJECT( IMP::npc, MembraneSurfaceLocationRestraint, MembraneSurfaceLocationRestraints); -IMP_SWIG_OBJECT( IMP::npc, PoreSideVolumeLocationRestraint, PoreSideVolumeLocationRestraints); -IMP_SWIG_OBJECT( IMP::npc, PerinuclearVolumeLocationRestraint, PerinuclearVolumeLocationRestraints); -IMP_SWIG_OBJECT( IMP::npc, AssemblySymmetryByDistanceRestraint, AssemblySymmetryByDistanceRestraints); -IMP_SWIG_OBJECT( IMP::npc, AssemblySymmetryByDihedralRestraint, AssemblySymmetryByDihedralRestraints); -IMP_SWIG_OBJECT( IMP::npc, ProteinProximityRestraint, ProteinProximityRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, ZAxialPositionLowerRestraint, ZAxialPositionLowerRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, ZAxialPositionUpperRestraint, ZAxialPositionUpperRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, XYRadialPositionLowerRestraint, XYRadialPositionLowerRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, XYRadialPositionUpperRestraint, XYRadialPositionUpperRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, ProteinContactRestraint, ProteinContactRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, ProteinChainRestraint, ProteinChainRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, MembraneSurfaceLocationRestraint, MembraneSurfaceLocationRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, PoreSideVolumeLocationRestraint, PoreSideVolumeLocationRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, PerinuclearVolumeLocationRestraint, PerinuclearVolumeLocationRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, AssemblySymmetryByDistanceRestraint, AssemblySymmetryByDistanceRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, AssemblySymmetryByDihedralRestraint, AssemblySymmetryByDihedralRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, ProteinProximityRestraint, ProteinProximityRestraints); IMP_SWIG_OBJECT( IMP::npc, CompositeRestraint, CompositeRestraints); -IMP_SWIG_OBJECT( IMP::npc, MinimumSphereDistancePairScore, MinimumSphereDistancePairScores); -IMP_SWIG_OBJECT( IMP::npc, MembraneExclusionRestraint, MembraneExclusionRestraints); -IMP_SWIG_OBJECT( IMP::npc, MembraneSurfaceLocationConditionalRestraint, MembraneSurfaceLocationConditionalRestraints); -IMP_SWIG_OBJECT( IMP::npc, XYRadialPositionRestraint, XYRadialPositionRestraints); -IMP_SWIG_OBJECT( IMP::npc, YAxialPositionLowerRestraint, YAxialPositionLowerRestraints); -IMP_SWIG_OBJECT( IMP::npc, YAxialPositionRestraint, YAxialPositionRestraints); -IMP_SWIG_OBJECT( IMP::npc, YAxialPositionUpperRestraint, YAxialPositionUpperRestraints); -IMP_SWIG_OBJECT( IMP::npc, ZAxialPositionRestraint, ZAxialPositionRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, MinimumSphereDistancePairScore, MinimumSphereDistancePairScores); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, MembraneExclusionRestraint, MembraneExclusionRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, MembraneSurfaceLocationConditionalRestraint, MembraneSurfaceLocationConditionalRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, XYRadialPositionRestraint, XYRadialPositionRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, YAxialPositionLowerRestraint, YAxialPositionLowerRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, YAxialPositionRestraint, YAxialPositionRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, YAxialPositionUpperRestraint, YAxialPositionUpperRestraints); +IMP_SWIG_OBJECT_SERIALIZE( IMP::npc, ZAxialPositionRestraint, ZAxialPositionRestraints); %include "IMP/npc/ProteinLocalizationRestraint.h" %include "IMP/npc/CompositeRestraint.h" diff --git a/modules/npc/src/MinimumSphereDistancePairScore.cpp b/modules/npc/src/MinimumSphereDistancePairScore.cpp index b3dae2d8d6..4c91c4d529 100644 --- a/modules/npc/src/MinimumSphereDistancePairScore.cpp +++ b/modules/npc/src/MinimumSphereDistancePairScore.cpp @@ -43,4 +43,6 @@ double MinimumSphereDistancePairScore::evaluate_index(Model *m, return v; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::MinimumSphereDistancePairScore); + IMPNPC_END_NAMESPACE diff --git a/modules/npc/src/ProteinLocalizationRestraint.cpp b/modules/npc/src/ProteinLocalizationRestraint.cpp index 5f2aa10285..e3e265ec9d 100644 --- a/modules/npc/src/ProteinLocalizationRestraint.cpp +++ b/modules/npc/src/ProteinLocalizationRestraint.cpp @@ -4,7 +4,7 @@ * Restrict max distance between at least one pair of particles of any * two distinct types. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -137,6 +137,14 @@ ModelObjectsTemp ZAxialPositionRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *ZAxialPositionRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.ZAxialPositionRestraint"); + ri->add_float("lower bound", lower_bound_); + ri->add_float("upper bound", upper_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM ZAxialPositionLowerRestraint @@ -221,6 +229,13 @@ ModelObjectsTemp ZAxialPositionLowerRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *ZAxialPositionLowerRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.ZAxialPositionLowerRestraint"); + ri->add_float("lower bound", lower_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM ZAxialPositionUpperRestraint @@ -305,6 +320,13 @@ ModelObjectsTemp ZAxialPositionUpperRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *ZAxialPositionUpperRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.ZAxialPositionUpperRestraint"); + ri->add_float("upper bound", upper_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM YAxialPositionRestraint @@ -406,6 +428,14 @@ ModelObjectsTemp YAxialPositionRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *YAxialPositionRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.YAxialPositionRestraint"); + ri->add_float("upper bound", upper_bound_); + ri->add_float("lower bound", lower_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM YAxialPositionLowerRestraint @@ -490,6 +520,13 @@ ModelObjectsTemp YAxialPositionLowerRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *YAxialPositionLowerRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.YAxialPositionLowerRestraint"); + ri->add_float("lower bound", lower_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM YAxialPositionUpperRestraint @@ -574,6 +611,13 @@ ModelObjectsTemp YAxialPositionUpperRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *YAxialPositionUpperRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.YAxialPositionUpperRestraint"); + ri->add_float("upper bound", upper_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM XYRadialPositionRestraint @@ -697,6 +741,14 @@ ModelObjectsTemp XYRadialPositionRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *XYRadialPositionRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.XYRadialPositionRestraint"); + ri->add_float("upper bound", upper_bound_); + ri->add_float("lower bound", lower_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM XYRadialPositionLowerRestraint @@ -792,6 +844,13 @@ ModelObjectsTemp XYRadialPositionLowerRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *XYRadialPositionLowerRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.XYRadialPositionLowerRestraint"); + ri->add_float("lower bound", lower_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - Immuno-EM XYRadialPositionUpperRestraint @@ -887,6 +946,13 @@ ModelObjectsTemp XYRadialPositionUpperRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *XYRadialPositionUpperRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.XYRadialPositionUpperRestraint"); + ri->add_float("upper bound", upper_bound_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - ProteinContactRestraint @@ -982,7 +1048,6 @@ ModelObjectsTemp ProteinContactRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } - /*##################################################### # Restraints setup - ProteinChainRestraint #####################################################*/ @@ -1241,6 +1306,15 @@ ModelObjectsTemp MembraneSurfaceLocationRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *MembraneSurfaceLocationRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.MembraneSurfaceLocationRestraint"); + ri->add_float("major radius", R_); + ri->add_float("minor radius", r_); + ri->add_float("thickness", thickness_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - MembraneSurfaceLocationConditionalRestraint @@ -1360,6 +1434,18 @@ ModelObjectsTemp MembraneSurfaceLocationConditionalRestraint::do_get_inputs() co return IMP::get_particles(get_model(), all); } +RestraintInfo *MembraneSurfaceLocationConditionalRestraint::get_static_info() + const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.MembraneSurfaceLocationConditionalRestraint"); + ri->add_float("major radius", R_); + ri->add_float("minor radius", r_); + ri->add_float("thickness", thickness_); + ri->add_float("sigma", sigma_); + ri->add_particle_indexes("particles1", sc1_->get_contents()); + ri->add_particle_indexes("particles2", sc2_->get_contents()); + return ri.release(); +} /*##################################################### # Restraints setup - MembraneExclusionRestraint @@ -1456,6 +1542,15 @@ ModelObjectsTemp MembraneExclusionRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +RestraintInfo *MembraneExclusionRestraint::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.npc.MembraneExclusionRestraint"); + ri->add_float("major radius", R_); + ri->add_float("minor radius", r_); + ri->add_float("thickness", thickness_); + ri->add_float("sigma", sigma_); + return ri.release(); +} /*##################################################### # Restraints setup - PoreSideVolumeLocationRestraint @@ -1884,4 +1979,25 @@ ModelObjectsTemp ProteinProximityRestraint::do_get_inputs() const { return IMP::get_particles(get_model(), all); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::ZAxialPositionRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::ZAxialPositionLowerRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::ZAxialPositionUpperRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::YAxialPositionRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::YAxialPositionLowerRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::YAxialPositionUpperRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::XYRadialPositionRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::XYRadialPositionLowerRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::XYRadialPositionUpperRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::ProteinContactRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::ProteinChainRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::MembraneSurfaceLocationRestraint); +IMP_OBJECT_SERIALIZE_IMPL( + IMP::npc::MembraneSurfaceLocationConditionalRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::MembraneExclusionRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::PoreSideVolumeLocationRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::PerinuclearVolumeLocationRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::AssemblySymmetryByDistanceRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::AssemblySymmetryByDihedralRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::npc::ProteinProximityRestraint); + IMPNPC_END_NAMESPACE diff --git a/modules/npc/test/test_min_pair_score.py b/modules/npc/test/test_min_pair_score.py index 05f44763b5..2499cfc699 100644 --- a/modules/npc/test/test_min_pair_score.py +++ b/modules/npc/test/test_min_pair_score.py @@ -3,10 +3,12 @@ import IMP.algebra import IMP.core import IMP.npc +import pickle + class Tests(IMP.test.TestCase): - def get_score(self, m, transforms): + def get_pair_score(self, m, transforms): p0 = IMP.Particle(m, "p0") IMP.core.XYZR.setup_particle(p0, IMP.algebra.Sphere3D( IMP.algebra.Vector3D(2,0,0.), 0.4)) @@ -16,6 +18,10 @@ def get_score(self, m, transforms): ps = IMP.npc.MinimumSphereDistancePairScore(IMP.core.Linear(0.0, 1.0), transforms) + return ps, p0, p1 + + def get_score(self, m, transforms): + ps, p0, p1 = self.get_pair_score(m, transforms) r = IMP.core.PairRestraint(m, ps, [p0,p1]) return r.evaluate(True) @@ -42,5 +48,35 @@ def test_bad_transform(self): IMP.algebra.Vector3D(10,0,0))] self.assertAlmostEqual(self.get_score(m, transforms), 6.5, delta=1e-6) + def test_pickle(self): + """Test (un-)pickle of MinimumSphereDistancePairScore""" + m = IMP.Model() + transforms = [IMP.algebra.Transformation3D( + IMP.algebra.get_identity_rotation_3d(), + IMP.algebra.Vector3D(-10,0,0))] + ps, p0, p1 = self.get_pair_score(m, transforms) + ps.set_name('foo') + self.assertAlmostEqual(ps.evaluate_index(m, (p0, p1), None), + 2.5, delta=1e-4) + dump = pickle.dumps(ps) + news = pickle.loads(dump) + self.assertEqual(news.get_name(), 'foo') + self.assertAlmostEqual(news.evaluate_index(m, (p0, p1), None), + 2.5, delta=1e-4) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of MinimumSphereDistancePairScore via poly ptr""" + m = IMP.Model() + transforms = [IMP.algebra.Transformation3D( + IMP.algebra.get_identity_rotation_3d(), + IMP.algebra.Vector3D(-10,0,0))] + ps, p0, p1 = self.get_pair_score(m, transforms) + r = IMP.core.PairRestraint(m, ps, (p0, p1)) + self.assertAlmostEqual(r.evaluate(False), 2.5, delta=1e-4) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertAlmostEqual(newr.evaluate(False), 2.5, delta=1e-4) + + if __name__ == '__main__': IMP.test.main() diff --git a/modules/npc/test/test_protein_localization_restraints.py b/modules/npc/test/test_protein_localization_restraints.py new file mode 100644 index 0000000000..fc56e592c4 --- /dev/null +++ b/modules/npc/test/test_protein_localization_restraints.py @@ -0,0 +1,204 @@ +import IMP +import IMP.test +import IMP.algebra +import IMP.core +import IMP.npc +import pickle + + +def setup_system(): + m = IMP.Model() + p = IMP.core.XYZR.setup_particle( + IMP.Particle(m), + IMP.algebra.Sphere3D(IMP.algebra.Vector3D(2,0,0.), 0.4)) + return m, p + + +def _parse_restraint_info(info): + """Convert RestraintInfo object to Python dict""" + d = {} + if info is None: + return d + info.set_was_used(True) + for typ in ('int', 'float', 'string', 'filename', 'floats', 'filenames', + 'particle_indexes'): + for i in range(getattr(info, 'get_number_of_' + typ)()): + key = getattr(info, 'get_%s_key' % typ)(i) + value = getattr(info, 'get_%s_value' % typ)(i) + d[key] = value + return d + + +class Tests(IMP.test.TestCase): + + def _check_pickle(self, r, score): + """Check that the restraint r can be (un-)pickled""" + r.set_name('foo') + self._check_pickle_non_polymorphic(r, score) + self._check_pickle_polymorphic(r, score) + + def _check_pickle_non_polymorphic(self, r, score): + self.assertAlmostEqual(r.evaluate(False), score, delta=1e-3) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(False), score, delta=1e-3) + + def _check_pickle_polymorphic(self, r, score): + sf = IMP.core.RestraintsScoringFunction([r]) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(False), score, delta=1e-3) + + def test_z_axial(self): + """Test ZAxialPositionRestraint""" + m, p = setup_system() + r = IMP.npc.ZAxialPositionRestraint(m, [p], 1.0, 2.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['lower bound'], 1.0, delta=1e-4) + self.assertAlmostEqual(info['upper bound'], 2.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.ZAxialPositionRestraint') + self._check_pickle(r, score=3.920) + + def test_z_axial_lower(self): + """Test ZAxialPositionLowerRestraint""" + m, p = setup_system() + r = IMP.npc.ZAxialPositionLowerRestraint(m, [p], 1.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['lower bound'], 1.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.ZAxialPositionLowerRestraint') + self._check_pickle(r, score=3.920) + + def test_z_axial_upper(self): + """Test ZAxialPositionUpperRestraint""" + m, p = setup_system() + r = IMP.npc.ZAxialPositionUpperRestraint(m, [p], -5.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['upper bound'], -5.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.ZAxialPositionUpperRestraint') + self._check_pickle(r, score=58.32) + + def test_y_axial(self): + """Test YAxialPositionRestraint""" + m, p = setup_system() + r = IMP.npc.YAxialPositionRestraint(m, [p], 1.0, 2.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['lower bound'], 1.0, delta=1e-4) + self.assertAlmostEqual(info['upper bound'], 2.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.YAxialPositionRestraint') + self._check_pickle(r, score=3.920) + + def test_y_axial_lower(self): + """Test YAxialPositionLowerRestraint""" + m, p = setup_system() + r = IMP.npc.YAxialPositionLowerRestraint(m, [p], 1.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['lower bound'], 1.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.YAxialPositionLowerRestraint') + self._check_pickle(r, score=3.920) + + def test_y_axial_upper(self): + """Test YAxialPositionUpperRestraint""" + m, p = setup_system() + r = IMP.npc.YAxialPositionUpperRestraint(m, [p], -2.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['upper bound'], -2.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.YAxialPositionUpperRestraint') + self._check_pickle(r, score=11.52) + + def test_xy_radial(self): + """Test XYRadialPositionRestraint""" + m, p = setup_system() + r = IMP.npc.XYRadialPositionRestraint(m, [p], 1.0, 2.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['lower bound'], 1.0, delta=1e-4) + self.assertAlmostEqual(info['upper bound'], 2.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], 'IMP.npc.XYRadialPositionRestraint') + self._check_pickle(r, score=0.32) + + def test_xy_radial_lower(self): + """Test XYRadialPositionLowerRestraint""" + m, p = setup_system() + r = IMP.npc.XYRadialPositionLowerRestraint(m, [p], 10.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['lower bound'], 10.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], + 'IMP.npc.XYRadialPositionLowerRestraint') + self._check_pickle(r, score=141.12) + + def test_xy_radial_upper(self): + """Test XYRadialPositionUpperRestraint""" + m, p = setup_system() + r = IMP.npc.XYRadialPositionUpperRestraint(m, [p], 2.0, True, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['upper bound'], 2.0, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], + 'IMP.npc.XYRadialPositionUpperRestraint') + self._check_pickle(r, score=0.32) + + def test_membrane_surface_localization_restraint(self): + """Test MembraneSurfaceLocationRestraint""" + m, p = setup_system() + r = IMP.npc.MembraneSurfaceLocationRestraint(m, [p], 40.0, 10.0, + 3.0, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['major radius'], 40.0, delta=1e-4) + self.assertAlmostEqual(info['minor radius'], 10.0, delta=1e-4) + # thickness is half of user value + self.assertAlmostEqual(info['thickness'], 1.5, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], + 'IMP.npc.MembraneSurfaceLocationRestraint') + self._check_pickle(r, score=1568.0) + + def test_membrane_exclusion_restraint(self): + """Test MembraneExclusionRestraint""" + m, p = setup_system() + p.set_coordinates([40., 2., 3.]) + r = IMP.npc.MembraneExclusionRestraint(m, [p], 40.0, 10.0, 3.0, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['major radius'], 40.0, delta=1e-4) + self.assertAlmostEqual(info['minor radius'], 10.0, delta=1e-4) + # thickness is half of user value + self.assertAlmostEqual(info['thickness'], 1.5, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], + 'IMP.npc.MembraneExclusionRestraint') + self._check_pickle(r, score=144.5) + + def test_membrane_surface_location_conditional_restraint(self): + """Test MembraneSurfaceLocationConditionalRestraint""" + m, p1 = setup_system() + p2 = IMP.core.XYZR.setup_particle( + IMP.Particle(m), + IMP.algebra.Sphere3D(IMP.algebra.Vector3D(4,0,0.), 0.4)) + r = IMP.npc.MembraneSurfaceLocationConditionalRestraint( + m, [p1], [p2], 40.0, 10.0, 3.0, 0.5) + info = _parse_restraint_info(r.get_static_info()) + self.assertAlmostEqual(info['major radius'], 40.0, delta=1e-4) + self.assertAlmostEqual(info['minor radius'], 10.0, delta=1e-4) + # thickness is half of user value + self.assertAlmostEqual(info['thickness'], 1.5, delta=1e-4) + self.assertAlmostEqual(info['sigma'], 0.5, delta=1e-4) + self.assertEqual(info['type'], + 'IMP.npc.MembraneSurfaceLocationConditionalRestraint') + p1ind, = info['particles1'] + self.assertEqual(p1ind, p1.get_particle_index()) + p2ind, = info['particles2'] + self.assertEqual(p2ind, p2.get_particle_index()) + self._check_pickle(r, score=1352.0) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/npctransport b/modules/npctransport index 7eea0cba54..30bc1f0e0b 160000 --- a/modules/npctransport +++ b/modules/npctransport @@ -1 +1 @@ -Subproject commit 7eea0cba54b41cffe173a6900593bb959cac9c57 +Subproject commit 30bc1f0e0b6ed2f52d9d07ca57a2ff5ba50eb37e diff --git a/modules/pmi/.codecov.yml b/modules/pmi/.codecov.yml index f48429a45b..c6b1cc2398 100644 --- a/modules/pmi/.codecov.yml +++ b/modules/pmi/.codecov.yml @@ -1,2 +1,4 @@ ignore: - test + - setup_git.py + - dependencies.py diff --git a/modules/pmi/.github/workflows/build.yml b/modules/pmi/.github/workflows/build.yml index fb507bb1de..69883b0081 100644 --- a/modules/pmi/.github/workflows/build.yml +++ b/modules/pmi/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python-version: ["2.7", "3.10"] + python-version: ["2.7", "3.11"] runs-on: ${{ matrix.os }} steps: @@ -37,4 +37,5 @@ jobs: make ./setup_environment.sh pytest --cov=.. --cov-branch --cov-report=xml -v ../test/test_*.py ../test/medium_test_*.py test/*/*.py flake8 ../pyext/src/ - - uses: codecov/codecov-action@v1 + ${GCC/gcc/gcov} $(find . -name "*.gcno") + - uses: codecov/codecov-action@v3 diff --git a/modules/pmi/examples/ambiguity.py b/modules/pmi/examples/ambiguity.py index bb098192c0..ca4e4c833d 100644 --- a/modules/pmi/examples/ambiguity.py +++ b/modules/pmi/examples/ambiguity.py @@ -17,6 +17,7 @@ import IMP.pmi.macros import IMP.pmi.restraints.stereochemistry import IMP.pmi.restraints.crosslinking +import ihm.cross_linkers import tempfile import os import sys @@ -95,7 +96,8 @@ length=21, label="XL", resolution=1, - slope=0.01) + slope=0.01, + linker=ihm.cross_linkers.dss) xlr.add_to_model() output_objects.append(xlr) # needed to sample the nuisance particles (noise params) diff --git a/modules/pmi/include/CrossLinkRestraintSet.h b/modules/pmi/include/CrossLinkRestraintSet.h new file mode 100644 index 0000000000..41d0077ba3 --- /dev/null +++ b/modules/pmi/include/CrossLinkRestraintSet.h @@ -0,0 +1,66 @@ +/** + * \file IMP/pmi/CrossLinkRestraintSet.h + * \brief A RestraintSet subclass to track cross-link metadata. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#ifndef IMPPMI_CROSS_LINK_RESTRAINT_SET_H +#define IMPPMI_CROSS_LINK_RESTRAINT_SET_H + +#include "pmi_config.h" +#include +#include +#include + +IMPPMI_BEGIN_NAMESPACE + +//! A RestraintSet subclass to track cross-link metadata. +/** This is provided so that we can write information about a set of + cross-links to an RMF file (e.g. the CSV file from which they were read). + */ +class IMPPMIEXPORT CrossLinkRestraintSet : public RestraintSet +{ + std::string filename_; + double length_, slope_; + std::string auth_name_, chemical_name_, smiles_, smiles_canonical_, inchi_, + inchi_key_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + filename_, length_, slope_, auth_name_, chemical_name_, smiles_, + smiles_canonical_, inchi_, inchi_key_); + } + IMP_OBJECT_SERIALIZE_DECL(CrossLinkRestraintSet); + + public: + CrossLinkRestraintSet(Model *m, + const std::string &name = "CrossLinkRestraintSet %1%") + : RestraintSet(m, name) {} + CrossLinkRestraintSet() {} + + void set_metadata(std::string filename, double length, double slope) { + filename_ = filename; + length_ = length; + slope_ = slope; + } + + void set_linker_auth_name(std::string name) { auth_name_ = name; } + void set_linker_chemical_name(std::string name) { chemical_name_ = name; } + void set_linker_smiles(std::string name) { smiles_ = name; } + void set_linker_smiles_canonical(std::string name) { + smiles_canonical_ = name; + } + void set_linker_inchi(std::string name) { inchi_ = name; } + void set_linker_inchi_key(std::string name) { inchi_key_ = name; } + + virtual RestraintInfo *get_static_info() const override; + + IMP_OBJECT_METHODS(CrossLinkRestraintSet); +}; + +IMPPMI_END_NAMESPACE + +#endif /* IMPPMI_CROSS_LINK_RESTRAINT_SET_H */ diff --git a/modules/pmi/include/TransformMover.h b/modules/pmi/include/TransformMover.h index 56efb3f0df..1b18edd4e1 100644 --- a/modules/pmi/include/TransformMover.h +++ b/modules/pmi/include/TransformMover.h @@ -2,7 +2,7 @@ * \file IMP/pmi/TransformMover.h * \brief A mover that transforms a rigid body * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -17,6 +17,9 @@ #include #include #include +#include +#include + IMPPMI_BEGIN_NAMESPACE //! Modify the transformation of a rigid body @@ -43,64 +46,72 @@ class IMPPMIEXPORT TransformMover : public IMP::core::MonteCarloMover { unsigned int not_accepted_; unsigned int constr_; -IMP::algebra::Vector3D get_center(){ - Float x=0; - Float y=0; - Float z=0; - unsigned int nelements=0; - for (unsigned int i=0;i void serialize(Archive &ar) { + ar(cereal::base_class(this), + last_transformation_, max_translation_, max_angle_, p1i_, p2i_, + pixyzs_, pirbs_, pis_, t_, c_, rbts_, xyzs_, axis_, tt_, called_, + not_accepted_, constr_); } - - for (unsigned int i=0;i 0, "Max translation must be positive"); diff --git a/modules/pmi/pyext/src/alphabets.py b/modules/pmi/pyext/src/alphabets.py index 3ae753aaf8..072f46dc47 100644 --- a/modules/pmi/pyext/src/alphabets.py +++ b/modules/pmi/pyext/src/alphabets.py @@ -9,11 +9,12 @@ class ResidueAlphabet(object): """Map between FASTA codes and residue types. Typically one would use the `amino_acid`, `rna`, or `dna` objects.""" - def __init__(self, charmm_to_one): + def __init__(self, charmm_to_one, chain_type=IMP.atom.UnknownChainType): self._one_to_charmm = {} for k, v in charmm_to_one.items(): self._one_to_charmm[v] = k self.charmm_to_one = charmm_to_one + self._chain_type = chain_type def get_residue_type_from_one_letter_code(self, code): """Given a one-letter code, return an IMP.atom.ResidueType""" @@ -25,6 +26,10 @@ def get_one_letter_code_from_residue_type(self, rt): # same for amino acids) return self.charmm_to_one.get(rt, 'X') + def get_chain_type(self): + """Get the IMP.atom.ChainType for this alphabet""" + return self._chain_type + """Mapping between FASTA one-letter codes and residue types for amino acids""" amino_acid = ResidueAlphabet( @@ -33,16 +38,16 @@ def get_one_letter_code_from_residue_type(self, rt): 'HIS': 'H', 'ILE': 'I', 'LEU': 'L', 'LYS': 'K', 'MET': 'M', 'PHE': 'F', 'PRO': 'P', 'SER': 'S', 'THR': 'T', 'TRP': 'W', 'TYR': 'Y', 'VAL': 'V', - 'UNK': 'X'}) + 'UNK': 'X'}, IMP.atom.Protein) """Mapping between FASTA one-letter codes and residue types for DNA""" dna = ResidueAlphabet( {'DADE': 'A', 'DURA': 'U', 'DCYT': 'C', 'DGUA': 'G', - 'DTHY': 'T', 'UNK': 'X'}) + 'DTHY': 'T', 'UNK': 'X'}, IMP.atom.DNA) """Mapping between FASTA one-letter codes and residue types for RNA""" rna = ResidueAlphabet( {'ADE': 'A', 'URA': 'U', 'CYT': 'C', 'GUA': 'G', - 'THY': 'T', 'UNK': 'X'}) + 'THY': 'T', 'UNK': 'X'}, IMP.atom.RNA) diff --git a/modules/pmi/pyext/src/io/crosslink.py b/modules/pmi/pyext/src/io/crosslink.py index 8cdd8f6f82..d79fbe4e59 100644 --- a/modules/pmi/pyext/src/io/crosslink.py +++ b/modules/pmi/pyext/src/io/crosslink.py @@ -614,7 +614,7 @@ def get_number_of_xlid(self): return len(self.data_base) def create_set_from_file(self, file_name, converter=None, - FixedFormatParser=None): + FixedFormatParser=None, encoding=None): ''' if FixedFormatParser is not specified, the file is comma-separated-values @@ -622,9 +622,11 @@ def create_set_from_file(self, file_name, converter=None, @param file_name a txt file to be parsed @param converter an instance of CrossLinkDataBaseKeywordsConverter @param FixedFormatParser a parser for a fixed format + @param encoding the encoding of the file, if not the locale + default (usually UTF-8) ''' if not FixedFormatParser: - xl_list = IMP.pmi.tools.get_db_from_csv(file_name) + xl_list = IMP.pmi.tools.get_db_from_csv(file_name, encoding) if converter is not None: self.cldbkc = converter @@ -726,10 +728,15 @@ def create_set_from_file(self, file_name, converter=None, ''' if FixedFormatParser is defined ''' + if sys.version_info[0] == 2: + def open_with_encoding(fname, mode, encoding): + return open(fname, mode) + else: + open_with_encoding = open new_xl_dict = {} nxl = 0 - with open(file_name, "r") as f: + with open_with_encoding(file_name, "r", encoding=encoding) as f: for line in f: xl = FixedFormatParser.get_data(line) if xl: @@ -925,6 +932,7 @@ def filter(self, FilterOperator): self._update() cdb = CrossLinkDataBase(self.cldbkc, new_xl_dict) cdb.dataset = self.dataset + cdb.name = self.name return cdb def filter_score(self, score): diff --git a/modules/pmi/pyext/src/macros.py b/modules/pmi/pyext/src/macros.py index 6ee6671b8b..38578cdd3e 100644 --- a/modules/pmi/pyext/src/macros.py +++ b/modules/pmi/pyext/src/macros.py @@ -179,10 +179,15 @@ def __init__(self, model, root_hier, self.vars = {} # add check hierarchy is multistate - self.output_objects = output_objects + if output_objects == []: + # The "[]" in the default parameters is a global object, so make + # our own copy here + self.output_objects = [] + else: + self.output_objects = output_objects self.rmf_output_objects = rmf_output_objects if (isinstance(root_hier, IMP.atom.Hierarchy) - and root_hier.get_name() == 'System'): + and not root_hier.get_parent()): if self.output_objects is not None: self.output_objects.append( IMP.pmi.io.TotalScoreOutput(self.model)) @@ -575,11 +580,6 @@ def execute_macro(self): output.close_rmf(rmfname) -@IMP.deprecated_object("2.18", "Use ReplicaExchange instead") -class ReplicaExchange0(ReplicaExchange): - pass - - class BuildSystem(object): """A macro to build a IMP::pmi::topology::System based on a TopologyReader object. @@ -610,7 +610,8 @@ class BuildSystem(object): 'RNA': IMP.pmi.alphabets.rna} def __init__(self, model, sequence_connectivity_scale=4.0, - force_create_gmm_files=False, resolutions=[1, 10]): + force_create_gmm_files=False, resolutions=[1, 10], + name='System'): """Constructor @param model An IMP Model @param sequence_connectivity_scale For scaling the connectivity @@ -620,9 +621,10 @@ def __init__(self, model, sequence_connectivity_scale=4.0, files don't exist. If number of Gaussians is zero, won't do anything. @param resolutions The resolutions to build for structured regions + @param name The name of the top-level hierarchy node. """ self.model = model - self.system = IMP.pmi.topology.System(self.model) + self.system = IMP.pmi.topology.System(self.model, name=name) self._readers = [] # the TopologyReaders (one per state) # TempResidues for each domain key=unique name, # value=(atomic_res,non_atomic_res). @@ -785,6 +787,7 @@ def add_state(self, reader, keep_chain_id=False, fasta_name_map=None, self._domain_res.append(these_domain_res) self._domains.append(these_domains) print('BuildSystem.add_state: State', len(self.system.states), 'added') + return state def get_molecules(self): """Return list of all molecules grouped by state. diff --git a/modules/pmi/pyext/src/restraints/crosslinking.py b/modules/pmi/pyext/src/restraints/crosslinking.py index 345c7c389b..2cc4d2919e 100644 --- a/modules/pmi/pyext/src/restraints/crosslinking.py +++ b/modules/pmi/pyext/src/restraints/crosslinking.py @@ -20,23 +20,6 @@ import warnings -class _DataRestraintSet(IMP.RestraintSet): - """Container for restraints shown in the RMF file and in Chimera""" - - def get_static_info(self): - # Add custom metadata to the container, for RMF - ri = IMP.RestraintInfo() - ri.add_string("type", "IMP.pmi.CrossLinkingMassSpectrometryRestraint") - ri.add_float("linker_length", self.length) - ri.add_float("slope", self.slope) - ri.add_filename("filename", self.filename or "") - if self.linker: - ri.add_string("linker_auth_name", self.linker.auth_name) - if self.linker.smiles: - ri.add_string("linker_smiles", self.linker.smiles) - return ri - - class CrossLinkingMassSpectrometryRestraint(IMP.pmi.restraints.RestraintBase): """Setup cross-link distance restraints from mass spectrometry data. The noise in the data and the structural uncertainty of cross-linked @@ -77,7 +60,7 @@ def __init__(self, root_hier, database=None, length=10.0, resolution=None, super(CrossLinkingMassSpectrometryRestraint, self).__init__( model, weight=weight, label=label, - restraint_set_class=_DataRestraintSet) + restraint_set_class=IMP.pmi.CrossLinkRestraintSet) if database is None: raise Exception("You must pass a database") @@ -96,21 +79,23 @@ def __init__(self, root_hier, database=None, length=10.0, resolution=None, self.linker = linker if linker is None: - warnings.warn( - "No linker chemistry specified; this will be guessed from the " - "label (%s). It is recommended to specify a linker as an " + raise ValueError( + "No linker chemistry specified. A linker must be given, as an " "ihm.ChemDescriptor object (see the " - "CrossLinkingMassSpectrometryRestraint documentation)." - % label, IMP.pmi.ParameterWarning) + "CrossLinkingMassSpectrometryRestraint documentation).") self.rs.set_name(self.rs.get_name() + "_Data") self.rspsi = self._create_restraint_set("PriorPsi") self.rssig = self._create_restraint_set("PriorSig") self.rslin = self._create_restraint_set("Linear") # Add custom metadata (will be saved in RMF output) - self.rs.filename = self.database.name - self.rs.length = length - self.rs.slope = slope - self.rs.linker = linker + self.rs.set_metadata(self.database.name, length, slope) + if linker: + self.rs.set_linker_auth_name(linker.auth_name) + for attr in ('chemical_name', 'smiles', 'smiles_canonical', + 'inchi', 'inchi_key'): + val = getattr(linker, attr) + if val: + getattr(self.rs, "set_linker_" + attr)(val) # dummy linear restraint used for Chimera display self.linear = IMP.core.Linear(0, 0.0) @@ -250,6 +235,10 @@ def __init__(self, root_hier, database=None, length=10.0, resolution=None, self.model, length, slope) + dr.set_source_protein1(c1) + dr.set_source_protein2(c2) + dr.set_source_residue1(r1) + dr.set_source_residue2(r2) restraints.append(dr) if self.database.sigma1_key not in xl.keys(): @@ -337,6 +326,9 @@ def __init__(self, root_hier, database=None, length=10.0, resolution=None, self.xl_restraints = restraints lw = IMP.isd.LogWrapper(restraints, 1.0) self.rs.add_restraint(lw) + indb.close() + exdb.close() + midb.close() def __set_dataset(self, ds): self.database.dataset = ds diff --git a/modules/pmi/pyext/src/restraints/em2d.py b/modules/pmi/pyext/src/restraints/em2d.py index fa2b6faeba..f5798dbad9 100644 --- a/modules/pmi/pyext/src/restraints/em2d.py +++ b/modules/pmi/pyext/src/restraints/em2d.py @@ -74,6 +74,8 @@ def __init__(self, hier, images, pixel_size, image_resolution, em2d = IMP.em2d.PCAFitRestraint( particles, images, pixel_size, image_resolution, projection_number, True) + if micrographs_number: + em2d.set_micrographs_number(micrographs_number) self._em2d_restraint = em2d self._num_images = len(images) self.rs.add_restraint(em2d) diff --git a/modules/pmi/pyext/src/restraints/npc.py b/modules/pmi/pyext/src/restraints/npc.py index 22e063b90e..c685baf3d4 100644 --- a/modules/pmi/pyext/src/restraints/npc.py +++ b/modules/pmi/pyext/src/restraints/npc.py @@ -19,6 +19,8 @@ class XYRadialPositionRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's distance from the z axis to within a given range. """ + _include_in_rmf = True + def __init__(self, hier, protein, lower_bound=0.0, upper_bound=0.0, consider_radius=False, sigma=1.0, term='C', label=None, weight=1.0): @@ -56,6 +58,8 @@ def __init__(self, hier, protein, lower_bound=0.0, upper_bound=0.0, class XYRadialPositionLowerRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's distance from the z axis to above a lower bound. """ + _include_in_rmf = True + def __init__(self, hier, protein, lower_bound=0.0, consider_radius=False, sigma=1.0, label=None, weight=1.0): """Constructor @@ -77,6 +81,8 @@ def __init__(self, hier, protein, lower_bound=0.0, class XYRadialPositionUpperRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's distance from the z axis to below an upper bound. """ + _include_in_rmf = True + def __init__(self, hier, protein, upper_bound=0.0, consider_radius=False, sigma=1.0, label=None, weight=1.0): """Constructor @@ -98,6 +104,8 @@ def __init__(self, hier, protein, upper_bound=0.0, class ZAxialPositionRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's z coordinate to within a given range. """ + _include_in_rmf = True + def __init__(self, hier, protein, lower_bound=0.0, upper_bound=0.0, consider_radius=False, sigma=1.0, term='C', label=None, weight=1.0): @@ -135,6 +143,8 @@ def __init__(self, hier, protein, lower_bound=0.0, class ZAxialPositionLowerRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's z coordinate to above a lower bound. """ + _include_in_rmf = True + def __init__(self, hier, protein, lower_bound=0.0, consider_radius=False, sigma=1.0, label=None, weight=1.0): """Constructor @@ -156,6 +166,8 @@ def __init__(self, hier, protein, lower_bound=0.0, class ZAxialPositionUpperRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's z coordinate to below an upper bound. """ + _include_in_rmf = True + def __init__(self, hier, protein, upper_bound=0.0, consider_radius=False, sigma=1.0, label=None, weight=1.0): """Constructor @@ -177,6 +189,8 @@ def __init__(self, hier, protein, upper_bound=0.0, class YAxialPositionRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's y coordinate to within a given range. """ + _include_in_rmf = True + def __init__(self, hier, protein, lower_bound=0.0, upper_bound=0.0, consider_radius=False, sigma=1.0, term='C', label=None, weight=1.0): @@ -214,6 +228,8 @@ def __init__(self, hier, protein, lower_bound=0.0, class YAxialPositionLowerRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's y coordinate to above a lower bound. """ + _include_in_rmf = True + def __init__(self, hier, protein, lower_bound=0.0, consider_radius=False, sigma=1.0, label=None, weight=1.0): """Constructor @@ -235,6 +251,8 @@ def __init__(self, hier, protein, lower_bound=0.0, class YAxialPositionUpperRestraint(IMP.pmi.restraints.RestraintBase): """Restrain a protein's y coordinate to below an upper bound. """ + _include_in_rmf = True + def __init__(self, hier, protein, upper_bound=0.0, consider_radius=False, sigma=1.0, label=None, weight=1.0): """Constructor @@ -256,6 +274,8 @@ def __init__(self, hier, protein, upper_bound=0.0, class MembraneSurfaceLocationRestraint(IMP.pmi.restraints.RestraintBase): """Localize protein on the surface of a half torus in the xy plane. """ + _include_in_rmf = True + def __init__(self, hier, protein, tor_R=540.0, tor_r=127.5, tor_th=45.0, sigma=0.2, resolution=1, label=None, weight=1.0): @@ -290,6 +310,8 @@ class MembraneSurfaceLocationConditionalRestraint( and (197,216,'Nup120'). It returns a minimum penalty score from two potential ALPS motifs. """ + _include_in_rmf = True + def __init__(self, hier, protein1, protein2, tor_R=540.0, tor_r=127.5, tor_th=45.0, sigma=0.2, resolution=1, label=None, weight=1.0): @@ -325,6 +347,8 @@ def __init__(self, hier, protein1, protein2, class MembraneExclusionRestraint(IMP.pmi.restraints.RestraintBase): """Keep protein away from a half torus in the xy plane. """ + _include_in_rmf = True + def __init__(self, hier, protein=None, tor_R=540.0, tor_r=127.5, tor_th=45.0, sigma=0.2, resolution=1, label=None, weight=1.0): diff --git a/modules/pmi/pyext/src/restraints/stereochemistry.py b/modules/pmi/pyext/src/restraints/stereochemistry.py index fbf6cfe3c2..7852cb6982 100644 --- a/modules/pmi/pyext/src/restraints/stereochemistry.py +++ b/modules/pmi/pyext/src/restraints/stereochemistry.py @@ -154,7 +154,8 @@ def __init__(self, included_objects, other_objects=None, resolution=1000, - kappa=1.0): + kappa=1.0, + label=None): """Constructor. @param included_objects Can be one of the following inputs: IMP Hierarchy, PMI System/State/Molecule/TempResidue, @@ -189,7 +190,7 @@ def __init__(self, if hierarchies is None: raise Exception("Must at least pass included objects") mdl = hierarchies[0].get_model() - super(ExcludedVolumeSphere, self).__init__(mdl) + super(ExcludedVolumeSphere, self).__init__(mdl, label=label) included_ps = [h.get_particle() for h in hierarchies] if bipartite: diff --git a/modules/pmi/pyext/src/samplers.py b/modules/pmi/pyext/src/samplers.py index 8f8a3aff86..cfadd1b4b4 100644 --- a/modules/pmi/pyext/src/samplers.py +++ b/modules/pmi/pyext/src/samplers.py @@ -82,80 +82,7 @@ def __init__(self, model, objects=None, temp=1.0, filterbyname=None, self.model = model self.movers_data = {} - # check if using PMI1 or just passed a list of movers - gather_objects = False - try: - objects[0].get_particles_to_sample() - gather_objects = True - except AttributeError: - self.mvs = objects - - if gather_objects: - IMP.handle_use_deprecated( - "Pass Movers to MonteCarlo(), not objects that implement " - "get_particles_to_sample()") - for ob in objects: - pts = ob.get_particles_to_sample() - for k in pts.keys(): - - if "Rigid_Bodies" in k: - mvs = self.get_rigid_body_movers( - pts[k][0], - pts[k][1], - pts[k][2]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs - - if "SR_Bodies" in k: - print(len(pts[k])) - mvs = self.get_super_rigid_body_movers( - pts[k][0], - pts[k][1], - pts[k][2]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs - - if "Floppy_Bodies" in k: - mvs = self.get_floppy_body_movers(pts[k][0], pts[k][1]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs - - if "X_coord" in k: - mvs = self.get_X_movers(pts[k][0], pts[k][1]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs - - if "Nuisances" in k: - if not self.isd_available: - raise ValueError( - "isd module needed to use nuisances") - mvs = self.get_nuisance_movers(pts[k][0], pts[k][1]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs - - if "Weights" in k: - if not self.isd_available: - raise ValueError( - "isd module needed to use weights") - mvs = self.get_weight_movers(pts[k][0], pts[k][1]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs - - if "Surfaces" in k: - mvs = self.get_surface_movers( - pts[k][0], - pts[k][1], - pts[k][2], - pts[k][3]) - for mv in mvs: - mv.set_name(k) - self.mvs += mvs + self.mvs = objects # SerialMover self.smv = IMP.core.SerialMover(self.mvs) diff --git a/modules/pmi/pyext/src/tools.py b/modules/pmi/pyext/src/tools.py index 81cb3aacf3..a71dca2394 100644 --- a/modules/pmi/pyext/src/tools.py +++ b/modules/pmi/pyext/src/tools.py @@ -41,12 +41,13 @@ def _get_system_for_hier(hier): while hier: # See if we labeled the Python object directly with the System if hasattr(hier, '_pmi2_system'): - return hier._pmi2_system() + h = hier._pmi2_system() + if h: + return h # Otherwise (maybe we got a new Python wrapper around the same C++ # object), try all extant systems - for ws in IMP.pmi.topology.System._all_systems: - s = ws() - if s and s.hier == hier: + for s in IMP.pmi.topology.System._all_systems: + if s.hier == hier: return s # Try the next level up in the hierarchy hier = hier.get_parent() @@ -208,70 +209,6 @@ def get_particle(self): return self.surface -@IMP.deprecated_object("2.18", "Create explicit MonteCarlo Movers instead") -class ParticleToSampleList(object): - - def __init__(self, label="None"): - - self.dictionary_particle_type = {} - self.dictionary_particle_transformation = {} - self.dictionary_particle_name = {} - self.label = label - - def add_particle(self, particle, particle_type, particle_transformation, - name): - if particle_type not in ["Rigid_Bodies", "Floppy_Bodies", "Nuisances", - "X_coord", "Weights", "Surfaces"]: - raise TypeError("not the right particle type") - else: - self.dictionary_particle_type[particle] = particle_type - if particle_type == "Rigid_Bodies": - if (isinstance(particle_transformation, tuple) - and len(particle_transformation) == 2 - and all(isinstance(x, float) - for x in particle_transformation)): - self.dictionary_particle_transformation[ - particle] = particle_transformation - self.dictionary_particle_name[particle] = name - else: - raise TypeError( - "ParticleToSampleList: not the right transformation " - "format for Rigid_Bodies, should be a tuple of floats") - elif particle_type == "Surfaces": - if (isinstance(particle_transformation, tuple) - and len(particle_transformation) == 3 - and all(isinstance(x, float) - for x in particle_transformation)): - self.dictionary_particle_transformation[ - particle] = particle_transformation - self.dictionary_particle_name[particle] = name - else: - raise TypeError( - "ParticleToSampleList: not the right transformation " - "format for Surfaces, should be a tuple of floats") - else: - if isinstance(particle_transformation, float): - self.dictionary_particle_transformation[ - particle] = particle_transformation - self.dictionary_particle_name[particle] = name - else: - raise TypeError( - "ParticleToSampleList: not the right transformation " - "format, should be a float") - - def get_particles_to_sample(self): - ps = {} - for particle in self.dictionary_particle_type: - key = self.dictionary_particle_type[particle] + \ - "ParticleToSampleList_" + \ - self.dictionary_particle_name[particle] + "_" + self.label - value = ( - [particle], - self.dictionary_particle_transformation[particle]) - ps[key] = value - return ps - - def get_cross_link_data(directory, filename, dist, omega, sigma, don=None, doff=None, prior=0, type_of_profile="gofr"): @@ -537,10 +474,15 @@ def select_by_tuple_2(hier, tuple_selection, resolution): return s.get_selected_particles() -def get_db_from_csv(csvfilename): +def get_db_from_csv(csvfilename, encoding=None): + if sys.version_info[0] == 2: + def open_with_encoding(fname, encoding): + return open(fname) + else: + open_with_encoding = open import csv outputlist = [] - with open(csvfilename) as fh: + with open_with_encoding(csvfilename, encoding=encoding) as fh: csvr = csv.DictReader(fh) for ls in csvr: outputlist.append(ls) diff --git a/modules/pmi/pyext/src/topology/__init__.py b/modules/pmi/pyext/src/topology/__init__.py index 9f70952601..889555f83c 100644 --- a/modules/pmi/pyext/src/topology/__init__.py +++ b/modules/pmi/pyext/src/topology/__init__.py @@ -133,10 +133,26 @@ def build(self): pass +class _OurWeakRef(object): + """A simple wrapper around weakref.ref which can be pickled. + Note that we throw the reference away at pickle time. It should + be able to be reconstructed from System._all_systems anyway.""" + + def __init__(self, system): + self._ref = weakref.ref(system) + + def __call__(self): + if hasattr(self, '_ref'): + return self._ref() + + def __getstate__(self): + return None + + class System(_SystemBase): """Represent the root node of the global IMP.atom.Hierarchy.""" - _all_systems = set() + _all_systems = weakref.WeakSet() def __init__(self, model=None, name="System"): """Constructor. @@ -150,16 +166,12 @@ def __init__(self, model=None, name="System"): self.states = [] self.built = False - System._all_systems.add(weakref.ref(self)) + System._all_systems.add(self) # the root hierarchy node self.hier = self._create_hierarchy() self.hier.set_name(name) - self.hier._pmi2_system = weakref.ref(self) - - def __del__(self): - System._all_systems = set(x for x in System._all_systems - if x() not in (None, self)) + self.hier._pmi2_system = _OurWeakRef(self) def get_states(self): """Get a list of all State objects in this system""" @@ -418,6 +430,7 @@ def __init__(self, state, name, sequence, chain_id, copy_num, # store the sequence self.chain = IMP.atom.Chain.setup_particle(self.hier, chain_id) self.chain.set_sequence(self.sequence) + self.chain.set_chain_type(alphabet.get_chain_type()) # create TempResidues from the sequence (if passed) self.residues = [] for ns, s in enumerate(sequence): diff --git a/modules/pmi/pyext/swig.i-in b/modules/pmi/pyext/swig.i-in index 8f3678c558..3d0cbd35b4 100644 --- a/modules/pmi/pyext/swig.i-in +++ b/modules/pmi/pyext/swig.i-in @@ -1,8 +1,9 @@ IMP_SWIG_OBJECT(IMP::pmi, CompositeRestraint, CompositeRestraints); +IMP_SWIG_OBJECT_SERIALIZE(IMP::pmi, CrossLinkRestraintSet, CrossLinkRestraintSets); IMP_SWIG_DECORATOR(IMP::pmi, Uncertainty, Uncertainties); IMP_SWIG_DECORATOR(IMP::pmi, Resolution, Resolutions); IMP_SWIG_DECORATOR(IMP::pmi, Symmetric, Symmetrics); -IMP_SWIG_OBJECT(IMP::pmi, TransformMover, TransformMovers); +IMP_SWIG_OBJECT_SERIALIZE(IMP::pmi, TransformMover, TransformMovers); IMP_SWIG_OBJECT(IMP::pmi, MembraneRestraint, MembraneRestraints); %pythoncode %{ @@ -24,6 +25,7 @@ class MissingFileWarning(UserWarning): %include "IMP/pmi/MembraneRestraint.h" %include "IMP/pmi/CompositeRestraint.h" +%include "IMP/pmi/CrossLinkRestraintSet.h" %include "IMP/pmi/Uncertainty.h" %include "IMP/pmi/Resolution.h" %include "IMP/pmi/Symmetric.h" diff --git a/modules/pmi/src/CrossLinkRestraintSet.cpp b/modules/pmi/src/CrossLinkRestraintSet.cpp new file mode 100644 index 0000000000..f5f05d8712 --- /dev/null +++ b/modules/pmi/src/CrossLinkRestraintSet.cpp @@ -0,0 +1,42 @@ +/** + * \file IMP/pmi/CrossLinkRestraintSet.cpp + * \brief A RestraintSet subclass to track cross-link metadata. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#include + +IMPPMI_BEGIN_NAMESPACE + +RestraintInfo *CrossLinkRestraintSet::get_static_info() const { + IMP_NEW(RestraintInfo, ri, ()); + ri->add_string("type", "IMP.pmi.CrossLinkingMassSpectrometryRestraint"); + ri->add_float("linker length", length_); + ri->add_float("slope", slope_); + ri->add_filename("filename", filename_); + if (!auth_name_.empty()) { + ri->add_string("linker author name", auth_name_); + if (!chemical_name_.empty()) { + ri->add_string("linker chemical name", chemical_name_); + } + if (!smiles_.empty()) { + ri->add_string("linker smiles", smiles_); + } + if (!smiles_canonical_.empty()) { + ri->add_string("linker smiles canonical", smiles_canonical_); + } + if (!inchi_.empty()) { + ri->add_string("linker inchi", inchi_); + } + if (!inchi_key_.empty()) { + ri->add_string("linker inchi key", inchi_key_); + } + } + return ri.release(); +} + +IMP_OBJECT_SERIALIZE_IMPL(IMP::pmi::CrossLinkRestraintSet); + +IMPPMI_END_NAMESPACE diff --git a/modules/pmi/src/TransformMover.cpp b/modules/pmi/src/TransformMover.cpp index 1d9e25232e..414b378102 100644 --- a/modules/pmi/src/TransformMover.cpp +++ b/modules/pmi/src/TransformMover.cpp @@ -129,4 +129,6 @@ ModelObjectsTemp TransformMover::do_get_inputs() const { return ret; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::pmi::TransformMover); + IMPPMI_END_NAMESPACE diff --git a/modules/pmi/test/expensive_test_new_cross_link_ms_restraint.py b/modules/pmi/test/expensive_test_new_cross_link_ms_restraint.py index c03ea6ead7..ae016c4f26 100644 --- a/modules/pmi/test/expensive_test_new_cross_link_ms_restraint.py +++ b/modules/pmi/test/expensive_test_new_cross_link_ms_restraint.py @@ -21,6 +21,19 @@ rem = None +def _parse_restraint_info(info): + """Convert RestraintInfo object to Python dict""" + d = {} + if info is None: + return d + info.set_was_used(True) + for typ in ('int', 'float', 'string', 'filename', 'floats', 'filenames'): + for i in range(getattr(info, 'get_number_of_' + typ)()): + key = getattr(info, 'get_%s_key' % typ)(i) + value = getattr(info, 'get_%s_value' % typ)(i) + d[key] = value + return d + def sphere_cap(r1, r2, d): sc = 0.0 if d <= max(r1, r2) - min(r1, r2): @@ -99,7 +112,7 @@ def setup_crosslinks_complex(self, root_hier, mode=None): length=21.0, slope=0.0, resolution=1.0, - label="XL") + label="XL", linker=ihm.cross_linkers.dss) xl.add_to_model() psi=xl.psi_dictionary["PSI"][0] psi.set_scale(0.05) @@ -228,6 +241,36 @@ def test_restraint_probability_complex(self): 'included.None.xl.db', 'missing.None.xl.db']: os.unlink(output) + def test_restraint_set_static_info(self): + """Test that RestraintSet static info is populated""" + m = IMP.Model() + rbeads, dof = self.init_representation_beads_pmi2(m) + xlbeads, cldb = self.setup_crosslinks_beads( + root_hier=rbeads, mode="single_category") + info = _parse_restraint_info(xlbeads.rs.get_static_info()) + self.assertAlmostEqual(info['linker length'], 21.0, delta=1e-5) + self.assertAlmostEqual(info['slope'], 0.01, delta=1e-5) + self.assertEqual(info['type'], + 'IMP.pmi.CrossLinkingMassSpectrometryRestraint') + self.assertEqual(info['linker author name'], 'DSS') + self.assertEqual( + sorted(info.keys()), + ['filename', 'linker author name', 'linker chemical name', + 'linker inchi', 'linker inchi key', 'linker length', + 'linker smiles', 'slope', 'type']) + + def test_restraint_source_info(self): + """Test that restraint source info is populated""" + m = IMP.Model() + rbeads, dof = self.init_representation_beads_pmi2(m) + xlbeads, cldb = self.setup_crosslinks_beads( + root_hier=rbeads, mode="single_category") + r = xlbeads.xl_list[3]["Restraint"] + self.assertEqual(r.get_source_protein1(), "ProtA") + self.assertEqual(r.get_source_protein2(), "ProtB") + self.assertEqual(r.get_source_residue1(), 11) + self.assertEqual(r.get_source_residue2(), 1) + def test_restraint_probability_beads(self): """Test restraint works for all-bead systems""" m = IMP.Model() diff --git a/modules/pmi/test/expensive_test_replica_exchange.py b/modules/pmi/test/expensive_test_replica_exchange.py index 8cb1a31618..959608cd1b 100644 --- a/modules/pmi/test/expensive_test_replica_exchange.py +++ b/modules/pmi/test/expensive_test_replica_exchange.py @@ -180,24 +180,22 @@ def test_macro_rmf_stat(self): tuple_selection2=(2,2,"A"), distancemin=10, distancemax=10) dr.add_to_model() - # Test old ReplicaExchange0 class - with IMP.allow_deprecated(): - rex = IMP.pmi.macros.ReplicaExchange0( - m, root_hier=hier, monte_carlo_sample_objects=dof.get_movers(), - output_objects=None, rmf_output_objects=[dr], - monte_carlo_temperature=1.0, - replica_exchange_minimum_temperature=1.0, - replica_exchange_maximum_temperature=2.5, - number_of_best_scoring_models=10, monte_carlo_steps=10, - number_of_frames=100, write_initial_rmf=True, - initial_rmf_name_suffix="initial", - stat_file_name_suffix="stat", best_pdb_name_suffix="model", - do_clean_first=True, do_create_directories=True, - global_output_directory="./test_replica_exchange_macro_output", - rmf_dir="rmfs/", best_pdb_dir="pdbs/", - replica_stat_file_suffix="stat_replica", - em_object_for_rmf=None, replica_exchange_object=None, - score_moved=True) + rex = IMP.pmi.macros.ReplicaExchange( + m, root_hier=hier, monte_carlo_sample_objects=dof.get_movers(), + output_objects=None, rmf_output_objects=[dr], + monte_carlo_temperature=1.0, + replica_exchange_minimum_temperature=1.0, + replica_exchange_maximum_temperature=2.5, + number_of_best_scoring_models=10, monte_carlo_steps=10, + number_of_frames=100, write_initial_rmf=True, + initial_rmf_name_suffix="initial", + stat_file_name_suffix="stat", best_pdb_name_suffix="model", + do_clean_first=True, do_create_directories=True, + global_output_directory="./test_replica_exchange_macro_output", + rmf_dir="rmfs/", best_pdb_dir="pdbs/", + replica_stat_file_suffix="stat_replica", + em_object_for_rmf=None, replica_exchange_object=None, + score_moved=True) # check whether the directory is existing, in case remove it try: diff --git a/modules/pmi/test/input/xl_dataset_test_utf16.dat b/modules/pmi/test/input/xl_dataset_test_utf16.dat new file mode 100644 index 0000000000..fc4ad93256 Binary files /dev/null and b/modules/pmi/test/input/xl_dataset_test_utf16.dat differ diff --git a/modules/pmi/test/medium_test_topology.py b/modules/pmi/test/medium_test_topology.py index d4cfe02a1d..3dcee71bac 100644 --- a/modules/pmi/test/medium_test_topology.py +++ b/modules/pmi/test/medium_test_topology.py @@ -11,6 +11,7 @@ import IMP.pmi.dof import IMP.pmi.macros import os +import shutil def get_atomic_residue_list(residues): @@ -698,6 +699,8 @@ def test_molecule_build(self): chain=m1.chain self.assertEqual(chain.get_sequence(),seqs["Protein_1"]) self.assertEqual(chain.get_id(),"A") + self.assertEqual(chain.get_chain_type(), IMP.atom.Protein) + self.assertEqual(chain.get_chain_type(), IMP.atom.LPolypeptide) #test PMIMoleculeHierarchy mol=m1.hier @@ -1081,6 +1084,7 @@ def test_write_multistate(self): self.assertEqual(len(hs),1) states = IMP.atom.get_by_type(hs[0],IMP.atom.STATE_TYPE) self.assertEqual(len(states),2) + shutil.rmtree('multistate_test') def test_pmi_molecule_hierarchy(self): model=IMP.Model() diff --git a/modules/pmi/test/standards_exceptions b/modules/pmi/test/standards_exceptions index 1d3fa89304..aad6c0db41 100644 --- a/modules/pmi/test/standards_exceptions +++ b/modules/pmi/test/standards_exceptions @@ -1,4 +1,4 @@ value_object_exceptions=[] function_name_exceptions=[] show_exceptions=[] -spelling_exceptions=[] +spelling_exceptions=['inchi', 'metadata'] diff --git a/modules/pmi/test/test_alphabets.py b/modules/pmi/test/test_alphabets.py index b4aa52efcf..f102082261 100644 --- a/modules/pmi/test/test_alphabets.py +++ b/modules/pmi/test/test_alphabets.py @@ -9,6 +9,7 @@ class Tests(IMP.test.TestCase): def test_amino_acid(self): """Test amino_acid alphabet""" alpha = IMP.pmi.alphabets.amino_acid + self.assertEqual(alpha.get_chain_type(), IMP.atom.Protein) for code, restyp in [ ('A', IMP.atom.ALA), ('R', IMP.atom.ARG), ('N', IMP.atom.ASN), ('D', IMP.atom.ASP), ('C', IMP.atom.CYS), ('E', IMP.atom.GLU), @@ -28,6 +29,7 @@ def test_amino_acid(self): def test_dna(self): """Test DNA alphabet""" alpha = IMP.pmi.alphabets.dna + self.assertEqual(alpha.get_chain_type(), IMP.atom.DNA) for code, restyp in [ ('A', IMP.atom.DADE), ('U', IMP.atom.DURA), ('C', IMP.atom.DCYT), ('G', IMP.atom.DGUA), ('T', IMP.atom.DTHY), ('X', IMP.atom.UNK)]: @@ -37,6 +39,7 @@ def test_dna(self): def test_rna(self): """Test RNA alphabet""" alpha = IMP.pmi.alphabets.rna + self.assertEqual(alpha.get_chain_type(), IMP.atom.RNA) for code, restyp in [ ('A', IMP.atom.ADE), ('U', IMP.atom.URA), ('C', IMP.atom.CYT), ('G', IMP.atom.GUA), ('T', IMP.atom.THY), ('X', IMP.atom.UNK)]: diff --git a/modules/pmi/test/test_ambiguous.py b/modules/pmi/test/test_ambiguous.py index d117b6343e..04441d69b8 100644 --- a/modules/pmi/test/test_ambiguous.py +++ b/modules/pmi/test/test_ambiguous.py @@ -6,6 +6,8 @@ import IMP.pmi.topology import IMP.pmi.restraints.crosslinking import IMP.pmi.output +import ihm.cross_linkers + class Tests(IMP.test.TestCase): def test_ambiguous(self): @@ -49,7 +51,8 @@ def test_ambiguous(self): xl = \ IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint( root_hier=hier, database=cldb, - length=21.0, slope=0.0, resolution=1.0) + length=21.0, slope=0.0, resolution=1.0, + linker=ihm.cross_linkers.dss) xl.sigma_dictionary['1.0'][0].set_scale(5.0) xl.psi_dictionary['0.05'][0].set_scale(0.1) diff --git a/modules/pmi/test/test_cross_link_restraint_set.py b/modules/pmi/test/test_cross_link_restraint_set.py new file mode 100644 index 0000000000..d82ca5340c --- /dev/null +++ b/modules/pmi/test/test_cross_link_restraint_set.py @@ -0,0 +1,102 @@ +import IMP.test +import IMP.pmi +import pickle + + +def _parse_restraint_info(info): + """Convert RestraintInfo object to Python dict""" + d = {} + if info is None: + return d + info.set_was_used(True) + for typ in ('int', 'float', 'string', 'filename', 'floats', 'filenames', + 'particle_indexes'): + for i in range(getattr(info, 'get_number_of_' + typ)()): + key = getattr(info, 'get_%s_key' % typ)(i) + value = getattr(info, 'get_%s_value' % typ)(i) + d[key] = value + return d + + +class Tests(IMP.test.TestCase): + def test_metadata_no_linker(self): + """Test metadata without linker info""" + m = IMP.Model() + r = IMP.pmi.CrossLinkRestraintSet(m, "foo") + r.set_metadata('test_fn', 25.0, 0.1) + info = _parse_restraint_info(r.get_static_info()) + self.assertEqual(len(info.keys()), 4) + self.assertAlmostEqual(info['linker length'], 25.0, delta=1e-3) + self.assertAlmostEqual(info['slope'], 0.1, delta=1e-3) + self.assertEqual(info['filename'], 'test_fn') + self.assertEqual( + info['type'], 'IMP.pmi.CrossLinkingMassSpectrometryRestraint') + + def test_metadata_linker_smiles(self): + """Test metadata with linker containing just SMILES info""" + m = IMP.Model() + r = IMP.pmi.CrossLinkRestraintSet(m, "foo") + r.set_metadata('test_fn', 25.0, 0.1) + r.set_linker_auth_name('DSS') + r.set_linker_smiles('CC') + info = _parse_restraint_info(r.get_static_info()) + self.assertEqual( + sorted(info.keys()), + ['filename', 'linker author name', 'linker length', + 'linker smiles', 'slope', 'type']) + self.assertEqual(info['linker author name'], 'DSS') + self.assertEqual(info['linker smiles'], 'CC') + + def test_metadata_linker_full(self): + """Test metadata with linker containing full info""" + m = IMP.Model() + r = IMP.pmi.CrossLinkRestraintSet(m, "foo") + r.set_metadata('test_fn', 25.0, 0.1) + r.set_linker_auth_name('DSS') + r.set_linker_chemical_name('chem') + r.set_linker_smiles('CC') + r.set_linker_smiles_canonical('CC2') + r.set_linker_inchi('testinchi') + r.set_linker_inchi_key('testinchikey') + info = _parse_restraint_info(r.get_static_info()) + self.assertEqual( + sorted(info.keys()), + ['filename', 'linker author name', 'linker chemical name', + 'linker inchi', 'linker inchi key', 'linker length', + 'linker smiles', 'linker smiles canonical', 'slope', 'type']) + self.assertEqual(info['linker author name'], 'DSS') + self.assertEqual(info['linker chemical name'], 'chem') + self.assertEqual(info['linker smiles'], 'CC') + self.assertEqual(info['linker smiles canonical'], 'CC2') + self.assertEqual(info['linker inchi'], 'testinchi') + self.assertEqual(info['linker inchi key'], 'testinchikey') + + def test_pickle(self): + """Test (un-)pickle of CrossLinkRestraintSet""" + m = IMP.Model() + r = IMP.pmi.CrossLinkRestraintSet(m, "foo") + r.set_metadata('test_fn', 25.0, 0.1) + dump = pickle.dumps(r) + newrsr = pickle.loads(dump) + self.assertEqual(newrsr.get_name(), "foo") + info = _parse_restraint_info(newrsr.get_static_info()) + self.assertAlmostEqual(info['linker length'], 25.0, delta=1e-3) + self.assertEqual(info['filename'], 'test_fn') + + def test_pickle_polymorphic(self): + """Test (un-)pickle of CrossLinkRestraintSet via polymorphic pointer""" + m = IMP.Model() + r = IMP.pmi.CrossLinkRestraintSet(m, "foo") + r.set_metadata('test_fn', 25.0, 0.1) + sf = IMP.core.RestraintsScoringFunction([r]) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newrsr, = newsf.restraints + self.assertEqual(newrsr.get_name(), "foo") + info = _parse_restraint_info(newrsr.get_static_info()) + self.assertAlmostEqual(info['linker length'], 25.0, delta=1e-3) + self.assertEqual(info['filename'], 'test_fn') + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/pmi/test/test_io_crosslink.py b/modules/pmi/test/test_io_crosslink.py index a8a66c63cc..8d0ac9264d 100644 --- a/modules/pmi/test/test_io_crosslink.py +++ b/modules/pmi/test/test_io_crosslink.py @@ -6,6 +6,7 @@ import IMP.atom import IMP.container import os +import sys import IMP.pmi.io.crosslink @@ -90,7 +91,7 @@ def test_setup_cldbkc(self): self.assertEqual(c,expected_converter) self.assertEqual(bc,expected_backward_converter) - def setup_cldb(self,input_data_set): + def setup_cldb(self, input_data_set, encoding=None): cldbkc=IMP.pmi.io.crosslink.CrossLinkDataBaseKeywordsConverter() cldbkc.set_protein1_key("prot1") cldbkc.set_protein2_key("prot2") @@ -99,9 +100,15 @@ def setup_cldb(self,input_data_set): cldbkc.set_unique_id_key("id") cldbkc.set_id_score_key("score") cldb=IMP.pmi.io.crosslink.CrossLinkDataBase(cldbkc) - cldb.create_set_from_file(self.get_input_file_name(input_data_set)) + cldb.create_set_from_file(self.get_input_file_name(input_data_set), + encoding=encoding) return cldb + @IMP.test.skipIf(sys.version_info[0] == 2, "Only works with Python 3") + def test_encoding(self): + """Test create_set_from_file with non-standard encoding""" + cldb = self.setup_cldb("xl_dataset_test_utf16.dat", encoding='utf-16') + def test_setup_cldb(self): cldb=self.setup_cldb("xl_dataset_test.dat") diff --git a/modules/pmi/test/test_mmcif.py b/modules/pmi/test/test_mmcif.py index 2358eff319..294ae06ae9 100644 --- a/modules/pmi/test/test_mmcif.py +++ b/modules/pmi/test/test_mmcif.py @@ -1140,10 +1140,11 @@ class DummyPostProcess(object): _ihm_ensemble_info.ensemble_precision_value _ihm_ensemble_info.ensemble_file_id _ihm_ensemble_info.details +_ihm_ensemble_info.model_group_superimposed_flag _ihm_ensemble_info.sub_sample_flag _ihm_ensemble_info.sub_sampling_type -1 'Ensemble 1 in state State_0' 99 1 . dRMSD 5 1 0.100 . . NO . -2 'Ensemble 2 in state State_0' 99 2 . dRMSD 5 1 0.100 42 . NO . +1 'Ensemble 1 in state State_0' 99 1 . dRMSD 5 1 0.100 . . . NO . +2 'Ensemble 2 in state State_0' 99 2 . dRMSD 5 1 0.100 42 . . NO . # """) diff --git a/modules/pmi/test/test_multistate.py b/modules/pmi/test/test_multistate.py index ac964ab6f5..1a4a7505f9 100644 --- a/modules/pmi/test/test_multistate.py +++ b/modules/pmi/test/test_multistate.py @@ -9,6 +9,8 @@ import IMP.pmi.restraints.crosslinking import IMP.pmi.samplers import IMP.pmi.output +import ihm.cross_linkers + class Tests(IMP.test.TestCase): def test_multistate(self): @@ -83,7 +85,7 @@ def test_multistate(self): xl = IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint( root_hier=hier, database=cldb, length=length, slope=slope, - resolution=1.0) + resolution=1.0, linker=ihm.cross_linkers.dss) psi = xl.psi_dictionary['PSI'][0] psi.set_scale(psiv) diff --git a/modules/pmi/test/test_pickle.py b/modules/pmi/test/test_pickle.py new file mode 100644 index 0000000000..3f953dfd7b --- /dev/null +++ b/modules/pmi/test/test_pickle.py @@ -0,0 +1,91 @@ +import IMP.test +import IMP.pmi.dof +import IMP.pmi.io.crosslink +import IMP.pmi.topology +import IMP.pmi.macros +import IMP.pmi.restraints.stereochemistry +import IMP.pmi.restraints.crosslinking +import ihm.cross_linkers +import pickle +import shutil +import os + +def make_system(): + m = IMP.Model() + s = IMP.pmi.topology.System(m) + st1 = s.create_state() + mol = st1.create_molecule("Rpb1", "MVGQQMVGQQMVGQQMVGQQ") + mol.add_representation(resolutions=[1]) + root_hier = s.build() + + dof = IMP.pmi.dof.DegreesOfFreedom(mol) + dof.create_flexible_beads(mol, max_trans=3.0, resolution=1) + + mols = IMP.pmi.tools.get_molecules(root_hier) + for mol in mols: + molname = mol.get_name() + cr = IMP.pmi.restraints.stereochemistry.ConnectivityRestraint( + mol, scale=2.0, label=molname) + cr.add_to_model() + + ev = IMP.pmi.restraints.stereochemistry.ExcludedVolumeSphere( + included_objects=root_hier, resolution=1) + ev.add_to_model() + + xldbkwc = IMP.pmi.io.crosslink.CrossLinkDataBaseKeywordsConverter() + xldbkwc.set_protein1_key("prot1") + xldbkwc.set_protein2_key("prot2") + xldbkwc.set_residue1_key("res1") + xldbkwc.set_residue2_key("res2") + + xl2db = IMP.pmi.io.crosslink.CrossLinkDataBase(xldbkwc) + with open('test_pickle.csv', 'w') as fh: + fh.write("prot1,res1,prot2,res2\nRpb1,1,Rpb1,18\n") + xl2db.create_set_from_file('test_pickle.csv') + os.unlink('test_pickle.csv') + + xl2 = IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint( + root_hier=root_hier, database=xl2db, length=21.0, slope=0.01, + resolution=1.0, label="Chen", weight=1., linker=ihm.cross_linkers.dss) + xl2.add_to_model() + + mc1 = IMP.pmi.macros.ReplicaExchange( + m, root_hier=root_hier, monte_carlo_sample_objects=dof.get_movers(), + monte_carlo_temperature=1.0, simulated_annealing=True, + simulated_annealing_minimum_temperature=1.0, + simulated_annealing_maximum_temperature=2.5, + simulated_annealing_minimum_temperature_nframes=200, + simulated_annealing_maximum_temperature_nframes=20, + replica_exchange_minimum_temperature=1.0, + replica_exchange_maximum_temperature=2.5, + number_of_best_scoring_models=10, monte_carlo_steps=5, + number_of_frames=5, global_output_directory="test_pickle_output") + return mc1 + + +class Tests(IMP.test.TestCase): + def test_pickle(self): + """Test that pickled ReplicaExchange objects work""" + mc1 = make_system() + dump = pickle.dumps((mc1.model, mc1)) + + # Run the original ReplicaExchange and get the final score + IMP.random_number_generator.seed(99) + mc1.execute_macro() + rs = IMP.pmi.tools.get_restraint_set(mc1.model) + original_score = rs.evaluate(False) + del mc1, rs + + # With the same random seed, we should get the exact same trajectory + # with the pickled object + newm, newmc1 = pickle.loads(dump) + IMP.random_number_generator.seed(99) + newmc1.execute_macro() + rs = IMP.pmi.tools.get_restraint_set(newmc1.model) + new_score = rs.evaluate(False) + self.assertAlmostEqual(original_score, new_score, delta=1e-4) + shutil.rmtree('test_pickle_output') + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/pmi/test/test_plane_dihedral.py b/modules/pmi/test/test_plane_dihedral.py index 8d27b5ab7a..cac4e17d85 100644 --- a/modules/pmi/test/test_plane_dihedral.py +++ b/modules/pmi/test/test_plane_dihedral.py @@ -51,7 +51,8 @@ def test_optimization(self): rb2.set_coordinates_are_optimized(True) for i in range(10): - target_angle = random.uniform(-math.pi, math.pi) + # Avoid issues comparing target to actual dihedral near +/- pi + target_angle = random.uniform(-math.pi + 0.02, math.pi - 0.02) r = IMP.pmi.restraints.stereochemistry.PlaneDihedralRestraint( [ps1, ps2], angle=target_angle * 180 / math.pi, k=1.) sf = IMP.core.RestraintsScoringFunction(r.rs) diff --git a/modules/pmi/test/test_tools.py b/modules/pmi/test/test_tools.py index ba54257b14..05998c17b5 100644 --- a/modules/pmi/test/test_tools.py +++ b/modules/pmi/test/test_tools.py @@ -52,33 +52,6 @@ def __init__(self, numproc, rank): class Tests(IMP.test.TestCase): - def test_particle_to_sample_list(self): - """Test ParticleToSampleList""" - with IMP.allow_deprecated(): - p = IMP.pmi.tools.ParticleToSampleList() - self.assertEqual(p.label, 'None') - self.assertRaises(TypeError, p.add_particle, 'P0', 'bad_type', 1, 'foo') - - p.add_particle('RB1', 'Rigid_Bodies', (1., 2.), 'myRB1') - # Test bad rigid body transformation - self.assertRaises(TypeError, p.add_particle, - 'RB1', 'Rigid_Bodies', [1., 2.], 'myRB1') - - p.add_particle('S1', 'Surfaces', (1., 2., 3.), 'myS1') - self.assertRaises(TypeError, p.add_particle, - 'S1', 'Surfaces', [1., 2.], 'myS1') - - p.add_particle('F1', 'Floppy_Bodies', 1., 'myF1') - self.assertRaises(TypeError, p.add_particle, - 'F1', 'Floppy_Bodies', 'badtransform', 'myF1') - - self.assertEqual(p.get_particles_to_sample(), - {'SurfacesParticleToSampleList_myS1_None': - (['S1'], (1.0, 2.0, 3.0)), - 'Rigid_BodiesParticleToSampleList_myRB1_None': - (['RB1'], (1.0, 2.0)), - 'Floppy_BodiesParticleToSampleList_myF1_None': (['F1'], 1.0)}) - def test_shuffle(self): """Test moving rbs, fbs""" mdl = IMP.Model() diff --git a/modules/pmi/test/test_topology_input.py b/modules/pmi/test/test_topology_input.py index c620e5f678..c7058059b8 100644 --- a/modules/pmi/test/test_topology_input.py +++ b/modules/pmi/test/test_topology_input.py @@ -130,11 +130,26 @@ def test_custom_chain_ids(self): fasta_dir=input_dir, gmm_dir=input_dir) bs = IMP.pmi.macros.BuildSystem(mdl) - bs.add_state(t, chain_ids='0123456789') + state = bs.add_state(t, chain_ids='0123456789') + self.assertEqual(state.short_name, "State_0") root_hier, dof = bs.execute_macro() chains = IMP.atom.get_by_type(root_hier, IMP.atom.CHAIN_TYPE) self.assertEqual([IMP.atom.Chain(c).get_id() for c in chains], ['0']) + def test_custom_system_name(self): + """Check that custom System name can be given to BuildSystem""" + mdl = IMP.Model() + tfile = self.get_input_file_name('topology_simple.txt') + input_dir = os.path.dirname(tfile) + t = IMP.pmi.topology.TopologyReader(tfile, + pdb_dir=input_dir, + fasta_dir=input_dir, + gmm_dir=input_dir) + bs = IMP.pmi.macros.BuildSystem(mdl, name="custom system") + state = bs.add_state(t) + root_hier, dof = bs.execute_macro() + self.assertEqual(root_hier.get_name(), "custom system") + def test_keep_chain_id(self): """Check that keep_chain_id works""" mdl = IMP.Model() diff --git a/modules/pmi/test/test_transform_mover.py b/modules/pmi/test/test_transform_mover.py index 4f9abc5dd3..03625359b0 100644 --- a/modules/pmi/test/test_transform_mover.py +++ b/modules/pmi/test/test_transform_mover.py @@ -12,6 +12,8 @@ import IMP.rmf import RMF import shutil +import os +import pickle # initialize Replica Exchange class try: @@ -69,7 +71,7 @@ def test_xyz_particles(self): IMP.rmf.save_frame(rh) del rh - #os.unlink("test_transform_mover_xyz.rmf3") + os.unlink("test_transform_mover_xyz.rmf3") def test_rigid_body_particles(self): @@ -121,7 +123,7 @@ def test_rigid_body_particles(self): mc.optimize(1) IMP.rmf.save_frame(rh) del rh - #os.unlink("test_transform_mover_rigid_body.rmf3") + os.unlink("test_transform_mover_rigid_body.rmf3") def test_xyz_particles_rotamer(self): @@ -179,6 +181,7 @@ def test_xyz_particles_rotamer(self): IMP.rmf.save_frame(rh) del rh + os.unlink("test_transform_mover_xyz_rotamer.rmf3") def test_pmi_representation_sampling_macro1_helix(self): @@ -239,7 +242,53 @@ def test_pmi_representation_sampling_macro1_helix(self): replica_stat_file_suffix="stat_replica", replica_exchange_object=rem) mc2.execute_macro() - #shutil.rmtree("test_transform_mover_output_2") + shutil.rmtree("test_transform_mover_output_2") + + def make_system(sel): + m = IMP.Model() + ps = [] + hs = [] + for i in range(10): + p = IMP.Particle(m) + h = IMP.atom.Hierarchy.setup_particle(p) + d = IMP.core.XYZR.setup_particle(p) + IMP.atom.Mass.setup_particle(p, 1.0) + d.set_coordinates(IMP.algebra.get_random_vector_in( + IMP.algebra.Sphere3D((0, 0, 0), 10))) + d.set_radius(1) + ps.append(p) + hs.append(h) + return m, ps, hs + + def test_pickle(self): + """Test (un-)pickle of TransformMover""" + m, ps, hs = self.make_system() + mvr = IMP.pmi.TransformMover(m, 1, 0.5) + mvr.set_maximum_translation(4.0) + mvr.set_name("foo") + for p in ps: + mvr.add_xyz_particle(IMP.core.XYZ(p)) + dump = pickle.dumps(mvr) + + newmvr = pickle.loads(dump) + self.assertEqual(newmvr.get_name(), "foo") + self.assertAlmostEqual(newmvr.get_maximum_translation(), + 4.0, delta=0.1) + + def test_pickle_polymorphic(self): + """Test (un-)pickle of TransformMover via polymorphic pointer""" + m, ps, hs = self.make_system() + mvr = IMP.pmi.TransformMover(m, 1, 0.5) + mvr.set_maximum_translation(4.0) + mvr.set_name("foo") + for p in ps: + mvr.add_xyz_particle(IMP.core.XYZ(p)) + sm = IMP.core.SerialMover([mvr]) + dump = pickle.dumps(sm) + + newsm = pickle.loads(dump) + newmvr, = newsm.get_movers() + self.assertEqual(newmvr.get_name(), "foo") if __name__ == '__main__': diff --git a/modules/pmi/tools/setup_ci.sh b/modules/pmi/tools/setup_ci.sh index 22bf86f27f..1064a675da 100755 --- a/modules/pmi/tools/setup_ci.sh +++ b/modules/pmi/tools/setup_ci.sh @@ -10,7 +10,7 @@ fi python_version=$1 conda config --remove channels defaults # get conda-forge, not main, packages -conda create --yes -q -n python${python_version} -c salilab -c conda-forge python=${python_version} pip scipy matplotlib imp-nightly gxx_linux-64 eigen swig cmake +conda create --yes -q -n python${python_version} -c salilab -c conda-forge python=${python_version} pip scipy matplotlib imp-nightly gxx_linux-64 eigen cereal swig cmake eval "$(conda shell.bash hook)" conda activate python${python_version} diff --git a/modules/pmi1 b/modules/pmi1 index 5c15359111..21b2230d1f 160000 --- a/modules/pmi1 +++ b/modules/pmi1 @@ -1 +1 @@ -Subproject commit 5c1535911129c49bf932a86f25184a96f36c49e0 +Subproject commit 21b2230d1f5633788d14c7ef0d3686d66c6bd87b diff --git a/modules/rmf/dependency/RMF/.github/workflows/build.yml b/modules/rmf/dependency/RMF/.github/workflows/build.yml index 09ff68d17b..ccb6790975 100644 --- a/modules/rmf/dependency/RMF/.github/workflows/build.yml +++ b/modules/rmf/dependency/RMF/.github/workflows/build.yml @@ -65,7 +65,6 @@ jobs: ../tools/coverage/setup.py PYTHONPATH=`pwd`/coverage cmake .. -DCMAKE_BUILD_TYPE="${{ matrix.build }}" -DCMAKE_CXX_FLAGS="${{ matrix.flags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.flags }}" -DCMAKE_MODULE_LINKER_FLAGS="${{ matrix.flags }}" -DCMAKE_SHARED_LINKER_FLAGS="${{ matrix.flags }}" make -j 2 - export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so ctest -j 2 --output-on-failure -L ${{ matrix.tests }} - name: Combine coverage run: | diff --git a/modules/rmf/dependency/RMF/CMakeLists.txt b/modules/rmf/dependency/RMF/CMakeLists.txt index 734992b33d..503ca657f9 100644 --- a/modules/rmf/dependency/RMF/CMakeLists.txt +++ b/modules/rmf/dependency/RMF/CMakeLists.txt @@ -119,6 +119,11 @@ else() link_directories(${Log4CXX_LIBRARY_DIR}) endif() +if(${PYTHON_NUMPY_FOUND}) + set(RMF_HAS_NUMPY "1" CACHE BOOL "Whether to include numpy support" FORCE) +else() + set(RMF_HAS_NUMPY "0" CACHE BOOL "Whether to include numpy support" FORCE) +endif() include(GNUInstallDirs) @@ -134,7 +139,8 @@ set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) # Version information set (RMF_VERSION_MAJOR 1) -set (RMF_VERSION_MINOR 4) +set (RMF_VERSION_MINOR 5) +set (RMF_VERSION_MICRO 1) set(RMF_SOVERSION "${RMF_VERSION_MAJOR}.${RMF_VERSION_MINOR}" CACHE INTERNAL "" FORCE) set(RMF_HAS_DEBUG_VECTOR 0 CACHE BOOL "Whether to use a bounds checked vector") diff --git a/modules/rmf/dependency/RMF/ChangeLog.md b/modules/rmf/dependency/RMF/ChangeLog.md index 5112e7eeba..217ffa8498 100644 --- a/modules/rmf/dependency/RMF/ChangeLog.md +++ b/modules/rmf/dependency/RMF/ChangeLog.md @@ -1,6 +1,29 @@ Change Log {#changelog} ========== +# 1.5.1 - 2023-06-08 # {#changelog_1_5_1} +- Any String or Strings attributes containing fileystem paths are now + rewritten when the RMF static frame is cloned (e.g. during `rmf_slice` + or `rmf_cat`) so that they are relative to the new file, not the old one. + This relies on the convention that path attributes have names ending in + "filename" or "filenames". +- Bugfix: particles without Cartesian coordinates are now handled correctly + by the `get_all_global_coordinates()` Python function. +- Bugfix: relative paths should now be set correctly when the path to the + RMF file itself contains one or more '..' components. + +# 1.5.0 - 2023-03-22 # {#changelog_1_5_0} +- Windows builds now require MS Visual Studio 2015 or later (for full C++11 + support). The following macros for pre-C++11 environments are no longer + needed and are deprecated: `RMF_NOEXCEPT`, `RMF_CANEXCEPT`. +- All RMF binaries now report the full version (including micro version) + when the --version flag is used (e.g. "1.4.1", not "1.4"). +- If built with NumPy, some Python-specific functions are now provided to + allow direct access to RMF data via NumPy arrays. +- File handles can now be explicitly closed (via a `close` method). Most IO + operations on a closed handle will now raise an error. In Python file handles + now support the context manager protocol so can be used in 'with' blocks. + # 1.4.1 - 2022-11-21 # {#changelog_1_4_1} - Build fixes to work with SWIG 4.1. - Various internal build scripts now use 'python3' rather than diff --git a/modules/rmf/dependency/RMF/README.md b/modules/rmf/dependency/RMF/README.md index 61ab395a1e..b2ecd3c0c2 100644 --- a/modules/rmf/dependency/RMF/README.md +++ b/modules/rmf/dependency/RMF/README.md @@ -14,7 +14,7 @@ and score data. The main documentation is found on the [web site](http://integrativemodeling.org/rmf/nightly/doc/). -Copyright 2007-2022 IMP Inventors. +Copyright 2007-2023 IMP Inventors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/modules/rmf/dependency/RMF/benchmark/benchmark_rmf.cpp b/modules/rmf/dependency/RMF/benchmark/benchmark_rmf.cpp index 709acc51b6..4dd8f90981 100644 --- a/modules/rmf/dependency/RMF/benchmark/benchmark_rmf.cpp +++ b/modules/rmf/dependency/RMF/benchmark/benchmark_rmf.cpp @@ -7,9 +7,9 @@ #include #include -#include #include #include +#include #include #include @@ -45,6 +45,21 @@ std::string show_size(unsigned int sz) { return oss.str(); } +class Timer { + std::chrono::steady_clock::time_point start_time_; +public: + Timer() { + start_time_ = std::chrono::steady_clock::now(); + } + + double elapsed() const { + auto end_time = std::chrono::steady_clock::now(); + auto time_span = std::chrono::duration_cast< + std::chrono::duration >(end_time - start_time_); + return time_span.count(); + } +}; + void benchmark_size(std::string path, std::string type) { unsigned int size = 0; if (boost::filesystem::is_directory(path)) { @@ -181,11 +196,11 @@ double load(RMF::FileConstHandle file, const RMF::NodeIDs& nodes) { std::pair benchmark_create(RMF::FileHandle file, std::string type) { RMF::NodeIDs atoms; - boost::timer timer; + Timer timer; boost::tuple cur = create(file, atoms); std::cout << type << ", create, " << timer.elapsed() << ", " << cur.get<0>() << std::endl; - boost::timer frame_timer; + Timer frame_timer; boost::tuple frames = create_frames(file, atoms); std::cout << type << ", create frame, " << frame_timer.elapsed() / 20.0 << ", " << frames.get<0>() << std::endl; @@ -194,7 +209,7 @@ std::pair benchmark_create(RMF::FileHandle file, void benchmark_traverse(RMF::FileConstHandle file, std::string type) { file.set_current_frame(RMF::FrameID(0)); - boost::timer timer; + Timer timer; double count = 0; double t; while (timer.elapsed() < 1) { @@ -211,17 +226,18 @@ void benchmark_load(RMF::FileConstHandle file, std::string type) { for(RMF::NodeID n : file.get_node_ids()) { if (ipcf.get_is(file.get_node(n))) nodes.push_back(n); } - boost::timer timer; + Timer timer; double dist = load(file, nodes); std::cout << type << ", load, " << timer.elapsed() / 20.0 << ", " << dist << std::endl; } RMF::FileConstHandle benchmark_open(std::string path, std::string type) { - boost::timer timer; + Timer timer; RMF::FileConstHandle ret; double count = 0; while (timer.elapsed() < 1) { + ret.close(); ret = RMF::open_rmf_file_read_only(path); ++count; } @@ -268,6 +284,21 @@ int main(int, char**) { } benchmark_size(name, "rmfz"); } +#if RMF_HAS_DEPRECATED_BACKENDS + { + const std::string name = name_base + ".rmf-hdf5"; + { + RMF::FileHandle fh = RMF::create_rmf_file(name); + benchmark_create(fh, "hdf5"); + } + { + RMF::FileConstHandle fh = benchmark_open(name, "hdf5"); + benchmark_traverse(fh, "hdf5"); + benchmark_load(fh, "hdf5"); + } + benchmark_size(name, "hdf5"); + } +#endif { RMF::BufferHandle buffer; { @@ -275,7 +306,7 @@ int main(int, char**) { benchmark_create(fh, "buffer"); } { - boost::timer timer; + Timer timer; RMF::FileConstHandle fh = RMF::open_rmf_buffer_read_only(buffer); std::cout << "buffer" << ", open, " << timer.elapsed() << ", 0" << std::endl; diff --git a/modules/rmf/dependency/RMF/bin/common.h b/modules/rmf/dependency/RMF/bin/common.h index e8037dcd1f..c630ac5330 100644 --- a/modules/rmf/dependency/RMF/bin/common.h +++ b/modules/rmf/dependency/RMF/bin/common.h @@ -44,7 +44,7 @@ void print_help_and_exit(char* argv[]) { void print_version_and_exit() { std::cout << "RMF version " << RMF_VERSION_MAJOR << "." << RMF_VERSION_MINOR - << std::endl; + << "." << RMF_VERSION_MICRO << std::endl; exit(0); } diff --git a/modules/rmf/dependency/RMF/bin/rmf3_dump.cpp b/modules/rmf/dependency/RMF/bin/rmf3_dump.cpp index 06f6e84925..d620169764 100644 --- a/modules/rmf/dependency/RMF/bin/rmf3_dump.cpp +++ b/modules/rmf/dependency/RMF/bin/rmf3_dump.cpp @@ -2,7 +2,7 @@ * Copyright 2007-2022 IMP Inventors. All rights reserved. */ -#include +#include #include #include #include @@ -38,7 +38,7 @@ int main(int argc, char** argv) { if (variables_map.count("verbose")) { internal_avro::EncoderPtr encoder = internal_avro::jsonEncoder(schema); - boost::shared_ptr os = + std::shared_ptr os = internal_avro::ostreamOutputStream(std::cout); encoder->init(*os); internal_avro::encode(*encoder, frame); diff --git a/modules/rmf/dependency/RMF/config.h.in b/modules/rmf/dependency/RMF/config.h.in index 69e3e0805e..6ce2e0a114 100644 --- a/modules/rmf/dependency/RMF/config.h.in +++ b/modules/rmf/dependency/RMF/config.h.in @@ -33,8 +33,10 @@ // Version number #define RMF_VERSION_MAJOR @RMF_VERSION_MAJOR@ #define RMF_VERSION_MINOR @RMF_VERSION_MINOR@ +#define RMF_VERSION_MICRO @RMF_VERSION_MICRO@ #define RMF_HAS_LOG4CXX @RMF_HAS_LOG4CXX@ +#define RMF_HAS_NUMPY @RMF_HAS_NUMPY@ #define RMF_HAS_DEPRECATED_BACKENDS @RMF_DEPRECATED_BACKENDS@ diff --git a/modules/rmf/dependency/RMF/doc/DecoratorsAndAttributes.md b/modules/rmf/dependency/RMF/doc/DecoratorsAndAttributes.md index 0106f11955..e7475ab863 100644 --- a/modules/rmf/dependency/RMF/doc/DecoratorsAndAttributes.md +++ b/modules/rmf/dependency/RMF/doc/DecoratorsAndAttributes.md @@ -21,6 +21,14 @@ All have the precondition that the appropriate value exists. For `set` - `set_static_foo`: set a value that is stored once for the whole file - `set_foo`: if there is no static value, set it, otherwise, if the passed value differs from the static value, set it as a frame value. +# Path attributes # {#pathattr} + +String attributes can be used either to store arbitrary text, or paths to files. +Paths are stored internally as relative paths, relative to the directory +containing the RMF file. (This ensures that if the entire directory structure +containing the RMF file is archived, the paths are still correct.) +However, the `set_*` methods will accept both absolute and relative paths, +and the `get_*` methods will always return absolute paths. # Physics # {#physics} diff --git a/modules/rmf/dependency/RMF/doc/FileFormat.md b/modules/rmf/dependency/RMF/doc/FileFormat.md index c1983f959b..6014df9668 100644 --- a/modules/rmf/dependency/RMF/doc/FileFormat.md +++ b/modules/rmf/dependency/RMF/doc/FileFormat.md @@ -105,11 +105,20 @@ The data types that can currently be stored in an RMF file are | Name | Description | C++ type | Python type | |--------:|--------------|:--------:|:-----------:| | RMF::Float | a floating point value | `float` | `float` | -| RMF::String | a utf8 string | `std::string` | `string` | +| RMF::String | a utf8 string | `std::string` | `str` | | RMF::Int | an 64 bit integer | `int` | `int`| | RMF::Vector3 | three Float values | RMF::Vector3 | RMF.Vector3 | | RMF::Vector4 | four Float values | RMF::Vector4 | RMF.Vector4 | +RMF::String can be used either to store arbitrary text, or paths to files. +Paths are stored as relative paths, relative to the directory containing +the RMF file. This ensures that if the entire directory structure containing +the RMF file is archived, the paths are still correct. The convention is that +string attributes containing paths are named ending in "filename" or +"filenames". Special handling is done on such attributes (e.g. if an RMF +is moved to a different directory with `rmf_slice` or `rmf_cat`, the relative +paths of the static frame are updated accordingly). + In addition, an arbitrary length list of any of the above can be stored. The type for that is the type for the single data with an \c s on the end, eg \c Floats for a list of \c Float values. These are passed as \c std::vector like lists in \c C++ and \c lists in \c Python. diff --git a/modules/rmf/dependency/RMF/doc/Main.md b/modules/rmf/dependency/RMF/doc/Main.md index 7de426e7c0..cdb4b4156a 100644 --- a/modules/rmf/dependency/RMF/doc/Main.md +++ b/modules/rmf/dependency/RMF/doc/Main.md @@ -19,7 +19,7 @@ See Also see the [rmf examples](https://github.com/salilab/rmf_examples) repository for examples of interesting or problematic RMF files. -Copyright 2007-2022 IMP Inventors. +Copyright 2007-2023 IMP Inventors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/modules/rmf/dependency/RMF/include/RMF/BufferConstHandle.h b/modules/rmf/dependency/RMF/include/RMF/BufferConstHandle.h index 4aa71609a9..e6804fec6c 100644 --- a/modules/rmf/dependency/RMF/include/RMF/BufferConstHandle.h +++ b/modules/rmf/dependency/RMF/include/RMF/BufferConstHandle.h @@ -12,8 +12,7 @@ #include "RMF/config.h" #include "infrastructure_macros.h" #include "exceptions.h" -#include -#include +#include #include #include @@ -29,7 +28,7 @@ namespace RMF { */ class BufferConstHandle { protected: - boost::shared_ptr > data_; + std::shared_ptr > data_; int compare(BufferConstHandle o) const { if (&*data_ < &*o.data_) return -1; @@ -42,13 +41,13 @@ class BufferConstHandle { public: #ifndef SWIG explicit BufferConstHandle(std::string r) - : data_(boost::make_shared >(r.begin(), r.end())) {} + : data_(std::make_shared >(r.begin(), r.end())) {} #endif explicit BufferConstHandle(const std::vector &r) - : data_(boost::make_shared >(r.begin(), r.end())) {} + : data_(std::make_shared >(r.begin(), r.end())) {} explicit BufferConstHandle(const std::vector &r) - : data_(boost::make_shared >(r.begin(), r.end())) {} - explicit BufferConstHandle(boost::shared_ptr > r) + : data_(std::make_shared >(r.begin(), r.end())) {} + explicit BufferConstHandle(std::shared_ptr > r) : data_(r) {} const std::vector &get_buffer() const { return *data_; } #ifndef SWIG @@ -65,7 +64,7 @@ class BufferConstHandle { return std::make_pair(reinterpret_cast(&(*data_)[0]), data_->size()); } - boost::shared_ptr > get() const { return data_; } + std::shared_ptr > get() const { return data_; } #endif }; diff --git a/modules/rmf/dependency/RMF/include/RMF/Decorator.h b/modules/rmf/dependency/RMF/include/RMF/Decorator.h index 7fa6c984e7..49d6251847 100644 --- a/modules/rmf/dependency/RMF/include/RMF/Decorator.h +++ b/modules/rmf/dependency/RMF/include/RMF/Decorator.h @@ -15,7 +15,7 @@ #include "internal/SharedData.h" #include "NodeConstHandle.h" #include "NodeHandle.h" -#include +#include RMF_ENABLE_WARNINGS namespace RMF { @@ -29,7 +29,7 @@ namespace RMF { class Decorator { private: NodeID id_; - boost::shared_ptr data_; + std::shared_ptr data_; protected: Decorator(NodeConstHandle handle) diff --git a/modules/rmf/dependency/RMF/include/RMF/FileConstHandle.h b/modules/rmf/dependency/RMF/include/RMF/FileConstHandle.h index 518fea48bb..063f89efb5 100644 --- a/modules/rmf/dependency/RMF/include/RMF/FileConstHandle.h +++ b/modules/rmf/dependency/RMF/include/RMF/FileConstHandle.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -99,7 +99,7 @@ class RMFEXPORT FileConstHandle { } protected: - boost::shared_ptr shared_; + std::shared_ptr shared_; public: RMF_COMPARISONS(FileConstHandle); @@ -108,17 +108,43 @@ class RMFEXPORT FileConstHandle { //! Empty root handle, no open file. FileConstHandle() {} #if !defined(RMF_DOXYGEN) && !defined(SWIG) - FileConstHandle(boost::shared_ptr shared); + FileConstHandle(std::shared_ptr shared); #endif //! Return the root of the hierarchy NodeConstHandle get_root_node() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); return NodeConstHandle(NodeID(0), shared_); } - std::string get_name() const { return shared_->get_file_name(); } + //! Return True iff the file is closed + bool get_is_closed() const { + return !shared_; + } + + //! Explicitly close the file handle. + /** Normally, an RMF file is automatically closed when this handle object + goes out of scope. If closed with this method, any further operations + on this handle will raise an error. + Trying to close a file that is already closed will do nothing. */ + void close() { + if (!get_is_closed()) { + shared_.reset(); + } + } + + std::string get_name() const { + if (shared_) { + return shared_->get_file_name(); + } else { + return "(closed RMF file handle)"; + } + } - std::string get_path() const { return shared_->get_file_path(); } + std::string get_path() const { + RMF_USAGE_CHECK(!get_is_closed(), "File is closed, no path."); + return shared_->get_file_path(); + } /** \name Methods for manipulating keys When using C++ it is most convenient to specify types @@ -193,22 +219,31 @@ class RMFEXPORT FileConstHandle { point. @{ */ - FrameID get_current_frame() const { return shared_->get_loaded_frame(); } + FrameID get_current_frame() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); + return shared_->get_loaded_frame(); + } + FrameType get_type(FrameID fr) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); return shared_->get_frame_data(fr).type; } std::string get_name(FrameID fr) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); return shared_->get_frame_data(fr).name; } FrameIDs get_children(FrameID id) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); const internal::FrameData& fd = shared_->get_frame_data(id); return FrameIDs(fd.children.begin(), fd.children.end()); } FrameIDs get_parents(FrameID id) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); const internal::FrameData& fd = shared_->get_frame_data(id); return FrameIDs(fd.parents.begin(), fd.parents.end()); } void set_current_frame(FrameID frame) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); RMF_USAGE_CHECK(frame != FrameID(), "Invalid frame passed."); RMF_USAGE_CHECK(frame != ALL_FRAMES, "Use set_static_value() and get_static_value() to " @@ -222,6 +257,7 @@ class RMFEXPORT FileConstHandle { /** Return the number of frames in the file. */ unsigned int get_number_of_frames() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); try { return shared_->get_number_of_frames(); } @@ -231,6 +267,7 @@ class RMFEXPORT FileConstHandle { /** Return the number of nodes in the file. */ unsigned int get_number_of_nodes() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); try { return shared_->get_number_of_nodes(); } @@ -239,7 +276,10 @@ class RMFEXPORT FileConstHandle { /** Return a string identifying the file type. */ - std::string get_file_type() const { return shared_->get_file_type(); } + std::string get_file_type() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); + return shared_->get_file_type(); + } /** Get all the frames that are roots (aren't subframes). */ FrameIDs get_root_frames() const; diff --git a/modules/rmf/dependency/RMF/include/RMF/FileHandle.h b/modules/rmf/dependency/RMF/include/RMF/FileHandle.h index d77abb8ee9..9fe4b5ac9f 100644 --- a/modules/rmf/dependency/RMF/include/RMF/FileHandle.h +++ b/modules/rmf/dependency/RMF/include/RMF/FileHandle.h @@ -9,8 +9,7 @@ #ifndef RMF_FILE_HANDLE_H #define RMF_FILE_HANDLE_H -#include -#include +#include #include #include @@ -54,17 +53,20 @@ class BufferHandle; */ class RMFEXPORT FileHandle : public FileConstHandle { friend class NodeHandle; - friend class boost::shared_ptr; + friend class std::shared_ptr; public: //! Empty file handle, no open file. FileHandle() {} #if !defined(RMF_DOXYGEN) && !defined(SWIG) - FileHandle(boost::shared_ptr shared_); + FileHandle(std::shared_ptr shared_); #endif //! Return the root of the hierarchy stored in the file. - NodeHandle get_root_node() const { return NodeHandle(NodeID(0), shared_); } + NodeHandle get_root_node() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); + return NodeHandle(NodeID(0), shared_); + } //! Add a frame and make it the current frame. FrameID add_frame(std::string name, FrameType t = FRAME) const; diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstAttributes.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstAttributes.h index fbfdcf9b25..e9a788ce33 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstAttributes.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstAttributes.h @@ -29,7 +29,7 @@ template class ConstAttributes : public Base { #ifndef SWIG protected: - ConstAttributes(boost::shared_ptr h) : Base(h) {} + ConstAttributes(std::shared_ptr h) : Base(h) {} ConstAttributes() {} #else private: diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstDataSetD.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstDataSetD.h index 9f718b0dbb..b1e43d9bd7 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstDataSetD.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstDataSetD.h @@ -18,8 +18,7 @@ #include "DataSetCreationPropertiesD.h" #include "infrastructure_macros.h" #include -#include -#include +#include RMF_ENABLE_WARNINGS @@ -50,7 +49,7 @@ class ConstDataSetD : public ConstDataSetAttributes { DataSetIndexD size_; }; - boost::shared_ptr data_; + std::shared_ptr data_; int compare(const ConstDataSetD& o) const { // not great, but... if (data_ && !o.data_) @@ -85,7 +84,7 @@ class ConstDataSetD : public ConstDataSetAttributes { typedef DataSetCreationPropertiesD CreationProperties; typedef DataSetAccessPropertiesD AccessProperties; - ConstDataSetD(boost::shared_ptr parent, std::string name, + ConstDataSetD(std::shared_ptr parent, std::string name, CreationProperties props) : data_(new Data()) { // std::cout << "Creating data set " << name << std::endl; @@ -97,7 +96,7 @@ class ConstDataSetD : public ConstDataSetAttributes { std::fill(maxs, maxs + D, H5S_UNLIMITED); RMF_HDF5_HANDLE(ds, H5Screate_simple(D, dims, maxs), &H5Sclose); // std::cout << "creating..." << name << std::endl; - P::open(boost::make_shared( + P::open(std::make_shared( H5Dcreate2(parent->get_hid(), name.c_str(), TypeTraits::get_hdf5_disk_type(), ds, H5P_DEFAULT, props.get_handle(), H5P_DEFAULT), @@ -105,13 +104,13 @@ class ConstDataSetD : public ConstDataSetAttributes { initialize(); // std::cout << "done..." << std::endl; } - ConstDataSetD(boost::shared_ptr parent, std::string name, + ConstDataSetD(std::shared_ptr parent, std::string name, AccessProperties props) : data_(new Data()) { RMF_USAGE_CHECK( H5Lexists(parent->get_hid(), name.c_str(), H5P_DEFAULT), RMF::internal::get_error_message("Data set ", name, " does not exist")); - P::open(boost::make_shared( + P::open(std::make_shared( H5Dopen2(parent->get_hid(), name.c_str(), props.get_handle()), &H5Dclose, name)); // RMF_HDF5_HANDLE(s, H5Dget_space(h_->get_hid()), H5Sclose); @@ -160,7 +159,7 @@ class ConstDataSetD : public ConstDataSetAttributes { RMF_USAGE_CHECK( H5Lexists(file, name.c_str(), H5P_DEFAULT), RMF::internal::get_error_message("Data set ", name, " does not exist")); - P::open(boost::make_shared( + P::open(std::make_shared( H5Dopen2(file, name.c_str(), H5P_DEFAULT), &H5Dclose, name)); // RMF_HDF5_HANDLE(s, H5Dget_space(h_->get_hid()), H5Sclose); RMF_HDF5_HANDLE(sel, H5Dget_space(Object::get_handle()), &H5Sclose); diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstFile.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstFile.h index efc3f6b2c7..3f3e9e91ab 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstFile.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstFile.h @@ -27,7 +27,7 @@ namespace HDF5 { class RMFEXPORT ConstFile : public ConstGroup { public: #if !defined(RMF_DOXYGEN) && !defined(SWIG) - ConstFile(boost::shared_ptr h); + ConstFile(std::shared_ptr h); #endif ConstFile(File f); ConstFile() {} diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstGroup.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstGroup.h index 4b3afa0c2d..f80cf42d19 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstGroup.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/ConstGroup.h @@ -38,7 +38,7 @@ RMF_ENABLE_WARNINGS namespace RMF { } #ifndef SWIG protected: - ConstGroup(boost::shared_ptr h); + ConstGroup(std::shared_ptr h); #endif public: ConstGroup() {}; diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetAccessPropertiesD.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetAccessPropertiesD.h index c2c0a508c6..9bd3633ab5 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetAccessPropertiesD.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetAccessPropertiesD.h @@ -11,7 +11,7 @@ #include "RMF/config.h" #include "DataSetIndexD.h" -#include +#include RMF_ENABLE_WARNINGS namespace RMF { namespace HDF5 { @@ -19,7 +19,7 @@ RMF_ENABLE_WARNINGS namespace RMF { /** A class to manage properties controlling access to HDF5 data sets.*/ template class DataSetAccessPropertiesD { - boost::shared_ptr h_; + std::shared_ptr h_; protected: DataSetAccessPropertiesD(hid_t type) diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetD.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetD.h index 6315a2a0c5..24bc7c04db 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetD.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/DataSetD.h @@ -38,10 +38,10 @@ class DataSetD : public MutableAttributes > { typedef DataSetCreationPropertiesD CreationProperties; typedef DataSetAccessPropertiesD AccessProperties; - DataSetD(boost::shared_ptr parent, std::string name, + DataSetD(std::shared_ptr parent, std::string name, CreationProperties props) : P(parent, name, props) {} - DataSetD(boost::shared_ptr parent, std::string name, + DataSetD(std::shared_ptr parent, std::string name, AccessProperties props) : P(parent, name, props) {} diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/File.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/File.h index edf081f49b..92fc44f62f 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/File.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/File.h @@ -55,7 +55,7 @@ RMF_ENABLE_WARNINGS namespace RMF { class RMFEXPORT File : public Group { public: #if !defined(RMF_DOXYGEN) && !defined(SWIG) - File(boost::shared_ptr h); + File(std::shared_ptr h); // silliness to make RMF easier to implement bool get_is_writable() const { unsigned int intent; diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/Group.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/Group.h index 6583a936ab..5394d395b4 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/Group.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/Group.h @@ -38,7 +38,7 @@ class RMFEXPORT Group : public MutableAttributes { } #ifndef SWIG protected: - Group(boost::shared_ptr h); + Group(std::shared_ptr h); #endif public: Group() {} diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/Object.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/Object.h index 05316bfaa4..1f8676afb4 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/Object.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/Object.h @@ -14,7 +14,7 @@ #include "handle.h" #include "infrastructure_macros.h" #include -#include +#include RMF_ENABLE_WARNINGS @@ -28,14 +28,14 @@ class File; the HDF5 manual} for more information. */ class RMFEXPORT Object { - boost::shared_ptr h_; + std::shared_ptr h_; #ifndef SWIG protected: - Object(boost::shared_ptr h); + Object(std::shared_ptr h); // silliness friend class Group; - boost::shared_ptr get_shared_handle() const { return h_; } - void open(boost::shared_ptr h) { h_ = h; } + std::shared_ptr get_shared_handle() const { return h_; } + void open(std::shared_ptr h) { h_ = h; } Object() {} #else private: diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/handle.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/handle.h index 6b99342e0a..9a7b5d28cb 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/handle.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/handle.h @@ -70,7 +70,13 @@ class RMFEXPORT Handle : public boost::noncopyable { } h_ = -1; } - ~Handle() RMF_CANEXCEPT { +// Older clang does not like exception specification in combination +// with std::shared_ptr +#if defined(__clang__) && __clang_major__ <= 7 + ~Handle() { +#else + ~Handle() noexcept(false) { +#endif if (h_ != -1) { RMF_HDF5_CALL(f_(h_)); } diff --git a/modules/rmf/dependency/RMF/include/RMF/HDF5/infrastructure_macros.h b/modules/rmf/dependency/RMF/include/RMF/HDF5/infrastructure_macros.h index f05ec25dee..f25740af1f 100644 --- a/modules/rmf/dependency/RMF/include/RMF/HDF5/infrastructure_macros.h +++ b/modules/rmf/dependency/RMF/include/RMF/HDF5/infrastructure_macros.h @@ -33,8 +33,8 @@ using RMF::operator<<; /** Create new HDF5 SharedData.handle.*/ #define RMF_HDF5_NEW_HANDLE(name, cmd, cleanup) \ - boost::shared_ptr name = \ - boost::make_shared(cmd, cleanup, #cmd) + std::shared_ptr name = \ + std::make_shared(cmd, cleanup, #cmd) #define RMF_HDF5_HANDLE(name, cmd, cleanup) \ RMF::HDF5::Handle name(cmd, cleanup, #cmd) diff --git a/modules/rmf/dependency/RMF/include/RMF/NodeConstHandle.h b/modules/rmf/dependency/RMF/include/RMF/NodeConstHandle.h index 860963c1a9..584910a059 100644 --- a/modules/rmf/dependency/RMF/include/RMF/NodeConstHandle.h +++ b/modules/rmf/dependency/RMF/include/RMF/NodeConstHandle.h @@ -1,6 +1,6 @@ /** * \file RMF/NodeConstHandle.h - * \brief Declaration of NodeConstHandlke. + * \brief Declaration of NodeConstHandle. * * Copyright 2007-2022 IMP Inventors. All rights reserved. * @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -110,7 +110,7 @@ class RMFEXPORT NodeConstHandle protected: NodeID node_; - boost::shared_ptr shared_; + std::shared_ptr shared_; // for error messages std::string get_file_name() const; // for error messages @@ -118,12 +118,12 @@ class RMFEXPORT NodeConstHandle #if !defined(SWIG) && !defined(RMF_DOXYGEN) public: - NodeConstHandle(NodeID node, boost::shared_ptr shared); + NodeConstHandle(NodeID node, std::shared_ptr shared); #endif public: #if !defined(RMF_DOXYGEN) && !defined(SWIG) - boost::shared_ptr get_shared_data() const { + std::shared_ptr get_shared_data() const { return shared_; } #endif @@ -175,7 +175,7 @@ class RMFEXPORT NodeConstHandle the passed type and returns a \c void* pointer in the namespace where the type is declared (so it is found via Koenig lookup). Support has already been - added for boost::shared_ptr. + added for std::shared_ptr. Either the association must not have been set before or overwrite must be true. If overwrite is true, diff --git a/modules/rmf/dependency/RMF/include/RMF/NodeHandle.h b/modules/rmf/dependency/RMF/include/RMF/NodeHandle.h index 36e27ca90d..3a842d6bc7 100644 --- a/modules/rmf/dependency/RMF/include/RMF/NodeHandle.h +++ b/modules/rmf/dependency/RMF/include/RMF/NodeHandle.h @@ -9,7 +9,7 @@ #ifndef RMF_NODE_HANDLE_H #define RMF_NODE_HANDLE_H -#include +#include #include #include @@ -71,7 +71,7 @@ class RMFEXPORT NodeHandle : public NodeConstHandle { } #if !defined(SWIG) && !defined(RMF_DOXYGEN) public: - NodeHandle(NodeID node, boost::shared_ptr shared); + NodeHandle(NodeID node, std::shared_ptr shared); #endif public: diff --git a/modules/rmf/dependency/RMF/include/RMF/TraverseHelper.h b/modules/rmf/dependency/RMF/include/RMF/TraverseHelper.h index afd32e9515..6474dba764 100644 --- a/modules/rmf/dependency/RMF/include/RMF/TraverseHelper.h +++ b/modules/rmf/dependency/RMF/include/RMF/TraverseHelper.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include RMF_ENABLE_WARNINGS @@ -38,7 +38,7 @@ typedef std::vector TraverseHelpers; */ class RMFEXPORT TraverseHelper : public NodeConstHandle { struct Index : public RMF_LARGE_UNORDERED_MAP {}; - boost::shared_ptr active_; + std::shared_ptr active_; struct Data { decorator::ChainFactory chain_factory_; decorator::ResidueFactory residue_factory_; @@ -60,7 +60,7 @@ class RMFEXPORT TraverseHelper : public NodeConstHandle { Data(NodeConstHandle root, std::string molecule_name, double resolution, int state_filter); }; - boost::shared_ptr data_; + std::shared_ptr data_; void visit_impl(NodeConstHandle n); diff --git a/modules/rmf/dependency/RMF/include/RMF/Vector.h b/modules/rmf/dependency/RMF/include/RMF/Vector.h index 0d6108ceec..73b0846ec6 100644 --- a/modules/rmf/dependency/RMF/include/RMF/Vector.h +++ b/modules/rmf/dependency/RMF/include/RMF/Vector.h @@ -14,9 +14,8 @@ #include "exceptions.h" #include #include -#include -#include -#include +#include +#include #include #include @@ -27,29 +26,27 @@ namespace RMF { #ifndef SWIG /** \brief Represent a point in some dimension. - [boost::array](http://www.boost.org/doc/libs/1_55_0/doc/html/array.html) - provides `operator[]()` and `begin()`/`end()` in C++. + std::array provides `operator[]()` and `begin()`/`end()` in C++. */ template class Vector - : public boost::array + : public std::array { - typedef boost::array P; + typedef std::array P; // work around swig template struct Convert {}; template - struct Convert > >::type> { - static void convert(const R& r, boost::array& d) { d = r; } + struct Convert >::value>::type> { + static void convert(const R& r, std::array& d) { d = r; } }; template - struct Convert< - R, typename boost::enable_if > > >::type> { - static void convert(const R& r, boost::array& d) { + struct Convert >::value>::type> { + static void convert(const R& r, std::array& d) { std::copy(boost::begin(r), boost::end(r), d.begin()); } }; diff --git a/modules/rmf/dependency/RMF/include/RMF/compiler_macros.h b/modules/rmf/dependency/RMF/include/RMF/compiler_macros.h index ecbcd589be..5231c981c8 100644 --- a/modules/rmf/dependency/RMF/include/RMF/compiler_macros.h +++ b/modules/rmf/dependency/RMF/include/RMF/compiler_macros.h @@ -27,26 +27,13 @@ // Deprecated; just use 'final' keyword instead #define RMF_FINAL final -#if defined(__GNUC__) && __cplusplus >= 201103L -#define RMF_HAS_NOEXCEPT 1 -#elif defined(__clang__) && defined(__has_feature) -#define RMF_HAS_NOEXCEPT __has_feature(cxx_noexcept) -#else -#define RMF_HAS_NOEXCEPT 0 -#endif - -#if RMF_HAS_NOEXCEPT +// Deprecated; just use 'noexcept' keyword instead #define RMF_NOEXCEPT noexcept #define RMF_CANEXCEPT noexcept(false) + #define RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(Name) \ Name(const Name &) = default; \ Name &operator=(const Name &) = default -#else -// probably should be finer here -#define RMF_NOEXCEPT throw() -#define RMF_CANEXCEPT -#define RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(Name) -#endif #if defined(__clang__) || defined(__GNUC__) #define RMF_PRAGMA(x) _Pragma(RMF_STRINGIFY(x)) diff --git a/modules/rmf/dependency/RMF/include/RMF/decorator/bond.h b/modules/rmf/dependency/RMF/include/RMF/decorator/bond.h index ab93d6cb5a..d8b0c19112 100644 --- a/modules/rmf/dependency/RMF/include/RMF/decorator/bond.h +++ b/modules/rmf/dependency/RMF/include/RMF/decorator/bond.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/include/RMF/decorator/reference.h b/modules/rmf/dependency/RMF/include/RMF/decorator/reference.h index 21e6c0889a..c1d1bacf49 100644 --- a/modules/rmf/dependency/RMF/include/RMF/decorator/reference.h +++ b/modules/rmf/dependency/RMF/include/RMF/decorator/reference.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/include/RMF/decorator/representation.h b/modules/rmf/dependency/RMF/include/RMF/decorator/representation.h index 303c9e3b5e..fbd4d081bd 100644 --- a/modules/rmf/dependency/RMF/include/RMF/decorator/representation.h +++ b/modules/rmf/dependency/RMF/include/RMF/decorator/representation.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/include/RMF/exceptions.h b/modules/rmf/dependency/RMF/include/RMF/exceptions.h index 85b3c989eb..088e7fe0c8 100644 --- a/modules/rmf/dependency/RMF/include/RMF/exceptions.h +++ b/modules/rmf/dependency/RMF/include/RMF/exceptions.h @@ -31,8 +31,8 @@ class RMFEXPORT Exception : public virtual std::exception, public: RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(Exception); Exception(); - const char* what() const RMF_NOEXCEPT override; - virtual ~Exception() RMF_NOEXCEPT; + const char* what() const noexcept override; + virtual ~Exception() noexcept; }; /** Use this instead of the more standard what() to get the @@ -49,7 +49,7 @@ class RMFEXPORT UsageException : public Exception { public: RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(UsageException); UsageException(); - ~UsageException() RMF_NOEXCEPT; + ~UsageException() noexcept; }; /** IOExceptions are thrown when some operation on a disk file fails. @@ -58,7 +58,7 @@ class RMFEXPORT IOException : public Exception { public: RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(IOException); IOException(); - ~IOException() RMF_NOEXCEPT; + ~IOException() noexcept; }; /** Internal exceptions are thrown when the library discovers that some @@ -69,7 +69,7 @@ class RMFEXPORT InternalException : public Exception { public: RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(InternalException); InternalException(); - ~InternalException() RMF_NOEXCEPT; + ~InternalException() noexcept; }; /** IndexExceptions are thrown when you walk off the end of something. @@ -78,7 +78,7 @@ class RMFEXPORT IndexException : public Exception { public: RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(IndexException); IndexException(); - ~IndexException() RMF_NOEXCEPT; + ~IndexException() noexcept; }; } diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/SharedData.h b/modules/rmf/dependency/RMF/include/RMF/internal/SharedData.h index 55817a73f6..5bce24bc34 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/SharedData.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/SharedData.h @@ -9,7 +9,7 @@ #ifndef RMF_INTERNAL_SHARED_DATA_H #define RMF_INTERNAL_SHARED_DATA_H -#include +#include #include #include "RMF/ID.h" @@ -61,7 +61,7 @@ class RMFEXPORT SharedData RMF_FOREACH_TYPE(RMF_SHARED_DATA_PARENT) public SharedDataFrames { std::string path_; bool write_; - boost::shared_ptr io_; + std::shared_ptr io_; FrameID loaded_frame_; public: @@ -73,7 +73,7 @@ class RMFEXPORT SharedData RMF_FOREACH_TYPE(RMF_HOIST); - SharedData(boost::shared_ptr io, std::string name, bool write, + SharedData(std::shared_ptr io, std::string name, bool write, bool created); void set_loaded_frame(FrameID frame); FrameID add_frame(std::string name, FrameType type); diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataData_impl.h b/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataData_impl.h index 70cdbb952e..6a7558c792 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataData_impl.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataData_impl.h @@ -22,7 +22,7 @@ #include #include -#include +#include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataUserData.h b/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataUserData.h index 88af574903..0c03c5b7e8 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataUserData.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/SharedDataUserData.h @@ -17,7 +17,7 @@ #include #include -#include +#include RMF_ENABLE_WARNINGS @@ -28,7 +28,7 @@ inline uintptr_t get_uint(const P* p) { return reinterpret_cast(p); } template -inline uintptr_t get_uint(boost::shared_ptr

p) { +inline uintptr_t get_uint(std::shared_ptr

p) { return reinterpret_cast(p.get()); } inline uintptr_t get_uint(NodeID id) { return id.get_index(); } diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/SharedData_impl.h b/modules/rmf/dependency/RMF/include/RMF/internal/SharedData_impl.h index a04234747a..e35669290c 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/SharedData_impl.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/SharedData_impl.h @@ -21,7 +21,7 @@ #include "SharedDataPath.h" #include -#include +#include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/paths.h b/modules/rmf/dependency/RMF/include/RMF/internal/paths.h index d1f465b59b..0d16949ea7 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/paths.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/paths.h @@ -2,7 +2,7 @@ * \file RMF/internal/SharedData.h * \brief Handle read/write of Model data from/to files. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -24,6 +24,9 @@ RMFEXPORT std::string get_relative_path(std::string base, std::string file); // Get an absolute path to file from the directory containing base RMFEXPORT std::string get_absolute_path(std::string base, std::string file); +// Return true iff both files are in the same directory +RMFEXPORT bool get_is_same_base_path(std::string file1, std::string file2); + RMFEXPORT std::string get_unique_path(); } // namespace internal } /* namespace RMF */ diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/shared_data_factories.h b/modules/rmf/dependency/RMF/include/RMF/internal/shared_data_factories.h index f6b3a2d6ad..bdc72d8af0 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/shared_data_factories.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/shared_data_factories.h @@ -9,7 +9,7 @@ #ifndef RMF_INTERNAL_SHARED_DATA_FACTORIES_H #define RMF_INTERNAL_SHARED_DATA_FACTORIES_H -#include +#include #include #include @@ -33,10 +33,10 @@ namespace RMF { namespace internal { -RMFEXPORT boost::shared_ptr create_file(const std::string& name); -RMFEXPORT boost::shared_ptr create_buffer(BufferHandle buffer); -RMFEXPORT boost::shared_ptr read_file(const std::string& name); -RMFEXPORT boost::shared_ptr read_buffer(BufferConstHandle buffer); +RMFEXPORT std::shared_ptr create_file(const std::string& name); +RMFEXPORT std::shared_ptr create_buffer(BufferHandle buffer); +RMFEXPORT std::shared_ptr read_file(const std::string& name); +RMFEXPORT std::shared_ptr read_buffer(BufferConstHandle buffer); } // namespace internal } /* namespace RMF */ diff --git a/modules/rmf/dependency/RMF/include/RMF/internal/swig_helpers.h b/modules/rmf/dependency/RMF/include/RMF/internal/swig_helpers.h index 68b4ad37f3..385d23f185 100644 --- a/modules/rmf/dependency/RMF/include/RMF/internal/swig_helpers.h +++ b/modules/rmf/dependency/RMF/include/RMF/internal/swig_helpers.h @@ -13,13 +13,8 @@ #include "RMF/infrastructure_macros.h" #include "RMF/exceptions.h" #include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -63,12 +58,10 @@ typedef PyPointer PyOwnerPointer; } \ } -using boost::enable_if; -using boost::mpl::and_; -using boost::mpl::not_; -using boost::is_convertible; -using boost::is_base_of; -using boost::is_pointer; +using std::enable_if; +using std::is_convertible; +using std::is_base_of; +using std::is_pointer; // using namespace boost; // using namespace boost::mpl; @@ -219,7 +212,7 @@ template struct ConvertSequence< T, ConvertT, typename enable_if, T> >::type> { + std::array, T>::value >::type> { static const int converter = 5; typedef ConvertSequenceHelper Helper; typedef typename ValueOrObject::type VT; @@ -254,7 +247,7 @@ struct ConvertSequence< template struct ConvertSequence, ConvertT> { static const int converter = 6; - typedef boost::array Intermediate; + typedef std::array Intermediate; typedef ConvertSequenceHelper Helper; typedef typename ValueOrObject::type VT; template diff --git a/modules/rmf/dependency/RMF/include/RMF/numpy_util.h b/modules/rmf/dependency/RMF/include/RMF/numpy_util.h new file mode 100644 index 0000000000..ee4633c82f --- /dev/null +++ b/modules/rmf/dependency/RMF/include/RMF/numpy_util.h @@ -0,0 +1,39 @@ +/** + * \file RMF/numpy_util.h + * \brief Utility functions to access data from Python with numpy. + * + * Copyright 2007-2023 IMP Inventors. All rights reserved. + * + */ + +#ifndef RMF_NUMPY_UTIL_H +#define RMF_NUMPY_UTIL_H + +#include "RMF/config.h" + +namespace RMF { + +// We only document the functions here. The implementations are provided +// in swig/RMF.numpy.i + +#ifdef RMF_DOXYGEN + +//! Get global XYZ coordinates for everything under the given node. +/** This will traverse the subset of the RMF file rooted at the given node + in a depth first manner and put the XYZ coordinates for all appropriate + nodes into the provided NumPy array, which must be an N*3 float array + where N is the number of XYZ particles. The coordinates are global, i.e. + they are transformed by any parent ReferenceFrame nodes. + + This function is primarily intended to extract trajectory frames + for visualization packages such as ChimeraX. It is only available to + Python and if RMF is built with NumPy support. + */ +void get_all_global_coordinates( + FileConstHandle &fh, NodeConstHandle &nh, PyObject *coord); + +#endif + +} /* namespace RMF */ + +#endif /* RMF_NUMPY_UTIL_H */ diff --git a/modules/rmf/dependency/RMF/include/RMF/types.h b/modules/rmf/dependency/RMF/include/RMF/types.h index 2688bbfe8d..12c76ed668 100644 --- a/modules/rmf/dependency/RMF/include/RMF/types.h +++ b/modules/rmf/dependency/RMF/include/RMF/types.h @@ -53,7 +53,7 @@ typedef RMF_TYPES Vector3s; /** Many Vector4s */ typedef RMF_TYPES Vector4s; -typedef boost::array IntRange; +typedef std::array IntRange; } /* namespace RMF */ diff --git a/modules/rmf/dependency/RMF/include/RMF/utility.h b/modules/rmf/dependency/RMF/include/RMF/utility.h index deb84469ca..a9d6ab231e 100644 --- a/modules/rmf/dependency/RMF/include/RMF/utility.h +++ b/modules/rmf/dependency/RMF/include/RMF/utility.h @@ -13,7 +13,7 @@ #include "RMF/config.h" #include "RMF/internal/errors.h" #include "Vector.h" -#include +#include RMF_ENABLE_WARNINGS @@ -65,7 +65,7 @@ RMFEXPORT void test_throw_exception(); /** Return a lower bound/upper bound pair that bounds the data stored in the * tree. */ -RMFEXPORT boost::array get_bounding_box(NodeConstHandle root); +RMFEXPORT std::array get_bounding_box(NodeConstHandle root); /** Return the diameter of the system. Unlike bounding box, this one can be called from python. */ diff --git a/modules/rmf/dependency/RMF/include/RMF/validate.h b/modules/rmf/dependency/RMF/include/RMF/validate.h index 724dfd8910..63c5babc9c 100644 --- a/modules/rmf/dependency/RMF/include/RMF/validate.h +++ b/modules/rmf/dependency/RMF/include/RMF/validate.h @@ -9,8 +9,7 @@ #ifndef RMF_VALIDATE_H #define RMF_VALIDATE_H -#include -#include +#include #include #include diff --git a/modules/rmf/dependency/RMF/plugins/vmd/Data.cpp b/modules/rmf/dependency/RMF/plugins/vmd/Data.cpp index 313002d23e..7e9b41c864 100644 --- a/modules/rmf/dependency/RMF/plugins/vmd/Data.cpp +++ b/modules/rmf/dependency/RMF/plugins/vmd/Data.cpp @@ -53,11 +53,11 @@ Data::Data(std::string name, int *num_atoms) bodies_.push_back(Body()); - boost::array default_chain = {{0}}; - boost::array default_resname = {{0}}; - boost::array default_altid = {{0}}; - boost::array default_segment = {{0}}; - boost::array na = + std::array default_chain = {{0}}; + std::array default_resname = {{0}}; + std::array default_altid = {{0}}; + std::array default_segment = {{0}}; + std::array na = fill_bodies(file_.get_root_node(), 0, default_chain, -1, default_resname, default_altid, default_segment, resolution_); fill_index(); @@ -143,13 +143,13 @@ int Data::handle_state(int body, RMF::NodeConstHandle cur) { } } -boost::tuple, boost::array > +boost::tuple, std::array > Data::handle_alternative(RMF::NodeConstHandle cur, int body, - boost::array chain, int resid, - boost::array resname, - boost::array altid, - boost::array segment, double resolution) { - boost::array count = {{0}}; + std::array chain, int resid, + std::array resname, + std::array altid, + std::array segment, double resolution) { + std::array count = {{0}}; if (resolution >= 0) { RMF::NodeConstHandle alt = altf_.get(cur).get_alternative(RMF::PARTICLE, resolution); @@ -160,7 +160,7 @@ Data::handle_alternative(RMF::NodeConstHandle cur, int body, for(RMF::NodeConstHandle c : boost::make_iterator_range(alts.begin() + 1, alts.end())) { altid[0] = 'A' + alt; - boost::array cur = fill_bodies(c, body, chain, resid, resname, + std::array cur = fill_bodies(c, body, chain, resid, resname, altid, segment, resolution); for (unsigned int i = 0; i < 2; ++i) { count[i] += cur[i]; @@ -172,13 +172,13 @@ Data::handle_alternative(RMF::NodeConstHandle cur, int body, } } -boost::array Data::fill_bodies(RMF::NodeConstHandle cur, int body, - boost::array chain, int resid, - boost::array resname, - boost::array altid, - boost::array segment, +std::array Data::fill_bodies(RMF::NodeConstHandle cur, int body, + std::array chain, int resid, + std::array resname, + std::array altid, + std::array segment, double resolution) { - boost::array ret = {{0}}; + std::array ret = {{0}}; // must be firest due to ret if (altf_.get_is(cur)) boost::tie(cur, altid, ret) = handle_alternative( @@ -203,7 +203,7 @@ boost::array Data::fill_bodies(RMF::NodeConstHandle cur, int body, } for(RMF::NodeConstHandle c : cur.get_children()) { - boost::array count = + std::array count = fill_bodies(c, body, chain, resid, resname, altid, segment, resolution); for (unsigned int i = 0; i < 2; ++i) { ret[i] += count[i]; diff --git a/modules/rmf/dependency/RMF/plugins/vmd/Data.h b/modules/rmf/dependency/RMF/plugins/vmd/Data.h index f275129008..02aaedd704 100644 --- a/modules/rmf/dependency/RMF/plugins/vmd/Data.h +++ b/modules/rmf/dependency/RMF/plugins/vmd/Data.h @@ -25,7 +25,7 @@ #include "RMF/infrastructure_macros.h" #include "RMF/types.h" #include "molfile_plugin.h" -#include +#include #include #include #include @@ -54,11 +54,11 @@ class Data { RMF::decorator::StateFactory stf_; struct AtomInfo { // can precompute the actual molfile_atom_t data to simplify things - boost::array chain_id; + std::array chain_id; int residue_index; - boost::array residue_name; - boost::array altid; - boost::array segment; + std::array residue_name; + std::array altid; + std::array segment; RMF::NodeID node_id; }; struct Body { @@ -80,29 +80,29 @@ class Data { RESTRAINTS = 2 }; int show_restraints_; - boost::array bounds_; + std::array bounds_; double max_radius_; bool done_; // find nodes to push to VMD - boost::array fill_bodies(RMF::NodeConstHandle cur, int body, - boost::array chain, int resid, - boost::array resname, - boost::array altid, - boost::array segment, + std::array fill_bodies(RMF::NodeConstHandle cur, int body, + std::array chain, int resid, + std::array resname, + std::array altid, + std::array segment, double resolution); void fill_index(); void fill_graphics(RMF::NodeConstHandle cur, RMF::CoordinateTransformer tr); void fill_bonds(RMF::NodeConstHandle cur); int handle_reference_frame(int body, RMF::NodeConstHandle cur); int handle_state(int body, RMF::NodeConstHandle cur); - boost::tuple, - boost::array > + boost::tuple, + std::array > handle_alternative(RMF::NodeConstHandle cur, int body, - boost::array chain, int resid, - boost::array resname, - boost::array altid, - boost::array segment, double resolution); + std::array chain, int resid, + std::array resname, + std::array altid, + std::array segment, double resolution); void handle_bond(RMF::NodeConstHandle cur); void handle_restraint(RMF::NodeConstHandle cur); double get_resolution(); diff --git a/modules/rmf/dependency/RMF/src/BufferConstHandle.cpp b/modules/rmf/dependency/RMF/src/BufferConstHandle.cpp index 9f33a3e232..4f4ae4f2c4 100644 --- a/modules/rmf/dependency/RMF/src/BufferConstHandle.cpp +++ b/modules/rmf/dependency/RMF/src/BufferConstHandle.cpp @@ -8,8 +8,7 @@ #include "RMF/BufferConstHandle.h" #include "RMF/log.h" -#include -#include +#include #include RMF_ENABLE_WARNINGS @@ -21,8 +20,8 @@ BufferConstHandle read_buffer(std::string file_name) { std::ios::in | std::ios::binary | std::ios::ate); unsigned int size = szstr.tellg(); std::ifstream in(file_name.c_str(), std::ios::in | std::ios::binary); - boost::shared_ptr > data = - boost::make_shared >(size); + std::shared_ptr > data = + std::make_shared >(size); RMF_TRACE("Found buffer of size " << data->size()); in.read(&(*data)[0], data->size()); return BufferConstHandle(data); diff --git a/modules/rmf/dependency/RMF/src/FileConstHandle.cpp b/modules/rmf/dependency/RMF/src/FileConstHandle.cpp index 824d256eb0..10edce2853 100644 --- a/modules/rmf/dependency/RMF/src/FileConstHandle.cpp +++ b/modules/rmf/dependency/RMF/src/FileConstHandle.cpp @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include @@ -25,7 +25,7 @@ RMF_ENABLE_WARNINGS namespace RMF { -FileConstHandle::FileConstHandle(boost::shared_ptr shared) +FileConstHandle::FileConstHandle(std::shared_ptr shared) : shared_(shared) {} NodeConstHandle FileConstHandle::get_node(NodeID id) const { diff --git a/modules/rmf/dependency/RMF/src/FileHandle.cpp b/modules/rmf/dependency/RMF/src/FileHandle.cpp index 5d569c6b91..1c65ef123e 100644 --- a/modules/rmf/dependency/RMF/src/FileHandle.cpp +++ b/modules/rmf/dependency/RMF/src/FileHandle.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include "RMF/BufferHandle.h" @@ -23,7 +23,7 @@ RMF_ENABLE_WARNINGS namespace RMF { -FileHandle::FileHandle(boost::shared_ptr shared) +FileHandle::FileHandle(std::shared_ptr shared) : FileConstHandle(shared) {} NodeHandle FileHandle::get_node(NodeID id) const { @@ -31,6 +31,7 @@ NodeHandle FileHandle::get_node(NodeID id) const { } void FileHandle::flush() const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); try { shared_->flush(); } @@ -38,20 +39,24 @@ void FileHandle::flush() const { } void FileHandle::set_description(std::string descr) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); shared_->set_description(descr); } void FileHandle::set_producer(std::string descr) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); shared_->set_producer(descr); } FrameID FileHandle::add_frame(std::string name, FrameType t) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); FrameID ret = shared_->add_frame(name, t); return ret; } FrameID FileHandle::add_frame(std::string name, FrameID parent, FrameType t) const { + RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file."); FrameID ret = shared_->add_frame(name, parent, t); return ret; } diff --git a/modules/rmf/dependency/RMF/src/NodeConstHandle.cpp b/modules/rmf/dependency/RMF/src/NodeConstHandle.cpp index 983018dbf7..e6213f31ae 100644 --- a/modules/rmf/dependency/RMF/src/NodeConstHandle.cpp +++ b/modules/rmf/dependency/RMF/src/NodeConstHandle.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include #include @@ -26,7 +26,7 @@ RMF_ENABLE_WARNINGS namespace RMF { NodeConstHandle::NodeConstHandle(NodeID node, - boost::shared_ptr shared) + std::shared_ptr shared) : node_(node), shared_(shared) {} FileConstHandle NodeConstHandle::get_file() const { diff --git a/modules/rmf/dependency/RMF/src/NodeHandle.cpp b/modules/rmf/dependency/RMF/src/NodeHandle.cpp index bde17c484c..36cd0a62a1 100644 --- a/modules/rmf/dependency/RMF/src/NodeHandle.cpp +++ b/modules/rmf/dependency/RMF/src/NodeHandle.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include "RMF/FileHandle.h" @@ -21,7 +21,7 @@ RMF_ENABLE_WARNINGS namespace RMF { NodeHandle::NodeHandle(NodeID node, - boost::shared_ptr shared) + std::shared_ptr shared) : NodeConstHandle(node, shared) {} NodeHandle NodeHandle::add_child(std::string name, NodeType t) const { diff --git a/modules/rmf/dependency/RMF/src/TraverseHelper.cpp b/modules/rmf/dependency/RMF/src/TraverseHelper.cpp index c414d03e38..8f07a7c1f5 100644 --- a/modules/rmf/dependency/RMF/src/TraverseHelper.cpp +++ b/modules/rmf/dependency/RMF/src/TraverseHelper.cpp @@ -7,7 +7,6 @@ */ #include "RMF/TraverseHelper.h" -#include RMF_ENABLE_WARNINGS @@ -33,8 +32,8 @@ TraverseHelper::Data::Data(NodeConstHandle root, std::string molecule_name, TraverseHelper::TraverseHelper(NodeConstHandle root, std::string molecule_name, double resolution, int state_filter) - : active_(boost::make_shared()), - data_(boost::make_shared(root, molecule_name, resolution, + : active_(std::make_shared()), + data_(std::make_shared(root, molecule_name, resolution, state_filter)) { visit_impl(root); } @@ -76,7 +75,7 @@ void TraverseHelper::visit_impl(NodeConstHandle n) { TraverseHelper TraverseHelper::visit(NodeConstHandle n) const { TraverseHelper ret; - ret.data_ = boost::make_shared(*data_); + ret.data_ = std::make_shared(*data_); ret.active_ = active_; ret.visit_impl(n); return ret; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/DataFile.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/DataFile.hh index b5ef7ee22b..ff7c757169 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/DataFile.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/DataFile.hh @@ -30,7 +30,7 @@ #include #include -#include "boost/array.hpp" +#include #include "boost/utility.hpp" #include #include @@ -46,7 +46,7 @@ enum Codec { /** * The sync value. */ -typedef boost::array DataFileSync; +typedef std::array DataFileSync; /** * Type-independent portion of DataFileWriter. @@ -60,8 +60,8 @@ class AVRO_DECL DataFileWriterBase : boost::noncopyable { const size_t syncInterval_; Codec codec_; - boost::shared_ptr stream_; - boost::shared_ptr buffer_; + std::shared_ptr stream_; + std::shared_ptr buffer_; const DataFileSync sync_; int64_t objectCount_; @@ -69,7 +69,7 @@ class AVRO_DECL DataFileWriterBase : boost::noncopyable { Metadata metadata_; - static boost::shared_ptr makeStream(const char* filename); + static std::shared_ptr makeStream(const char* filename); static DataFileSync makeSync(); void writeHeader(); @@ -107,7 +107,7 @@ class AVRO_DECL DataFileWriterBase : boost::noncopyable { * Constructs a data file writer to a given stream with the given schema * and sync interval. */ - DataFileWriterBase(boost::shared_ptr stream, + DataFileWriterBase(std::shared_ptr stream, const ValidSchema& schema, size_t syncInterval, Codec codec = NULL_CODEC); @@ -134,7 +134,7 @@ class AVRO_DECL DataFileWriterBase : boost::noncopyable { */ template class DataFileWriter : boost::noncopyable { - boost::shared_ptr base_; + std::shared_ptr base_; public: /** @@ -147,7 +147,7 @@ class DataFileWriter : boost::noncopyable { /** * Constructs a new data file. */ - DataFileWriter(boost::shared_ptr stream, + DataFileWriter(std::shared_ptr stream, const ValidSchema& schema, size_t syncInterval = 16 * 1024, Codec codec = NULL_CODEC) : base_(new DataFileWriterBase(stream, schema, syncInterval, codec)) {} @@ -183,7 +183,7 @@ class DataFileWriter : boost::noncopyable { */ class AVRO_DECL DataFileReaderBase : boost::noncopyable { const std::string filename_; - const boost::shared_ptr stream_; + const std::shared_ptr stream_; const DecoderPtr decoder_; int64_t objectCount_; bool eof_; @@ -193,7 +193,7 @@ class AVRO_DECL DataFileReaderBase : boost::noncopyable { ValidSchema readerSchema_; ValidSchema dataSchema_; DecoderPtr dataDecoder_; - boost::shared_ptr dataStream_; + std::shared_ptr dataStream_; typedef std::map > Metadata; Metadata metadata_; @@ -237,7 +237,7 @@ class AVRO_DECL DataFileReaderBase : boost::noncopyable { * This function should be called exactly once after constructing * the DataFileReaderBase object. */ - DataFileReaderBase(boost::shared_ptr stream); + DataFileReaderBase(std::shared_ptr stream); /** * Initializes the reader so that the reader and writer schemas @@ -292,7 +292,7 @@ class AVRO_DECL DataFileReaderBase : boost::noncopyable { */ template class DataFileReader : boost::noncopyable { - boost::shared_ptr base_; + std::shared_ptr base_; public: /** @@ -317,7 +317,7 @@ class DataFileReader : boost::noncopyable { * Constructs the reader for the given stream and the reader is * expected to use the given schema. */ - DataFileReader(boost::shared_ptr stream, + DataFileReader(std::shared_ptr stream, const ValidSchema& readerSchema) : base_(new DataFileReaderBase(stream)) { base_->init(readerSchema); @@ -327,7 +327,7 @@ class DataFileReader : boost::noncopyable { * Constructs the reader for the given stream and the reader is * expected to use the schema that is used with data. */ - DataFileReader(boost::shared_ptr stream) + DataFileReader(std::shared_ptr stream) : base_(new DataFileReaderBase(stream)) { base_->init(); } @@ -341,7 +341,7 @@ class DataFileReader : boost::noncopyable { * The schema present in the data file will be used for reading * from this reader. */ - DataFileReader(boost::shared_ptr base) : base_(base) { + DataFileReader(std::shared_ptr base) : base_(base) { base_->init(); } @@ -354,7 +354,7 @@ class DataFileReader : boost::noncopyable { * The argument readerSchema will be used for reading * from this reader. */ - DataFileReader(boost::shared_ptr base, + DataFileReader(std::shared_ptr base, const ValidSchema& readerSchema) : base_(base) { base_->init(readerSchema); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Decoder.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Decoder.hh index 52c36f6802..da6acb67d7 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Decoder.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Decoder.hh @@ -27,7 +27,7 @@ #include "ValidSchema.hh" #include "Stream.hh" -#include +#include /// \file /// @@ -158,7 +158,7 @@ class AVRO_DECL Decoder { /** * Shared pointer to Decoder. */ -typedef boost::shared_ptr DecoderPtr; +typedef std::shared_ptr DecoderPtr; /** * ResolvingDecoder is derived from \ref Decoder, with an additional @@ -177,7 +177,7 @@ class AVRO_DECL ResolvingDecoder : public Decoder { /** * Shared pointer to ResolvingDecoder. */ -typedef boost::shared_ptr ResolvingDecoderPtr; +typedef std::shared_ptr ResolvingDecoderPtr; /** * Returns an decoder that can decode binary Avro standard. */ diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Encoder.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Encoder.hh index 48709b5618..f64d4e6f91 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Encoder.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Encoder.hh @@ -27,7 +27,7 @@ #include "ValidSchema.hh" #include "Stream.hh" -#include +#include /// \file /// @@ -141,7 +141,7 @@ class AVRO_DECL Encoder { /** * Shared pointer to Encoder. */ -typedef boost::shared_ptr EncoderPtr; +typedef std::shared_ptr EncoderPtr; /** * Returns an encoder that can encode binary Avro standard. diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Node.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Node.hh index cce86c3d7e..6ab7145437 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Node.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Node.hh @@ -23,7 +23,7 @@ #include #include -#include +#include #include "Exception.hh" #include "Types.hh" @@ -33,7 +33,7 @@ namespace internal_avro { class Node; -typedef boost::shared_ptr NodePtr; +typedef std::shared_ptr NodePtr; class AVRO_DECL Name { std::string ns_; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/NodeImpl.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/NodeImpl.hh index eca8984186..599a8b2e27 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/NodeImpl.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/NodeImpl.hh @@ -23,7 +23,6 @@ #include #include -#include #include "Node.hh" #include "NodeConcepts.hh" @@ -178,7 +177,7 @@ class AVRO_DECL NodePrimitive : public NodeImplPrimitive { }; class AVRO_DECL NodeSymbolic : public NodeImplSymbolic { - typedef boost::weak_ptr NodeWeakPtr; + typedef std::weak_ptr NodeWeakPtr; public: NodeSymbolic() : NodeImplSymbolic(AVRO_SYMBOLIC) {} @@ -437,8 +436,8 @@ inline NodePtr resolveSymbol(const NodePtr &node) { if (node->type() != AVRO_SYMBOLIC) { throw Exception("Only symbolic nodes may be resolved"); } - boost::shared_ptr symNode = - boost::static_pointer_cast(node); + std::shared_ptr symNode = + std::static_pointer_cast(node); return symNode->getNode(); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Parser.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Parser.hh index 1100522ed7..dae3faab45 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Parser.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Parser.hh @@ -85,7 +85,7 @@ class Parser : private boost::noncopyable { } template - void readFixed(boost::array &val) { + void readFixed(std::array &val) { reader_.readFixed(val); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Reader.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Reader.hh index a732cdd86f..8cb2c5fde4 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Reader.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Reader.hh @@ -110,7 +110,7 @@ class ReaderImpl : private boost::noncopyable { } template - void readFixed(boost::array &val) { + void readFixed(std::array &val) { this->readFixed(val.c_array(), N); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/ResolverSchema.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/ResolverSchema.hh index e4285cd6a4..fe2d96e450 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/ResolverSchema.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/ResolverSchema.hh @@ -20,7 +20,7 @@ #define avro_ResolverSchema_hh__ #include -#include +#include #include #include "Config.hh" @@ -47,7 +47,7 @@ class AVRO_DECL ResolverSchema { void parse(Reader &reader, uint8_t *address); - boost::shared_ptr resolver_; + std::shared_ptr resolver_; }; } // namespace internal_avro diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Serializer.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Serializer.hh index b928ef0425..66799b0673 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Serializer.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Serializer.hh @@ -59,7 +59,7 @@ class Serializer : private boost::noncopyable { } template - void writeFixed(const boost::array &val) { + void writeFixed(const std::array &val) { writer_.writeFixed(val); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Specific.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Specific.hh index 7c97e893d0..c04718e940 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Specific.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Specific.hh @@ -24,7 +24,7 @@ #include #include -#include "boost/array.hpp" +#include #include "Config.hh" #include "Encoder.hh" @@ -180,18 +180,18 @@ struct codec_traits > { * codec_traits for Avro fixed. */ template -struct codec_traits > { +struct codec_traits > { /** * Encodes a given value. */ - static void encode(Encoder& e, const boost::array& b) { + static void encode(Encoder& e, const std::array& b) { e.encodeFixed(&b[0], N); } /** * Decodes into a given value. */ - static void decode(Decoder& d, boost::array& s) { + static void decode(Decoder& d, std::array& s) { std::vector v(N); d.decodeFixed(N, v); std::copy(&v[0], &v[0] + N, &s[0]); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Stream.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Stream.hh index ed9f7b69de..776c89c36a 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Stream.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Stream.hh @@ -127,7 +127,7 @@ class AVRO_DECL OutputStream : boost::noncopyable { /** * Returns a new OutputStream, which grows in memory chunks of specified size. */ -AVRO_DECL boost::shared_ptr memoryOutputStream(size_t chunkSize = +AVRO_DECL std::shared_ptr memoryOutputStream(size_t chunkSize = 4 * 1024); /** @@ -135,7 +135,7 @@ AVRO_DECL boost::shared_ptr memoryOutputStream(size_t chunkSize = * It does not copy the data, the byte array should remain valid * until the InputStream is used. */ -AVRO_DECL boost::shared_ptr memoryInputStream(const uint8_t* data, +AVRO_DECL std::shared_ptr memoryInputStream(const uint8_t* data, size_t len); /** @@ -145,7 +145,7 @@ AVRO_DECL boost::shared_ptr memoryInputStream(const uint8_t* data, * input stream are the snapshot of the outputstream. One can construct * any number of memory input stream from a single memory output stream. */ -AVRO_DECL boost::shared_ptr memoryInputStream( +AVRO_DECL std::shared_ptr memoryInputStream( const OutputStream& source); /** @@ -155,7 +155,7 @@ AVRO_DECL boost::shared_ptr memoryInputStream( * If there is a file with the given name, it is truncated and overwritten. * If there is no file with the given name, it is created. */ -AVRO_DECL boost::shared_ptr fileOutputStream(const char* filename, +AVRO_DECL std::shared_ptr fileOutputStream(const char* filename, size_t bufferSize = 8 * 1024); @@ -163,7 +163,7 @@ AVRO_DECL boost::shared_ptr fileOutputStream(const char* filename, * Returns a new InputStream whose contents come from the given file. * Data is read in chunks of given buffer size. */ -AVRO_DECL boost::shared_ptr fileInputStream(const char* filename, +AVRO_DECL std::shared_ptr fileInputStream(const char* filename, size_t bufferSize = 8 * 1024); @@ -172,7 +172,7 @@ AVRO_DECL boost::shared_ptr fileInputStream(const char* filename, * std::ostream. The std::ostream object should outlive the returned * OutputStream. */ -AVRO_DECL boost::shared_ptr ostreamOutputStream( +AVRO_DECL std::shared_ptr ostreamOutputStream( std::ostream& os, size_t bufferSize = 8 * 1024); /** @@ -180,7 +180,7 @@ AVRO_DECL boost::shared_ptr ostreamOutputStream( * std::istream. The std::istream object should outlive the returned * InputStream. */ -AVRO_DECL boost::shared_ptr istreamInputStream(std::istream& in, +AVRO_DECL std::shared_ptr istreamInputStream(std::istream& in, size_t bufferSize = 8 * 1024); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Writer.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Writer.hh index 4963cbfa66..224433bf65 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Writer.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Writer.hh @@ -49,7 +49,7 @@ class WriterImpl : private boost::noncopyable { void writeValue(int32_t val) { validator_.checkTypeExpected(AVRO_INT); - boost::array bytes; + std::array bytes; size_t size = encodeInt32(val, bytes); buffer_.writeTo(reinterpret_cast(bytes.data()), size); } @@ -98,7 +98,7 @@ class WriterImpl : private boost::noncopyable { } template - void writeFixed(const boost::array &val) { + void writeFixed(const std::array &val) { validator_.checkFixedSizeExpected(val.size()); buffer_.writeTo(reinterpret_cast(val.data()), val.size()); } @@ -143,7 +143,7 @@ class WriterImpl : private boost::noncopyable { private: void putLong(int64_t val) { - boost::array bytes; + std::array bytes; size_t size = encodeInt64(val, bytes); buffer_.writeTo(reinterpret_cast(bytes.data()), size); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/Zigzag.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/Zigzag.hh index 646ebe99e0..593d14072d 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/Zigzag.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/Zigzag.hh @@ -20,7 +20,8 @@ #define avro_Encoding_hh__ #include -#include +#include +#include #include "Config.hh" /// \file @@ -34,8 +35,8 @@ AVRO_DECL int64_t decodeZigzag64(uint64_t input); AVRO_DECL uint32_t encodeZigzag32(int32_t input); AVRO_DECL int32_t decodeZigzag32(uint32_t input); -AVRO_DECL size_t encodeInt32(int32_t input, boost::array &output); -AVRO_DECL size_t encodeInt64(int64_t input, boost::array &output); +AVRO_DECL size_t encodeInt32(int32_t input, std::array &output); +AVRO_DECL size_t encodeInt64(int64_t input, std::array &output); } // namespace internal_avro diff --git a/modules/rmf/dependency/RMF/src/avrocpp/api/buffer/detail/BufferDetail.hh b/modules/rmf/dependency/RMF/src/avrocpp/api/buffer/detail/BufferDetail.hh index 33f948fb88..e79542b69c 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/api/buffer/detail/BufferDetail.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/api/buffer/detail/BufferDetail.hh @@ -19,7 +19,7 @@ #ifndef avro_BufferDetail_hh__ #define avro_BufferDetail_hh__ -#include +#include #include #include #include @@ -93,7 +93,7 @@ class CallOnDestroy { class Chunk { public: - typedef boost::shared_ptr SharedPtr; + typedef std::shared_ptr SharedPtr; /// Default constructor, allocates a new underlying block for this chunk. Chunk(size_type size) @@ -112,7 +112,7 @@ class Chunk { private: // reference counted object will call a functor when it's destroyed - boost::shared_ptr callOnDestroy_; + std::shared_ptr callOnDestroy_; public: /// Remove readable bytes from the front of the chunk by advancing the @@ -270,8 +270,8 @@ class BufferImpl : boost::noncopyable { public: typedef std::deque ChunkList; - typedef boost::shared_ptr SharedPtr; - typedef boost::shared_ptr ConstSharedPtr; + typedef std::shared_ptr SharedPtr; + typedef std::shared_ptr ConstSharedPtr; /// Default constructor, creates a buffer without any chunks BufferImpl() : freeSpace_(0), size_(0) {} diff --git a/modules/rmf/dependency/RMF/src/avrocpp/examples/custom.cc b/modules/rmf/dependency/RMF/src/avrocpp/examples/custom.cc index 8ba97407f5..86da4c6a1e 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/examples/custom.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/examples/custom.cc @@ -39,14 +39,14 @@ struct codec_traits > { }; } int main() { - boost::shared_ptr out = + std::shared_ptr out = internal_avro::memoryOutputStream(); internal_avro::EncoderPtr e = internal_avro::binaryEncoder(); e->init(*out); std::complex c1(1.0, 2.0); internal_avro::encode(*e, c1); - boost::shared_ptr in = + std::shared_ptr in = internal_avro::memoryInputStream(*out); internal_avro::DecoderPtr d = internal_avro::binaryDecoder(); d->init(*in); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/examples/generated.cc b/modules/rmf/dependency/RMF/src/avrocpp/examples/generated.cc index 1e37a6d874..890fdca65d 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/examples/generated.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/examples/generated.cc @@ -21,7 +21,7 @@ #include "avro/Decoder.hh" int main() { - boost::shared_ptr out = + std::shared_ptr out = internal_avro::memoryOutputStream(); internal_avro::EncoderPtr e = internal_avro::binaryEncoder(); e->init(*out); @@ -30,7 +30,7 @@ int main() { c1.im = 2.13; internal_avro::encode(*e, c1); - boost::shared_ptr in = + std::shared_ptr in = internal_avro::memoryInputStream(*out); internal_avro::DecoderPtr d = internal_avro::binaryDecoder(); d->init(*in); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/examples/generic.cc b/modules/rmf/dependency/RMF/src/avrocpp/examples/generic.cc index 18baec784e..09c1fd2a84 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/examples/generic.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/examples/generic.cc @@ -33,7 +33,7 @@ int main() { internal_avro::ValidSchema cpxSchema; internal_avro::compileJsonSchema(ifs, cpxSchema); - boost::shared_ptr out = + std::shared_ptr out = internal_avro::memoryOutputStream(); internal_avro::EncoderPtr e = internal_avro::binaryEncoder(); e->init(*out); @@ -42,7 +42,7 @@ int main() { c1.im = 105.77; internal_avro::encode(*e, c1); - boost::shared_ptr in = + std::shared_ptr in = internal_avro::memoryInputStream(*out); internal_avro::DecoderPtr d = internal_avro::binaryDecoder(); d->init(*in); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/examples/resolving.cc b/modules/rmf/dependency/RMF/src/avrocpp/examples/resolving.cc index 48334bfeb5..6abc2bfbb7 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/examples/resolving.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/examples/resolving.cc @@ -38,7 +38,7 @@ int main() { internal_avro::ValidSchema cpxSchema = load("cpx.json"); internal_avro::ValidSchema imaginarySchema = load("imaginary.json"); - boost::shared_ptr out = + std::shared_ptr out = internal_avro::memoryOutputStream(); internal_avro::EncoderPtr e = internal_avro::binaryEncoder(); e->init(*out); @@ -47,7 +47,7 @@ int main() { c1.im = 105.77; internal_avro::encode(*e, c1); - boost::shared_ptr in = + std::shared_ptr in = internal_avro::memoryInputStream(*out); internal_avro::DecoderPtr d = internal_avro::resolvingDecoder( cpxSchema, imaginarySchema, internal_avro::binaryDecoder()); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/examples/validating.cc b/modules/rmf/dependency/RMF/src/avrocpp/examples/validating.cc index 56b059a26f..4ae1e64572 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/examples/validating.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/examples/validating.cc @@ -46,7 +46,7 @@ int main() { internal_avro::ValidSchema cpxSchema; internal_avro::compileJsonSchema(ifs, cpxSchema); - boost::shared_ptr out = + std::shared_ptr out = internal_avro::memoryOutputStream(); internal_avro::EncoderPtr e = internal_avro::validatingEncoder( cpxSchema, internal_avro::binaryEncoder()); @@ -54,7 +54,7 @@ int main() { std::complex c1(1.0, 2.0); internal_avro::encode(*e, c1); - boost::shared_ptr in = + std::shared_ptr in = internal_avro::memoryInputStream(*out); internal_avro::DecoderPtr d = internal_avro::validatingDecoder( cpxSchema, internal_avro::binaryDecoder()); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryDecoder.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryDecoder.cc index 28e384c24c..7a00db04b5 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryDecoder.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryDecoder.cc @@ -22,12 +22,11 @@ #include "Zigzag.hh" #include "Exception.hh" -#include -#include +#include namespace internal_avro { -using boost::make_shared; +using std::make_shared; class BinaryDecoder : public Decoder { StreamReader in_; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryEncoder.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryEncoder.cc index 4725b7fb61..573f589dfa 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryEncoder.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/BinaryEncoder.cc @@ -18,13 +18,12 @@ #include "Encoder.hh" #include "Zigzag.hh" -#include -#include +#include namespace internal_avro { -using boost::make_shared; -using boost::shared_ptr; +using std::make_shared; +using std::shared_ptr; class BinaryEncoder : public Encoder { StreamWriter out_; @@ -114,7 +113,7 @@ void BinaryEncoder::startItem() {} void BinaryEncoder::encodeUnionIndex(size_t e) { doEncodeLong(e); } void BinaryEncoder::doEncodeLong(int64_t l) { - boost::array bytes; + std::array bytes; size_t size = encodeInt64(l, bytes); out_.writeBytes(bytes.data(), size); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/Compiler.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/Compiler.cc index 5397a35bf1..82d720ac46 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/Compiler.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/Compiler.cc @@ -217,8 +217,8 @@ static NodePtr makeNode(const Entity& e, const map& m, result = NodePtr(new NodeRecord()); st[nm] = result; NodePtr r = makeRecordNode(e, nm, m, st, nm.ns()); - (boost::dynamic_pointer_cast(r)) - ->swap(*boost::dynamic_pointer_cast(result)); + (std::dynamic_pointer_cast(r)) + ->swap(*std::dynamic_pointer_cast(result)); } else { result = (type == "enum") ? makeEnumNode(e, nm, m) : makeFixedNode(e, nm, m); @@ -278,7 +278,7 @@ ValidSchema compileJsonSchemaFromString(const std::string& input) { } static ValidSchema compile(std::istream& is) { - boost::shared_ptr in = istreamInputStream(is); + std::shared_ptr in = istreamInputStream(is); return compileJsonSchemaFromStream(*in); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/DataFile.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/DataFile.cc index 5ef97e4f0f..4308461df4 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/DataFile.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/DataFile.cc @@ -28,14 +28,14 @@ #include namespace internal_avro { -using boost::shared_ptr; +using std::shared_ptr; using std::ostringstream; using std::istringstream; using std::vector; using std::copy; using std::string; -using boost::array; +using std::array; const string AVRO_SCHEMA_KEY("avro.schema"); const string AVRO_CODEC_KEY("avro.codec"); @@ -77,7 +77,7 @@ DataFileWriterBase::DataFileWriterBase(const char* filename, setup(); } -DataFileWriterBase::DataFileWriterBase(boost::shared_ptr stream, +DataFileWriterBase::DataFileWriterBase(std::shared_ptr stream, const ValidSchema& schema, size_t syncInterval, Codec codec) @@ -133,7 +133,7 @@ void DataFileWriterBase::sync() { int64_t byteCount = buffer_->byteCount(); internal_avro::encode(*encoderPtr_, byteCount); encoderPtr_->flush(); - boost::shared_ptr in = memoryInputStream(*buffer_); + std::shared_ptr in = memoryInputStream(*buffer_); copy(*in, *stream_); } else { std::vector buf; @@ -146,12 +146,12 @@ void DataFileWriterBase::sync() { const uint8_t* data; size_t len; - boost::shared_ptr input = memoryInputStream(*buffer_); + std::shared_ptr input = memoryInputStream(*buffer_); while (input->next(&data, &len)) { boost::iostreams::write(os, reinterpret_cast(data), len); } } - boost::shared_ptr in = memoryInputStream( + std::shared_ptr in = memoryInputStream( reinterpret_cast(&buf[0]), buf.size()); int64_t byteCount = buf.size(); internal_avro::encode(*encoderPtr_, byteCount); @@ -213,7 +213,7 @@ DataFileReaderBase::DataFileReaderBase(const char* filename) readHeader(); } -DataFileReaderBase::DataFileReaderBase(boost::shared_ptr stream) +DataFileReaderBase::DataFileReaderBase(std::shared_ptr stream) : filename_("stream"), stream_(stream), decoder_(binaryDecoder()), @@ -311,9 +311,9 @@ class BoundedInputStream : public InputStream { BoundedInputStream(InputStream& in, size_t limit) : in_(in), limit_(limit) {} }; -boost::shared_ptr boundedInputStream(InputStream& in, +std::shared_ptr boundedInputStream(InputStream& in, size_t limit) { - return boost::shared_ptr(new BoundedInputStream(in, limit)); + return std::shared_ptr(new BoundedInputStream(in, limit)); } bool DataFileReaderBase::readDataBlock() { @@ -330,7 +330,7 @@ bool DataFileReaderBase::readDataBlock() { internal_avro::decode(*decoder_, byteCount); decoder_->init(*stream_); - boost::shared_ptr st = + std::shared_ptr st = boundedInputStream(*stream_, static_cast(byteCount)); if (codec_ == NULL_CODEC) { dataDecoder_->init(*st); @@ -350,7 +350,7 @@ bool DataFileReaderBase::readDataBlock() { os_->push(boost::iostreams::basic_array_source(&compressed_[0], compressed_.size())); - boost::shared_ptr in = istreamInputStream(*os_); + std::shared_ptr in = istreamInputStream(*os_); dataDecoder_->init(*in); dataStream_ = in; } @@ -396,7 +396,7 @@ void DataFileReaderBase::seekBlockBytes(int64_t offset) { objectCount_ = 0; // if we have leftover data from a previous iteration - boost::array old_data; + std::array old_data; const uint8_t *p = 0; size_t n = 0; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/FileStream.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/FileStream.cc index e1d16aeae8..75c8eb2829 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/FileStream.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/FileStream.cc @@ -153,7 +153,7 @@ struct IStreamBufferCopyIn : public BufferCopyIn { class BufferCopyInInputStream : public InputStream { const size_t bufferSize_; uint8_t* const buffer_; - boost::shared_ptr in_; + std::shared_ptr in_; size_t byteCount_; uint8_t* next_; size_t available_; @@ -213,7 +213,7 @@ class BufferCopyInInputStream : public InputStream { } public: - BufferCopyInInputStream(boost::shared_ptr& in, + BufferCopyInInputStream(std::shared_ptr& in, size_t bufferSize) : bufferSize_(bufferSize), buffer_(new uint8_t[bufferSize]), @@ -293,7 +293,7 @@ struct OStreamBufferCopyOut : public BufferCopyOut { class BufferCopyOutputStream : public OutputStream { size_t bufferSize_; uint8_t* const buffer_; - boost::shared_ptr out_; + std::shared_ptr out_; uint8_t* next_; size_t available_; size_t byteCount_; @@ -326,7 +326,7 @@ class BufferCopyOutputStream : public OutputStream { } public: - BufferCopyOutputStream(boost::shared_ptr out, + BufferCopyOutputStream(std::shared_ptr out, size_t bufferSize) : bufferSize_(bufferSize), buffer_(new uint8_t[bufferSize]), @@ -338,31 +338,31 @@ class BufferCopyOutputStream : public OutputStream { ~BufferCopyOutputStream() { delete[] buffer_; } }; -boost::shared_ptr fileInputStream(const char* filename, +std::shared_ptr fileInputStream(const char* filename, size_t bufferSize) { - boost::shared_ptr in(new FileBufferCopyIn(filename)); - return boost::shared_ptr( + std::shared_ptr in(new FileBufferCopyIn(filename)); + return std::shared_ptr( new BufferCopyInInputStream(in, bufferSize)); } -boost::shared_ptr istreamInputStream(istream& is, +std::shared_ptr istreamInputStream(istream& is, size_t bufferSize) { - boost::shared_ptr in(new IStreamBufferCopyIn(is)); - return boost::shared_ptr( + std::shared_ptr in(new IStreamBufferCopyIn(is)); + return std::shared_ptr( new BufferCopyInInputStream(in, bufferSize)); } -boost::shared_ptr fileOutputStream(const char* filename, +std::shared_ptr fileOutputStream(const char* filename, size_t bufferSize) { - boost::shared_ptr out(new FileBufferCopyOut(filename)); - return boost::shared_ptr( + std::shared_ptr out(new FileBufferCopyOut(filename)); + return std::shared_ptr( new BufferCopyOutputStream(out, bufferSize)); } -boost::shared_ptr ostreamOutputStream(ostream& os, +std::shared_ptr ostreamOutputStream(ostream& os, size_t bufferSize) { - boost::shared_ptr out(new OStreamBufferCopyOut(os)); - return boost::shared_ptr( + std::shared_ptr out(new OStreamBufferCopyOut(os)); + return std::shared_ptr( new BufferCopyOutputStream(out, bufferSize)); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/Resolver.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/Resolver.cc index bb7fa6aee3..8f445f1841 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/Resolver.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/Resolver.cc @@ -29,7 +29,7 @@ namespace internal_avro { class ResolverFactory; -typedef boost::shared_ptr ResolverPtr; +typedef std::shared_ptr ResolverPtr; typedef boost::ptr_vector ResolverPtrVector; // #define DEBUG_VERBOSE diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/Stream.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/Stream.cc index a062db2b0a..c84602a044 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/Stream.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/Stream.cc @@ -154,21 +154,21 @@ class MemoryOutputStream : public OutputStream { void flush() {} }; -boost::shared_ptr memoryOutputStream(size_t chunkSize) { - return boost::shared_ptr(new MemoryOutputStream(chunkSize)); +std::shared_ptr memoryOutputStream(size_t chunkSize) { + return std::shared_ptr(new MemoryOutputStream(chunkSize)); } -boost::shared_ptr memoryInputStream(const uint8_t* data, +std::shared_ptr memoryInputStream(const uint8_t* data, size_t len) { - return boost::shared_ptr(new MemoryInputStream2(data, len)); + return std::shared_ptr(new MemoryInputStream2(data, len)); } -boost::shared_ptr memoryInputStream(const OutputStream& source) { +std::shared_ptr memoryInputStream(const OutputStream& source) { const MemoryOutputStream& mos = dynamic_cast(source); return (mos.data_.empty()) - ? boost::shared_ptr(new MemoryInputStream2(0, 0)) - : boost::shared_ptr( + ? std::shared_ptr(new MemoryInputStream2(0, 0)) + : std::shared_ptr( new MemoryInputStream(mos.data_, mos.chunkSize_, (mos.chunkSize_ - mos.available_))); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/ValidSchema.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/ValidSchema.cc index a6f15b9e0d..7fc2a365c8 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/ValidSchema.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/ValidSchema.cc @@ -26,8 +26,8 @@ using std::string; using std::make_pair; using boost::format; -using boost::shared_ptr; -using boost::static_pointer_cast; +using std::shared_ptr; +using std::static_pointer_cast; namespace internal_avro { diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/Zigzag.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/Zigzag.cc index fc415c73de..98032cbf44 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/Zigzag.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/Zigzag.cc @@ -38,7 +38,7 @@ int32_t decodeZigzag32(uint32_t input) { ((input >> 1) ^ -(static_cast(input) & 1))); } -size_t encodeInt64(int64_t input, boost::array &output) { +size_t encodeInt64(int64_t input, std::array &output) { // get the zigzag encoding uint64_t val = encodeZigzag64(input); @@ -54,7 +54,7 @@ size_t encodeInt64(int64_t input, boost::array &output) { return bytesOut; } -size_t encodeInt32(int32_t input, boost::array &output) { +size_t encodeInt32(int32_t input, std::array &output) { // get the zigzag encoding uint32_t val = encodeZigzag32(input); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/avrogencpp.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/avrogencpp.cc index 85b9c1d9ef..82fbe451b1 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/avrogencpp.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/avrogencpp.cc @@ -168,7 +168,7 @@ string CodeGen::cppTypeOf(const NodePtr& n) { case internal_avro::AVRO_MAP: return "std::mapleafAt(1)) + " >"; case internal_avro::AVRO_FIXED: - return "boost::array(n->fixedSize()) + + return "std::array(n->fixedSize()) + ">"; case internal_avro::AVRO_SYMBOLIC: return cppTypeOf(resolveSymbol(n)); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/json/JsonDom.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/json/JsonDom.cc index 428b92f314..3cb435dc37 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/json/JsonDom.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/json/JsonDom.cc @@ -82,7 +82,7 @@ Entity loadEntity(InputStream& in) { } Entity loadEntity(const uint8_t* text, size_t len) { - boost::shared_ptr in = memoryInputStream(text, len); + std::shared_ptr in = memoryInputStream(text, len); return loadEntity(*in); } @@ -127,12 +127,12 @@ void writeEntity(JsonGenerator& g, const Entity& n) { } std::string Entity::toString() const { - boost::shared_ptr out = memoryOutputStream(); + std::shared_ptr out = memoryOutputStream(); JsonGenerator g; g.init(*out); writeEntity(g, *this); g.flush(); - boost::shared_ptr in = memoryInputStream(*out); + std::shared_ptr in = memoryInputStream(*out); const uint8_t* p = 0; size_t n = 0; size_t c = 0; @@ -142,7 +142,7 @@ std::string Entity::toString() const { std::string result; result.resize(c); c = 0; - boost::shared_ptr in2 = memoryInputStream(*out); + std::shared_ptr in2 = memoryInputStream(*out); while (in2->next(&p, &n)) { ::memcpy(&result[c], p, n); c += n; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/JsonCodec.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/JsonCodec.cc index 395345936b..d5a3ea46bb 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/JsonCodec.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/JsonCodec.cc @@ -23,9 +23,7 @@ #include #include #include -#include -#include -#include +#include #include #include @@ -42,8 +40,8 @@ namespace internal_avro { namespace parsing { -using boost::shared_ptr; -using boost::static_pointer_cast; +using std::shared_ptr; +using std::static_pointer_cast; using std::map; using std::vector; @@ -57,7 +55,7 @@ using internal_avro::json::JsonGenerator; class JsonGrammarGenerator : public ValidatingGrammarGenerator { Production doGenerate(const NodePtr& n, - std::map >& m); + std::map >& m); }; static std::string nameOf(const NodePtr& n) { @@ -70,7 +68,7 @@ static std::string nameOf(const NodePtr& n) { } Production JsonGrammarGenerator::doGenerate( - const NodePtr& n, std::map >& m) { + const NodePtr& n, std::map >& m) { switch (n->type()) { case AVRO_NULL: case AVRO_BOOL: @@ -104,7 +102,7 @@ Production JsonGrammarGenerator::doGenerate( bool found = m.find(n) != m.end(); - shared_ptr p = boost::make_shared(result); + shared_ptr p = std::make_shared(result); m[n] = p; return found ? Production(1, Symbol::indirect(p)) : result; @@ -118,7 +116,7 @@ Production JsonGrammarGenerator::doGenerate( } Symbol r[] = {Symbol::nameListSymbol(nn), Symbol::enumSymbol()}; Production result(r, r + 2); - m[n] = boost::make_shared(result); + m[n] = std::make_shared(result); return result; } case AVRO_UNION: { @@ -635,12 +633,12 @@ void JsonEncoder

::encodeUnionIndex(size_t e) { } // namespace parsing DecoderPtr jsonDecoder(const ValidSchema& s) { - return boost::make_shared > >(s); } EncoderPtr jsonEncoder(const ValidSchema& schema) { - return boost::make_shared< + return std::make_shared< parsing::JsonEncoder > >( schema); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ResolvingDecoder.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ResolvingDecoder.cc index 549ceac07e..8ff5cdb41c 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ResolvingDecoder.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ResolvingDecoder.cc @@ -24,9 +24,7 @@ #include #include #include -#include -#include -#include +#include #include #include @@ -40,12 +38,12 @@ namespace internal_avro { -using boost::make_shared; +using std::make_shared; namespace parsing { -using boost::shared_ptr; -using boost::static_pointer_cast; +using std::shared_ptr; +using std::static_pointer_cast; using std::map; using std::pair; @@ -188,7 +186,7 @@ Production ResolvingGrammarGenerator::resolveRecords( if (p.size() == 1) { result.push_back(p[0]); } else { - result.push_back(Symbol::indirect(boost::make_shared(p))); + result.push_back(Symbol::indirect(std::make_shared(p))); } } } @@ -249,7 +247,7 @@ Production ResolvingGrammarGenerator::doGenerate( Symbol r[] = {Symbol::sizeCheckSymbol(reader->fixedSize()), Symbol::fixedSymbol()}; Production result(r, r + 2); - m[make_pair(writer, reader)] = boost::make_shared(result); + m[make_pair(writer, reader)] = std::make_shared(result); return result; } break; @@ -261,7 +259,7 @@ Production ResolvingGrammarGenerator::doGenerate( const bool found = m.find(key) != m.end(); - shared_ptr p = boost::make_shared(result); + shared_ptr p = std::make_shared(result); m[key] = p; return found ? Production(1, Symbol::indirect(p)) : result; } @@ -272,7 +270,7 @@ Production ResolvingGrammarGenerator::doGenerate( Symbol r[] = {Symbol::enumAdjustSymbol(writer, reader), Symbol::enumSymbol(), }; Production result(r, r + 2); - m[make_pair(writer, reader)] = boost::make_shared(result); + m[make_pair(writer, reader)] = std::make_shared(result); return result; } break; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/Symbol.hh b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/Symbol.hh index 61031e97e6..321ca1c140 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/Symbol.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/Symbol.hh @@ -25,8 +25,7 @@ #include #include -#include -#include +#include #include #include "Node.hh" @@ -202,11 +201,11 @@ class Symbol { return Symbol(sPlaceholder, n); } - static Symbol indirect(const boost::shared_ptr& p) { + static Symbol indirect(const std::shared_ptr& p) { return Symbol(sIndirect, p); } - static Symbol symbolic(const boost::weak_ptr& p) { + static Symbol symbolic(const std::weak_ptr& p) { return Symbol(sSymbolic, p); } @@ -233,17 +232,17 @@ class Symbol { template void fixup(Production& p, - const std::map >& m) { + const std::map >& m) { for (Production::iterator it = p.begin(); it != p.end(); ++it) { fixup(*it, m); } } template -void fixup(Symbol& s, const std::map >& m) { +void fixup(Symbol& s, const std::map >& m) { switch (s.kind()) { case Symbol::sIndirect: - fixup(*s.extra >(), m); + fixup(*s.extra >(), m); break; case Symbol::sAlternative: { std::vector* vv = s.extrap >(); @@ -259,7 +258,7 @@ void fixup(Symbol& s, const std::map >& m) { } break; case Symbol::sPlaceholder: s = Symbol::symbolic( - boost::weak_ptr(m.find(s.extra())->second)); + std::weak_ptr(m.find(s.extra())->second)); break; case Symbol::sUnionAdjust: fixup(s.extrap >()->second, m); @@ -325,15 +324,15 @@ class SimpleParser { append(boost::tuples::get<0>(*s.extrap())); continue; case Symbol::sIndirect: { - boost::shared_ptr pp = - s.extra >(); + std::shared_ptr pp = + s.extra >(); parsingStack.pop(); append(*pp); } continue; case Symbol::sSymbolic: { - boost::shared_ptr pp( - s.extra >()); + std::shared_ptr pp( + s.extra >()); parsingStack.pop(); append(*pp); } @@ -465,15 +464,15 @@ class SimpleParser { } } break; case Symbol::sIndirect: { - boost::shared_ptr pp = - t.extra >(); + std::shared_ptr pp = + t.extra >(); parsingStack.pop(); append(*pp); } continue; case Symbol::sSymbolic: { - boost::shared_ptr pp( - t.extra >()); + std::shared_ptr pp( + t.extra >()); parsingStack.pop(); append(*pp); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.cc b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.cc index 00ab7e0eb7..c0f473897b 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.cc @@ -22,9 +22,7 @@ #include #include #include -#include -#include -#include +#include #include #include "ValidSchema.hh" @@ -36,9 +34,9 @@ namespace internal_avro { namespace parsing { -using boost::shared_ptr; -using boost::weak_ptr; -using boost::static_pointer_cast; +using std::shared_ptr; +using std::weak_ptr; +using std::static_pointer_cast; using std::map; using std::vector; @@ -82,7 +80,7 @@ Production ValidatingGrammarGenerator::doGenerate( Symbol r[] = {Symbol::sizeCheckSymbol(n->fixedSize()), Symbol::fixedSymbol()}; Production result(r, r + 2); - m[n] = boost::make_shared(result); + m[n] = std::make_shared(result); return result; } case AVRO_RECORD: { @@ -99,7 +97,7 @@ Production ValidatingGrammarGenerator::doGenerate( bool found = m.find(n) != m.end(); - shared_ptr p = boost::make_shared(result); + shared_ptr p = std::make_shared(result); m[n] = p; return found ? Production(1, Symbol::indirect(p)) : result; @@ -107,7 +105,7 @@ Production ValidatingGrammarGenerator::doGenerate( case AVRO_ENUM: { Symbol r[] = {Symbol::sizeCheckSymbol(n->names()), Symbol::enumSymbol()}; Production result(r, r + 2); - m[n] = boost::make_shared(result); + m[n] = std::make_shared(result); return result; } case AVRO_ARRAY: { @@ -513,13 +511,13 @@ void ValidatingEncoder

::encodeUnionIndex(size_t e) { } // namespace parsing DecoderPtr validatingDecoder(const ValidSchema& s, const DecoderPtr& base) { - return boost::make_shared > >(s, base); } EncoderPtr validatingEncoder(const ValidSchema& schema, const EncoderPtr& base) { - return boost::make_shared > >(schema, base); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.hh b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.hh index 441cd67265..1f2b934550 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.hh +++ b/modules/rmf/dependency/RMF/src/avrocpp/impl/parsing/ValidatingCodec.hh @@ -21,7 +21,6 @@ #include #include -#include "boost/make_shared.hpp" #include "Symbol.hh" #include "ValidSchema.hh" @@ -34,13 +33,13 @@ class ValidatingGrammarGenerator { protected: template static void doFixup(Production& p, - const std::map >& m); + const std::map >& m); template static void doFixup(Symbol& s, - const std::map >& m); + const std::map >& m); virtual Production doGenerate( - const NodePtr& n, std::map >& m); + const NodePtr& n, std::map >& m); Production generate(const NodePtr& schema); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/AvrogencppTests.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/AvrogencppTests.cc index b3dade27b3..09f70a6a5a 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/AvrogencppTests.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/AvrogencppTests.cc @@ -119,7 +119,7 @@ void testEncoding() { ValidSchema s; ifstream ifs("jsonschemas/bigrecord"); compileJsonSchema(ifs, s); - boost::shared_ptr os = memoryOutputStream(); + std::shared_ptr os = memoryOutputStream(); EncoderPtr e = validatingEncoder(s, binaryEncoder()); e->init(*os); testgen::RootRecord t1; @@ -128,7 +128,7 @@ void testEncoding() { e->flush(); DecoderPtr d = validatingDecoder(s, binaryDecoder()); - boost::shared_ptr is = memoryInputStream(*os); + std::shared_ptr is = memoryInputStream(*os); d->init(*is); testgen::RootRecord t2; internal_avro::decode(*d, t2); @@ -177,7 +177,7 @@ void testEncoding2() { ifstream ifs(schemaFilename::value); compileJsonSchema(ifs, s); - boost::shared_ptr os = memoryOutputStream(); + std::shared_ptr os = memoryOutputStream(); EncoderPtr e = validatingEncoder(s, binaryEncoder()); e->init(*os); T t1; @@ -186,7 +186,7 @@ void testEncoding2() { e->flush(); DecoderPtr d = validatingDecoder(s, binaryDecoder()); - boost::shared_ptr is = memoryInputStream(*os); + std::shared_ptr is = memoryInputStream(*os); d->init(*is); T t2; internal_avro::decode(*d, t2); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/CodecTests.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/CodecTests.cc index 1fa9e77dd1..862766b297 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/CodecTests.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/CodecTests.cc @@ -43,7 +43,7 @@ namespace internal_avro { /* void dump(const OutputStream& os) { - boost::shared_ptr in = memoryInputStream(os); + std::shared_ptr in = memoryInputStream(os); const char *b; size_t n; std::cout << os.byteCount() << std::endl; @@ -221,11 +221,11 @@ static vector randomValues(const char* calls) { return result; } -static boost::shared_ptr generate(Encoder& e, const char* calls, +static std::shared_ptr generate(Encoder& e, const char* calls, const vector& values) { Scanner sc(calls); vector::const_iterator it = values.begin(); - boost::shared_ptr ob = memoryOutputStream(); + std::shared_ptr ob = memoryOutputStream(); e.init(*ob); while (!sc.isDone()) { @@ -501,7 +501,7 @@ ValidSchema makeValidSchema(const char* schema) { } void testEncoder(const EncoderPtr& e, const char* writerCalls, - vector& v, boost::shared_ptr& p) { + vector& v, std::shared_ptr& p) { v = randomValues(writerCalls); p = generate(*e, writerCalls, v); } @@ -577,7 +577,7 @@ void testCodec(const TestData& td) { for (unsigned int i = 0; i < count; ++i) { vector v; - boost::shared_ptr p; + std::shared_ptr p; testEncoder(CodecFactory::newEncoder(vs), td.calls, v, p); // dump(*p); @@ -592,7 +592,7 @@ void testCodec(const TestData& td) { BOOST_TEST_CHECKPOINT("Test: " << testNo << ' ' << " schema: " << td.schema << " calls: " << td.calls << " skip-level: " << skipLevel); - boost::shared_ptr in = memoryInputStream(*p); + std::shared_ptr in = memoryInputStream(*p); testDecoder(CodecFactory::newDecoder(vs), v, *in, td.calls, skipLevel); } } @@ -613,7 +613,7 @@ void testCodecResolving(const TestData3& td) { for (unsigned int i = 0; i < count; ++i) { vector v; - boost::shared_ptr p; + std::shared_ptr p; testEncoder(CodecFactory::newEncoder(vs), td.writerCalls, v, p); // dump(*p); @@ -626,7 +626,7 @@ void testCodecResolving(const TestData3& td) { << " reader schema: " << td.readerSchema << " reader calls: " << td.readerCalls << " skip-level: " << skipLevel); - boost::shared_ptr in = memoryInputStream(*p); + std::shared_ptr in = memoryInputStream(*p); testDecoder(CodecFactory::newDecoder(vs, rvs), v, *in, td.readerCalls, skipLevel); } @@ -655,7 +655,7 @@ void testCodecResolving2(const TestData4& td) { ValidSchema vs = makeValidSchema(td.writerSchema); vector wd = mkValues(td.writerValues); - boost::shared_ptr p = + std::shared_ptr p = generate(*CodecFactory::newEncoder(vs), td.writerCalls, wd); // dump(*p); @@ -669,7 +669,7 @@ void testCodecResolving2(const TestData4& td) { << " reader schema: " << td.readerSchema << " reader calls: " << td.readerCalls << " skip-level: " << skipLevel); - boost::shared_ptr in = memoryInputStream(*p); + std::shared_ptr in = memoryInputStream(*p); testDecoder(CodecFactory::newDecoder(vs, rvs), rd, *in, td.readerCalls, skipLevel); } @@ -686,9 +686,9 @@ void testReaderFail(const TestData2& td) { ValidSchema vs = makeValidSchema(td.schema); vector v; - boost::shared_ptr p; + std::shared_ptr p; testEncoder(CodecFactory::newEncoder(vs), td.correctCalls, v, p); - boost::shared_ptr in = memoryInputStream(*p); + std::shared_ptr in = memoryInputStream(*p); BOOST_CHECK_THROW(testDecoder(CodecFactory::newDecoder(vs), v, *in, td.incorrectCalls, td.depth), Exception); @@ -703,7 +703,7 @@ void testWriterFail(const TestData2& td) { ValidSchema vs = makeValidSchema(td.schema); vector v; - boost::shared_ptr p; + std::shared_ptr p; BOOST_CHECK_THROW( testEncoder(CodecFactory::newEncoder(vs), td.incorrectCalls, v, p), Exception); @@ -718,17 +718,17 @@ void testGeneric(const TestData& td) { for (unsigned int i = 0; i < count; ++i) { vector v; - boost::shared_ptr p; + std::shared_ptr p; testEncoder(CodecFactory::newEncoder(vs), td.calls, v, p); // dump(*p); DecoderPtr d1 = CodecFactory::newDecoder(vs); - boost::shared_ptr in1 = memoryInputStream(*p); + std::shared_ptr in1 = memoryInputStream(*p); d1->init(*in1); GenericDatum datum(vs); internal_avro::decode(*d1, datum); EncoderPtr e2 = CodecFactory::newEncoder(vs); - boost::shared_ptr ob = memoryOutputStream(); + std::shared_ptr ob = memoryOutputStream(); e2->init(*ob); internal_avro::encode(*e2, datum); @@ -736,7 +736,7 @@ void testGeneric(const TestData& td) { BOOST_TEST_CHECKPOINT("Test: " << testNo << ' ' << " schema: " << td.schema << " calls: " << td.calls); - boost::shared_ptr in2 = memoryInputStream(*ob); + std::shared_ptr in2 = memoryInputStream(*ob); testDecoder(CodecFactory::newDecoder(vs), v, *in2, td.calls, td.depth); } } @@ -757,11 +757,11 @@ void testGenericResolving(const TestData3& td) { for (unsigned int i = 0; i < count; ++i) { vector v; - boost::shared_ptr p; + std::shared_ptr p; testEncoder(CodecFactory::newEncoder(wvs), td.writerCalls, v, p); // dump(*p); DecoderPtr d1 = CodecFactory::newDecoder(wvs); - boost::shared_ptr in1 = memoryInputStream(*p); + std::shared_ptr in1 = memoryInputStream(*p); d1->init(*in1); GenericReader gr(wvs, rvs, d1); @@ -769,7 +769,7 @@ void testGenericResolving(const TestData3& td) { gr.read(datum); EncoderPtr e2 = CodecFactory::newEncoder(rvs); - boost::shared_ptr ob = memoryOutputStream(); + std::shared_ptr ob = memoryOutputStream(); e2->init(*ob); internal_avro::encode(*e2, datum); e2->flush(); @@ -779,7 +779,7 @@ void testGenericResolving(const TestData3& td) { << " writer-calls: " << td.writerCalls << " reader-schema: " << td.readerSchema << " calls: " << td.readerCalls); - boost::shared_ptr in2 = memoryInputStream(*ob); + std::shared_ptr in2 = memoryInputStream(*ob); testDecoder(CodecFactory::newDecoder(rvs), v, *in2, td.readerCalls, td.depth); } @@ -801,11 +801,11 @@ void testGenericResolving2(const TestData4& td) { const vector wd = mkValues(td.writerValues); - boost::shared_ptr p = + std::shared_ptr p = generate(*CodecFactory::newEncoder(wvs), td.writerCalls, wd); // dump(*p); DecoderPtr d1 = CodecFactory::newDecoder(wvs); - boost::shared_ptr in1 = memoryInputStream(*p); + std::shared_ptr in1 = memoryInputStream(*p); d1->init(*in1); GenericReader gr(wvs, rvs, d1); @@ -813,7 +813,7 @@ void testGenericResolving2(const TestData4& td) { gr.read(datum); EncoderPtr e2 = CodecFactory::newEncoder(rvs); - boost::shared_ptr ob = memoryOutputStream(); + std::shared_ptr ob = memoryOutputStream(); e2->init(*ob); internal_avro::encode(*e2, datum); e2->flush(); @@ -1384,7 +1384,7 @@ void add_tests(boost::unit_test::test_suite& ts) { static void testStreamLifetimes() { EncoderPtr e = binaryEncoder(); { - boost::shared_ptr s1 = memoryOutputStream(); + std::shared_ptr s1 = memoryOutputStream(); e->init(*s1); e->encodeInt(100); e->encodeDouble(4.73); @@ -1392,7 +1392,7 @@ static void testStreamLifetimes() { } { - boost::shared_ptr s2 = memoryOutputStream(); + std::shared_ptr s2 = memoryOutputStream(); e->init(*s2); e->encodeDouble(3.14); e->flush(); @@ -1400,7 +1400,7 @@ static void testStreamLifetimes() { } static void testLimits(const EncoderPtr& e, const DecoderPtr& d) { - boost::shared_ptr s1 = memoryOutputStream(); + std::shared_ptr s1 = memoryOutputStream(); { e->init(*s1); e->encodeDouble(std::numeric_limits::infinity()); @@ -1413,7 +1413,7 @@ static void testLimits(const EncoderPtr& e, const DecoderPtr& d) { } { - boost::shared_ptr s2 = memoryInputStream(*s1); + std::shared_ptr s2 = memoryInputStream(*s1); d->init(*s2); BOOST_CHECK_EQUAL(d->decodeDouble(), std::numeric_limits::infinity()); diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/DataFileTests.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/DataFileTests.cc index 1d7c4f7244..c79346ebe1 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/DataFileTests.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/DataFileTests.cc @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "DataFile.hh" @@ -27,7 +26,7 @@ #include "Stream.hh" #include "Compiler.hh" -using boost::shared_ptr; +using std::shared_ptr; using std::string; using std::pair; using std::vector; @@ -35,8 +34,8 @@ using std::map; using std::istringstream; using std::ostringstream; -using boost::array; -using boost::shared_ptr; +using std::array; +using std::shared_ptr; using boost::unit_test::test_suite; using internal_avro::ValidSchema; @@ -323,7 +322,7 @@ class DataFileTest { * Constructs the DataFileReader in two steps. */ void testReadDoubleTwoStep() { - boost::shared_ptr base( + std::shared_ptr base( new internal_avro::DataFileReaderBase(filename)); internal_avro::DataFileReader df(base); BOOST_CHECK_EQUAL(toString(writerSchema), toString(df.readerSchema())); @@ -347,7 +346,7 @@ class DataFileTest { * reader schema. */ void testReadDoubleTwoStepProject() { - boost::shared_ptr base( + std::shared_ptr base( new internal_avro::DataFileReaderBase(filename)); internal_avro::DataFileReader df(base, readerSchema); @@ -375,7 +374,7 @@ class DataFileTest { // first create a large file ValidSchema dschema = internal_avro::compileJsonSchemaFromString(prsch); { - boost::shared_ptr > writer( + std::shared_ptr > writer( new internal_avro::DataFileWriter(filename, dschema)); for (size_t i = 0; i < number_of_objects; ++i) { @@ -392,7 +391,7 @@ class DataFileTest { // check seeking to the start and end { - boost::shared_ptr > reader( + std::shared_ptr > reader( new internal_avro::DataFileReader(filename)); BOOST_REQUIRE_NE(reader->sizeBytes(), -1); // test that seek to the start gets the first element @@ -410,7 +409,7 @@ class DataFileTest { { std::vector dividers; { - boost::shared_ptr > reader( + std::shared_ptr > reader( new internal_avro::DataFileReader(filename)); int size = reader->sizeBytes(); dividers.push_back(reader->blockOffsetBytes()); @@ -424,7 +423,7 @@ class DataFileTest { } std::vector found; for (size_t i = 1; i < dividers.size(); ++i) { - boost::shared_ptr > reader( + std::shared_ptr > reader( new internal_avro::DataFileReader(filename)); reader->seekBlockBytes(dividers[i - 1]); block_offsets.insert(reader->blockOffsetBytes()); @@ -446,7 +445,7 @@ class DataFileTest { { for (std::set::const_iterator it = block_offsets.begin(); it != block_offsets.end(); ++it) { - boost::shared_ptr > reader( + std::shared_ptr > reader( new internal_avro::DataFileReader(filename)); reader->seekBlockBytes(*it); BOOST_CHECK_EQUAL(reader->blockOffsetBytes(), *it); @@ -462,11 +461,11 @@ class DataFileTest { const size_t number_of_objects = 100; // first create a large file ValidSchema dschema = internal_avro::compileJsonSchemaFromString(prsch); - boost::shared_ptr buf = + std::shared_ptr buf = internal_avro::memoryOutputStream(); { - boost::shared_ptr > writer = - boost::make_shared >( + std::shared_ptr > writer = + std::make_shared >( buf, dschema); for (size_t i = 0; i < number_of_objects; ++i) { @@ -482,10 +481,10 @@ class DataFileTest { } { { - boost::shared_ptr inbuf = + std::shared_ptr inbuf = internal_avro::memoryInputStream(*buf); - boost::shared_ptr > reader = - boost::make_shared >( + std::shared_ptr > reader = + std::make_shared >( inbuf); std::vector found; PaddedRecord record; @@ -509,8 +508,8 @@ class DataFileTest { // first create a large file ValidSchema dschema = internal_avro::compileJsonSchemaFromString(prsch); { - boost::shared_ptr > writer = - boost::make_shared >( + std::shared_ptr > writer = + std::make_shared >( filename, dschema, 16 * 1024, internal_avro::DEFLATE_CODEC); for (size_t i = 0; i < number_of_objects; ++i) { @@ -526,8 +525,8 @@ class DataFileTest { } { { - boost::shared_ptr > reader = - boost::make_shared >( + std::shared_ptr > reader = + std::make_shared >( filename, dschema); std::vector found; PaddedRecord record; diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/SpecificTests.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/SpecificTests.cc index 18d8aac868..7c1cc4add6 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/SpecificTests.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/SpecificTests.cc @@ -25,7 +25,7 @@ using std::string; using std::vector; using std::map; -using boost::array; +using std::array; namespace internal_avro { @@ -60,7 +60,7 @@ struct codec_traits { namespace specific { class Test { - boost::shared_ptr os; + std::shared_ptr os; EncoderPtr e; DecoderPtr d; @@ -77,7 +77,7 @@ class Test { template void decode(T& t) { - boost::shared_ptr is = memoryInputStream(*os); + std::shared_ptr is = memoryInputStream(*os); d->init(*is); internal_avro::decode(*d, t); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/StreamTests.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/StreamTests.cc index 76aaf25dd1..687aa5657f 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/StreamTests.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/StreamTests.cc @@ -105,17 +105,17 @@ struct Verify2 { template void testEmpty_memoryStream() { - boost::shared_ptr os = memoryOutputStream(); - boost::shared_ptr is = memoryInputStream(*os); + std::shared_ptr os = memoryOutputStream(); + std::shared_ptr is = memoryInputStream(*os); V()(*is); } template void testNonEmpty_memoryStream(const TestData& td) { - boost::shared_ptr os = memoryOutputStream(td.chunkSize); + std::shared_ptr os = memoryOutputStream(td.chunkSize); F()(*os, td.dataSize); - boost::shared_ptr is = memoryInputStream(*os); + std::shared_ptr is = memoryInputStream(*os); V()(*is, td.dataSize); } @@ -126,7 +126,7 @@ void testNonEmpty2(const TestData& td) { } uint8_t v2 = 0; - boost::shared_ptr is = + std::shared_ptr is = memoryInputStream(v.empty() ? &v2 : &v[0], v.size()); Verify1()(*is, td.dataSize); } @@ -142,8 +142,8 @@ struct FileRemover { template void testEmpty_fileStream() { FileRemover fr(filename); - { boost::shared_ptr os = fileOutputStream(filename); } - boost::shared_ptr is = fileInputStream(filename); + { std::shared_ptr os = fileOutputStream(filename); } + std::shared_ptr is = fileInputStream(filename); V()(*is); } @@ -151,12 +151,12 @@ template void testNonEmpty_fileStream(const TestData& td) { FileRemover fr(filename); { - boost::shared_ptr os = + std::shared_ptr os = fileOutputStream(filename, td.chunkSize); F()(*os, td.dataSize); } - boost::shared_ptr is = fileInputStream(filename, td.chunkSize); + std::shared_ptr is = fileInputStream(filename, td.chunkSize); V()(*is, td.dataSize); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/testgentest.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/testgentest.cc index be749a49a1..d326ea7d21 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/testgentest.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/testgentest.cc @@ -506,7 +506,7 @@ struct TestSchemaResolving { template void addTestCase(boost::unit_test::test_suite &test) { - boost::shared_ptr newtest(new T); + std::shared_ptr newtest(new T); test.add(BOOST_CLASS_TEST_CASE(&T::test, newtest)); } diff --git a/modules/rmf/dependency/RMF/src/avrocpp/test/unittest.cc b/modules/rmf/dependency/RMF/src/avrocpp/test/unittest.cc index 829568259a..186ea547ed 100644 --- a/modules/rmf/dependency/RMF/src/avrocpp/test/unittest.cc +++ b/modules/rmf/dependency/RMF/src/avrocpp/test/unittest.cc @@ -317,7 +317,7 @@ struct TestSchema { template void readFixed(Parser &p) { - boost::array input; + std::array input; p.readFixed(input); BOOST_CHECK_EQUAL(input.size(), 16U); @@ -728,7 +728,7 @@ struct TestResolution { template void addTestCase(boost::unit_test::test_suite &test) { - boost::shared_ptr newtest(new T); + std::shared_ptr newtest(new T); test.add(BOOST_CLASS_TEST_CASE(&T::test, newtest)); } diff --git a/modules/rmf/dependency/RMF/src/backend/BackwardsIO.cpp b/modules/rmf/dependency/RMF/src/backend/BackwardsIO.cpp index 4fbc3fb5c9..b1a8e2efee 100644 --- a/modules/rmf/dependency/RMF/src/backend/BackwardsIO.cpp +++ b/modules/rmf/dependency/RMF/src/backend/BackwardsIO.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "BackwardsIO.h" @@ -8,17 +8,17 @@ RMF_ENABLE_WARNINGS namespace RMF { namespace backends { namespace { -boost::array make_array(std::string a, std::string b, +std::array make_array(std::string a, std::string b, std::string c) { - boost::array ret; + std::array ret; ret[0] = a; ret[1] = b; ret[2] = c; return ret; } -boost::array make_array(std::string a, std::string b, +std::array make_array(std::string a, std::string b, std::string c, std::string d) { - boost::array ret; + std::array ret; ret[0] = a; ret[1] = b; ret[2] = c; @@ -26,7 +26,7 @@ boost::array make_array(std::string a, std::string b, return ret; } } -typedef std::pair > P3; +typedef std::pair > P3; const P3 vector_3_names[] = { P3("coordinates", make_array("cartesian x", "cartesian y", "cartesian z")), P3("translation", @@ -40,11 +40,11 @@ const P3 vector_3_names[] = { "torque cartesian z"))}; const int vector_3_names_size = sizeof(vector_3_names) / - sizeof(std::pair >); + sizeof(std::pair >); V3N vector_3_names_map(vector_3_names, vector_3_names + vector_3_names_size); -typedef std::pair > P4; +typedef std::pair > P4; const P4 vector_4_names[] = { P4("orientation", make_array("orientation r", "orientation i", @@ -55,7 +55,7 @@ const P4 vector_4_names[] = { "reference frame orientation k"))}; const int vector_4_names_size = sizeof(vector_4_names) / - sizeof(std::pair >); + sizeof(std::pair >); V4N vector_4_names_map(vector_4_names, vector_4_names + vector_4_names_size); @@ -64,7 +64,7 @@ const P3 vectors_3_names[] = { make_array("cartesian xs", "cartesian ys", "cartesian zs"))}; const int vectors_3_names_size = sizeof(vectors_3_names) / - sizeof(std::pair >); + sizeof(std::pair >); V3N vectors_3_names_map(vectors_3_names, vectors_3_names + vectors_3_names_size); diff --git a/modules/rmf/dependency/RMF/src/backend/BackwardsIO.h b/modules/rmf/dependency/RMF/src/backend/BackwardsIO.h index c6f326b69d..426f58e38d 100644 --- a/modules/rmf/dependency/RMF/src/backend/BackwardsIO.h +++ b/modules/rmf/dependency/RMF/src/backend/BackwardsIO.h @@ -9,7 +9,7 @@ #ifndef RMF_INTERNAL_BACKWARDS_IO_H #define RMF_INTERNAL_BACKWARDS_IO_H -#include +#include #include #include #include @@ -41,11 +41,11 @@ RMF_ENABLE_WARNINGS namespace RMF { namespace backends { - typedef RMF_LARGE_UNORDERED_MAP > + typedef RMF_LARGE_UNORDERED_MAP > V3N; extern V3N vector_3_names_map; extern V3N vectors_3_names_map; - typedef RMF_LARGE_UNORDERED_MAP > + typedef RMF_LARGE_UNORDERED_MAP > V4N; extern V4N vector_4_names_map; @@ -92,13 +92,13 @@ RMF_ENABLE_WARNINGS namespace RMF { } template - inline boost::array get_vector_subkey_names( + inline std::array get_vector_subkey_names( std::string key_name, RMF_VECTOR) const { typename RMF_LARGE_UNORDERED_MAP< - std::string, boost::array >::const_iterator it = + std::string, std::array >::const_iterator it = get_vector_names_map(RMF_VECTOR()).find(key_name); if (it == get_vector_names_map(RMF_VECTOR()).end()) { - boost::array ret; + std::array ret; for (unsigned int i = 0; i < D; ++i) { std::ostringstream ossk; ossk << "_" << key_name << "_" << i; @@ -111,13 +111,13 @@ RMF_ENABLE_WARNINGS namespace RMF { } template - inline boost::array get_vectors_subkey_names( + inline std::array get_vectors_subkey_names( std::string key_name, RMF_VECTOR) const { typename RMF_LARGE_UNORDERED_MAP< - std::string, boost::array >::const_iterator it = + std::string, std::array >::const_iterator it = get_vectors_names_map(RMF_VECTOR()).find(key_name); if (it == get_vectors_names_map(RMF_VECTOR()).end()) { - boost::array ret; + std::array ret; for (unsigned int i = 0; i < D; ++i) { std::ostringstream ossk; ossk << "_" << key_name << "_" << i; @@ -139,7 +139,7 @@ RMF_ENABLE_WARNINGS namespace RMF { if (key != StringsKey()) { ret = sd_->get_static_value(NodeID(0), key); } - typedef std::pair > KP; + typedef std::pair > KP; for(KP kp : get_vector_names_map(RMF_VECTOR())) { ret.push_back(kp.first); } @@ -158,7 +158,7 @@ RMF_ENABLE_WARNINGS namespace RMF { if (key != StringsKey()) { ret = sd_->get_static_value(NodeID(0), key); } - typedef std::pair > KP; + typedef std::pair > KP; for(KP kp : get_vectors_names_map(RMF_VECTOR())) { ret.push_back(kp.first); } @@ -174,7 +174,7 @@ RMF_ENABLE_WARNINGS namespace RMF { RMF_LARGE_UNORDERED_MAP map; for(std::string key_name : get_vector_names(category_b, RMF_VECTOR())) { - boost::array subkey_names = + std::array subkey_names = get_vector_subkey_names(key_name, RMF_VECTOR()); for (unsigned int i = 0; i < D; ++i) { FloatKey cur_key = @@ -202,13 +202,13 @@ RMF_ENABLE_WARNINGS namespace RMF { typedef ID > > VectorKey; std::vector keys = sda->get_keys(category_a, Traits >()); - typedef boost::array, D> Data; + typedef std::array, D> Data; RMF_LARGE_UNORDERED_MAP map; Strings key_names; for(VectorKey k : keys) { std::string name = sda->get_name(k); key_names.push_back(name); - boost::array subkey_names = + std::array subkey_names = get_vector_subkey_names(name, RMF_VECTOR()); for (unsigned int i = 0; i < D; ++i) { map[k][i] = sdb->get_key(category_b, subkey_names[i], FloatTraits()); @@ -241,7 +241,7 @@ RMF_ENABLE_WARNINGS namespace RMF { RMF_LARGE_UNORDERED_MAP map; for(std::string key_name : get_vectors_names(category_b, RMF_VECTOR<3>())) { - boost::array subkey_names = + std::array subkey_names = get_vectors_subkey_names(key_name, RMF_VECTOR<3>()); for (unsigned int i = 0; i < 3; ++i) { FloatsKey cur_key = @@ -273,13 +273,13 @@ RMF_ENABLE_WARNINGS namespace RMF { Category category_b, H) { typedef Vector3sKey VectorKey; std::vector keys = sda->get_keys(category_a, Vector3sTraits()); - typedef boost::array, 3> Data; + typedef std::array, 3> Data; RMF_LARGE_UNORDERED_MAP map; Strings key_names; for(VectorKey k : keys) { std::string name = sda->get_name(k); key_names.push_back(name); - boost::array subkey_names = + std::array subkey_names = get_vectors_subkey_names(name, RMF_VECTOR<3>()); for (unsigned int i = 0; i < 3; ++i) { map[k][i] = sdb->get_key(category_b, subkey_names[i], FloatsTraits()); diff --git a/modules/rmf/dependency/RMF/src/backend/IO.cpp b/modules/rmf/dependency/RMF/src/backend/IO.cpp index d69a57798c..376bf6482d 100644 --- a/modules/rmf/dependency/RMF/src/backend/IO.cpp +++ b/modules/rmf/dependency/RMF/src/backend/IO.cpp @@ -30,16 +30,16 @@ namespace RMF { namespace backends { namespace { RMF_LARGE_UNORDERED_MAP test_buffers; -struct GetFactories : public std::vector > { +struct GetFactories : public std::vector > { GetFactories() { - std::vector > favro2 = avro2::get_factories(); + std::vector > favro2 = avro2::get_factories(); insert(end(), favro2.begin(), favro2.end()); #if RMF_HAS_DEPRECATED_BACKENDS - std::vector > fhdf5 = + std::vector > fhdf5 = hdf5_backend::get_factories(); insert(end(), fhdf5.begin(), fhdf5.end()); - std::vector > favro = + std::vector > favro = avro_backend::get_factories(); insert(end(), favro.begin(), favro.end()); #endif @@ -47,7 +47,7 @@ struct GetFactories : public std::vector > { } factories; } -boost::shared_ptr create_file(const std::string &name) { +std::shared_ptr create_file(const std::string &name) { if (boost::filesystem::exists(name)) { unlink(name.c_str()); } @@ -55,30 +55,30 @@ boost::shared_ptr create_file(const std::string &name) { test_buffers[name] = BufferHandle(); return create_buffer(test_buffers.find(name)->second); } else { - for(boost::shared_ptr f : factories) { + for(std::shared_ptr f : factories) { if (!boost::algorithm::ends_with(name, f->get_file_extension())) continue; - boost::shared_ptr cur = f->create_file(name); + std::shared_ptr cur = f->create_file(name); if (cur) return cur; } } - return boost::shared_ptr(); + return std::shared_ptr(); } -boost::shared_ptr create_buffer(BufferHandle buffer) { - for(boost::shared_ptr f : factories) { - boost::shared_ptr cur = f->create_buffer(buffer); +std::shared_ptr create_buffer(BufferHandle buffer) { + for(std::shared_ptr f : factories) { + std::shared_ptr cur = f->create_buffer(buffer); if (cur) return cur; } - return boost::shared_ptr(); + return std::shared_ptr(); } -boost::shared_ptr read_file(const std::string &name) { +std::shared_ptr read_file(const std::string &name) { if (boost::algorithm::ends_with(name, "_rmf_test_buffer")) { return read_buffer(test_buffers.find(name)->second); } else { - for(boost::shared_ptr f : factories) { + for(std::shared_ptr f : factories) { // if (!boost::algorithm::ends_with(name, f->get_file_extension())) // continue; try { - boost::shared_ptr cur = f->read_file(name); + std::shared_ptr cur = f->read_file(name); if (cur) return cur; } catch (const std::exception &e) { @@ -86,14 +86,14 @@ boost::shared_ptr read_file(const std::string &name) { } } } - return boost::shared_ptr(); + return std::shared_ptr(); } -boost::shared_ptr read_buffer(BufferConstHandle buffer) { - for(boost::shared_ptr f : factories) { - boost::shared_ptr cur = f->read_buffer(buffer); +std::shared_ptr read_buffer(BufferConstHandle buffer) { + for(std::shared_ptr f : factories) { + std::shared_ptr cur = f->read_buffer(buffer); if (cur) return cur; } - return boost::shared_ptr(); + return std::shared_ptr(); } } } diff --git a/modules/rmf/dependency/RMF/src/backend/IO.h b/modules/rmf/dependency/RMF/src/backend/IO.h index 5ffbf287ec..693f6c9b06 100644 --- a/modules/rmf/dependency/RMF/src/backend/IO.h +++ b/modules/rmf/dependency/RMF/src/backend/IO.h @@ -9,7 +9,7 @@ #ifndef RMF_INTERNAL_IO_H #define RMF_INTERNAL_IO_H -#include +#include #include #include "RMF/BufferConstHandle.h" @@ -59,10 +59,10 @@ struct IO { virtual ~IO() {} }; -RMFEXPORT boost::shared_ptr create_file(const std::string &name); -RMFEXPORT boost::shared_ptr create_buffer(BufferHandle buffer); -RMFEXPORT boost::shared_ptr read_file(const std::string &name); -RMFEXPORT boost::shared_ptr read_buffer(BufferConstHandle buffer); +RMFEXPORT std::shared_ptr create_file(const std::string &name); +RMFEXPORT std::shared_ptr create_buffer(BufferHandle buffer); +RMFEXPORT std::shared_ptr read_file(const std::string &name); +RMFEXPORT std::shared_ptr read_buffer(BufferConstHandle buffer); } // namespace internal } /* namespace RMF */ diff --git a/modules/rmf/dependency/RMF/src/backend/IOFactory.h b/modules/rmf/dependency/RMF/src/backend/IOFactory.h index 12af15065d..a2baf30f50 100644 --- a/modules/rmf/dependency/RMF/src/backend/IOFactory.h +++ b/modules/rmf/dependency/RMF/src/backend/IOFactory.h @@ -14,7 +14,7 @@ #include "RMF/BufferHandle.h" #include "RMF/BufferConstHandle.h" #include "RMF/infrastructure_macros.h" -#include +#include RMF_ENABLE_WARNINGS @@ -25,17 +25,17 @@ namespace backends { class IOFactory { public: virtual std::string get_file_extension() const = 0; - virtual boost::shared_ptr read_buffer(BufferConstHandle) const { - return boost::shared_ptr(); + virtual std::shared_ptr read_buffer(BufferConstHandle) const { + return std::shared_ptr(); } - virtual boost::shared_ptr read_file(const std::string &) const { - return boost::shared_ptr(); + virtual std::shared_ptr read_file(const std::string &) const { + return std::shared_ptr(); } - virtual boost::shared_ptr create_buffer(BufferHandle) const { - return boost::shared_ptr(); + virtual std::shared_ptr create_buffer(BufferHandle) const { + return std::shared_ptr(); } - virtual boost::shared_ptr create_file(const std::string &) const { - return boost::shared_ptr(); + virtual std::shared_ptr create_file(const std::string &) const { + return std::shared_ptr(); } virtual ~IOFactory() {} }; diff --git a/modules/rmf/dependency/RMF/src/backend/SharedDataAdaptor.h b/modules/rmf/dependency/RMF/src/backend/SharedDataAdaptor.h index 68460c13fd..6d49863052 100644 --- a/modules/rmf/dependency/RMF/src/backend/SharedDataAdaptor.h +++ b/modules/rmf/dependency/RMF/src/backend/SharedDataAdaptor.h @@ -12,7 +12,7 @@ #include "RMF/config.h" #include "RMF/internal/SharedData.h" #include "RMF/log.h" -#include +#include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/src/backend/avro/Frame.json b/modules/rmf/dependency/RMF/src/backend/avro/Frame.json index 3bc96d562c..faa4576201 100644 --- a/modules/rmf/dependency/RMF/src/backend/avro/Frame.json +++ b/modules/rmf/dependency/RMF/src/backend/avro/Frame.json @@ -64,7 +64,7 @@ "type": "record", "name": "KeyInfo", "fields":[ - { "name": "id", "type": "int"} + { "name": "id", "type": "int"}, { "name": "name", "type": "string"}, { "name": "category", "type": "int"}, { "name": "type", "type": { @@ -214,7 +214,7 @@ }} } ]}} - } + }, { "name": "vector4s_data", "type": { "type": "array", "items": { "type": "record", "name": "Vector4sNodeData", "fields": [ {"name": "key", "type": "int"}, diff --git a/modules/rmf/dependency/RMF/src/backend/avro/factory.cpp b/modules/rmf/dependency/RMF/src/backend/avro/factory.cpp index 998bc8e0fc..421daa2778 100644 --- a/modules/rmf/dependency/RMF/src/backend/avro/factory.cpp +++ b/modules/rmf/dependency/RMF/src/backend/avro/factory.cpp @@ -6,8 +6,7 @@ * */ -#include -#include +#include #include #include "RMF/BufferConstHandle.h" @@ -39,13 +38,13 @@ class Avro2IOFileFactory : public backends::IOFactory { else return ".rmf"; } - virtual boost::shared_ptr read_file(const std::string &name) + virtual std::shared_ptr read_file(const std::string &name) const override { - return boost::make_shared > >(name); + return std::make_shared > >(name); } - virtual boost::shared_ptr create_file(const std::string &name) + virtual std::shared_ptr create_file(const std::string &name) const override { - return boost::make_shared > >(name); + return std::make_shared > >(name); } }; @@ -54,29 +53,29 @@ class Avro2IOBufferFactory : public backends::IOFactory { virtual std::string get_file_extension() const override { return ".none"; } - virtual boost::shared_ptr read_buffer(BufferConstHandle buffer) + virtual std::shared_ptr read_buffer(BufferConstHandle buffer) const override { try { - return boost::make_shared > >( + return std::make_shared > >( buffer); } catch (const std::exception &e) { RMF_INFO("Avro2 reader can't read buffer: " << e.what()); - return boost::shared_ptr(); + return std::shared_ptr(); } } - virtual boost::shared_ptr create_buffer(BufferHandle buffer) + virtual std::shared_ptr create_buffer(BufferHandle buffer) const override { - return boost::make_shared >(buffer); + return std::make_shared >(buffer); } }; -std::vector > get_factories() { - std::vector > ret; - ret.push_back(boost::make_shared >()); - ret.push_back(boost::make_shared >()); - ret.push_back(boost::make_shared >()); - ret.push_back(boost::make_shared()); +std::vector > get_factories() { + std::vector > ret; + ret.push_back(std::make_shared >()); + ret.push_back(std::make_shared >()); + ret.push_back(std::make_shared >()); + ret.push_back(std::make_shared()); return ret; } diff --git a/modules/rmf/dependency/RMF/src/backend/avro/factory.h b/modules/rmf/dependency/RMF/src/backend/avro/factory.h index b42de2eab9..4e48188ab4 100644 --- a/modules/rmf/dependency/RMF/src/backend/avro/factory.h +++ b/modules/rmf/dependency/RMF/src/backend/avro/factory.h @@ -21,7 +21,7 @@ RMF_ENABLE_WARNINGS namespace RMF { namespace avro2 { -RMFEXPORT std::vector > get_factories(); +RMFEXPORT std::vector > get_factories(); } } diff --git a/modules/rmf/dependency/RMF/src/backend/avro/io.h b/modules/rmf/dependency/RMF/src/backend/avro/io.h index cc3530720f..5f2ca374f0 100644 --- a/modules/rmf/dependency/RMF/src/backend/avro/io.h +++ b/modules/rmf/dependency/RMF/src/backend/avro/io.h @@ -19,8 +19,7 @@ #include "RMF/internal/SharedData.h" #include "RMF/internal/shared_data_ranges.h" #include -#include -#include +#include RMF_ENABLE_WARNINGS diff --git a/modules/rmf/dependency/RMF/src/backend/avro/traits.cpp b/modules/rmf/dependency/RMF/src/backend/avro/traits.cpp index 3b2a7e4476..86d6755b29 100644 --- a/modules/rmf/dependency/RMF/src/backend/avro/traits.cpp +++ b/modules/rmf/dependency/RMF/src/backend/avro/traits.cpp @@ -455,14 +455,14 @@ struct codec_traits { namespace RMF { namespace avro2 { -void flush_buffer(boost::shared_ptr writer, - boost::shared_ptr stream, +void flush_buffer(std::shared_ptr writer, + std::shared_ptr stream, BufferHandle buffer) { RMF_INFO("Flushing to buffer"); // avoid rewriting later writer->flush(); buffer.access_buffer().clear(); - boost::shared_ptr input_stream = + std::shared_ptr input_stream = internal_avro::memoryInputStream(*stream); const uint8_t* data; size_t len; @@ -473,23 +473,23 @@ void flush_buffer(boost::shared_ptr writer, } BufferConstHandle try_convert(BufferConstHandle buffer, std::string message) { - boost::shared_ptr stream = + std::shared_ptr stream = internal_avro::memoryInputStream(buffer.get_uint8_t().first, buffer.get_uint8_t().second); - boost::shared_ptr > reader; + std::shared_ptr > reader; try { - reader = boost::make_shared >( + reader = std::make_shared >( stream, valid_backwards_schema); } catch (const std::exception &e) { RMF_THROW(Message(message + " and " + e.what()), IOException); } - boost::shared_ptr out_stream = + std::shared_ptr out_stream = internal_avro::memoryOutputStream(); - boost::shared_ptr writer = - boost::make_shared( + std::shared_ptr writer = + std::make_shared( out_stream, internal_avro::compileJsonSchemaFromString( RMF::data_avro::frame_json), 16 * 1024, internal_avro::DEFLATE_CODEC); diff --git a/modules/rmf/dependency/RMF/src/backend/avro/traits.h b/modules/rmf/dependency/RMF/src/backend/avro/traits.h index 45ee69b343..34bfce3a21 100644 --- a/modules/rmf/dependency/RMF/src/backend/avro/traits.h +++ b/modules/rmf/dependency/RMF/src/backend/avro/traits.h @@ -16,8 +16,7 @@ #include "avrocpp/api/Compiler.hh" #include "data_file.h" #include "generated/embed_jsons.h" -#include -#include +#include RMF_ENABLE_WARNINGS @@ -33,7 +32,7 @@ internal_avro::ValidSchema get_schema() { } struct FileWriterTraitsBase { - boost::shared_ptr writer_; + std::shared_ptr writer_; std::string path_; FileWriterTraitsBase(std::string path) : path_(path) {} template @@ -57,7 +56,7 @@ struct FileWriterTraitsBase { template struct ReaderTraits { Base base_file_data_, base_frame_; - boost::shared_ptr > reader_; + std::shared_ptr > reader_; template ReaderTraits(T path) @@ -94,7 +93,7 @@ struct ReaderTraits { } void load_file_data(FileData &fd) { RMF_INFO("Loading file data"); - boost::shared_ptr > reader = + std::shared_ptr > reader = base_file_data_.template get_reader(); avro2::load_file_data(*reader, fd); } @@ -117,20 +116,20 @@ struct FileReaderBase { FileReaderBase(std::string path) : path_(path) { get_reader(); } template - boost::shared_ptr > get_reader() { - return boost::make_shared >(path_.c_str(), + std::shared_ptr > get_reader() { + return std::make_shared >(path_.c_str(), get_schema()); } }; RMFEXPORT void flush_buffer( - boost::shared_ptr writer, - boost::shared_ptr stream, BufferHandle buffer); + std::shared_ptr writer, + std::shared_ptr stream, BufferHandle buffer); struct BufferWriterTraits { - boost::shared_ptr writer_; + std::shared_ptr writer_; BufferHandle buffer_; - boost::shared_ptr stream_; + std::shared_ptr stream_; BufferWriterTraits(BufferHandle buffer) : buffer_(buffer) { stream_ = internal_avro::memoryOutputStream(); writer_.reset(new internal_avro::DataFileWriterBase( @@ -165,11 +164,11 @@ struct BufferReaderBase { } } template - boost::shared_ptr > get_reader() { - boost::shared_ptr stream = + std::shared_ptr > get_reader() { + std::shared_ptr stream = internal_avro::memoryInputStream(buffer_.get_uint8_t().first, buffer_.get_uint8_t().second); - return boost::make_shared >(stream, + return std::make_shared >(stream, get_schema()); } }; diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileReader.h b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileReader.h index b9615538f5..73b291ac4b 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileReader.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileReader.h @@ -10,7 +10,7 @@ #define RMF_INTERNAL_MULTIPLE_AVRO_FILE_READER_H #include "avrocpp/api/DataFile.hh" -#include +#include #include #include @@ -44,7 +44,7 @@ namespace avro_backend { class MultipleAvroFileReader : public MultipleAvroFileBase { typedef MultipleAvroFileBase P; struct CategoryData { - boost::shared_ptr > + std::shared_ptr > reader; // frame is always something valid RMF_avro_backend::Data data; diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileWriter.h b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileWriter.h index c0fac20b51..4821f607f4 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileWriter.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/MultipleAvroFileWriter.h @@ -12,7 +12,7 @@ #include "avrocpp/api/DataFile.hh" #include "AllJSON.h" #include "FrameJSON.h" -#include +#include #include #include @@ -43,7 +43,7 @@ class MultipleAvroFileWriter : public MultipleAvroFileBase { std::vector static_categories_dirty_; struct CategoryData { - boost::shared_ptr > + std::shared_ptr > writer; RMF_avro_backend::Data data; bool dirty; @@ -53,7 +53,7 @@ class MultipleAvroFileWriter : public MultipleAvroFileBase { RMF_avro_backend::Data null_frame_data_; RMF_avro_backend::Data null_static_frame_data_; - boost::shared_ptr > + std::shared_ptr > frame_writer_; RMF_avro_backend::Frame frame_; diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.cpp b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.cpp index 8c3a727a46..8d1b257984 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.cpp +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.cpp @@ -50,7 +50,7 @@ SingleAvroFile::SingleAvroFile(std::string path, bool create, null_static_frame_data_.frame = -1; } -SingleAvroFile::SingleAvroFile(boost::shared_ptr > buffer, +SingleAvroFile::SingleAvroFile(std::shared_ptr > buffer, bool create, bool) : AvroKeysAndCategories("buffer"), dirty_(false), @@ -104,9 +104,9 @@ void SingleAvroFile::flush() { } else { buffer_->clear(); std::ostringstream oss(std::ios_base::binary); - boost::shared_ptr os = + std::shared_ptr os = internal_avro::ostreamOutputStream(oss); - boost::shared_ptr encoder = + std::shared_ptr encoder = internal_avro::binaryEncoder(); encoder->init(*os); internal_avro::encode(*encoder, all_); @@ -135,10 +135,10 @@ void SingleAvroFile::reload() { RMF_THROW(Message("Can't read input file on reload"), IOException); } } else if (!buffer_ && text_) { - boost::shared_ptr decoder = + std::shared_ptr decoder = internal_avro::jsonDecoder(internal_avro::compileJsonSchemaFromString( data_deprecated_avro::all_json)); - boost::shared_ptr stream = + std::shared_ptr stream = internal_avro::fileInputStream(get_file_path().c_str()); decoder->init(*stream); bool success = false; @@ -153,10 +153,10 @@ void SingleAvroFile::reload() { RMF_THROW(Message("Can't read input file on reload"), IOException); } } else { - boost::shared_ptr is = + std::shared_ptr is = internal_avro::memoryInputStream( reinterpret_cast(&(*buffer_)[0]), buffer_->size()); - boost::shared_ptr decoder = + std::shared_ptr decoder = internal_avro::binaryDecoder(); decoder->init(*is); internal_avro::decode(*decoder, all_); diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.h b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.h index a8c8a3efc4..1b4ba8eee4 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/SingleAvroFile.h @@ -10,7 +10,7 @@ #define RMF_INTERNAL_SINGLE_AVRO_FILE_H #include "AllJSON.h" -#include +#include #include #include #include @@ -33,7 +33,7 @@ class SingleAvroFile : public AvroKeysAndCategories { bool dirty_; bool text_; - boost::shared_ptr > buffer_; + std::shared_ptr > buffer_; RMF_avro_backend::Data null_frame_data_; RMF_avro_backend::Data null_static_frame_data_; @@ -146,7 +146,7 @@ class SingleAvroFile : public AvroKeysAndCategories { void reload(); SingleAvroFile(std::string path, bool create, bool read_only); - SingleAvroFile(boost::shared_ptr > buffer, bool create, + SingleAvroFile(std::shared_ptr > buffer, bool create, bool read_only); SingleAvroFile(); ~SingleAvroFile() { flush(); } diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.cpp b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.cpp index d5bea82ab6..140b3d00e4 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.cpp +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.cpp @@ -21,7 +21,7 @@ namespace RMF { namespace avro_backend { void show(const RMF_avro_backend::Data& data, std::ostream& out) { - boost::shared_ptr< ::internal_avro::OutputStream> os = + std::shared_ptr< ::internal_avro::OutputStream> os = internal_avro::ostreamOutputStream(out); ::internal_avro::EncoderPtr encoder = internal_avro::jsonEncoder(internal_avro::compileJsonSchemaFromString( diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.h b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.h index 776badd483..199758695e 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/avro_schema_io.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -90,9 +90,9 @@ void write_text(const Data& data, internal_avro::ValidSchema schema, std::string path) { std::string temppath = path + ".new"; { - boost::shared_ptr encoder = + std::shared_ptr encoder = internal_avro::jsonEncoder(schema); - boost::shared_ptr stream = + std::shared_ptr stream = internal_avro::fileOutputStream(temppath.c_str()); encoder->init(*stream); try { diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/create.cpp b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/create.cpp index fea467079e..c6fea31d2d 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/create.cpp +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/create.cpp @@ -9,8 +9,7 @@ #include "factory.h" #include -#include -#include +#include #include #include #include @@ -48,13 +47,13 @@ struct SingleTextAvroFactory : public RMF::backends::IOFactory { virtual std::string get_file_extension() const override { return ".rmf-text"; } - virtual boost::shared_ptr read_file( + virtual std::shared_ptr read_file( const std::string& name) const override { - return boost::make_shared(name, false, true); + return std::make_shared(name, false, true); } - virtual boost::shared_ptr create_file( + virtual std::shared_ptr create_file( const std::string& name) const override { - return boost::make_shared(name, true, false); + return std::make_shared(name, true, false); } virtual ~SingleTextAvroFactory() {} }; @@ -63,18 +62,18 @@ struct SingleAvroFactory : public SingleTextAvroFactory { virtual std::string get_file_extension() const override { return ".rmfa"; } - /*virtual boost::shared_ptr create_buffer( + /*virtual std::shared_ptr create_buffer( BufferHandle buffer) const override { - return boost::make_shared(buffer); + return std::make_shared(buffer); }*/ - virtual boost::shared_ptr read_buffer( + virtual std::shared_ptr read_buffer( BufferConstHandle buffer) const override { try { - return boost::make_shared(buffer); + return std::make_shared(buffer); } catch (const std::exception &e) { RMF_INFO("Can't read buffer with old reader: " << e.what()); - return boost::shared_ptr(); + return std::shared_ptr(); } } virtual ~SingleAvroFactory() {} @@ -84,22 +83,22 @@ struct MultipleAvroFactory : public RMF::backends::IOFactory { virtual std::string get_file_extension() const override { return ".rmf-avro"; } - virtual boost::shared_ptr read_file( + virtual std::shared_ptr read_file( const std::string& name) const override { - return boost::make_shared(name, false, true); + return std::make_shared(name, false, true); } - virtual boost::shared_ptr create_file( + virtual std::shared_ptr create_file( const std::string& name) const override { - return boost::make_shared(name, true, false); + return std::make_shared(name, true, false); } virtual ~MultipleAvroFactory() {} }; } // namespace -std::vector > get_factories() { - std::vector > ret; - ret.push_back(boost::make_shared()); - ret.push_back(boost::make_shared()); - ret.push_back(boost::make_shared()); +std::vector > get_factories() { + std::vector > ret; + ret.push_back(std::make_shared()); + ret.push_back(std::make_shared()); + ret.push_back(std::make_shared()); return ret; } } // namespace avro_backend diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/factory.h b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/factory.h index 52f7670e4a..adbefb71dc 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_avro/factory.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_avro/factory.h @@ -9,7 +9,7 @@ RMF_ENABLE_WARNINGS namespace RMF { namespace avro_backend { -RMFEXPORT std::vector > get_factories(); +RMFEXPORT std::vector > get_factories(); } } diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/HDF5SharedData.h b/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/HDF5SharedData.h index e9ee640a78..6bce500666 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/HDF5SharedData.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/HDF5SharedData.h @@ -10,8 +10,7 @@ #define RMF_INTERNAL_HDF_5SHARED_DATA_H #include -#include -#include +#include #include #include #include @@ -184,7 +183,7 @@ class HDF5SharedData : public backends::BackwardsIOBase { // category, type, per_frame typedef HDF5DataSetCacheD DS; typedef boost::ptr_vector > PVDS; - typedef boost::array Pair; + typedef std::array Pair; mutable std::vector cache_; public: diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/create.cpp b/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/create.cpp index 78da7e9f15..d236559ca0 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/create.cpp +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/create.cpp @@ -8,8 +8,7 @@ #include "factory.h" -#include -#include +#include #include #include @@ -36,21 +35,21 @@ struct HDF5Factory : public RMF::backends::IOFactory { virtual std::string get_file_extension() const override { return ".rmf-hdf5"; } - virtual boost::shared_ptr read_file( + virtual std::shared_ptr read_file( const std::string& name) const override { - return boost::make_shared(name, false, true); + return std::make_shared(name, false, true); } - virtual boost::shared_ptr create_file( + virtual std::shared_ptr create_file( const std::string& name) const override { - return boost::make_shared(name, true, false); + return std::make_shared(name, true, false); } virtual ~HDF5Factory() {} }; } // namespace -std::vector > get_factories() { - return std::vector >( - 1, boost::make_shared()); +std::vector > get_factories() { + return std::vector >( + 1, std::make_shared()); } } // namespace avro_backend } // namespace RMF diff --git a/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/factory.h b/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/factory.h index 61739b19f2..4a792373c6 100644 --- a/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/factory.h +++ b/modules/rmf/dependency/RMF/src/backend/deprecated_hdf5/factory.h @@ -9,7 +9,7 @@ RMF_ENABLE_WARNINGS namespace RMF { namespace hdf5_backend { -RMFEXPORT std::vector > get_factories(); +RMFEXPORT std::vector > get_factories(); } } diff --git a/modules/rmf/dependency/RMF/src/exceptions.cpp b/modules/rmf/dependency/RMF/src/exceptions.cpp index 761ced4e2f..65ebe3c77f 100644 --- a/modules/rmf/dependency/RMF/src/exceptions.cpp +++ b/modules/rmf/dependency/RMF/src/exceptions.cpp @@ -19,7 +19,7 @@ RMF_ENABLE_WARNINGS namespace RMF { Exception::Exception() {} -const char* Exception::what() const RMF_NOEXCEPT { +const char* Exception::what() const noexcept { try { if (message_.empty()) { message_ = get_message(*this); @@ -30,7 +30,7 @@ const char* Exception::what() const RMF_NOEXCEPT { return message_.c_str(); } -Exception::~Exception() RMF_NOEXCEPT {} +Exception::~Exception() noexcept {} std::string get_message(const Exception& e) { using namespace RMF::internal::ErrorInfo; try { @@ -95,16 +95,16 @@ std::string get_message(const Exception& e) { } } UsageException::UsageException() : Exception() {} -UsageException::~UsageException() RMF_NOEXCEPT {} +UsageException::~UsageException() noexcept {} IOException::IOException() : Exception() {} -IOException::~IOException() RMF_NOEXCEPT {} +IOException::~IOException() noexcept {} IndexException::IndexException() : Exception() {} -IndexException::~IndexException() RMF_NOEXCEPT {} +IndexException::~IndexException() noexcept {} InternalException::InternalException() : Exception() {} -InternalException::~InternalException() RMF_NOEXCEPT {} +InternalException::~InternalException() noexcept {} } /* namespace RMF */ diff --git a/modules/rmf/dependency/RMF/src/hdf5_wrapper.cpp b/modules/rmf/dependency/RMF/src/hdf5_wrapper.cpp index 0f2958ce90..06bdfdfb60 100644 --- a/modules/rmf/dependency/RMF/src/hdf5_wrapper.cpp +++ b/modules/rmf/dependency/RMF/src/hdf5_wrapper.cpp @@ -16,9 +16,8 @@ #include #include #include -#include #include -#include +#include #include #include #include @@ -46,24 +45,24 @@ bool show_errors = false; void set_show_errors(bool tf) { show_errors = tf; } -Object::Object(boost::shared_ptr h) : h_(h) {} +Object::Object(std::shared_ptr h) : h_(h) {} File Object::get_file() const { RMF_HDF5_NEW_HANDLE(h, H5Iget_file_id(get_handle()), &H5Fclose); return File(h); } -Group::Group(boost::shared_ptr h) : P(h) {} +Group::Group(std::shared_ptr h) : P(h) {} -ConstGroup::ConstGroup(boost::shared_ptr h) : P(h) {} +ConstGroup::ConstGroup(std::shared_ptr h) : P(h) {} Group::Group(Group parent, std::string name) - : P(boost::make_shared(H5Gopen2(parent.get_handle(), + : P(std::make_shared(H5Gopen2(parent.get_handle(), name.c_str(), H5P_DEFAULT), &H5Gclose, name)) {} ConstGroup::ConstGroup(ConstGroup parent, std::string name) - : P(boost::make_shared(H5Gopen2(parent.get_handle(), + : P(std::make_shared(H5Gopen2(parent.get_handle(), name.c_str(), H5P_DEFAULT), &H5Gclose, name)) {} @@ -110,12 +109,12 @@ bool ConstGroup::get_child_is_group(unsigned int i) const { return get_child_is_group(get_child_name(i)); } ConstGroup ConstGroup::get_child_group(std::string name) const { - return ConstGroup(boost::make_shared + return ConstGroup(std::make_shared ( H5Gopen2(get_handle(), name.c_str(), H5P_DEFAULT), &H5Gclose, "open group")); } Group Group::get_child_group(std::string name) const { - return Group(boost::make_shared + return Group(std::make_shared (H5Gopen2(get_handle(), name.c_str(), H5P_DEFAULT), &H5Gclose, "open group")); } @@ -199,8 +198,8 @@ File open_file_read_only_returning_nonconst(std::string name) { return File(h); } -File::File(boost::shared_ptr h) : Group(h) {} -ConstFile::ConstFile(boost::shared_ptr h) : ConstGroup(h) {} +File::File(std::shared_ptr h) : Group(h) {} +ConstFile::ConstFile(std::shared_ptr h) : ConstGroup(h) {} ConstFile::ConstFile(File h) : ConstGroup(h.get_shared_handle()) {} void File::flush() { RMF_HDF5_CALL(H5Fflush(get_handle(), H5F_SCOPE_LOCAL)); } diff --git a/modules/rmf/dependency/RMF/src/internal/SharedData.cpp b/modules/rmf/dependency/RMF/src/internal/SharedData.cpp index 0672d4143b..c527f22206 100644 --- a/modules/rmf/dependency/RMF/src/internal/SharedData.cpp +++ b/modules/rmf/dependency/RMF/src/internal/SharedData.cpp @@ -32,7 +32,7 @@ namespace internal { namespace { RMF_LARGE_UNORDERED_SET open_for_writing; } -SharedData::SharedData(boost::shared_ptr io, std::string name, +SharedData::SharedData(std::shared_ptr io, std::string name, bool write, bool created) : path_(name), write_(write), io_(io) { if (!created) { @@ -40,7 +40,7 @@ SharedData::SharedData(boost::shared_ptr io, std::string name, } RMF_USAGE_CHECK( open_for_writing.find(get_file_path()) == open_for_writing.end(), - "Opening a file that is still being written is asking for trouble."); + "This file is currently being written to. Close it first."); if (write) open_for_writing.insert(get_file_path()); } diff --git a/modules/rmf/dependency/RMF/src/internal/clone_shared_data.h b/modules/rmf/dependency/RMF/src/internal/clone_shared_data.h index 19d9e0e55c..ecc9ab4366 100644 --- a/modules/rmf/dependency/RMF/src/internal/clone_shared_data.h +++ b/modules/rmf/dependency/RMF/src/internal/clone_shared_data.h @@ -2,7 +2,7 @@ * \file RMF/internal/SharedData.h * \brief Handle read/write of Model data from/to files. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -13,10 +13,12 @@ #include "RMF/log.h" #include "RMF/internal/shared_data_ranges.h" #include "RMF/internal/SharedData.h" +#include "RMF/internal/paths.h" #include "shared_data_maps.h" #include "shared_data_equality.h" #include +#include RMF_ENABLE_WARNINGS @@ -167,12 +169,86 @@ void clone_values_category(SDA* sda, Category cata, SDB* sdb, Category catb, RMF_FOREACH_TYPE(RMF_CLONE_VALUES); } +// Return true iff an attribute contains a filesystem path. +// Unfortunately RMF stores both paths and non-path strings in String(s) +// attributes (and we can't easily add a separate Path(s) type without +// breaking backwards compatibility), so we do this based on the name +// of the attribute. The convention is to end path attribute names in +// "filename" or "filenames" but we have to also include a few that +// predate this convention. +inline bool is_string_key_path(std::string name) { + return boost::algorithm::ends_with(name, "filename") || + boost::algorithm::ends_with(name, "filenames") || + name == "cluster density" || + name == "image files" || + name == "path"; +} + +// Rewrite a String node attribute containing a relative path +template +void rewrite_node_path(SDB *sdb, NodeID n, ID k, + StringTraits::ReturnType s, + const std::string &from_path, + const std::string &to_path) { + sdb->set_static_value( + n, k, get_relative_path(to_path, get_absolute_path(from_path, s))); +} + +// Rewrite a Strings node attribute containing relative paths +template +void rewrite_node_path(SDB *sdb, NodeID n, ID k, + StringsTraits::ReturnType s, + const std::string &from_path, + const std::string &to_path) { + for (std::string &es : s) { + es = get_relative_path(to_path, get_absolute_path(from_path, es)); + } + sdb->set_static_value(n, k, s); +} + +// Rewrite all relative paths (in String or Strings attributes) in the +// given category, that were relative to from_path, to be relative to to_path +template +void rewrite_paths_type(SDB *sdb, Category catb, + const std::string &from_path, + const std::string &to_path) { + std::vector> keysb = sdb->get_keys(catb, Traits()); + for (auto &k : keysb) { + if (is_string_key_path(sdb->get_name(k))) { + for(NodeID n : get_nodes(sdb)) { + typename Traits::ReturnType s = sdb->get_static_value(n, k); + if (!Traits::get_is_null_value(s)) { + rewrite_node_path(sdb, n, k, s, from_path, to_path); + } + } + } + } +} + +// Rewrite all path attributes, that were relative to sba, to be +// relative to sdb +template +void rewrite_relative_paths(SDA* sda, SDB* sdb) { + std::string from_path = sda->get_file_path(); + std::string to_path = sdb->get_file_path(); + for (Category catb : sdb->get_categories()) { + // Both String and Strings attributes can contain paths + rewrite_paths_type(sdb, catb, from_path, to_path); + rewrite_paths_type(sdb, catb, from_path, to_path); + } +} + template void clone_static_data(SDA* sda, SDB* sdb) { for(Category cata : sda->get_categories()) { Category catb = sdb->get_category(sda->get_name(cata)); clone_values_category(sda, cata, sdb, catb, StaticValues()); } + // Path attributes are relative to sda, so rewrite (if necessary) to + // be relative to sdb + if (!get_is_same_base_path(sda->get_file_path(), sdb->get_file_path())) { + rewrite_relative_paths(sda, sdb); + } } template diff --git a/modules/rmf/dependency/RMF/src/internal/paths.cpp b/modules/rmf/dependency/RMF/src/internal/paths.cpp index c147bfc153..b898d843c8 100644 --- a/modules/rmf/dependency/RMF/src/internal/paths.cpp +++ b/modules/rmf/dependency/RMF/src/internal/paths.cpp @@ -2,7 +2,7 @@ * \file RMF/paths.cpp * \brief Handle read/write of Model data from/to files. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -96,8 +96,9 @@ boost::filesystem::path normalize(const boost::filesystem::path& p) { boost::filesystem::path relpath(boost::filesystem::path p, boost::filesystem::path base) { boost::filesystem::path cwd = boost::filesystem::current_path(); - boost::filesystem::path absp = abspath(p, cwd); - boost::filesystem::path absbase = abspath(base.parent_path(), cwd); + // Handle any . or .. path components + boost::filesystem::path absp = normalize(abspath(p, cwd)); + boost::filesystem::path absbase = normalize(abspath(base.parent_path(), cwd)); size_t lenbase = count_path_components(absbase); size_t common = get_common_prefix(absp, absbase); @@ -139,6 +140,20 @@ std::string get_relative_path(std::string base, std::string file) { #endif } +bool get_is_same_base_path(std::string file1, std::string file2) { +#ifdef _MSC_VER + return false; +#else + boost::filesystem::path f1(file1), f2(file2); + boost::filesystem::path absf1 = normalize(abspath(f1.parent_path(), + boost::filesystem::current_path())); + boost::filesystem::path absf2 = normalize(abspath(f2.parent_path(), + boost::filesystem::current_path())); + return (absf1 == absf2); +#endif +} + + std::string get_absolute_path(std::string base, std::string file) { #ifdef _MSC_VER return file; diff --git a/modules/rmf/dependency/RMF/src/internal/shared_data_factories.cpp b/modules/rmf/dependency/RMF/src/internal/shared_data_factories.cpp index 7ca77527f0..fafc84acc5 100644 --- a/modules/rmf/dependency/RMF/src/internal/shared_data_factories.cpp +++ b/modules/rmf/dependency/RMF/src/internal/shared_data_factories.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include "RMF/BufferConstHandle.h" @@ -22,36 +22,36 @@ RMF_ENABLE_WARNINGS namespace RMF { namespace internal { -boost::shared_ptr create_file(const std::string& name) { - boost::shared_ptr io = backends::create_file(name); +std::shared_ptr create_file(const std::string& name) { + std::shared_ptr io = backends::create_file(name); if (!io) { RMF_THROW(Message("Can't create file") << File(name), IOException); } - return boost::make_shared(io, name, true, true); + return std::make_shared(io, name, true, true); } -boost::shared_ptr create_buffer(BufferHandle buffer) { - boost::shared_ptr io = backends::create_buffer(buffer); +std::shared_ptr create_buffer(BufferHandle buffer) { + std::shared_ptr io = backends::create_buffer(buffer); if (!io) { RMF_THROW(Message("Can't create buffer"), IOException); } - return boost::make_shared(io, "buffer", true, true); + return std::make_shared(io, "buffer", true, true); } -boost::shared_ptr read_file(const std::string& name) { - boost::shared_ptr io = backends::read_file(name); +std::shared_ptr read_file(const std::string& name) { + std::shared_ptr io = backends::read_file(name); if (!io) { RMF_THROW(Message("Can't read file") << File(name), IOException); } - boost::shared_ptr ret = - boost::make_shared(io, name, false, false); + std::shared_ptr ret = + std::make_shared(io, name, false, false); return ret; } -boost::shared_ptr read_buffer(BufferConstHandle buffer) { - boost::shared_ptr io = backends::read_buffer(buffer); +std::shared_ptr read_buffer(BufferConstHandle buffer) { + std::shared_ptr io = backends::read_buffer(buffer); if (!io) { RMF_THROW(Message("Can't read buffer"), IOException); } - boost::shared_ptr ret = - boost::make_shared(io, "buffer", false, false); + std::shared_ptr ret = + std::make_shared(io, "buffer", false, false); return ret; } diff --git a/modules/rmf/dependency/RMF/src/signature.cpp b/modules/rmf/dependency/RMF/src/signature.cpp index 6107b7270d..23a5f44409 100644 --- a/modules/rmf/dependency/RMF/src/signature.cpp +++ b/modules/rmf/dependency/RMF/src/signature.cpp @@ -8,7 +8,7 @@ #include "RMF/utility.h" -#include +#include #include #include #include diff --git a/modules/rmf/dependency/RMF/src/utility.cpp b/modules/rmf/dependency/RMF/src/utility.cpp index 95ad996da2..e8155b69fb 100644 --- a/modules/rmf/dependency/RMF/src/utility.cpp +++ b/modules/rmf/dependency/RMF/src/utility.cpp @@ -8,7 +8,7 @@ #include "RMF/utility.h" -#include +#include #include #include #include @@ -105,7 +105,7 @@ void test_throw_exception() { namespace { void handle_vector(const CoordinateTransformer &tr, const Vector3 &v, float r, - boost::array &bb) { + std::array &bb) { Vector3 trv = tr.get_global_coordinates(v); for (unsigned int i = 0; i < 3; ++i) { bb[0][i] = std::min(trv[i] - r, bb[0][i]); @@ -119,7 +119,7 @@ void get_bounding_box_impl(NodeConstHandle root, CoordinateTransformer tr, decorator::CylinderFactory cf, decorator::GaussianParticleFactory gpf, decorator::ReferenceFrameFactory rff, - boost::array &bb) { + std::array &bb) { if (rff.get_is(root)) { tr = CoordinateTransformer(tr, rff.get(root)); } @@ -150,8 +150,8 @@ void get_bounding_box_impl(NodeConstHandle root, CoordinateTransformer tr, } } -boost::array get_bounding_box(NodeConstHandle root) { - boost::array ret; +std::array get_bounding_box(NodeConstHandle root) { + std::array ret; float v = std::numeric_limits::max(); ret[0] = RMF::Vector3(v, v, v); ret[1] = RMF::Vector3(-v, -v, -v); @@ -165,7 +165,7 @@ boost::array get_bounding_box(NodeConstHandle root) { } float get_diameter(NodeConstHandle root) { - boost::array bb = get_bounding_box(root); + std::array bb = get_bounding_box(root); float max = 0; for (unsigned int i = 0; i < 3; ++i) { max = std::max(bb[1][i] - bb[0][i], max); diff --git a/modules/rmf/dependency/RMF/swig/CMakeLists.txt b/modules/rmf/dependency/RMF/swig/CMakeLists.txt index 2c44f1a2c1..e96238210a 100644 --- a/modules/rmf/dependency/RMF/swig/CMakeLists.txt +++ b/modules/rmf/dependency/RMF/swig/CMakeLists.txt @@ -9,6 +9,10 @@ include_directories(${HDF5_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS}) +if(${PYTHON_NUMPY_FOUND}) + include_directories(${PYTHON_NUMPY_INCLUDE_DIR}) +endif() + FILE(GLOB rmf_headers "${PROJECT_SOURCE_DIR}/include/RMF/*.h" "${PROJECT_BINARY_DIR}/include/RMF/*.h" "${PROJECT_BINARY_DIR}/include/RMF/decorator/*.h") FILE(GLOB SWIG_INCLUDES "${PROJECT_SOURCE_DIR}/swig/RMF.*.i") diff --git a/modules/rmf/dependency/RMF/swig/RMF.FileConstHandle.i b/modules/rmf/dependency/RMF/swig/RMF.FileConstHandle.i index 02c2befbfd..2c273ddfc2 100644 --- a/modules/rmf/dependency/RMF/swig/RMF.FileConstHandle.i +++ b/modules/rmf/dependency/RMF/swig/RMF.FileConstHandle.i @@ -4,6 +4,13 @@ namespace RMF { %extend RMF::FileConstHandle { %pythoncode %{ + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + return False + def get_frames(self): class MyRange: def __init__(self, mx): diff --git a/modules/rmf/dependency/RMF/swig/RMF.exceptions.i b/modules/rmf/dependency/RMF/swig/RMF.exceptions.i index 0e039d951f..9a479e3901 100644 --- a/modules/rmf/dependency/RMF/swig/RMF.exceptions.i +++ b/modules/rmf/dependency/RMF/swig/RMF.exceptions.i @@ -9,6 +9,12 @@ void handle_imp_exception(void) { // for windows where there may be multiple std::exceptions // the order is to avoid warnings about redundancy PyErr_SetString(PyExc_IOError, e.what()); + } catch (const std::domain_error &e) { + PyErr_SetString(PyExc_ValueError, e.what()); + } catch (const std::runtime_error &e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + } catch (const std::invalid_argument &e) { + PyErr_SetString(PyExc_TypeError, e.what()); } catch (const std::exception &e) { PyErr_SetString(PyExc_IOError, e.what()); } catch (...) { diff --git a/modules/rmf/dependency/RMF/swig/RMF.i b/modules/rmf/dependency/RMF/swig/RMF.i index dd6566cfc4..d21cf1acdb 100644 --- a/modules/rmf/dependency/RMF/swig/RMF.i +++ b/modules/rmf/dependency/RMF/swig/RMF.i @@ -34,6 +34,7 @@ #include #include +#include #include "RMF/internal/swig_helpers.h" #include "RMF.h" @@ -68,7 +69,7 @@ // hack, I don't understand what swig is doing typedef RMF::Vector<3U> Vector3; typedef RMF::Vector<4U> Vector4; - typedef boost::array IntRange; + typedef std::array IntRange; %} %include "RMF.range.i" @@ -94,7 +95,8 @@ %inline %{ std::string _get_rmf_version() { std::ostringstream oss; - oss << RMF_VERSION_MAJOR << "." << RMF_VERSION_MINOR; + oss << RMF_VERSION_MAJOR << "." << RMF_VERSION_MINOR + << "." << RMF_VERSION_MICRO; return oss.str(); } %} @@ -161,3 +163,4 @@ RMF_SWIG_VECTOR(RMF, TraverseHelper) %include "RMF.python.i" +%include "RMF.numpy.i" diff --git a/modules/rmf/dependency/RMF/swig/RMF.numpy.i b/modules/rmf/dependency/RMF/swig/RMF.numpy.i new file mode 100644 index 0000000000..9726df6033 --- /dev/null +++ b/modules/rmf/dependency/RMF/swig/RMF.numpy.i @@ -0,0 +1,132 @@ +#if RMF_HAS_NUMPY +%begin %{ +static int numpy_import_retval; +%} + +%{ +// Silence warnings about old NumPy API +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +%} + +%init { + numpy_import_retval = _import_array(); + /* If numpy was not found, continue anyway without numpy support */ + PyErr_Clear(); +} + +%{ +// Return true iff `o` is a numpy array of the given type laid out in +// a contiguous chunk of memory +bool is_native_numpy_array(PyObject *o, int numpy_type) { + if (!o || !PyArray_Check(o)) { return false; }// not a numpy array + + PyArrayObject *a = (PyArrayObject *)o; + int array_type = PyArray_TYPE(a); + if (array_type != NPY_NOTYPE + && !PyArray_EquivTypenums(array_type, numpy_type)) { + return false; // data type does not match + } + + return PyArray_ISCONTIGUOUS(a) && PyArray_ISNOTSWAPPED(a); +} + +// Return true iff `o` is a 2D numpy array of the given type laid out in +// a contiguous chunk of memory +bool is_native_numpy_2d_array(PyObject *o, int numpy_type, npy_intp ncol) { + if (is_native_numpy_array(o, numpy_type)) { + PyArrayObject *a = (PyArrayObject *)o; + return PyArray_NDIM(a) == 2 && PyArray_DIM(a, 1) == ncol; + } else { + return false; + } +} + +// Utility class to visit RMF nodes and extract XYZ coordinates +class _OurVisitor { + RMF::decorator::ReferenceFrameConstFactory refframef_; + RMF::decorator::IntermediateParticleConstFactory iparticlef_; + RMF::decorator::BallConstFactory ballf_; + RMF::decorator::AlternativesConstFactory altf_; + // Dimension of the NumPy array + npy_intp ncoord_; + // Raw data in the N*3 NumPy array + double *data_; + + void add_coordinates(const RMF::Vector3 &v) { + numxyz++; + if (numxyz > ncoord_) { + std::ostringstream oss; + oss << "More XYZ particles were found in the RMF file than " + << "were provided (" << ncoord_ << ") in the numpy array"; + throw std::domain_error(oss.str()); + } + *data_++ = v[0]; + *data_++ = v[1]; + *data_++ = v[2]; + } + +public: + _OurVisitor(RMF::FileConstHandle fh, npy_intp ncoord, double *data) + : refframef_(fh), iparticlef_(fh), ballf_(fh), altf_(fh), + ncoord_(ncoord), data_(data) {} + + void handle_node(RMF::NodeConstHandle &nh, RMF::CoordinateTransformer tran) { + if (refframef_.get_is(nh)) { + tran = RMF::CoordinateTransformer(tran, refframef_.get(nh)); + } + if (ballf_.get_is(nh)) { + RMF::Vector3 coord = tran.get_global_coordinates( + ballf_.get(nh).get_coordinates()); + add_coordinates(coord); + } else if (iparticlef_.get_is(nh)) { + RMF::Vector3 coord = tran.get_global_coordinates( + iparticlef_.get(nh).get_coordinates()); + add_coordinates(coord); + } + for (auto &child : nh.get_children()) { + handle_node(child, tran); + } + if (altf_.get_is(nh)) { + RMF::decorator::AlternativesConst alt = altf_.get(nh); + RMF::NodeConstHandles altp = alt.get_alternatives(RMF::PARTICLE); + // Skip first element (already handled above by get_children()) + for (auto altpi = altp.begin() + 1; altpi < altp.end(); ++altpi) { + handle_node(*altpi, tran); + } + for (auto &childg : alt.get_alternatives(RMF::GAUSSIAN_PARTICLE)) { + handle_node(childg, tran); + } + } + } + + size_t numxyz = 0; +}; + +%} + +%inline %{ +void get_all_global_coordinates( + RMF::FileConstHandle &fh, RMF::NodeConstHandle &nh, PyObject *coord) { + if (numpy_import_retval != 0) { + throw std::runtime_error("NumPy did not initialize"); + } + if (!is_native_numpy_2d_array(coord, NPY_DOUBLE, 3)) { + throw std::invalid_argument("NumPy array is not a native N*3 double array"); + } + + PyArrayObject *acoord = (PyArrayObject *)coord; + npy_intp ncoord = PyArray_DIM(acoord, 0); + double *data = (double *)PyArray_DATA(acoord); + + _OurVisitor v(fh, ncoord, data); + v.handle_node(nh, RMF::CoordinateTransformer()); + if (v.numxyz != ncoord) { + std::ostringstream oss; + oss << "Fewer XYZ particles were found in the RMF file (" << v.numxyz + << ") than were provided (" << ncoord << ") in the numpy array"; + throw std::domain_error(oss.str()); + } +} +%} +#endif diff --git a/modules/rmf/dependency/RMF/swig/RMF.range.i b/modules/rmf/dependency/RMF/swig/RMF.range.i index 762ccb137a..0318455240 100644 --- a/modules/rmf/dependency/RMF/swig/RMF.range.i +++ b/modules/rmf/dependency/RMF/swig/RMF.range.i @@ -1,4 +1,4 @@ -namespace boost { +namespace std { template struct array { array(); @@ -7,7 +7,7 @@ struct array { }; } -%extend boost::array { +%extend std::array { %pythoncode %{ def __getitem__(self, d): if d >= self.size() or d < 0: @@ -18,4 +18,4 @@ struct array { return self.size() %} } -%template(IntRange) boost::array; +%template(IntRange) std::array; diff --git a/modules/rmf/dependency/RMF/swig/RMF_HDF5.i b/modules/rmf/dependency/RMF/swig/RMF_HDF5.i index 847f427d86..671d7236d1 100644 --- a/modules/rmf/dependency/RMF/swig/RMF_HDF5.i +++ b/modules/rmf/dependency/RMF/swig/RMF_HDF5.i @@ -14,8 +14,7 @@ RMF_VC_PRAGMA(warning( disable: 4503 )) #include #include -#include -#include +#include #include #include "RMF/internal/swig_helpers.h" diff --git a/modules/rmf/dependency/RMF/test/test_associations.cpp b/modules/rmf/dependency/RMF/test/test_associations.cpp index f662864879..b16ac289de 100644 --- a/modules/rmf/dependency/RMF/test/test_associations.cpp +++ b/modules/rmf/dependency/RMF/test/test_associations.cpp @@ -6,7 +6,7 @@ * */ #include -#include +#include #include #include #include @@ -44,11 +44,11 @@ void test(const char* fname) { assert(c0.get_association() == &a0); RMF::NodeHandle c2 = fh.get_root_node().add_child("c2", RMF::GEOMETRY); - boost::shared_ptr si(new int(3)); + std::shared_ptr si(new int(3)); c2.set_association(si); RMF::NodeHandle c2b = fh.get_node_from_association(si); assert(c2 == c2b); - boost::shared_ptr sib = c2.get_association >(); + std::shared_ptr sib = c2.get_association >(); assert(sib == si); RMF::NodeHandle c3 = fh.get_root_node().add_child("c3", RMF::GEOMETRY); diff --git a/modules/rmf/dependency/RMF/test/test_avro2_low_level.cpp b/modules/rmf/dependency/RMF/test/test_avro2_low_level.cpp index 2567dd6673..c0e2c5cf7d 100644 --- a/modules/rmf/dependency/RMF/test/test_avro2_low_level.cpp +++ b/modules/rmf/dependency/RMF/test/test_avro2_low_level.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ void read_raw(std::string name) { int read = 0; while (reader.read(frame)) { internal_avro::EncoderPtr encoder = internal_avro::jsonEncoder(schema); - boost::shared_ptr os = + std::shared_ptr os = internal_avro::ostreamOutputStream(std::cout); encoder->init(*os); internal_avro::encode(*encoder, frame); diff --git a/modules/rmf/dependency/RMF/test/test_avro2_validate.cpp b/modules/rmf/dependency/RMF/test/test_avro2_validate.cpp index 22147648a5..029af4eaaa 100644 --- a/modules/rmf/dependency/RMF/test/test_avro2_validate.cpp +++ b/modules/rmf/dependency/RMF/test/test_avro2_validate.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include @@ -54,7 +54,7 @@ void validate_one(Tout fr, Tin) { fr.nodes.back().id = NodeID(1); fr.nodes.back().type = ROOT; fr.nodes.back().parents.push_back(NodeID(1)); - boost::shared_ptr out_stream = + std::shared_ptr out_stream = internal_avro::memoryOutputStream(); { internal_avro::EncoderPtr encoder = internal_avro::binaryEncoder(); @@ -65,7 +65,7 @@ void validate_one(Tout fr, Tin) { internal_avro::encode(*ve, fr); } { - boost::shared_ptr in_stream = + std::shared_ptr in_stream = internal_avro::memoryInputStream(*out_stream); internal_avro::DecoderPtr decoder = internal_avro::binaryDecoder(); decoder->init(*in_stream); @@ -78,7 +78,7 @@ void validate_one(Tout fr, Tin) { } template void validate_raw(T fr) { - boost::shared_ptr out_stream = + std::shared_ptr out_stream = internal_avro::memoryOutputStream(); { internal_avro::EncoderPtr encoder = internal_avro::binaryEncoder(); @@ -89,7 +89,7 @@ void validate_raw(T fr) { internal_avro::encode(*ve, fr); } { - boost::shared_ptr in_stream = + std::shared_ptr in_stream = internal_avro::memoryInputStream(*out_stream); internal_avro::DecoderPtr decoder = internal_avro::binaryDecoder(); decoder->init(*in_stream); diff --git a/modules/rmf/dependency/RMF/test/test_file_handle.py b/modules/rmf/dependency/RMF/test/test_file_handle.py new file mode 100644 index 0000000000..d25feb37cc --- /dev/null +++ b/modules/rmf/dependency/RMF/test/test_file_handle.py @@ -0,0 +1,41 @@ +import unittest +import RMF + + +class Tests(unittest.TestCase): + + def test_closed_repr(self): + """Test show of closed file handle""" + fh = RMF.FileConstHandle() + _ = repr(fh) + fh = RMF.FileHandle() + _ = repr(fh) + + def test_closed_file_methods(self): + """Test methods on closed files""" + fh = RMF.FileConstHandle() + self.assertTrue(fh.get_is_closed()) + self.assertRaises(IOError, fh.set_current_frame, RMF.FrameID(0)) + self.assertRaises(IOError, fh.get_path) + self.assertRaises(IOError, fh.get_current_frame) + self.assertRaises(IOError, fh.get_type, RMF.FrameID(0)) + self.assertRaises(IOError, fh.get_name, RMF.FrameID(0)) + self.assertRaises(IOError, fh.get_children, RMF.FrameID(0)) + self.assertRaises(IOError, fh.get_parents, RMF.FrameID(0)) + self.assertRaises(IOError, fh.get_number_of_frames) + self.assertRaises(IOError, fh.get_number_of_nodes) + self.assertRaises(IOError, fh.get_file_type) + self.assertRaises(IOError, fh.get_root_node) + + fh = RMF.FileHandle() + self.assertTrue(fh.get_is_closed()) + self.assertRaises(IOError, fh.get_root_node) + self.assertRaises(IOError, fh.add_frame, "f0") + self.assertRaises(IOError, fh.add_frame, "f1", RMF.FrameID(0)) + self.assertRaises(IOError, fh.set_description, "foo") + self.assertRaises(IOError, fh.set_producer, "foo") + self.assertRaises(IOError, fh.flush) + + +if __name__ == '__main__': + unittest.main() diff --git a/modules/rmf/dependency/RMF/test/test_file_level.py b/modules/rmf/dependency/RMF/test/test_file_level.py index c40922fcac..4ad8212862 100644 --- a/modules/rmf/dependency/RMF/test/test_file_level.py +++ b/modules/rmf/dependency/RMF/test/test_file_level.py @@ -16,6 +16,7 @@ def test_perturbed(self): for suffix in RMF.suffixes: f = RMF.create_rmf_file( RMF._get_temporary_file_path("test_file_perturbed." + suffix)) + self.assertFalse(f.get_is_closed()) r = f.get_root_node() print(r.get_type()) sc = f.get_category("sequence") @@ -109,6 +110,35 @@ def test_base_frames(self): self.assertEqual(f.get_current_frame(), RMF.FrameID()) f.set_current_frame(RMF.FrameID(0)) -if __name__ == '__main__': + def test_close(self): + """Test explicit close of file handle""" + for suffix in RMF.suffixes: + path = RMF._get_temporary_file_path("test_close." + suffix) + f = RMF.create_rmf_file(path) + self.assertEqual(f.get_number_of_frames(), 0) + f.add_frame("hi", RMF.FRAME) + self.assertEqual(f.get_number_of_frames(), 1) + f.close() + self.assertTrue(f.get_is_closed()) + self.assertRaises(IOError, f.get_number_of_frames) + f2 = RMF.open_rmf_file_read_only(path) + self.assertEqual(f2.get_number_of_frames(), 1) + + def test_context_manager(self): + """Test file handle context manager support""" + for suffix in RMF.suffixes: + path = RMF._get_temporary_file_path( + "test_context_manager." + suffix) + with RMF.create_rmf_file(path) as f: + self.assertEqual(f.get_number_of_frames(), 0) + f.add_frame("hi", RMF.FRAME) + self.assertEqual(f.get_number_of_frames(), 1) + self.assertTrue(f.get_is_closed()) + self.assertRaises(IOError, f.get_number_of_frames) + with RMF.open_rmf_file_read_only(path) as f2: + self.assertEqual(f2.get_number_of_frames(), 1) + self.assertTrue(f2.get_is_closed()) + +if __name__ == '__main__': unittest.main() diff --git a/modules/rmf/dependency/RMF/test/test_json_encode_decode.cpp b/modules/rmf/dependency/RMF/test/test_json_encode_decode.cpp index 97df5cb085..cdae78042f 100644 --- a/modules/rmf/dependency/RMF/test/test_json_encode_decode.cpp +++ b/modules/rmf/dependency/RMF/test/test_json_encode_decode.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -18,10 +18,10 @@ ::internal_avro::ValidSchema get_valid_schema() { return ::internal_avro::compileJsonSchemaFromString(schema); } std::string encode(std::vector data) { - boost::shared_ptr encoder = + std::shared_ptr encoder = internal_avro::jsonEncoder(get_valid_schema()); std::ostringstream oss; - boost::shared_ptr stream = + std::shared_ptr stream = internal_avro::ostreamOutputStream(oss); encoder->init(*stream); internal_avro::encode(*encoder, data); @@ -30,10 +30,10 @@ std::string encode(std::vector data) { return oss.str(); } std::vector decode(std::string buffer) { - boost::shared_ptr decoder = + std::shared_ptr decoder = internal_avro::jsonDecoder(get_valid_schema()); std::istringstream iss(buffer); - boost::shared_ptr stream = + std::shared_ptr stream = internal_avro::istreamInputStream(iss); decoder->init(*stream); std::vector data; diff --git a/modules/rmf/dependency/RMF/test/test_numpy.py b/modules/rmf/dependency/RMF/test/test_numpy.py new file mode 100644 index 0000000000..e09a1e7e59 --- /dev/null +++ b/modules/rmf/dependency/RMF/test/test_numpy.py @@ -0,0 +1,63 @@ +from __future__ import print_function +import RMF +import unittest +if RMF.RMF_HAS_NUMPY: + import numpy + + +def _make_rmf(with_coordinates=True): + b = RMF.BufferHandle() + rmf = RMF.create_rmf_buffer(b) + pf = RMF.ParticleFactory(rmf) + rf = RMF.ReferenceFrameFactory(rmf) + root = rmf.get_root_node() + p = root.add_child("particle", RMF.REPRESENTATION) + pf.get(p).set_radius(1.0) + pf.get(p).set_mass(1.0) + pf.get(p).set_coordinates(RMF.Vector3(1, 2, 3)) + refframe = root.add_child("refframe", RMF.REPRESENTATION) + rf.get(refframe).set_translation(RMF.Vector3(4, 1, 1)) + rf.get(refframe).set_rotation(RMF.Vector4(1, 0, 0, 0)) + p = refframe.add_child("particle", RMF.REPRESENTATION) + pf.get(p).set_mass(1.0) + if with_coordinates: + pf.get(p).set_radius(1.0) + pf.get(p).set_coordinates(RMF.Vector3(4, 5, 6)) + return rmf + + +class Tests(unittest.TestCase): + + @unittest.skipUnless(RMF.RMF_HAS_NUMPY, "No numpy support") + def test_get_global_coordinates(self): + """Test get global coordinates as numpy array""" + rmf = _make_rmf() + root = rmf.get_root_node() + # coord array of wrong type + self.assertRaises(TypeError, RMF.get_all_global_coordinates, rmf, + root, "foo") + # coord array of wrong dimension + self.assertRaises(ValueError, RMF.get_all_global_coordinates, rmf, + root, numpy.empty((1, 3))) + self.assertRaises(ValueError, RMF.get_all_global_coordinates, rmf, + root, numpy.empty((8, 3))) + coord = numpy.empty((2, 3)) + RMF.get_all_global_coordinates(rmf, root, coord) + # Second coordinate should be transformed by the reference frame + expected_coord = numpy.array([[1., 2., 3.], [8., 6., 7.]]) + self.assertLess(numpy.linalg.norm(coord - expected_coord), 1e-4) + + @unittest.skipUnless(RMF.RMF_HAS_NUMPY, "No numpy support") + def test_get_global_coordinates_particle_no_coords(self): + """Test get global coordinates with a Particle with no coordinates""" + rmf = _make_rmf(with_coordinates=False) + root = rmf.get_root_node() + # The second Particle should be ignored since it has no coordinates + coord = numpy.empty((1, 3)) + RMF.get_all_global_coordinates(rmf, root, coord) + expected_coord = numpy.array([[1., 2., 3.]]) + self.assertLess(numpy.linalg.norm(coord - expected_coord), 1e-4) + + +if __name__ == '__main__': + unittest.main() diff --git a/modules/rmf/dependency/RMF/test/test_paths.py b/modules/rmf/dependency/RMF/test/test_paths.py index 17ad4a6417..eefff4d496 100644 --- a/modules/rmf/dependency/RMF/test/test_paths.py +++ b/modules/rmf/dependency/RMF/test/test_paths.py @@ -77,5 +77,67 @@ def test_paths(self): if sys.platform != 'win32': shutil.rmtree(tmpdir) + def test_parent_path(self): + """Test parent paths in a named RMF file""" + tmpdir = RMF._get_temporary_file_path('test_parent_path') + subdir = os.path.join(tmpdir, 'sub1', 'sub2') + os.makedirs(subdir) + # Earlier versions of RMF incorrectly handled RMF files with .. + # in their path, so check this here: + rmf = RMF.create_rmf_file(os.path.join(subdir, '..', 'test.rmf3')) + key = self.get_filename_key(rmf) + node, prov = self.make_test_node(rmf) + + ap = os.path.join(subdir, 'foo.pdb') + prov.set_filename(ap) + + if sys.platform == 'win32': + # On Windows, filenames are not altered + self.assertEqual(node.get_value(key), ap) + self.assertEqual(prov.get_filename(), ap) + else: + # On Mac/Linux, internally, a relative path should be stored + self.assertEqual(node.get_value(key), 'sub2/foo.pdb') + # API should return an absolute path + self.assertEqual(prov.get_filename(), ap) + + def test_clone_rewrite_path(self): + """Test that clone rewrites relative paths""" + tmpdir = RMF._get_temporary_file_path('test_clone_rewrite_path') + subdir = os.path.join(tmpdir, 'sub1') + subsubdir = os.path.join(subdir, 'sub2') + os.makedirs(subsubdir) + rmf = RMF.create_rmf_file(os.path.join(subdir, 'test.rmf3')) + key = self.get_filename_key(rmf) + node, prov = self.make_test_node(rmf) + + ap = os.path.join(subsubdir, 'foo.pdb') + prov.set_filename(ap) + + if sys.platform != 'win32': + # On Mac/Linux, internally, a relative path should be stored + self.assertEqual(node.get_value(key), 'sub2/foo.pdb') + # API should return an absolute path + self.assertEqual(prov.get_filename(), ap) + del rmf, node, prov + + inr = RMF.open_rmf_file_read_only(os.path.join(subdir, 'test.rmf3')) + outr = RMF.create_rmf_file(os.path.join(subsubdir, 'test.rmf3')) + RMF.clone_file_info(inr, outr) + RMF.clone_hierarchy(inr, outr) + RMF.clone_static_frame(inr, outr) + rt = outr.get_root_node() + f = RMF.StructureProvenanceFactory(outr) + node, = rt.get_children() + self.assertTrue(f.get_is(node)) + prov = f.get(node) + if sys.platform != 'win32': + # New file should have a different relative path + key = self.get_filename_key(outr) + self.assertEqual(node.get_value(key), 'foo.pdb') + # API should return the same absolute path + self.assertEqual(prov.get_filename(), ap) + + if __name__ == '__main__': unittest.main() diff --git a/modules/rmf/dependency/RMF/tools/build/_decorators.py b/modules/rmf/dependency/RMF/tools/build/_decorators.py index bc9293add7..1812f173d9 100755 --- a/modules/rmf/dependency/RMF/tools/build/_decorators.py +++ b/modules/rmf/dependency/RMF/tools/build/_decorators.py @@ -72,8 +72,25 @@ def get_check(self): class Attribute(Base): + def _is_path(self, name): + """Return True iff `name` describes a filesystem path attribute. + Unfortunately internally RMF stores both paths and non-path + strings in String(s) attributes (and we can't easily add a + separate Path(s) type without breaking backwards compatibility), + and uses the attribute name to distinguish them. Check here that + we haven't used a path-like name for a string or vice versa.""" + return (name.endswith("filename") or name.endswith("filenames") + or name in ("cluster density", "image files", "path")) + + def _check_string_name(self, name): + if self._is_path(name): + raise ValueError("Cannot use a 'path' name (%s) for a " + "string Attribute" % name) + def __init__(self, name, attribute_type, function_name=None, default=None): + if attribute_type in ('String', 'Strings'): + self._check_string_name(name) if not function_name: self.function_name = name.replace(" ", "_") else: @@ -154,6 +171,11 @@ class PathAttribute(Attribute): the RMF file (in-memory RMFs are considered to be in the current working directory) but the API always returns absolute paths.""" + def _check_string_name(self, name): + if not self._is_path(name): + raise ValueError("Cannot use a non-path name (%s) " + "for a PathAttribute" % name) + def __init__(self, name, function_name=None): Attribute.__init__(self, name, "String", function_name) self.get_methods = """ @@ -178,6 +200,12 @@ def __init__(self, name, function_name=None): class OptionalPathAttribute(Attribute): """Like a PathAttribute, but it can be empty.""" + + def _check_string_name(self, name): + if not self._is_path(name): + raise ValueError("Cannot use a non-path name (%s) " + "for an OptionalPathAttribute" % name) + def __init__(self, name, function_name=None): Attribute.__init__(self, name, "String", function_name) self.get_methods = """ @@ -211,7 +239,7 @@ def __init__(self, name, function_name=None): class AttributePair(Base): def __init__(self, name, data_type, return_type, begin, end): - Base.__init__(self, name, "boost::array<%sKey, 2>" % + Base.__init__(self, name, "std::array<%sKey, 2>" % data_type, return_type) self.helpers = """ template DATA get_NAME_keys(H fh) const { DATA ret; @@ -556,7 +584,7 @@ def make_header(name, infos, deps): #include #include #include -#include +#include #include """ % {"name": name, "NAME": name.upper()}) for d in deps: diff --git a/modules/rmf/dependency/RMF/tools/dev_tools/.github/workflows/build.yml b/modules/rmf/dependency/RMF/tools/dev_tools/.github/workflows/build.yml index d719007528..bb9873950c 100644 --- a/modules/rmf/dependency/RMF/tools/dev_tools/.github/workflows/build.yml +++ b/modules/rmf/dependency/RMF/tools/dev_tools/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python-version: [2.7, 3.7, 3.8, 3.9, "3.10"] + python-version: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11"] runs-on: ${{ matrix.os }} steps: @@ -20,8 +20,9 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install 'pytest-flake8<1.1' pytest-cov + pip install pytest flake8 pytest-cov - name: Test run: | - py.test --cov=. --cov-branch --cov-report=xml -v --flake8 . + py.test --cov=. --cov-branch --cov-report=xml -v . + flake8 --ignore=E402,W503 --exclude python_tools/reindent.py - uses: codecov/codecov-action@v1 diff --git a/modules/rmf/dependency/RMF/tools/dev_tools/make_all_header.py b/modules/rmf/dependency/RMF/tools/dev_tools/make_all_header.py index ec9af48aac..b10deee041 100755 --- a/modules/rmf/dependency/RMF/tools/dev_tools/make_all_header.py +++ b/modules/rmf/dependency/RMF/tools/dev_tools/make_all_header.py @@ -6,6 +6,7 @@ import sys import glob +import datetime import os sys.path.append(os.path.split(sys.argv[0])[0]) @@ -27,13 +28,14 @@ def _add_includes(headers, output): includepath = sys.argv[1][sys.argv[1].find("include") + len("include") + 1:] +year = datetime.datetime.now().year output = ["""/** * \\file %s * \\brief Include all non-deprecated headers in %s. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-%d IMP Inventors. All rights reserved. */ -""" % (includepath, includepath[:-2].replace('/', '.'))] +""" % (includepath, includepath[:-2].replace('/', '.'), year)] guard = includepath.replace( "/", "_").replace("\\", diff --git a/modules/rmf/dependency/RMF/tools/dev_tools/pytest.ini b/modules/rmf/dependency/RMF/tools/dev_tools/pytest.ini deleted file mode 100644 index aec0cb16fd..0000000000 --- a/modules/rmf/dependency/RMF/tools/dev_tools/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -flake8-ignore = E402 W503 -addopts = --ignore=python_tools/reindent.py diff --git a/modules/rmf/dependency/RMF/tools/dev_tools/python_tools/__init__.py b/modules/rmf/dependency/RMF/tools/dev_tools/python_tools/__init__.py index 17fd602769..aecd175fbb 100644 --- a/modules/rmf/dependency/RMF/tools/dev_tools/python_tools/__init__.py +++ b/modules/rmf/dependency/RMF/tools/dev_tools/python_tools/__init__.py @@ -174,8 +174,8 @@ def get_modules(source): def split(string, sep=":"): - return([x.replace("@", ":") - for x in string.replace("\\:", "@").split(sep) if x != ""]) + return ([x.replace("@", ":") + for x in string.replace("\\:", "@").split(sep) if x != ""]) def get_project_info(path): diff --git a/modules/rmf/dependency/RMF/tools/dev_tools/test/test_header.py b/modules/rmf/dependency/RMF/tools/dev_tools/test/test_header.py index a00c32bd4a..ef3f7b0647 100644 --- a/modules/rmf/dependency/RMF/tools/dev_tools/test/test_header.py +++ b/modules/rmf/dependency/RMF/tools/dev_tools/test/test_header.py @@ -1,6 +1,7 @@ import unittest import subprocess import os +import datetime import utils TOPDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) @@ -26,13 +27,14 @@ def test_header(self): 'include/test/subdir'], cwd=tmpdir) stdout, stderr = p.communicate() self.assertEqual(p.returncode, 0) + year = datetime.datetime.now().year self.assertEqual(utils.read_file(os.path.join(tmpdir, 'include/test.h')), """/** * \\file test.h * \\brief Include all non-deprecated headers in test. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-%d IMP Inventors. All rights reserved. */ #ifndef TEST_H @@ -43,7 +45,7 @@ def test_header(self): #include #endif #endif /* TEST_H */ -""") +""" % year) if __name__ == '__main__': diff --git a/modules/rmf/dependency/RMF/tools/new-release.txt b/modules/rmf/dependency/RMF/tools/new-release.txt index f5a213ab05..600e8a3940 100644 --- a/modules/rmf/dependency/RMF/tools/new-release.txt +++ b/modules/rmf/dependency/RMF/tools/new-release.txt @@ -1,8 +1,7 @@ To make a new release: - Update ChangeLog.md with release date and features. -- Add version number as RMF_VERSION_MAJOR and RMF_VERSION_MINOR - to CMakeLists.txt. +- Add version number as RMF_VERSION_(MAJOR,MINOR,MICRO) to CMakeLists.txt. - git push origin develop - Make sure all CI passes - Merge into main: @@ -11,5 +10,5 @@ To make a new release: - git diff develop - git push origin main - Tag the new release: - - git tag -s -u 22A3BF2B x.y.z; git push origin x.y.z + - git tag -s -u E6414C85 x.y.z; git push origin x.y.z - Make new release on GitHub diff --git a/modules/rmf/include/HierarchyLoadLink.h b/modules/rmf/include/HierarchyLoadLink.h index fff11c4ee5..ff3323e954 100644 --- a/modules/rmf/include/HierarchyLoadLink.h +++ b/modules/rmf/include/HierarchyLoadLink.h @@ -27,7 +27,9 @@ #include #include #include +#include #include + IMPRMF_BEGIN_NAMESPACE /** Manage the loading link between an RMF file and an atom::Hierarchy. @@ -61,7 +63,7 @@ class IMPRMFEXPORT HierarchyLoadLink : public SimpleLoadLink { load_gaussians(h), load_rigid_bodies(h) {} }; - typedef boost::unordered_map > + typedef boost::unordered_map > DM; DM data_; virtual bool get_is(RMF::NodeConstHandle nh) const override { diff --git a/modules/rmf/include/HierarchySaveLink.h b/modules/rmf/include/HierarchySaveLink.h index 824c1b89f9..f960d91c2a 100644 --- a/modules/rmf/include/HierarchySaveLink.h +++ b/modules/rmf/include/HierarchySaveLink.h @@ -28,6 +28,8 @@ #include #include #include +#include + IMPRMF_BEGIN_NAMESPACE /** Manage the save link between an RMF file and an atom::Hierarchy. @@ -49,7 +51,7 @@ class IMPRMFEXPORT HierarchySaveLink : public SimpleSaveLink { save_gaussians(h), save_rigid_bodies(h) {} }; - typedef boost::unordered_map > + typedef boost::unordered_map > DM; DM data_; RMF::decorator::AlternativesFactory af_; diff --git a/modules/rmf/src/HierarchyLoadLink.cpp b/modules/rmf/src/HierarchyLoadLink.cpp index 8b9828c668..a87baad06e 100644 --- a/modules/rmf/src/HierarchyLoadLink.cpp +++ b/modules/rmf/src/HierarchyLoadLink.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include IMPRMF_BEGIN_NAMESPACE @@ -196,7 +195,7 @@ Particle *HierarchyLoadLink::do_create(RMF::NodeConstHandle node, Model *m) { IMP_FUNCTION_LOG; ParticleIndex ret = m->add_particle(node.get_name()); - data_.insert(std::make_pair(ret, boost::make_shared(node.get_file()))); + data_.insert(std::make_pair(ret, std::make_shared(node.get_file()))); create_recursive(m, ret, ret, node, ParticleIndexes(), *data_[ret]); data_.find(ret)->second->load_bonds.setup_bonds(node, m, ret); if (!atom::Hierarchy(m, ret).get_is_valid(true)) { @@ -286,7 +285,7 @@ void HierarchyLoadLink::do_add_link(Particle *o, RMF::NodeConstHandle node) { IMP_FUNCTION_LOG; data_.insert(std::make_pair(o->get_index(), - boost::make_shared(node.get_file()))); + std::make_shared(node.get_file()))); add_link_recursive(o->get_model(), o->get_index(), o->get_index(), node, ParticleIndexes(), *data_.find(o->get_index())->second); diff --git a/modules/rmf/src/HierarchySaveLink.cpp b/modules/rmf/src/HierarchySaveLink.cpp index e25d49a2cc..015c3d7b6e 100644 --- a/modules/rmf/src/HierarchySaveLink.cpp +++ b/modules/rmf/src/HierarchySaveLink.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include IMPRMF_BEGIN_NAMESPACE @@ -33,7 +32,7 @@ void HierarchySaveLink::do_add(Particle *p, RMF::NodeHandle cur) { IMP_USAGE_CHECK(atom::Hierarchy(p).get_is_valid(true), "Invalid hierarchy passed."); data_.insert( - std::make_pair(p->get_index(), boost::make_shared(cur.get_file()))); + std::make_pair(p->get_index(), std::make_shared(cur.get_file()))); add_recursive(p->get_model(), p->get_index(), p->get_index(), ParticleIndexes(), cur, *data_[p->get_index()]); P::add_link(p, cur); diff --git a/modules/rmf/src/restraint_io.cpp b/modules/rmf/src/restraint_io.cpp index ef204e4c70..7bc363c2d2 100644 --- a/modules/rmf/src/restraint_io.cpp +++ b/modules/rmf/src/restraint_io.cpp @@ -80,6 +80,30 @@ Restraints RMFRestraint::do_create_current_decomposition() const { RMFRestraint::RMFRestraint(Model *m, std::string name) : Restraint(m, name) {} +class RMFRestraintSet; +IMP_OBJECTS(RMFRestraintSet, RMFRestraintSets); +/** A dummy restraint object to represent restraint sets loaded from + an RMF file.*/ +class RMFRestraintSet : public RestraintSet { + PointerMember info_; + + public: + RMFRestraintSet(const RestraintsTemp &rs, double weight, + const std::string &name) : RestraintSet(rs, weight, name) {} + +#ifndef IMP_DOXYGEN + RestraintInfo *get_info() { + if (!info_) { + info_ = new RestraintInfo(); + } + return info_; + } + RestraintInfo *get_dynamic_info() const override { return info_; } + RestraintInfo *get_static_info() const override { return info_; } +#endif + IMP_OBJECT_METHODS(RMFRestraintSet); +}; + class Subset : public ConstVector, Particle *> { typedef ConstVector, Particle *> P; static ParticlesTemp get_sorted(ParticlesTemp ps) { @@ -102,6 +126,11 @@ class Subset : public ConstVector, Particle *> { } }; +inline std::size_t hash_value(const Subset &t) { + return t.__hash__(); +} + + IMP_VALUES(Subset, Subsets); template @@ -159,6 +188,7 @@ class RestraintLoadLink : public SimpleLoadLink { typedef std::pair ParticleIndexesData; typedef SimpleLoadLink P; RMF::decorator::ScoreFactory sf_; + RMF::decorator::AliasFactory af_; RMF::decorator::RepresentationFactory rf_; RMF::decorator::GaussianParticleFactory gaussian_factory_; RMF::decorator::IntermediateParticleFactory ipf_; @@ -234,12 +264,14 @@ class RestraintLoadLink : public SimpleLoadLink { } Pointer ret; if (!childr.empty()) { - ret = new RestraintSet(childr, 1.0, name.get_name()); + IMP_NEW(RMFRestraintSet, r, (childr, 1.0, name.get_name())); + ret = r; + load_restraint_info(r->get_info(), name, static_pis, dynamic_pis); } else { IMP_NEW(RMFRestraint, r, (m, name.get_name())); ret = r; r->set_particles(inputs); - load_restraint_info(r, name, static_pis, dynamic_pis); + load_restraint_info(r->get_info(), name, static_pis, dynamic_pis); } if (name.get_has_value(weight_key_)) { ret->set_weight(name.get_value(weight_key_)); @@ -281,9 +313,15 @@ class RestraintLoadLink : public SimpleLoadLink { std::vector &dynamic_pis) { ParticleIndexes pis; for(RMF::NodeConstHandle ch : parent.get_children()) { - Particle *p = get_association(ch); - pis.push_back(p->get_index()); - setup_particle(ch, m, p->get_index()); + if (af_.get_is(ch)) { + Particle *p = get_association(af_.get(ch).get_aliased()); + pis.push_back(p->get_index()); + // assume particle is already set up + } else { + Particle *p = get_association(ch); + pis.push_back(p->get_index()); + setup_particle(ch, m, p->get_index()); + } } // todo: distinguish static and dynamic pis static_pis.push_back(ParticleIndexesData(parent.get_name(), pis)); @@ -340,29 +378,29 @@ class RestraintLoadLink : public SimpleLoadLink { } } - void load_restraint_info(RMFRestraint *r, RMF::NodeConstHandle nh, + void load_restraint_info(RestraintInfo *info, RMF::NodeConstHandle nh, std::vector &static_pis, std::vector &dynamic_pis) { RMF::FileConstHandle fh = nh.get_file(); RMF_FOREACH(RMF::IntKey k, iks_) { if (!nh.get_value(k).get_is_null()) { - r->get_info()->add_int(fh.get_name(k), nh.get_value(k)); + info->add_int(fh.get_name(k), nh.get_value(k)); } } RMF_FOREACH(RMF::FloatKey k, fks_) { if (!nh.get_value(k).get_is_null()) { - r->get_info()->add_float(fh.get_name(k), nh.get_value(k)); + info->add_float(fh.get_name(k), nh.get_value(k)); } } RMF_FOREACH(RMF::StringKey k, sks_) { if (!nh.get_value(k).get_is_null()) { - r->get_info()->add_string(fh.get_name(k), nh.get_value(k)); + info->add_string(fh.get_name(k), nh.get_value(k)); } } RMF_FOREACH(RMF::StringKey k, filenameks_) { if (!nh.get_value(k).get_is_null()) { - r->get_info()->add_filename(fh.get_name(k), - RMF::internal::get_absolute_path( + info->add_filename(fh.get_name(k), + RMF::internal::get_absolute_path( fh.get_path(), nh.get_value(k))); } } @@ -371,7 +409,7 @@ class RestraintLoadLink : public SimpleLoadLink { // No automatic conversion from RMF::Floats to IMP::Floats RMF::Floats rvalue = nh.get_value(k); Floats value(rvalue.begin(), rvalue.end()); - r->get_info()->add_floats(fh.get_name(k), value); + info->add_floats(fh.get_name(k), value); } } RMF_FOREACH(RMF::IntsKey k, isks_) { @@ -379,7 +417,7 @@ class RestraintLoadLink : public SimpleLoadLink { // No automatic conversion from RMF::Ints to IMP::Ints RMF::Ints rvalue = nh.get_value(k); Ints value(rvalue.begin(), rvalue.end()); - r->get_info()->add_ints(fh.get_name(k), value); + info->add_ints(fh.get_name(k), value); } } RMF_FOREACH(RMF::StringsKey k, ssks_) { @@ -387,7 +425,7 @@ class RestraintLoadLink : public SimpleLoadLink { // No automatic conversion from RMF::Strings to IMP::Strings RMF::Strings rvalue = nh.get_value(k); Strings value(rvalue.begin(), rvalue.end()); - r->get_info()->add_strings(fh.get_name(k), value); + info->add_strings(fh.get_name(k), value); } } RMF_FOREACH(RMF::StringsKey k, filenamesks_) { @@ -398,17 +436,15 @@ class RestraintLoadLink : public SimpleLoadLink { for (const auto &it : rvalue) { value.push_back(RMF::internal::get_absolute_path(fh.get_path(), it)); } - r->get_info()->add_filenames(fh.get_name(k), value); + info->add_filenames(fh.get_name(k), value); } } for (unsigned i = 0; i < static_pis.size(); ++i) { - r->get_info()->add_particle_indexes(static_pis[i].first, - static_pis[i].second); + info->add_particle_indexes(static_pis[i].first, static_pis[i].second); } for (unsigned i = 0; i < dynamic_pis.size(); ++i) { - r->get_info()->add_particle_indexes(dynamic_pis[i].first, - dynamic_pis[i].second); + info->add_particle_indexes(dynamic_pis[i].first, dynamic_pis[i].second); } } @@ -416,6 +452,7 @@ class RestraintLoadLink : public SimpleLoadLink { RestraintLoadLink(RMF::FileConstHandle fh) : P("RestraintLoadLink%1%"), sf_(fh), + af_(fh), rf_(fh), gaussian_factory_(fh), ipf_(fh), diff --git a/modules/rmf/test/test_restraint_sets.py b/modules/rmf/test/test_restraint_sets.py index 0e65ac0605..72c8d96854 100644 --- a/modules/rmf/test/test_restraint_sets.py +++ b/modules/rmf/test/test_restraint_sets.py @@ -21,7 +21,7 @@ def test_0(self): IMP.core.XYZR.setup_particle(p).set_radius(1) IMP.rmf.add_hierarchies(f, [p]) rs = IMP.RestraintSet(m, 1.0) - r = IMP._ConstRestraint(1, [p]) + r = IMP._ConstRestraint(m, [p], 1) r.set_name("restraint") rs.add_restraint(r) rs.evaluate(False) @@ -53,7 +53,7 @@ def test_1(self): IMP.rmf.add_hierarchies(f, [p]) rs0 = IMP.RestraintSet(m, 1.0) rs1 = IMP.RestraintSet(m, 1.0) - r = IMP._ConstRestraint(1, [p]) + r = IMP._ConstRestraint(m, [p], 1) r.set_name("restraint") rs0.add_restraint(r) rs0.evaluate(False) diff --git a/modules/rmf/test/test_restraints.py b/modules/rmf/test/test_restraints.py index c60f0b70e9..2b349e2f71 100644 --- a/modules/rmf/test/test_restraints.py +++ b/modules/rmf/test/test_restraints.py @@ -9,9 +9,9 @@ class MockRestraint(IMP.Restraint): - def __init__(self, val, ps): + def __init__(self, m, ps, val): self.ps = ps - IMP.Restraint.__init__(self, ps[0].get_model(), "MockRestraint %1%") + IMP.Restraint.__init__(self, m, "MockRestraint %1%") def unprotected_evaluate(self, accum): return 0. @@ -28,8 +28,9 @@ def do_get_inputs(self): def get_static_info(self): i = IMP.RestraintInfo() if len(self.ps) >= 5: + # Include a duplicate (which will use an Alias node in RMF) i.add_particle_indexes("static particles", - [self.ps[1], self.ps[2], self.ps[3]]) + [self.ps[1], self.ps[2], self.ps[3], self.ps[3]]) return i def get_dynamic_info(self): @@ -48,6 +49,17 @@ def get_dynamic_info(self): return i +class MockRestraintSet(IMP.RestraintSet): + + def __init__(self, m, ps, val): + IMP.RestraintSet.__init__(self, m, "MockRestraintSet %1%") + + def get_dynamic_info(self): + i = IMP.RestraintInfo() + i.add_int("test int", 99) + return i + + class Tests(IMP.test.TestCase): def _write_restraint(self, name, cls=IMP._ConstRestraint, extra_ps=0): @@ -77,7 +89,7 @@ def _write_restraint(self, name, cls=IMP._ConstRestraint, extra_ps=0): scale.set_lower(0.0) scale.set_upper(10.0) ps.extend([p1, p2, p3, p4]) - r = cls(1, ps) + r = cls(m, ps, 1) r.evaluate(False) IMP.rmf.add_restraint(f, r) IMP.rmf.save_frame(f, str(0)) @@ -85,7 +97,7 @@ def _write_restraint(self, name, cls=IMP._ConstRestraint, extra_ps=0): scale.set_scale(0.5) IMP.rmf.save_frame(f, str(1)) - def _read_restraint(self, name, extra_ps=0): + def _read_restraint(self, name, extra_ps=0, inputs=True): IMP.add_to_log(IMP.TERSE, "Starting reading back\n") f = RMF.open_rmf_file_read_only(name) m = IMP.Model() @@ -95,7 +107,8 @@ def _read_restraint(self, name, extra_ps=0): IMP.rmf.load_frame(f, RMF.FrameID(0)) print([IMP.Particle.get_from(x).get_index() for x in r.get_inputs()]) print([x.get_index() for x in ps]) - self.assertEqual(len(r.get_inputs()), 1 + extra_ps) + if inputs: + self.assertEqual(len(r.get_inputs()), 1 + extra_ps) return m, r, f def test_0(self): @@ -243,6 +256,17 @@ def test_dynamic_info(self): self.assertEqual(info.get_filenames_key(0), "test filenames") self.assertEqual(len(info.get_filenames_value(0)), 2) + def test_dynamic_info_restraint_set(self): + """Test dynamic RestraintSet info""" + for suffix in IMP.rmf.suffixes: + name = self.get_tmp_file_name("dynamic_info_set" + suffix) + self._write_restraint(name, cls=MockRestraintSet) + m, r, rmf = self._read_restraint(name, inputs=False) + info = r.get_dynamic_info() + self.assertEqual(info.get_number_of_int(), 1) + self.assertEqual(info.get_int_key(0), "test int") + self.assertEqual(info.get_int_value(0), 99) + def test_associated_particles(self): """Test handling of restraint associated particles""" for suffix in IMP.rmf.suffixes: @@ -255,8 +279,10 @@ def test_associated_particles(self): 'static particles') self.assertEqual([m.get_particle_name(i) for i in info.get_particle_indexes_value(0)], - ['extra0', 'extra1', 'extra2']) - ind0, ind1, ind2 = info.get_particle_indexes_value(0) + ['extra0', 'extra1', 'extra2', 'extra2']) + ind0, ind1, ind2, ind3 = info.get_particle_indexes_value(0) + # last particle (ind3) should be an alias to ind2 + self.assertEqual(ind2, ind3) self.assertEqual(info.get_particle_indexes_key(1), 'dynamic particles') self.assertEqual([m.get_particle_name(i) diff --git a/modules/rotamer/include/RotamerLibrary.h b/modules/rotamer/include/RotamerLibrary.h index 84e4dacd35..8f602a0ed5 100644 --- a/modules/rotamer/include/RotamerLibrary.h +++ b/modules/rotamer/include/RotamerLibrary.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,10 +63,10 @@ class IMPROTAMEREXPORT RotamerAngleTuple { float chi4_; float probability_; - friend class boost::serialization::access; + friend class cereal::access; - template void serialize(Archive &ar, const unsigned int) { - ar & chi1_ & chi2_ & chi3_ & chi4_ & probability_; + template void serialize(Archive &ar) { + ar(chi1_, chi2_, chi3_, chi4_, probability_); } }; diff --git a/modules/rotamer/pyext/swig.i-in b/modules/rotamer/pyext/swig.i-in index 2f123cbfd1..690c401794 100644 --- a/modules/rotamer/pyext/swig.i-in +++ b/modules/rotamer/pyext/swig.i-in @@ -1,8 +1,3 @@ -%{ -#include -#include -%} - IMP_SWIG_VALUE_SERIALIZE(IMP::rotamer, RotamerAngleTuple, RotamerAngleTuples); IMP_SWIG_VALUE(IMP::rotamer, ResidueRotamer, ResidueRotamers); IMP_SWIG_OBJECT(IMP::rotamer, RotamerLibrary, RotamerLibraries); diff --git a/modules/sampcon b/modules/sampcon index 3e34e58cc4..e86d27ffcd 160000 --- a/modules/sampcon +++ b/modules/sampcon @@ -1 +1 @@ -Subproject commit 3e34e58cc4283fd7f181fe71884f5f6ab8f04ac5 +Subproject commit e86d27ffcdb4c32e9778e35dfbd0e427a9c6e692 diff --git a/modules/saxs/examples/profile.py b/modules/saxs/examples/profile.py index 4b3507dbe2..e0d1c28c1a 100644 --- a/modules/saxs/examples/profile.py +++ b/modules/saxs/examples/profile.py @@ -4,7 +4,7 @@ # to the experimental one. # # This application is available as a web service at salilab.org/foxs. It is -# also available as C++ code in IMP/applications. +# also available as C++ code in IMP at modules/foxs/bin/foxs.cpp. # # The experimental data for lysozyme is taken from crysol program # (www.embl-hamburg.de/ExternalInfo/Research/Sax/crysol.html) diff --git a/modules/saxs/examples/profile_fit.py b/modules/saxs/examples/profile_fit.py index 852ddab435..f42dcb774c 100644 --- a/modules/saxs/examples/profile_fit.py +++ b/modules/saxs/examples/profile_fit.py @@ -6,7 +6,7 @@ # of the molecule. # # This application is available as a web service at salilab.org/foxs. It is -# also available as C++ code in IMP/applications. +# also available as C++ code in IMP at modules/foxs/bin/foxs.cpp. # # The experimental data for lysozyme is taken from crysol program # (www.embl-hamburg.de/ExternalInfo/Research/Sax/crysol.html) diff --git a/modules/saxs/include/Profile.h b/modules/saxs/include/Profile.h index 9fd095c84c..222aeba91f 100644 --- a/modules/saxs/include/Profile.h +++ b/modules/saxs/include/Profile.h @@ -2,7 +2,7 @@ * \file IMP/saxs/Profile.h * \brief A class for profile storing and computation * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -18,6 +18,9 @@ #include #include +#include +#include +#include IMPSAXS_BEGIN_NAMESPACE @@ -298,11 +301,66 @@ class IMPSAXSEXPORT Profile : public Object { std::string name_; // file name unsigned int id_; // identifier - Profile* beam_profile_; + Pointer beam_profile_; + private: + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), q_, intensity_, error_, + min_q_, max_q_, delta_q_, partial_profiles_, c1_, c2_, + experimental_, average_radius_, average_volume_, + name_, id_, beam_profile_); + if (std::is_base_of::value) { + // q_mapping_ is regenerated when needed in resample() + q_mapping_.clear(); + bool default_ff_table; + ar(default_ff_table); + if (default_ff_table) { + ff_table_ = get_default_form_factor_table(); + } else { + ff_table_ = nullptr; + } + } else { + if (ff_table_ == nullptr) { + ar(false); + } else if (ff_table_ == get_default_form_factor_table()) { + ar(true); + } else { + IMP_THROW("Serialization of profiles using non-default form " + "factors is not supported", IMP::ValueException); + } + } + } + IMP_OBJECT_SERIALIZE_DECL(Profile); }; IMP_OBJECTS(Profile, Profiles); IMPSAXS_END_NAMESPACE +namespace cereal { + template + inline void serialize( + Archive &ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, + _MaxCols> &matrix) { + int rows, cols; + if (std::is_base_of::value) { + rows = matrix.rows(); + cols = matrix.cols(); + } + ar(rows, cols); + + if (std::is_base_of::value) { + if (rows != matrix.rows() || cols != matrix.cols()) { + matrix.resize(rows, cols); + } + } + auto mat_data = cereal::binary_data(matrix.data(), + rows * cols * sizeof(_Scalar)); + if (matrix.size() != 0) { + ar(mat_data); + } + } +} + #endif /* IMPSAXS_PROFILE_H */ diff --git a/modules/saxs/include/Restraint.h b/modules/saxs/include/Restraint.h index 9cf31a2d0a..05422182e6 100644 --- a/modules/saxs/include/Restraint.h +++ b/modules/saxs/include/Restraint.h @@ -2,7 +2,7 @@ * \file IMP/saxs/Restraint.h * \brief Calculate score based on fit to SAXS profile. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -21,6 +21,8 @@ #include #include #include +#include +#include IMPSAXS_BEGIN_NAMESPACE @@ -53,6 +55,8 @@ class IMPSAXSEXPORT Restraint : public IMP::Restraint { Restraint(const Particles& particles, const Profile* exp_profile, FormFactorType ff_type = HEAVY_ATOMS); + Restraint() {} + virtual double unprotected_evaluate(IMP::DerivativeAccumulator* accum) const override; @@ -64,11 +68,30 @@ class IMPSAXSEXPORT Restraint : public IMP::Restraint { IMP_OBJECT_METHODS(Restraint); protected: - FormFactorType ff_type_; + ParticleIndexes particles_; Pointer handler_; Pointer > profile_fitter_; // computes profiles // computes derivatives Pointer derivative_calculator_; + private: + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + if (std::is_base_of::value) { + Pointer exp_profile = const_cast( + profile_fitter_->get_profile()); + ar(handler_->get_form_factor_type(), particles_, exp_profile); + } else { + FormFactorType ff_type; + Pointer exp_profile; + ar(ff_type, particles_, exp_profile); + handler_ = new RigidBodiesProfileHandler( + IMP::get_particles(get_model(), particles_), ff_type); + profile_fitter_ = new ProfileFitter(exp_profile); + derivative_calculator_ = new DerivativeCalculator(exp_profile); + } + } + IMP_OBJECT_SERIALIZE_DECL(Restraint); }; IMPSAXS_END_NAMESPACE diff --git a/modules/saxs/include/RigidBodiesProfileHandler.h b/modules/saxs/include/RigidBodiesProfileHandler.h index 8d539d83c8..609f164334 100644 --- a/modules/saxs/include/RigidBodiesProfileHandler.h +++ b/modules/saxs/include/RigidBodiesProfileHandler.h @@ -41,6 +41,8 @@ class IMPSAXSEXPORT RigidBodiesProfileHandler : public Object { ModelObjectsTemp do_get_inputs() const; + FormFactorType get_form_factor_type() const { return ff_type_; } + IMP_OBJECT_METHODS(RigidBodiesProfileHandler); protected: diff --git a/modules/saxs/pyext/swig.i-in b/modules/saxs/pyext/swig.i-in index 69cc3f6ce9..fad7d51ff1 100644 --- a/modules/saxs/pyext/swig.i-in +++ b/modules/saxs/pyext/swig.i-in @@ -11,9 +11,10 @@ namespace std { %ignore operator>>(std::istream& q, IntensityEntry& e); //%template(_Vector3Ds) ::std::vector< ::IMP::algebra::Vector3D>; -IMP_SWIG_OBJECT(IMP::saxs, Profile, Profiles); +IMP_SWIG_OBJECT_SERIALIZE(IMP::saxs, Profile, Profiles); IMP_SWIG_OBJECT(IMP::saxs, ChiScore, ChiScores); IMP_SWIG_OBJECT(IMP::saxs, ChiScoreLog, ChiScoreLogs); +IMP_SWIG_OBJECT_SERIALIZE(IMP::saxs, Restraint, Restraints); /* Wrap our own classes */ %include "IMP/saxs/FormFactorTable.h" diff --git a/modules/saxs/src/Profile.cpp b/modules/saxs/src/Profile.cpp index 1283255c11..060f7c6058 100644 --- a/modules/saxs/src/Profile.cpp +++ b/modules/saxs/src/Profile.cpp @@ -56,6 +56,7 @@ Profile::Profile(const std::string& file_name, bool fit_file, double max_q, int id_(0), beam_profile_(nullptr) { set_was_used(true); + ff_table_ = nullptr; if (fit_file) experimental_ = false; read_SAXS_file(file_name, fit_file, max_q, units); } @@ -1213,4 +1214,6 @@ void Profile::calculate_profile_reciprocal_partial(const Particles& particles, sum_partial_profiles(1.0, 0.0, false); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::saxs::Profile); + IMPSAXS_END_NAMESPACE diff --git a/modules/saxs/src/Restraint.cpp b/modules/saxs/src/Restraint.cpp index bf8ed613c1..a4ff58e751 100644 --- a/modules/saxs/src/Restraint.cpp +++ b/modules/saxs/src/Restraint.cpp @@ -16,9 +16,8 @@ IMPSAXS_BEGIN_NAMESPACE Restraint::Restraint(const Particles& particles, const Profile* exp_profile, FormFactorType ff_type) - : IMP::Restraint(IMP::internal::get_model(particles), "SAXS restraint"), - ff_type_(ff_type) { - + : IMP::Restraint(IMP::internal::get_model(particles), "SAXS restraint") { + particles_ = IMP::get_indexes(static_cast(particles)); handler_ = new RigidBodiesProfileHandler(particles, ff_type); profile_fitter_ = new ProfileFitter(exp_profile); derivative_calculator_ = new DerivativeCalculator(exp_profile); @@ -86,7 +85,8 @@ RestraintInfo *Restraint::get_static_info() const { IMP_NEW(RestraintInfo, ri, ()); const Profile *p = profile_fitter_->get_profile(); ri->add_string("type", "IMP.saxs.Restraint"); - ri->add_string("form factor type", get_ff_type_string(ff_type_)); + ri->add_string("form factor type", + get_ff_type_string(handler_->get_form_factor_type())); ri->add_filename("filename", p->get_name()); ri->add_float("min q", p->get_min_q()); ri->add_float("max q", p->get_max_q()); @@ -94,4 +94,6 @@ RestraintInfo *Restraint::get_static_info() const { return ri.release(); } +IMP_OBJECT_SERIALIZE_IMPL(IMP::saxs::Restraint); + IMPSAXS_END_NAMESPACE diff --git a/modules/saxs/test/standards_exceptions b/modules/saxs/test/standards_exceptions index 4a57a973cc..1a597abf4d 100644 --- a/modules/saxs/test/standards_exceptions +++ b/modules/saxs/test/standards_exceptions @@ -1,4 +1,4 @@ spelling_exceptions=['pdb', 'chisquare'] show_exceptions=['DistBase', 'FloatDistribution', 'SolventAccessibleSurface', 'VectorDistribution'] -value_object_exceptions=['DeltaDistributionFunction', 'DistBase', 'FitParameters', 'FloatDistribution', 'FormFactorTable', 'RadialDistributionFunction', 'RadiusOfGyrationRestraint', 'Restraint', 'SolventAccessibleSurface', 'VectorDistribution', 'ProfileFitterChi', 'ProfileFitterChiLog', 'WeightedFitParameters', 'WeightedProfileFitter', 'ProfileFitterRatioVolatility', 'WeightedProfileFitterChi'] +value_object_exceptions=['DeltaDistributionFunction', 'DistBase', 'FitParameters', 'FloatDistribution', 'FormFactorTable', 'RadialDistributionFunction', 'RadiusOfGyrationRestraint', 'SolventAccessibleSurface', 'VectorDistribution', 'ProfileFitterChi', 'ProfileFitterChiLog', 'WeightedFitParameters', 'WeightedProfileFitter', 'ProfileFitterRatioVolatility', 'WeightedProfileFitterChi'] function_name_exceptions=['DeltaDistributionFunction.calculate_derivative_distribution', 'DistBase.append', 'DistBase.assign', 'DistBase.back', 'DistBase.begin', 'DistBase.capacity', 'DistBase.empty', 'DistBase.end', 'DistBase.erase', 'DistBase.front', 'DistBase.insert', 'DistBase.iterator', 'DistBase.rbegin', 'DistBase.rend', 'DistBase.resize', 'DistBase.size', 'FloatDistribution.append', 'FloatDistribution.assign', 'FloatDistribution.back', 'FloatDistribution.begin', 'FloatDistribution.capacity', 'FloatDistribution.empty', 'FloatDistribution.end', 'FloatDistribution.erase', 'FloatDistribution.front', 'FloatDistribution.insert', 'FloatDistribution.iterator', 'FloatDistribution.rbegin', 'FloatDistribution.rend', 'FloatDistribution.resize', 'FloatDistribution.size', 'Profile.background_adjust', 'Profile.calculate_I0', 'Profile.calculate_profile', 'Profile.calculate_profile_constant_form_factor', 'Profile.calculate_profile_partial', 'Profile.calculate_profile_reciprocal_partial', 'Profile.calculate_profile_symmetric', 'Profile.copy_errors', 'Profile.distribution_2_profile', 'Profile.downsample', 'Profile.is_partial_profile', 'Profile.is_uniform_sampling', 'Profile.mean_intensity', 'Profile.offset', 'Profile.profile_2_distribution', 'Profile.radius_of_gyration', 'Profile.read_SAXS_file', 'Profile.resample', 'Profile.scale', 'Profile.size', 'Profile.sum_partial_profiles', 'Profile.write_SAXS_file', 'ProfileFitterChi.fit_profile', 'ProfileFitterChi.resample', 'ProfileFitterChi.write_SAXS_fit_file', 'ProfileFitterChiLog.fit_profile', 'ProfileFitterChiLog.resample', 'ProfileFitterChiLog.write_SAXS_fit_file', 'ProfileFitterRatioVolatility.fit_profile', 'ProfileFitterRatioVolatility.resample', 'ProfileFitterRatioVolatility.write_SAXS_fit_file', 'RadialDistributionFunction.R_factor_score', 'RadialDistributionFunction.append', 'RadialDistributionFunction.assign', 'RadialDistributionFunction.back', 'RadialDistributionFunction.begin', 'RadialDistributionFunction.capacity', 'RadialDistributionFunction.empty', 'RadialDistributionFunction.end', 'RadialDistributionFunction.erase', 'RadialDistributionFunction.fit', 'RadialDistributionFunction.front', 'RadialDistributionFunction.insert', 'RadialDistributionFunction.iterator', 'RadialDistributionFunction.normalize', 'RadialDistributionFunction.rbegin', 'RadialDistributionFunction.rend', 'RadialDistributionFunction.resize', 'RadialDistributionFunction.scale', 'RadialDistributionFunction.size', 'WeightedProfileFitterChi.fit_profile', 'WeightedProfileFitterChi.resample', 'WeightedProfileFitterChi.write_SAXS_fit_file'] diff --git a/modules/saxs/test/test_profile.py b/modules/saxs/test/test_profile.py new file mode 100644 index 0000000000..6fede24362 --- /dev/null +++ b/modules/saxs/test/test_profile.py @@ -0,0 +1,24 @@ +import IMP.test +import IMP.saxs +import pickle + + +class Tests(IMP.test.TestCase): + + def test_pickle(self): + """Test (un-)pickle of Profile""" + p = IMP.saxs.Profile(self.get_input_file_name('lyzexp.dat')) + p.set_name("foo") + self.assertAlmostEqual(p.get_min_q(), 0.04138, delta=1e-4) + self.assertAlmostEqual(p.get_max_q(), 0.49836, delta=1e-4) + self.assertAlmostEqual(p.get_delta_q(), 0.0023315, delta=1e-4) + dump = pickle.dumps(p) + newp = pickle.loads(dump) + self.assertEqual(p.get_name(), "foo") + self.assertAlmostEqual(newp.get_min_q(), 0.04138, delta=1e-4) + self.assertAlmostEqual(newp.get_max_q(), 0.49836, delta=1e-4) + self.assertAlmostEqual(newp.get_delta_q(), 0.0023315, delta=1e-4) + + +if __name__ == '__main__': + IMP.test.main() diff --git a/modules/saxs/test/test_saxs.py b/modules/saxs/test/test_saxs.py index f4f0b11856..7bb2bfce2c 100644 --- a/modules/saxs/test/test_saxs.py +++ b/modules/saxs/test/test_saxs.py @@ -4,6 +4,7 @@ import IMP.atom import IMP.core import IMP.saxs +import pickle import os import time import io @@ -83,8 +84,7 @@ def test_saxs_profile(self): print('RatioVolatilityScore after adjustment of excluded volume and water layer parameters = ' + str(vr)) self.assertAlmostEqual(vr, 5.70, delta=0.01) - def test_saxs_restraint(self): - """Check saxs restraint""" + def make_restraint(self): m = IMP.Model() #! read PDB @@ -101,6 +101,11 @@ def test_saxs_restraint(self): #! calculate SAXS profile model_profile = IMP.saxs.Profile() model_profile.calculate_profile(particles) + return m, particles, exp_profile, model_profile + + def test_saxs_restraint(self): + """Check saxs restraint""" + m, particles, exp_profile, model_profile = self.make_restraint() #! calculate chi-square saxs_score = IMP.saxs.ProfileFitterChi(exp_profile) @@ -219,6 +224,30 @@ def test_background_adjust(self): # rather than causing a crash exp_profile.background_adjust(2000.) + def test_pickle_restraint(self): + """Check (un-)pickle of SAXS restraint""" + m, particles, exp_profile, model_profile = self.make_restraint() + r = IMP.saxs.Restraint(particles, exp_profile) + r.set_name("foo") + self.assertAlmostEqual(r.evaluate(False), 0.2916, delta=0.01) + dump = pickle.dumps(r) + newr = pickle.loads(dump) + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(False), 0.2916, delta=0.01) + + def test_pickle_restraint_polymorphic(self): + """Check (un-)pickle of SAXS restraint via polymorphic pointer""" + m, particles, exp_profile, model_profile = self.make_restraint() + r = IMP.saxs.Restraint(particles, exp_profile) + r.set_name("foo") + sf = IMP.core.RestraintsScoringFunction([r]) + self.assertAlmostEqual(sf.evaluate(False), 0.2916, delta=0.01) + dump = pickle.dumps(sf) + newsf = pickle.loads(dump) + newr, = newsf.restraints + self.assertEqual(newr.get_name(), "foo") + self.assertAlmostEqual(newr.evaluate(False), 0.2916, delta=0.01) + if __name__ == '__main__': IMP.test.main() diff --git a/modules/score_functor/include/DistancePairScore.h b/modules/score_functor/include/DistancePairScore.h index 1f40a2bcb4..0bc3770994 100644 --- a/modules/score_functor/include/DistancePairScore.h +++ b/modules/score_functor/include/DistancePairScore.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include IMPSCOREFUNCTOR_BEGIN_NAMESPACE @@ -29,6 +31,12 @@ template class DistancePairScore : public PairScore { DistanceScoreT ds_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this), ds_); + } + public: typedef DistanceScoreT DistanceScore; @@ -36,6 +44,7 @@ class DistancePairScore : public PairScore { DistancePairScore(const DistanceScore &t0, std::string name = "FunctorDistancePairScore %1%") : PairScore(name), ds_(t0) {} + DistancePairScore() {} virtual double evaluate_index(Model *m, const ParticleIndexPair &pip, diff --git a/modules/score_functor/include/Harmonic.h b/modules/score_functor/include/Harmonic.h index 9c2b9eb78c..4dc7ce4652 100644 --- a/modules/score_functor/include/Harmonic.h +++ b/modules/score_functor/include/Harmonic.h @@ -12,6 +12,8 @@ #include #include "Score.h" #include +#include + IMPSCOREFUNCTOR_BEGIN_NAMESPACE /** A harmonic score on the directed distance between a pair of particles, @@ -20,8 +22,13 @@ IMPSCOREFUNCTOR_BEGIN_NAMESPACE class Harmonic : public Score { double k_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(k_); + } public: Harmonic(double k) : k_(k) {} + Harmonic() {} template double get_score(Model *, const Array &, diff --git a/modules/score_functor/include/HarmonicLowerBound.h b/modules/score_functor/include/HarmonicLowerBound.h index d98109f731..5f1c5fe18f 100644 --- a/modules/score_functor/include/HarmonicLowerBound.h +++ b/modules/score_functor/include/HarmonicLowerBound.h @@ -14,6 +14,8 @@ #include #include "Score.h" #include +#include + IMPSCOREFUNCTOR_BEGIN_NAMESPACE /** A harmonic score on the negative directed distance between @@ -23,8 +25,14 @@ IMPSCOREFUNCTOR_BEGIN_NAMESPACE class HarmonicLowerBound : public Score { double k_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(k_); + } + public: HarmonicLowerBound(double k) : k_(k) {} + HarmonicLowerBound() {} template double get_score(Model *, const Array &, diff --git a/modules/score_functor/include/HarmonicUpperBound.h b/modules/score_functor/include/HarmonicUpperBound.h index f8032ceda8..345d34bbfc 100644 --- a/modules/score_functor/include/HarmonicUpperBound.h +++ b/modules/score_functor/include/HarmonicUpperBound.h @@ -13,6 +13,8 @@ #include #include "Score.h" #include +#include + IMPSCOREFUNCTOR_BEGIN_NAMESPACE /** A harmonic score on the positive directed distance between @@ -22,8 +24,13 @@ IMPSCOREFUNCTOR_BEGIN_NAMESPACE class HarmonicUpperBound : public Score { double k_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(k_); + } public: HarmonicUpperBound(double k) : k_(k) {} + HarmonicUpperBound() {} template double get_score(Model *, const Array &, diff --git a/modules/score_functor/include/LinearLowerBound.h b/modules/score_functor/include/LinearLowerBound.h index 5e273c2e1e..255a97b41e 100644 --- a/modules/score_functor/include/LinearLowerBound.h +++ b/modules/score_functor/include/LinearLowerBound.h @@ -22,6 +22,7 @@ class LinearLowerBound : public Score { public: LinearLowerBound(double k) : k_(k) {} + LinearLowerBound() : k_(0.0) {} // depend on get_is_trivially_zero template double get_score(Model *, diff --git a/modules/score_functor/include/Shift.h b/modules/score_functor/include/Shift.h index 4a98f32fb9..7f156526a0 100644 --- a/modules/score_functor/include/Shift.h +++ b/modules/score_functor/include/Shift.h @@ -12,6 +12,9 @@ #include #include #include +#include +#include + IMPSCOREFUNCTOR_BEGIN_NAMESPACE /** A shift the distance by subtracting x0 and pass it to the base @@ -21,8 +24,14 @@ class Shift : public BaseDistanceScore { typedef BaseDistanceScore P; double x0_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), x0_); + } + public: Shift(double x0, BaseDistanceScore base) : P(base), x0_(x0) {} + Shift() {} template double get_score(Model *m, const Array &pi, diff --git a/modules/score_functor/include/SphereDistance.h b/modules/score_functor/include/SphereDistance.h index 4d6045cf14..05e5991637 100644 --- a/modules/score_functor/include/SphereDistance.h +++ b/modules/score_functor/include/SphereDistance.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include IMPSCOREFUNCTOR_BEGIN_NAMESPACE @@ -19,6 +21,11 @@ IMPSCOREFUNCTOR_BEGIN_NAMESPACE and pass it off to BaseDistanceScore.*/ template class SphereDistance : public BaseDistanceScore { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + /* Caching the rsum makes things 30% faster with a linear score, but doesn't work in non-trivial cases (eg AddScores where get_maximum_range() isn't necessarily called first). I don't see how to fix the nontrivial @@ -32,6 +39,7 @@ class SphereDistance : public BaseDistanceScore { public: SphereDistance(BaseDistanceScore base) : P(base) {} + SphereDistance() {} double get_score(Model *m, const ParticleIndexPair &pi, double distance) const { return P::get_score(m, pi, distance - get_rsum(m, pi)); diff --git a/modules/score_functor/include/Statistical.h b/modules/score_functor/include/Statistical.h index 35e83c700c..93e1450a64 100644 --- a/modules/score_functor/include/Statistical.h +++ b/modules/score_functor/include/Statistical.h @@ -82,6 +82,8 @@ class Statistical : public Score { "Constructor can only be used for bipartite scores."); } + Statistical() {} + // depend on get_is_trivially_zero double get_score(Model *m, const ParticleIndexPair &pp, double distance) const { diff --git a/modules/score_functor/include/UnaryFunctionEvaluate.h b/modules/score_functor/include/UnaryFunctionEvaluate.h index b875e43e29..67c09d58c7 100644 --- a/modules/score_functor/include/UnaryFunctionEvaluate.h +++ b/modules/score_functor/include/UnaryFunctionEvaluate.h @@ -13,14 +13,23 @@ #include #include #include +#include + IMPSCOREFUNCTOR_BEGIN_NAMESPACE /** A DistanceScore that uses a UnaryFunction.*/ class UnaryFunctionEvaluate : public Score { IMP::PointerMember uf_; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(uf_); + } + public: UnaryFunctionEvaluate(IMP::UnaryFunction *uf) : uf_(uf) {} + UnaryFunctionEvaluate() {} template double get_score(Model *, const Array &, diff --git a/modules/score_functor/include/distance_pair_score_macros.h b/modules/score_functor/include/distance_pair_score_macros.h index 42a66c1b47..40539f9a4a 100644 --- a/modules/score_functor/include/distance_pair_score_macros.h +++ b/modules/score_functor/include/distance_pair_score_macros.h @@ -11,6 +11,8 @@ #define IMPSCORE_FUNCTOR_DISTANCE_PAIR_SCORE_MACROS_H #include "DistancePairScore.h" +#include +#include #if defined(SWIG) || defined(IMP_DOXYGEN) /** Use this macro to define PairScores based on the @@ -29,6 +31,7 @@ \ public: \ Name Args; \ + Name() {} \ double evaluate_index(Model *m, \ const ParticleIndexPair &pip, \ DerivativeAccumulator *da) const; \ @@ -41,9 +44,16 @@ #define IMP_FUNCTOR_DISTANCE_PAIR_SCORE(Name, Functor, Args, PassArgs) \ class Name : public IMP::score_functor::DistancePairScore { \ typedef IMP::score_functor::DistancePairScore P; \ + friend class cereal::access; \ + template void serialize(Archive &ar) { \ + ar(cereal::base_class< \ + IMP::score_functor::DistancePairScore >(this)); \ + } \ + IMP_OBJECT_SERIALIZE_DECL(Name); \ \ public: \ Name Args : P(Functor PassArgs, name) {} \ + Name() {} \ } #endif diff --git a/modules/statistics/include/internal/histogram.h b/modules/statistics/include/internal/histogram.h index 46a6ee8a5f..a1eb989183 100644 --- a/modules/statistics/include/internal/histogram.h +++ b/modules/statistics/include/internal/histogram.h @@ -1,5 +1,6 @@ /** - * \file random_generator.h \brief random number generator + * \file histogram.h + * \brief histogram internals * * Copyright 2007-2022 IMP Inventors. All rights reserved. * diff --git a/modules/statistics/src/internal/VQClustering.cpp b/modules/statistics/src/internal/VQClustering.cpp index 6b8d15ba11..635f8eba9a 100644 --- a/modules/statistics/src/internal/VQClustering.cpp +++ b/modules/statistics/src/internal/VQClustering.cpp @@ -9,9 +9,10 @@ #include #include #include -#include -#include +#include + IMPSTATISTICS_BEGIN_INTERNAL_NAMESPACE + using namespace algebra::internal; typedef std::pair ValInd; @@ -86,7 +87,7 @@ void VQClustering::sampling(Array1DD_VEC *tracking) { if (show_status_bar_) { show_number_of_runs = par_.number_of_runs_; } - boost::progress_display show_progress(show_number_of_runs); + IMP::internal::BoostProgressDisplay show_progress(show_number_of_runs); Array1DD_VEC centers_sample; for (int run_ind = 0; run_ind < par_.number_of_runs_; ++run_ind) { if (show_status_bar_) { diff --git a/modules/test/pyext/src/__init__.py b/modules/test/pyext/src/__init__.py index 52a8b6bd97..a6bb84fb28 100644 --- a/modules/test/pyext/src/__init__.py +++ b/modules/test/pyext/src/__init__.py @@ -196,7 +196,7 @@ def get_tmp_file_name(self, filename): def get_magnitude(self, vector): """Get the magnitude of a list of floats""" - return sum([x*x for x in vector], 0)**.5 + return sum(x*x for x in vector)**.5 def assertRaisesUsageException(self, c, *args, **keys): """Assert that the given callable object raises UsageException. @@ -220,8 +220,7 @@ def assertXYZDerivativesInTolerance(self, sf, xyz, tolerance=0, percentage=0): """Assert that x,y,z analytical derivatives match numerical within a tolerance, or a percentage (of the analytical value), whichever - is larger. `sf` should be a ScoringFunction or Restraint, - although for backwards compatibility a Model is also accepted.""" + is larger. `sf` should be a ScoringFunction or Restraint.""" sf.evaluate(True) derivs = xyz.get_derivatives() num_derivs = xyz_numerical_derivatives(sf, xyz, 0.01) diff --git a/tools/build/cmake_templates/ModuleBenchmark.cmake b/tools/build/cmake_templates/ModuleBenchmark.cmake index 02697afe79..0cb98cb743 100644 --- a/tools/build/cmake_templates/ModuleBenchmark.cmake +++ b/tools/build/cmake_templates/ModuleBenchmark.cmake @@ -1,4 +1,4 @@ -include_directories(%(includepath)s) +include_directories(SYSTEM %(includepath)s) link_directories(%(libpath)s) add_definitions("-DIMP_EXECUTABLE") diff --git a/tools/build/cmake_templates/ModuleBin.cmake b/tools/build/cmake_templates/ModuleBin.cmake index 101f72a7a3..877a18ce18 100644 --- a/tools/build/cmake_templates/ModuleBin.cmake +++ b/tools/build/cmake_templates/ModuleBin.cmake @@ -1,4 +1,4 @@ -include_directories(%(includepath)s) +include_directories(SYSTEM %(includepath)s) link_directories(%(libpath)s) add_definitions("-DIMP_EXECUTABLE") diff --git a/tools/build/cmake_templates/ModuleExamples.cmake b/tools/build/cmake_templates/ModuleExamples.cmake index faae1b0504..cce4fbed16 100644 --- a/tools/build/cmake_templates/ModuleExamples.cmake +++ b/tools/build/cmake_templates/ModuleExamples.cmake @@ -1,4 +1,4 @@ -include_directories(%(includepath)s) +include_directories(SYSTEM %(includepath)s) link_directories(%(libpath)s) include(Files.cmake) diff --git a/tools/build/cmake_templates/ModuleLib.cmake b/tools/build/cmake_templates/ModuleLib.cmake index 13ee7d8be5..9cb4fee9dc 100644 --- a/tools/build/cmake_templates/ModuleLib.cmake +++ b/tools/build/cmake_templates/ModuleLib.cmake @@ -4,7 +4,7 @@ FILE(GLOB gensources FILE(GLOB genheaders "${CMAKE_BINARY_DIR}/include/%(subdir)s/*.h") -include_directories(%(includepath)s) +include_directories(SYSTEM %(includepath)s) link_directories(%(libpath)s) add_definitions("-DIMP%(CPPNAME)s_EXPORTS") diff --git a/tools/build/cmake_templates/ModuleSwig.cmake b/tools/build/cmake_templates/ModuleSwig.cmake index f8f2319d62..4c22e46238 100644 --- a/tools/build/cmake_templates/ModuleSwig.cmake +++ b/tools/build/cmake_templates/ModuleSwig.cmake @@ -18,13 +18,13 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") endif() endif() -include_directories(%(python_includepath)s) +include_directories(SYSTEM %(python_includepath)s) link_directories(%(libpath)s) GET_DIRECTORY_PROPERTY(includes INCLUDE_DIRECTORIES) # SWIG doesn't need Python.h in its own include path -include_directories(${PYTHON_INCLUDE_DIRS}) +include_directories(SYSTEM ${PYTHON_INCLUDE_DIRS}) # this is needed for some reason that I don't understand set(swig_path %(swigpath)s) diff --git a/tools/build/cmake_templates/ModuleTest.cmake b/tools/build/cmake_templates/ModuleTest.cmake index b6ef0fc522..fff3f10821 100644 --- a/tools/build/cmake_templates/ModuleTest.cmake +++ b/tools/build/cmake_templates/ModuleTest.cmake @@ -1,4 +1,4 @@ -include_directories(%(includepath)s) +include_directories(SYSTEM %(includepath)s) link_directories(%(libpath)s) add_definitions("-DIMP_EXECUTABLE") diff --git a/tools/build/cmake_templates/ModuleUtil.cmake b/tools/build/cmake_templates/ModuleUtil.cmake index e4e23a7996..af616bd9ef 100644 --- a/tools/build/cmake_templates/ModuleUtil.cmake +++ b/tools/build/cmake_templates/ModuleUtil.cmake @@ -1,4 +1,4 @@ -include_directories(%(includepath)s) +include_directories(SYSTEM %(includepath)s) link_directories(%(libpath)s) add_definitions("-DIMP_EXECUTABLE") diff --git a/tools/build/container_templates/container/ClassnamesConstraint.h b/tools/build/container_templates/container/ClassnamesConstraint.h index 3894b5f3d8..b65f3d0eda 100644 --- a/tools/build/container_templates/container/ClassnamesConstraint.h +++ b/tools/build/container_templates/container/ClassnamesConstraint.h @@ -3,7 +3,7 @@ * \brief Use a ClassnameModifier applied to a PLURALVARIABLETYPE to * maintain an invariant * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCONTAINER_CLASSNAMES_CONSTRAINT_H @@ -15,6 +15,8 @@ #include #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE // for swig @@ -32,7 +34,7 @@ IMPCONTAINER_BEGIN_NAMESPACE \see core::ClassnameConstraint */ -class ClassnamesConstraint : +class IMPCONTAINEREXPORT ClassnamesConstraint : #if defined(SWIG) || defined(IMP_DOXYGEN) public Constraint #else @@ -43,6 +45,13 @@ class ClassnamesConstraint : typedef IMP::internal::ContainerConstraint< ClassnameModifier, ClassnameModifier, ClassnameContainer> P; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); + } + + IMP_OBJECT_SERIALIZE_DECL(ClassnamesConstraint); + public: /** \param[in] c The Container to hold the elements to process \param[in] before The ClassnameModifier to apply to all elements @@ -55,6 +64,9 @@ class ClassnamesConstraint : ClassnameContainerAdaptor c, std::string name = "ClassnamesConstraint %1%") : P(before, after, c, name) {} + + ClassnamesConstraint() {} + #if defined(IMP_DOXYGEN) || defined(SWIG) protected: void do_update_attributes(); diff --git a/tools/build/container_templates/container/ClassnamesRestraint.h b/tools/build/container_templates/container/ClassnamesRestraint.h index 372b64554f..b258dcae14 100644 --- a/tools/build/container_templates/container/ClassnamesRestraint.h +++ b/tools/build/container_templates/container/ClassnamesRestraint.h @@ -2,7 +2,7 @@ * \file IMP/container/ClassnamesRestraint.h * \brief Apply a ClassnameScore to each Classname in a list. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -13,6 +13,8 @@ #include #include #include +#include +#include IMPCONTAINER_BEGIN_NAMESPACE @@ -37,6 +39,13 @@ class ClassnamesRestraint : typedef IMP::internal::ContainerRestraint< ClassnameScore, ClassnameContainer> P; + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); + } + IMP_OBJECT_SERIALIZE_DECL(ClassnamesRestraint); + public: //! Create the restraint with a shared container /** \param[in] ss The function to apply to each particle. @@ -48,6 +57,8 @@ class ClassnamesRestraint : std::string name = "ClassnamesRestraint %1%") : P(ss, pc, name) {} + ClassnamesRestraint() {} + #if defined(IMP_DOXYGEN) || defined(SWIG) double unprotected_evaluate(IMP::DerivativeAccumulator *accum) const; IMP::ModelObjectsTemp do_get_inputs() const; diff --git a/tools/build/container_templates/container/InContainerClassnameFilter.h b/tools/build/container_templates/container/InContainerClassnameFilter.h index 3a31749d4e..cd8fa16543 100644 --- a/tools/build/container_templates/container/InContainerClassnameFilter.h +++ b/tools/build/container_templates/container/InContainerClassnameFilter.h @@ -19,11 +19,11 @@ IMPCONTAINER_BEGIN_NAMESPACE -//! A filter which returns true if a container containers the Classname +//! A filter which returns true if a container contains the Classname /** This predicate returns 1 if the passed tuple is in the container. \note Use the handle_permutations parameter to the constructor to - determine whether only exact matchers, or matches under permutation - are considered matching. By default they are are. + determine whether only exact matches, or matches under permutation + are considered matching. By default permutations are allowed. */ class IMPCONTAINEREXPORT InContainerClassnameFilter : public ClassnamePredicate { diff --git a/tools/build/container_templates/container/ListClassnameContainer.h b/tools/build/container_templates/container/ListClassnameContainer.h index bd46e3a3c2..65cd2727a8 100644 --- a/tools/build/container_templates/container/ListClassnameContainer.h +++ b/tools/build/container_templates/container/ListClassnameContainer.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include IMPCONTAINER_BEGIN_NAMESPACE @@ -43,6 +45,7 @@ class IMPCONTAINEREXPORT ListClassnameContainer : ListClassnameContainer(Model *m, std::string name = "ListClassnameContainer %1%"); ListClassnameContainer(Model *m, const char *name); + ListClassnameContainer() {} #endif #if defined(SWIG) || defined(IMP_DOXYGEN) @@ -73,6 +76,13 @@ class IMPCONTAINEREXPORT ListClassnameContainer : std::size_t do_get_contents_hash() const; #endif IMP_OBJECT_METHODS(ListClassnameContainer); + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class

(this)); + } + IMP_OBJECT_SERIALIZE_DECL(ListClassnameContainer); }; IMP_OBJECTS(ListClassnameContainer, ListClassnameContainers); diff --git a/tools/build/container_templates/container/PredicateClassnamesRestraint.h b/tools/build/container_templates/container/PredicateClassnamesRestraint.h index 3b941828e9..277b78a1bf 100644 --- a/tools/build/container_templates/container/PredicateClassnamesRestraint.h +++ b/tools/build/container_templates/container/PredicateClassnamesRestraint.h @@ -2,7 +2,7 @@ * \file IMP/container/PredicateClassnamesRestraint.h * \brief Apply a ClassnameScore to each Classname in a list. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -10,8 +10,12 @@ #define IMPCONTAINER_PREDICATE_CLASSNAMES_RESTRAINT_H #include +#include #include #include "generic.h" +#include +#include +#include #if IMP_CONTAINER_HAS_ROBIN_MAP==1 @@ -61,6 +65,21 @@ class IMPCONTAINEREXPORT PredicateClassnamesRestraint : public Restraint { // bool is_unknown_score_set_; bool error_on_unknown_; PointerMember unknown_score_; + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), + predicate_, input_, scores_, + is_get_inputs_ignores_individual_scores_, + error_on_unknown_, unknown_score_); + if (std::is_base_of::value) { + // Force lists_ to be rebuilt (from scores_) + lists_.clear(); + input_version_ = -1; + } + } + IMP_OBJECT_SERIALIZE_DECL(PredicateClassnamesRestraint); + // void update_lists_with_item(INDEXTYPE const &it) const; void update_lists_if_necessary() const; @@ -70,6 +89,8 @@ class IMPCONTAINEREXPORT PredicateClassnamesRestraint : public Restraint { std::string name = "PredicateClassnamesRestraint %1%"); + PredicateClassnamesRestraint() {} + /** Apply the passed score to all pairs whose predicate values match the passed value.*/ void set_score(int predicate_value, ClassnameScore *score); diff --git a/tools/build/container_templates/container/classnames.cpp b/tools/build/container_templates/container/classnames.cpp index 185964709c..f70bb8b7bb 100644 --- a/tools/build/container_templates/container/classnames.cpp +++ b/tools/build/container_templates/container/classnames.cpp @@ -13,6 +13,8 @@ #include "IMP/container/ClassnameContainerSet.h" #include "IMP/container/ClassnameContainerStatistics.h" #include "IMP/container/ClassnamesOptimizerState.h" +#include "IMP/container/ClassnamesConstraint.h" +#include "IMP/container/ClassnamesRestraint.h" #include "IMP/container/DistributeClassnamesScoreState.h" #include "IMP/container/DynamicListClassnameContainer.h" #include "IMP/container/InContainerClassnameFilter.h" @@ -497,7 +499,7 @@ PredicateClassnamesRestraint::PredicateClassnamesRestraint( predicate_(pred), input_(input), is_get_inputs_ignores_individual_scores_(false), - input_version_(input->get_contents_hash()), + input_version_(-1), // is_unknown_score_set_(false), error_on_unknown_(true), unknown_score_(nullptr) @@ -603,4 +605,9 @@ void PredicateClassnamesRestraint::set_unknown_score(ClassnameScore *score) { //is_unknown_score_set_=true; } +IMP_OBJECT_SERIALIZE_IMPL(IMP::container::ListClassnameContainer); +IMP_OBJECT_SERIALIZE_IMPL(IMP::container::ClassnamesConstraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::container::ClassnamesRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::container::PredicateClassnamesRestraint); + IMPCONTAINER_END_NAMESPACE diff --git a/tools/build/container_templates/container/internal/ClassnameContainerIndex.h b/tools/build/container_templates/container/internal/ClassnameContainerIndex.h index 90774796c4..9c3a4f7424 100644 --- a/tools/build/container_templates/container/internal/ClassnameContainerIndex.h +++ b/tools/build/container_templates/container/internal/ClassnameContainerIndex.h @@ -16,8 +16,8 @@ IMPCONTAINER_BEGIN_INTERNAL_NAMESPACE -/** Store an index that allows one to quickly determine of something - is in a container.*/ +/** Store an index that allows one to quickly determine if something + is in a container. */ class IMPCONTAINEREXPORT ClassnameContainerIndex : public ScoreState { Pointer container_; std::size_t container_version_; diff --git a/tools/build/container_templates/core/ClassnameConstraint.h b/tools/build/container_templates/core/ClassnameConstraint.h index 2117f9dba4..094f223732 100644 --- a/tools/build/container_templates/core/ClassnameConstraint.h +++ b/tools/build/container_templates/core/ClassnameConstraint.h @@ -3,7 +3,7 @@ * \brief Use a ClassnameModifier applied to a PLURALVARIABLETYPE to * maintain an invariant * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCORE_CLASSNAME_CONSTRAINT_H @@ -13,6 +13,8 @@ #include #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE //! Apply a ClassnameFunction to a Classname @@ -32,19 +34,16 @@ class ClassnameConstraint : ClassnameDerivativeModifier> #endif { - public: - /** \deprecated_at{2.1} Use the model/index constructor. - */ - IMPCORE_DEPRECATED_METHOD_DECL(2.1) - ClassnameConstraint(ClassnameModifier *before, - ClassnameDerivativeModifier *after, ARGUMENTTYPE vt, - std::string name = "ClassnameConstraint %1%") - : IMP::internal::TupleConstraint< - ClassnameModifier, ClassnameDerivativeModifier>(before, after, vt, - name) { - IMPCORE_DEPRECATED_METHOD_DEF(2.1, "Use the model/index constructor."); + + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class< + IMP::internal::TupleConstraint >(this)); } + IMP_OBJECT_SERIALIZE_DECL(ClassnameConstraint); + public: ClassnameConstraint(ClassnameModifier *before, ClassnameDerivativeModifier *after, Model *m, PASSINDEXTYPE vt, @@ -55,6 +54,8 @@ class ClassnameConstraint : vt, name, can_skip) {} + ClassnameConstraint() {} + #if defined(IMP_DOXYGEN) || defined(SWIG) protected: void do_update_attributes(); diff --git a/tools/build/container_templates/core/ClassnameRestraint.h b/tools/build/container_templates/core/ClassnameRestraint.h index 8ee9aad8ce..6d00ab8b7a 100644 --- a/tools/build/container_templates/core/ClassnameRestraint.h +++ b/tools/build/container_templates/core/ClassnameRestraint.h @@ -2,7 +2,7 @@ * \file IMP/core/ClassnameRestraint.h * \brief Apply a ClassnameScore to a Classname. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. * */ @@ -15,6 +15,8 @@ #include #include +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -29,6 +31,13 @@ class ClassnameRestraint : public IMP::internal::TupleRestraint #endif { + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class< + IMP::internal::TupleRestraint >(this)); + } + IMP_OBJECT_SERIALIZE_DECL(ClassnameRestraint); public: //! Create the restraint. /** This function takes the function to apply to the @@ -38,6 +47,7 @@ class ClassnameRestraint : std::string name = "ClassnameRestraint %1%") : IMP::internal::TupleRestraint(ss, m, vt, name) { } + ClassnameRestraint() {} #if defined(SWIG) || defined(IMP_DOXYGEN) protected: diff --git a/tools/build/container_templates/core/classname_predicates.cpp b/tools/build/container_templates/core/classname_predicates.cpp index 3e2d2ac752..377d244e4c 100644 --- a/tools/build/container_templates/core/classname_predicates.cpp +++ b/tools/build/container_templates/core/classname_predicates.cpp @@ -1,10 +1,12 @@ /** * \file ClassnamePredicate.cpp \brief Define ClassnamePredicate * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #include +#include +#include #include IMPCORE_BEGIN_NAMESPACE @@ -26,4 +28,10 @@ CoinFlipClassnamePredicate::CoinFlipClassnamePredicate(double p, std::string name) : ClassnamePredicate(name), p_(p), rng_(0., 1.) {} +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::ClassnameRestraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::ClassnameConstraint); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::ConstantClassnamePredicate); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::UnorderedTypeClassnamePredicate); +IMP_OBJECT_SERIALIZE_IMPL(IMP::core::AllSameClassnamePredicate); + IMPCORE_END_NAMESPACE diff --git a/tools/build/container_templates/core/classname_predicates.h b/tools/build/container_templates/core/classname_predicates.h index 55740956c2..66fd86a486 100644 --- a/tools/build/container_templates/core/classname_predicates.h +++ b/tools/build/container_templates/core/classname_predicates.h @@ -2,7 +2,7 @@ * \file IMP/core/classname_predicates.h * \brief Define some predicates. * - * Copyright 2007-2022 IMP Inventors. All rights reserved. + * Copyright 2007-2023 IMP Inventors. All rights reserved. */ #ifndef IMPCORE_CLASSNAME_PREDICATES_H @@ -14,6 +14,8 @@ #include #include #include "internal/container_helpers.h" +#include +#include IMPCORE_BEGIN_NAMESPACE @@ -22,9 +24,18 @@ IMPCORE_BEGIN_NAMESPACE class IMPCOREEXPORT ConstantClassnamePredicate : public ClassnamePredicate { int v_; + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this), v_); + } + IMP_OBJECT_SERIALIZE_DECL(ConstantClassnamePredicate); + public: ConstantClassnamePredicate(int v, std::string name = "ConstClassnamePredicate%1%"); + + ConstantClassnamePredicate() {} + virtual int get_value_index(Model *, PASSINDEXTYPE) const override { return v_; @@ -44,6 +55,12 @@ class IMPCOREEXPORT ConstantClassnamePredicate : public ClassnamePredicate { class IMPCOREEXPORT UnorderedTypeClassnamePredicate : public ClassnamePredicate { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(UnorderedTypeClassnamePredicate); + public: UnorderedTypeClassnamePredicate(std::string name = "UnorderedTypeClassnamePredicate%1%"); @@ -113,6 +130,12 @@ class IMPCOREEXPORT OrderedTypeClassnamePredicate : public ClassnamePredicate { /** Return true if all members of the tuple are the same. */ class IMPCOREEXPORT AllSameClassnamePredicate : public ClassnamePredicate { + friend class cereal::access; + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + } + IMP_OBJECT_SERIALIZE_DECL(AllSameClassnamePredicate); + public: AllSameClassnamePredicate(std::string name = "AllSameClassnamePredicate%1%"); virtual int get_value_index(Model *m, PASSINDEXTYPE pi) const diff --git a/tools/build/container_templates/kernel/ClassnameContainer.h b/tools/build/container_templates/kernel/ClassnameContainer.h index 3bbfae06d2..e5627cacf3 100644 --- a/tools/build/container_templates/kernel/ClassnameContainer.h +++ b/tools/build/container_templates/kernel/ClassnameContainer.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include IMPKERNEL_BEGIN_NAMESPACE class ClassnameModifier; @@ -119,6 +121,7 @@ class IMPKERNELEXPORT ClassnameContainer : public Container { protected: ClassnameContainer(Model *m, std::string name = "ClassnameContainer %1%"); + ClassnameContainer() {} virtual void do_apply(const ClassnameModifier *sm) const = 0; virtual void do_apply_moved(const ClassnameModifier *sm, @@ -145,6 +148,18 @@ class IMPKERNELEXPORT ClassnameContainer : public Container { mutable std::size_t contents_hash_; mutable PLURALINDEXTYPE contents_cache_; mutable bool cache_initialized_; + + friend class cereal::access; + + template void serialize(Archive &ar) { + ar(cereal::base_class(this)); + // clear cache on read + if (std::is_base_of::value) { + contents_hash_ = -1; + cache_initialized_ = false; + } + } + }; /** This class allows either a list or a container to be diff --git a/tools/build/container_templates/kernel/ClassnameScore.h b/tools/build/container_templates/kernel/ClassnameScore.h index 5e78915753..2322376898 100644 --- a/tools/build/container_templates/kernel/ClassnameScore.h +++ b/tools/build/container_templates/kernel/ClassnameScore.h @@ -13,6 +13,8 @@ #include "DerivativeAccumulator.h" #include "internal/container_helpers.h" #include +#include +#include #include "model_object_helpers.h" IMPKERNEL_BEGIN_NAMESPACE @@ -133,6 +135,14 @@ class IMPKERNELEXPORT ClassnameScore : public ParticleInputs, PASSINDEXTYPE vt) const; IMP_REF_COUNTED_DESTRUCTOR(ClassnameScore); + + private: + friend class cereal::access; + + template void serialize(Archive &ar) { + // Neither we nor ParticleInputs stores data, but Object does + ar(cereal::base_class(this)); + } }; IMPKERNEL_END_NAMESPACE diff --git a/tools/build/container_templates/kernel/classnames.cpp b/tools/build/container_templates/kernel/classnames.cpp index e38650eed8..51cd6081b3 100644 --- a/tools/build/container_templates/kernel/classnames.cpp +++ b/tools/build/container_templates/kernel/classnames.cpp @@ -192,4 +192,7 @@ Restraints ClassnameScore::create_current_decomposition( return do_create_current_decomposition(m, vt); } +template<> +IMP_OBJECT_SERIALIZE_IMPL(IMP::internal::StaticListContainer); + IMPKERNEL_END_NAMESPACE diff --git a/tools/build/copy_directory_deref.py b/tools/build/copy_directory_deref.py new file mode 100755 index 0000000000..62b453e08f --- /dev/null +++ b/tools/build/copy_directory_deref.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +"""Like cmake -E copy_directory, but dereference any symlinks""" + +import shutil +import sys + + +def main(): + if len(sys.argv) != 3: + raise ValueError("Usage: %s src dst" % sys.argv[0]) + _, src, dst = sys.argv + shutil.copytree(src, dst, symlinks=False) + + +if __name__ == '__main__': + main() diff --git a/tools/build/setup_swig_wrappers.py b/tools/build/setup_swig_wrappers.py index bc271f4f6a..1a41f7c837 100755 --- a/tools/build/setup_swig_wrappers.py +++ b/tools/build/setup_swig_wrappers.py @@ -4,6 +4,7 @@ """ import os.path +import datetime import tools from optparse import OptionParser @@ -46,13 +47,14 @@ def build_wrapper(module, finder, sorted, target, source): swig_module_name = "IMP" if module.name == 'kernel' \ else "IMP." + module.name + year = datetime.datetime.now().year contents.append( """%%module(directors="1", allprotected="1", moduleimport="import $module") "%s" %%feature("autodoc", 1); %%pythonbegin %%{ # This wrapper is part of IMP, -# Copyright 2007-2022 IMP Inventors. All rights reserved. +# Copyright 2007-%d IMP Inventors. All rights reserved. from __future__ import print_function, division, absolute_import %%} @@ -74,6 +76,8 @@ def build_wrapper(module, finder, sorted, target, source): #include #include #include +// for serialization/pickle support +#include #ifdef __cplusplus extern "C" @@ -88,7 +92,7 @@ def build_wrapper(module, finder, sorted, target, source): #endif SWIG_init(); %%} -""" % swig_module_name) # noqa: E501 +""" % (swig_module_name, year)) # noqa: E501 # some of the typemap code ends up before this is swig sees the # typemaps first all_deps = [x for x in finder.get_dependent_modules([module]) @@ -104,6 +108,8 @@ def build_wrapper(module, finder, sorted, target, source): %include "std_string.i" %include "std_pair.i" +// Help SWIG with cereal macros +#define CEREAL_CLASS_VERSION(x, y) %pythoncode %{ _value_types=[] diff --git a/tools/cmake/UseIMP.cmake b/tools/cmake/UseIMP.cmake index 1054794241..c4d088977c 100644 --- a/tools/cmake/UseIMP.cmake +++ b/tools/cmake/UseIMP.cmake @@ -40,6 +40,7 @@ function(imp_build_module sourcedir) # Add include directories of mandatory IMP dependencies include_directories(SYSTEM ${Boost_INCLUDE_DIR}) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR}) + include_directories(SYSTEM ${cereal_INCLUDE_DIRS}) imp_find_python() diff --git a/tools/debian/control b/tools/debian/control index 9abf66e649..da30e5782c 100644 --- a/tools/debian/control +++ b/tools/debian/control @@ -1,7 +1,7 @@ Source: imp Priority: optional Maintainer: Ben Webb -Build-Depends: debhelper (>= 8.0.0), cmake, swig, libboost-filesystem-dev, libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-random-dev, libboost-regex-dev, libboost-thread-dev, libcgal-dev, libhdf5-dev, libfftw3-dev, libopencv-dev, libgsl0-dev, python2-dev, coreutils, unzip, wget, python3-dev, symlinks, libann-dev, libeigen3-dev, libprotobuf-dev, libopenmpi-dev +Build-Depends: debhelper (>= 8.0.0), cmake, swig, libboost-filesystem-dev, libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-random-dev, libboost-regex-dev, libboost-thread-dev, libcgal-dev, libhdf5-dev, libfftw3-dev, libopencv-dev, libgsl0-dev, python2-dev, coreutils, unzip, wget, python3-dev, symlinks, libann-dev, libeigen3-dev, libcereal-dev, libprotobuf-dev, libopenmpi-dev Standards-Version: 3.9.4 Section: libs Homepage: https://integrativemodeling.org/ @@ -11,7 +11,7 @@ Vcs-Browser: https://github.com/salilab/imp/ Package: imp-dev Section: libdevel Architecture: any -Depends: imp (= ${binary:Version}), ${misc:Depends}, cmake, swig, libboost-filesystem-dev, libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-random-dev, libboost-regex-dev, libboost-thread-dev, libcgal-dev, libhdf5-dev, libfftw3-dev, libopencv-dev, libgsl0-dev, python3-dev, libann-dev, libeigen3-dev, libprotobuf-dev +Depends: imp (= ${binary:Version}), ${misc:Depends}, cmake, swig, libboost-filesystem-dev, libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-random-dev, libboost-regex-dev, libboost-thread-dev, libcgal-dev, libhdf5-dev, libfftw3-dev, libopencv-dev, libgsl0-dev, python3-dev, libann-dev, libeigen3-dev, libcereal-dev, libprotobuf-dev Description: The Integrative Modeling Platform Headers to compile against IMP. diff --git a/tools/debian/copyright b/tools/debian/copyright index 058b418c31..c54b3e3b59 100644 --- a/tools/debian/copyright +++ b/tools/debian/copyright @@ -2,7 +2,7 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: imp Source: https://integrativemodeling.org/ -Copyright: 2007-2022 IMP Inventors +Copyright: 2007-2023 IMP Inventors License: LGPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/tools/maintenance/bump_rmf.sh b/tools/maintenance/bump_rmf.sh deleted file mode 100755 index f9dd3bc42a..0000000000 --- a/tools/maintenance/bump_rmf.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/csh - -pushd modules/rmf/dependency/RMF_source -git checkout develop -git pull origin develop -git submodule update -set hash=`git rev-parse HEAD` -popd -echo "Committing" -git commit modules/rmf/dependency/RMF_source -m "bump RMF to salilab/rmf@$hash" --no-verify diff --git a/tools/maintenance/update_copyright_year.py b/tools/maintenance/update_copyright_year.py new file mode 100755 index 0000000000..1e555db1b6 --- /dev/null +++ b/tools/maintenance/update_copyright_year.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + +""" +Update the year range in the IMP copyright notice. This is displayed in +the documentation and by command line tools. Should be run before the +first stable release in a given year. + +Note that each .cpp and .h file also has a copyright notice which includes +a year range, but we no longer update those in bulk each year, as these +updates muddy the git logs and provide no meaningful copyright protection. +Instead, we update individual files ad hoc, only when significant changes +are made. +""" + +import datetime +import re + + +FILES = ["README.md", "doc/manual/licenses.md", "tools/debian/copyright", + "modules/kernel/src/base_utility.cpp"] +YEAR = datetime.datetime.now().year + + +def patch_file(f): + with open(f) as fh: + old_contents = fh.read() + new_contents = re.sub(r"Copyright 2007\-\d+", "Copyright 2007-%d" % YEAR, + old_contents) + if new_contents == old_contents: + print("WARNING: nothing substituted in " + f) + else: + with open(f, 'w') as fh: + fh.write(new_contents) + + +def main(): + for f in FILES: + patch_file(f) + + +if __name__ == '__main__': + main() diff --git a/tools/nightly-tests/test-install/SConstruct b/tools/nightly-tests/test-install/SConstruct index 87183687c8..4ae5b1f6a6 100644 --- a/tools/nightly-tests/test-install/SConstruct +++ b/tools/nightly-tests/test-install/SConstruct @@ -48,7 +48,7 @@ if path: # Test compiling and running a C++ program that links against IMP testcpp = env.Program('test.cpp', CPPPATH=cpppath, LIBPATH=libpath, CXXFLAGS=cxxflags, LINKFLAGS=linkflags, - LIBS=['imp_core', 'imp_algebra', + LIBS=['imp_core', 'imp_algebra', 'imp_score_functor', 'imp_example', 'imp_container', 'imp_kernel']) runcpp = env.Command('cpp.out', testcpp, "./$SOURCES > $TARGET") diff --git a/tools/rpm/IMP.spec.in b/tools/rpm/IMP.spec.in index bca88a5059..24008df131 100644 --- a/tools/rpm/IMP.spec.in +++ b/tools/rpm/IMP.spec.in @@ -56,7 +56,7 @@ BuildRequires: swig3 >= 3.0 BuildRequires: swig >= 3.0 %endif BuildRequires: gsl-devel, fftw-devel -BuildRequires: zlib-devel, perl, eigen3-devel +BuildRequires: zlib-devel, perl, eigen3-devel, cereal-devel %if 0%{?fedora} || 0%{?rhel} <= 7 BuildRequires: ann-devel %endif @@ -167,7 +167,7 @@ as well as easy addition of new functionality. Group: Applications/Engineering Summary: Development package for IMP developers. Requires: %{name} = %{version}-%{release} -Requires: gsl-devel, fftw-devel, zlib-devel, eigen3-devel +Requires: gsl-devel, fftw-devel, zlib-devel, eigen3-devel, cereal-devel Requires: boost-devel, hdf5-devel, protobuf-devel %if 0%{?fedora} || 0%{?rhel} <= 7 Requires: ann-devel @@ -539,6 +539,9 @@ find ${RPM_BUILD_ROOT}%{_prefix}/share/IMP/tools -name '*.py' -exec perl -pi -e %endif %changelog +* Thu Jun 22 2023 Ben Webb 2.19.0-1 +- 2.19.0 release. + * Thu Dec 15 2022 Ben Webb 2.18.0-1 - 2.18.0 release. diff --git a/tools/w32/make-package.sh b/tools/w32/make-package.sh index 13550522df..889566412f 100755 --- a/tools/w32/make-package.sh +++ b/tools/w32/make-package.sh @@ -118,61 +118,36 @@ PYVERS="36 37 38 39 310 311" if [ "${BITS}" = "32" ]; then MAKENSIS="makensis" DLLSRC=/usr/lib/w32comp/windows/system - - # Add redist MSVC runtime DLLs - cp ${DLLSRC}/msvcp140.dll ${DLLSRC}/concrt140.dll ${DLLSRC}/vcruntime140.dll \ - ${ROOT}/bin || exit 1 - - # Add other DLL dependencies - cp ${DLLSRC}/hdf5.dll ${DLLSRC}/libgsl.dll ${DLLSRC}/libgslcblas.dll \ - ${DLLSRC}/boost_filesystem-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_program_options-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_system-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_date_time-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_graph-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_regex-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_thread-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_random-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_iostreams-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_zlib-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/boost_serialization-vc140-mt-x${BITS}-1_72.dll \ - ${DLLSRC}/libgmp-10.dll \ - ${DLLSRC}/libmpfr-4.dll \ - ${DLLSRC}/libfftw3-3.dll \ - ${DLLSRC}/libTAU1.dll \ - ${DLLSRC}/zlib1.dll \ - ${DLLSRC}/opencv_core455.dll ${DLLSRC}/opencv_highgui455.dll \ - ${DLLSRC}/opencv_imgcodecs455.dll ${DLLSRC}/opencv_videoio455.dll \ - ${DLLSRC}/opencv_imgproc455.dll ${ROOT}/bin || exit 1 else MAKENSIS="makensis -DIMP_64BIT" DLLSRC=/usr/lib/w64comp/windows/system32 - # Add redist MSVC runtime DLLs - cp ${DLLSRC}/msvc*110.dll ${ROOT}/bin || exit 1 - # Add other DLL dependencies - cp ${DLLSRC}/hdf5.dll ${DLLSRC}/libgsl.dll ${DLLSRC}/libgslcblas.dll \ - ${DLLSRC}/boost_filesystem-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_program_options-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_system-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_date_time-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_graph-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_regex-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_thread-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_random-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_iostreams-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_zlib-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_chrono-vc110-mt-1_55.dll \ - ${DLLSRC}/boost_serialization-vc110-mt-1_55.dll \ - ${DLLSRC}/CGAL-vc110-mt-4.4.dll \ - ${DLLSRC}/libgmp-10.dll \ - ${DLLSRC}/libmpfr-4.dll \ - ${DLLSRC}/libfftw3-3.dll \ - ${DLLSRC}/libTAU1.dll \ - ${DLLSRC}/zlib1.dll \ - ${DLLSRC}/opencv_core248.dll ${DLLSRC}/opencv_highgui248.dll \ - ${DLLSRC}/opencv_imgproc248.dll ${ROOT}/bin || exit 1 fi +# Add redist MSVC runtime DLLs +cp ${DLLSRC}/msvcp140.dll ${DLLSRC}/concrt140.dll ${DLLSRC}/vcruntime140.dll \ + ${ROOT}/bin || exit 1 + +# Add other DLL dependencies +cp ${DLLSRC}/hdf5.dll ${DLLSRC}/libgsl.dll ${DLLSRC}/libgslcblas.dll \ + ${DLLSRC}/boost_filesystem-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_program_options-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_system-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_date_time-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_graph-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_regex-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_thread-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_random-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_iostreams-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/boost_zlib-vc140-mt-x${BITS}-1_72.dll \ + ${DLLSRC}/libgmp-10.dll \ + ${DLLSRC}/libmpfr-4.dll \ + ${DLLSRC}/libfftw3-3.dll \ + ${DLLSRC}/libTAU1.dll \ + ${DLLSRC}/zlib1.dll \ + ${DLLSRC}/opencv_core455.dll ${DLLSRC}/opencv_highgui455.dll \ + ${DLLSRC}/opencv_imgcodecs455.dll ${DLLSRC}/opencv_videoio455.dll \ + ${DLLSRC}/opencv_imgproc455.dll ${ROOT}/bin || exit 1 + # Check all installed binaries for DLL dependencies, to make sure we # didn't miss any dumpbin /DEPENDENTS ${ROOT}/bin/*.exe ${ROOT}/bin/*.dll ${ROOT}/python/*/*.pyd \