diff --git a/.github/workflows/test_openmm_dmff_plugin.yml b/.github/workflows/test_openmm_dmff_plugin.yml new file mode 100644 index 000000000..f6da47259 --- /dev/null +++ b/.github/workflows/test_openmm_dmff_plugin.yml @@ -0,0 +1,50 @@ +name: OpenMM DMFF Plugin tests. + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.9] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + source $CONDA/bin/activate + conda create -n dmff_omm -y python=${{ matrix.python-version }} numpy openmm=7.7 -c conda-forge + conda activate dmff_omm + conda install -y libtensorflow_cc=2.9.1 -c conda-forge + pip install setuptools==59.5.0 + mkdir /tmp/omm_dmff_working_dir + cd /tmp/omm_dmff_working_dir + wget https://github.com/tensorflow/tensorflow/archive/refs/tags/v2.9.1.tar.gz + tar -xvf v2.9.1.tar.gz + cp -r tensorflow-2.9.1/tensorflow/c ${CONDA_PREFIX}/include/tensorflow/ + git clone https://github.com/serizba/cppflow.git + cd cppflow + git apply ${GITHUB_WORKSPACE}/backend/openmm_dmff_plugin/tests/cppflow_empty_constructor.patch + mkdir ${CONDA_PREFIX}/include/cppflow + cp -r include/cppflow ${CONDA_PREFIX}/include/ + - name: Install OpenMM DMFF Plugin + run: | + source $CONDA/bin/activate dmff_omm + cd ${GITHUB_WORKSPACE}/backend/openmm_dmff_plugin + mkdir build && cd build + export OPENMM_INSTALLED_DIR=$CONDA_PREFIX + export CPPFLOW_INSTALLED_DIR=$CONDA_PREFIX + export LIBTENSORFLOW_INSTALLED_DIR=$CONDA_PREFIX + cmake .. -DOPENMM_DIR=${OPENMM_INSTALLED_DIR} -DCPPFLOW_DIR=${CPPFLOW_INSTALLED_DIR} -DTENSORFLOW_DIR=${LIBTENSORFLOW_INSTALLED_DIR} -DUSE_HIGH_PRECISION=ON + make && make install + make PythonInstall + - name: Run Tests + run: | + source $CONDA/bin/activate dmff_omm + python -m OpenMMDMFFPlugin.tests.test_dmff_plugin_nve -n 100 diff --git a/.gitignore b/.gitignore index 74c7e80e1..23773fb36 100644 --- a/.gitignore +++ b/.gitignore @@ -784,4 +784,4 @@ FodyWeavers.xsd */_version.py # hmtff cache -*.hmtff/ \ No newline at end of file +*.hmtff/ diff --git a/backend/openmm_dmff_plugin/.gitignore b/backend/openmm_dmff_plugin/.gitignore new file mode 100644 index 000000000..94dd7c7ae --- /dev/null +++ b/backend/openmm_dmff_plugin/.gitignore @@ -0,0 +1,6 @@ +**/build +**/.vscode +**/__pycache__ +*.dcd +**/output +**/.devcontainer \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/CMakeLists.txt b/backend/openmm_dmff_plugin/CMakeLists.txt new file mode 100644 index 000000000..398875e24 --- /dev/null +++ b/backend/openmm_dmff_plugin/CMakeLists.txt @@ -0,0 +1,149 @@ +#--------------------------------------------------- +# OpenMM DMFF Plugin +#---------------------------------------------------- + +CMAKE_MINIMUM_REQUIRED(VERSION 3.5) +SET(CMAKE_VERBOSE_MAKEFILE OFF) + +project(OpenMMDMFF) + +# We need to know where OpenMM is installed so we can access the headers and libraries. +SET(OPENMM_DIR "/usr/local/openmm" CACHE PATH "Where OpenMM is installed") +INCLUDE_DIRECTORIES("${OPENMM_DIR}/include") +LINK_DIRECTORIES("${OPENMM_DIR}/lib" "${OPENMM_DIR}/lib/plugins") + + +# Include the cppflow +SET(CPPFLOW_DIR "/usr/local/cppflow/" CACHE PATH "Where cppflow is installed") +INCLUDE_DIRECTORIES("${CPPFLOW_DIR}/include") +LINK_DIRECTORIES("${CPPFLOW_DIR}/lib") + +# Include the tensorflow +SET(TENSORFLOW_DIR "/usr/local/tensorflow/" CACHE PATH "Where libtensorflow is installed") +INCLUDE_DIRECTORIES("${TENSORFLOW_DIR}/include") +LINK_DIRECTORIES("${TENSORFLOW_DIR}/lib") + +# Specify the C++ version we are building for. +SET (CMAKE_CXX_STANDARD 17) + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-ignored-attributes -Wl,--allow-multiple-definition -Wl,--no-as-needed") + +# Set if high precision (double) is used. By default, it is off. +OPTION(USE_HIGH_PRECISION "Use high precision (double) for calculations" OFF) + +IF(USE_HIGH_PRECISION) + message(STATUS "USE_HIGH_PRECISION is enabled") + ADD_DEFINITIONS(-DUSE_HIGH_PRECISION) +endif () + +if (USE_HIGH_PRECISION) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHIGH_PRECISION") +else () + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif () + +# Select where to install +IF(${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT}) + IF(WIN32) + SET(CMAKE_INSTALL_PREFIX "$ENV{ProgramFiles}/OpenMM" CACHE PATH "Where to install the plugin" FORCE) + ELSE(WIN32) + SET(CMAKE_INSTALL_PREFIX "${OPENMM_DIR}" CACHE PATH "Where to install the plugin" FORCE) + ENDIF(WIN32) +ENDIF(${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT}) + +# Put all the tests and libraries in a single output directory. +IF(NOT EXECUTABLE_OUTPUT_PATH) + SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR} + CACHE INTERNAL "Single output directory for building all executables.") +ENDIF() +IF(NOT LIBRARY_OUTPUT_PATH) + SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR} + CACHE INTERNAL "Single output directory for building all libraries.") +ENDIF() +SET(${PROJECT_NAME}_EXECUTABLE_DIR ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) +SET(${PROJECT_NAME}_LIBRARY_DIR ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) + +# The source is organized into subdirectories, but we handle them all from +# this CMakeLists file rather than letting CMake visit them as SUBDIRS. +SET(DMFF_PLUGIN_SOURCE_SUBDIRS openmmapi serialization) + +# Set the library name +SET(DMFF_LIBRARY_NAME OpenMMDMFF) +SET(SHARED_DMFF_TARGET ${DMFF_LIBRARY_NAME}) + +# These are all the places to search for header files that are to be part of the API. +SET(API_INCLUDE_DIRS "openmmapi/include" "openmmapi/include/internal") + +# Locate header files. +SET(API_INCLUDE_FILES) +FOREACH(dir ${API_INCLUDE_DIRS}) + FILE(GLOB fullpaths ${dir}/*.h) + SET(API_INCLUDE_FILES ${API_INCLUDE_FILES} ${fullpaths}) +ENDFOREACH(dir) + +# Collect source files +SET(SOURCE_FILES) # empty +SET(SOURCE_INCLUDE_FILES) +FOREACH(subdir ${DMFF_PLUGIN_SOURCE_SUBDIRS}) + FILE(GLOB src_files ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/src/*.cpp) + FILE(GLOB incl_files ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/src/*.h) + SET(SOURCE_FILES ${SOURCE_FILES} ${src_files}) #append + SET(SOURCE_INCLUDE_FILES ${SOURCE_INCLUDE_FILES} ${incl_files}) + + ## Make sure we find these locally before looking in OpenMM/include if + ## OpenMM was previously installed there. + INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/include) +ENDFOREACH(subdir) + +# Create the library. + +ADD_LIBRARY(${SHARED_DMFF_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_INCLUDE_FILES}) +SET_TARGET_PROPERTIES(${SHARED_DMFF_TARGET} + PROPERTIES COMPILE_FLAGS "-DDMFF_BUILDING_SHARED_LIBRARY ${EXTRA_COMPILE_FLAGS}" + LINK_FLAGS "${EXTRA_COMPILE_FLAGS}") +TARGET_LINK_LIBRARIES(${SHARED_DMFF_TARGET} OpenMM) +TARGET_LINK_LIBRARIES(${SHARED_DMFF_TARGET} tensorflow_cc) + +INSTALL_TARGETS(/lib RUNTIME_DIRECTORY /lib ${SHARED_DMFF_TARGET}) + +# install headers +FILE(GLOB API_ONLY_INCLUDE_FILES "openmmapi/include/*.h") +INSTALL (FILES ${API_ONLY_INCLUDE_FILES} DESTINATION include) +FILE(GLOB API_ONLY_INCLUDE_FILES_INTERNAL "openmmapi/include/internal/*.h") +INSTALL (FILES ${API_ONLY_INCLUDE_FILES_INTERNAL} DESTINATION include/internal) + +# Enable testing +# Set no testing here. +ENABLE_TESTING() +ADD_SUBDIRECTORY(serialization/tests) + +# Use reference platform default. +ADD_SUBDIRECTORY(platforms/reference) + +FIND_PACKAGE(CUDA QUIET) +IF(CUDA_FOUND) + message(STATUS "CUDA found, building CUDA implementation") + SET(PLUGIN_BUILD_CUDA_LIB ON CACHE BOOL "Build implementation for CUDA: ON") +ELSE(CUDA_FOUND) + message(STATUS "CUDA not found, not building CUDA implementation") + SET(PLUGIN_BUILD_CUDA_LIB OFF CACHE BOOL "Build implementation for CUDA: OFF") +ENDIF(CUDA_FOUND) +IF(PLUGIN_BUILD_CUDA_LIB) + ADD_SUBDIRECTORY(platforms/cuda) +ENDIF(PLUGIN_BUILD_CUDA_LIB) + + +# Build the Python API +FIND_PROGRAM(PYTHON_EXECUTABLE python) +FIND_PROGRAM(SWIG_EXECUTABLE swig) +IF(PYTHON_EXECUTABLE AND SWIG_EXECUTABLE) + message(STATUS "Python and SWIG found, building Python wrappers") + SET(PLUGIN_BUILD_PYTHON_WRAPPERS ON CACHE BOOL "Build wrappers for Python") +ELSE(PYTHON_EXECUTABLE AND SWIG_EXECUTABLE) + message(FATAL_ERROR "Python or SWIG not found, not building Python wrappers") + SET(PLUGIN_BUILD_PYTHON_WRAPPERS OFF CACHE BOOL "Build wrappers for Python") +ENDIF(PYTHON_EXECUTABLE AND SWIG_EXECUTABLE) +IF(PLUGIN_BUILD_PYTHON_WRAPPERS) + ADD_SUBDIRECTORY(python) +ENDIF(PLUGIN_BUILD_PYTHON_WRAPPERS) + diff --git a/backend/openmm_dmff_plugin/README.md b/backend/openmm_dmff_plugin/README.md new file mode 100644 index 000000000..07a8032e0 --- /dev/null +++ b/backend/openmm_dmff_plugin/README.md @@ -0,0 +1,75 @@ +# OpenMM Plugin for DMFF + + +This is a plugin for [OpenMM](http://openmm.org) that used the trained JAX model by [DMFF](https://github.com/deepmodeling/DMFF) as an independent Force class for dynamics. +To use it, you need to save you DMFF model with the script in `DMFF/backend/save_dmff2tf.py`. + +## Installation + +### Create environment with conda +Install the python, openmm and cudatoolkit. +```shell + +mkdir omm_dmff_working_dir && cd omm_dmff_working_dir +conda create -n dmff_omm -c conda-forge python=3.9 openmm cudatoolkit=11.6 +conda activate dmff_omm +``` +### Download `libtensorflow_cc` and install `cppflow` package +Install the precompiled libtensorflow_cc library from deepmodeling channel. +```shell + +conda install -c deepmodeling libtensorflow_cc=2.9.1=cuda112h02da4e0_0 +``` +Download the tensorflow sources file. Copy the `c` direcotry in source code to installed header files of tensorflow library, since it's needed by package `cppflow`. +```shell + +wget https://github.com/tensorflow/tensorflow/archive/refs/tags/v2.9.1.tar.gz +tar -xvf v2.9.1.tar.gz +cp -r tensorflow-2.9.1/tensorflow/c ${CONDA_PREFIX}/include/tensorflow/ +``` +Download `cppflow` and move the headers library to environment path. +```shell + +git clone https://github.com/serizba/cppflow.git +cd cppflow +git apply DMFF/backend/openmm_dmff_plugin/tests/cppflow_empty_constructor.patch +mkdir ${CONDA_PREFIX}/include/cppflow +cp -r include/cppflow ${CONDA_PREFIX}/include/ +``` + +### Install the OpenMM DMFF plugin from source + +Compile the plugin from source with following steps. +1. Set up environment variables. + ```shell + export OPENMM_INSTALLED_DIR=$CONDA_PREFIX + export CPPFLOW_INSTALLED_DIR=$CONDA_PREFIX + export LIBTENSORFLOW_INSTALLED_DIR=$CONDA_PREFIX + cd DMFF/backend/openmm_dmff_plugin/ + mkdir build && cd build + ``` + +2. Run `cmake` command with required parameters. + ```shell + cmake .. -DOPENMM_DIR=${OPENMM_INSTALLED_DIR} -DCPPFLOW_DIR=${CPPFLOW_INSTALLED_DIR} -DTENSORFLOW_DIR=${LIBTENSORFLOW_INSTALLED_DIR} + make && make install + make PythonInstall + ``` + +3. Test the plugin in Python interface, reference platform. + ```shell + python -m OpenMMDMFFPlugin.tests.test_dmff_plugin_nve -n 100 + python -m OpenMMDMFFPlugin.tests.test_dmff_plugin_nvt -n 100 --platform CUDA + ``` +## Usage +Add the following lines to your Python script to use the plugin. +More details can refer to the script in `python/OpenMMDMFFPlugin/tests/test_dmff_plugin_nve.py`. + +```python + +from OpenMMDMFFPlugin import DMFFModel +# Set up the dmff_system with the dmff_model. +dmff_model = DMFFModel(dp_model) +dmff_model.setUnitTransformCoefficients(1, 1, 1) +dmff_system = dmff_model.createSystem(topology) +``` diff --git a/backend/openmm_dmff_plugin/openmmapi/include/DMFFForce.h b/backend/openmm_dmff_plugin/openmmapi/include/DMFFForce.h new file mode 100644 index 000000000..cfacf83c0 --- /dev/null +++ b/backend/openmm_dmff_plugin/openmmapi/include/DMFFForce.h @@ -0,0 +1,116 @@ +#ifndef OPENMM_DMFFFORCE_H_ +#define OPENMM_DMFFFORCE_H_ + +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "openmm/Context.h" +#include "openmm/Force.h" +#include +// Include cppflow header files for model load and evaluation. +#include +#include + +#include "internal/windowsExportDMFF.h" + +using namespace std; + +#if HIGH_PRECISION +typedef double FORCETYPE; +typedef double COORDTYPE; +typedef double ENERGYTYPE; +#else +typedef float FORCETYPE; +typedef float COORDTYPE; +typedef float ENERGYTYPE; +#endif + +namespace DMFFPlugin { +class OPENMM_EXPORT_DMFF DMFFForce : public OpenMM::Force { +public: + /** + * @brief Construct a new DMFF Force object. Used for NVT/NPT/NVE simulations. + * + * @param GraphFile + */ + DMFFForce(const string& GraphFile); + ~DMFFForce(); + /** + * @brief Set the Unit Transform Coefficients. + * + * @param coordCoefficient : the coordinate transform coefficient. + * @param forceCoefficient : the force transform coefficient. + * @param energyCoefficient : the energy transform coefficient. + */ + void setUnitTransformCoefficients(const double coordCoefficient, const double forceCoefficient, const double energyCoefficient); + + const std::string& getDMFFGraphFile() const; + /** + * @brief Get the Coord Unit Coefficient. + * + * @return double + */ + double getCoordUnitCoefficient() const; + /** + * @brief Get the Force Unit Coefficient. + * + * @return double + */ + double getForceUnitCoefficient() const; + /** + * @brief Get the Energy Unit Coefficient. + * + * @return double + */ + double getEnergyUnitCoefficient() const; + /** + * @brief Get the Cutoff radius of the model used. + * + * @return double + */ + double getCutoff() const; + void updateParametersInContext(OpenMM::Context& context); + bool usesPeriodicBoundaryConditions() const { + return use_pbc; + } +protected: + OpenMM::ForceImpl* createImpl() const; +private: + string graph_file; + bool use_pbc = true; + double cutoff = 1.2; + double coordCoeff, forceCoeff, energyCoeff; + +}; + +} // namespace DMFFPlugin + +#endif /*OPENMM_DMFFFORCE_H_*/ diff --git a/backend/openmm_dmff_plugin/openmmapi/include/DMFFKernels.h b/backend/openmm_dmff_plugin/openmmapi/include/DMFFKernels.h new file mode 100644 index 000000000..657264420 --- /dev/null +++ b/backend/openmm_dmff_plugin/openmmapi/include/DMFFKernels.h @@ -0,0 +1,74 @@ +#ifndef DMFF_KERNELS_H_ +#define DMFF_KERNELS_H_ + +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForce.h" +#include "openmm/KernelImpl.h" +#include "openmm/Platform.h" +#include "openmm/System.h" +#include + +namespace DMFFPlugin { + +/** + * This kernel is invoked by DMFFForce to calculate the forces acting on the system and the energy of the system. + */ +class CalcDMFFForceKernel : public OpenMM::KernelImpl { +public: + static std::string Name() { + return "CalcDMFFForce"; + } + CalcDMFFForceKernel(std::string name, const OpenMM::Platform& platform) : OpenMM::KernelImpl(name, platform) { + } + /** + * Initialize the kernel. + * + * @param system the System this kernel will be applied to + * @param force the DMFFForce this kernel will be used for + */ + virtual void initialize(const OpenMM::System& system, const DMFFForce& force) = 0; + /** + * Execute the kernel to calculate the forces and/or energy. + * + * @param context the context in which to execute this kernel + * @param includeForces true if forces should be calculated + * @param includeEnergy true if the energy should be calculated + * @return the potential energy due to the force + */ + virtual double execute(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy) = 0; + +}; + +} // namespace DMFFPlugin + +#endif /*DMFF_KERNELS_H_*/ diff --git a/backend/openmm_dmff_plugin/openmmapi/include/internal/DMFFForceImpl.h b/backend/openmm_dmff_plugin/openmmapi/include/internal/DMFFForceImpl.h new file mode 100644 index 000000000..79cac2fc4 --- /dev/null +++ b/backend/openmm_dmff_plugin/openmmapi/include/internal/DMFFForceImpl.h @@ -0,0 +1,74 @@ +#ifndef OPENMM_DMFFFORCEIMPL_H_ +#define OPENMM_DMFFFORCEIMPL_H_ + +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForce.h" +#include "openmm/internal/ForceImpl.h" +#include "openmm/Kernel.h" +#include +#include +#include + +namespace DMFFPlugin { + +class System; + +/** + * This is the internal implementation of DMFFForce. + */ + +class OPENMM_EXPORT_DMFF DMFFForceImpl : public OpenMM::ForceImpl { +public: + DMFFForceImpl(const DMFFForce& owner); + ~DMFFForceImpl(); + void initialize(OpenMM::ContextImpl& context); + const DMFFForce& getOwner() const { + return owner; + } + void updateContextState(OpenMM::ContextImpl& context, bool& forcesInvalid) { + // This force field doesn't update the state directly. + } + double calcForcesAndEnergy(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy, int groups); + std::map getDefaultParameters() { + return std::map(); // This force field doesn't define any parameters. + } + std::vector getKernelNames(); + //void updateParametersInContext(OpenMM::ContextImpl& context); +private: + const DMFFForce& owner; + OpenMM::Kernel kernel; +}; + +} // namespace DMFFPlugin + +#endif /*OPENMM_DMFFFORCEIMPL_H_*/ diff --git a/backend/openmm_dmff_plugin/openmmapi/include/internal/windowsExportDMFF.h b/backend/openmm_dmff_plugin/openmmapi/include/internal/windowsExportDMFF.h new file mode 100644 index 000000000..0304ea92b --- /dev/null +++ b/backend/openmm_dmff_plugin/openmmapi/include/internal/windowsExportDMFF.h @@ -0,0 +1,41 @@ +#ifndef OPENMM_WINDOWSEXPORTDMFF_H_ +#define OPENMM_WINDOWSEXPORTDMFF_H_ + +/* + * Shared libraries are messy in Visual Studio. We have to distinguish three + * cases: + * (1) this header is being used to build the OpenMM shared library + * (dllexport) + * (2) this header is being used by a *client* of the OpenMM shared + * library (dllimport) + * (3) we are building the OpenMM static library, or the client is + * being compiled with the expectation of linking with the + * OpenMM static library (nothing special needed) + * In the CMake script for building this library, we define one of the symbols + * DMFF_BUILDING_{SHARED|STATIC}_LIBRARY + * Client code normally has no special symbol defined, in which case we'll + * assume it wants to use the shared library. However, if the client defines + * the symbol OPENMM_USE_STATIC_LIBRARIES we'll suppress the dllimport so + * that the client code can be linked with static libraries. Note that + * the client symbol is not library dependent, while the library symbols + * affect only the OpenMM library, meaning that other libraries can + * be clients of this one. However, we are assuming all-static or all-shared. + */ + +#ifdef _MSC_VER + // We don't want to hear about how sprintf is "unsafe". + #pragma warning(disable:4996) + // Keep MS VC++ quiet about lack of dll export of private members. + #pragma warning(disable:4251) + #if defined(DMFF_BUILDING_SHARED_LIBRARY) + #define OPENMM_EXPORT_DMFF __declspec(dllexport) + #elif defined(DMFF_BUILDING_STATIC_LIBRARY) || defined(DMFF_USE_STATIC_LIBRARIES) + #define OPENMM_EXPORT_DMFF + #else + #define OPENMM_EXPORT_DMFF __declspec(dllimport) // i.e., a client of a shared library + #endif +#else + #define OPENMM_EXPORT_DMFF // Linux, Mac +#endif + +#endif // OPENMM_WINDOWSEXPORTDMFF_H_ diff --git a/backend/openmm_dmff_plugin/openmmapi/src/DMFFForce.cpp b/backend/openmm_dmff_plugin/openmmapi/src/DMFFForce.cpp new file mode 100644 index 000000000..093f8dc29 --- /dev/null +++ b/backend/openmm_dmff_plugin/openmmapi/src/DMFFForce.cpp @@ -0,0 +1,75 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForce.h" +#include "internal/DMFFForceImpl.h" +#include "openmm/OpenMMException.h" +#include "openmm/internal/AssertionUtilities.h" +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + + +DMFFForce::DMFFForce(const string& GraphFile){ + graph_file = GraphFile; +} + +DMFFForce::~DMFFForce(){ + return; +} + +void DMFFForce::setUnitTransformCoefficients(const double coordCoefficient, const double forceCoefficient, const double energyCoefficient){ + coordCoeff = coordCoefficient; + forceCoeff = forceCoefficient; + energyCoeff = energyCoefficient; +} + +double DMFFForce::getCoordUnitCoefficient() const {return coordCoeff;} +double DMFFForce::getForceUnitCoefficient() const {return forceCoeff;} +double DMFFForce::getEnergyUnitCoefficient() const {return energyCoeff;} + +double DMFFForce::getCutoff() const {return cutoff;} + +const string& DMFFForce::getDMFFGraphFile() const{return graph_file;} + + + +ForceImpl* DMFFForce::createImpl() const { + return new DMFFForceImpl(*this); +} + +void DMFFForce::updateParametersInContext(Context& context) { + // Nothing to be done here. + return; +} + diff --git a/backend/openmm_dmff_plugin/openmmapi/src/DMFFForceImpl.cpp b/backend/openmm_dmff_plugin/openmmapi/src/DMFFForceImpl.cpp new file mode 100644 index 000000000..61be22069 --- /dev/null +++ b/backend/openmm_dmff_plugin/openmmapi/src/DMFFForceImpl.cpp @@ -0,0 +1,71 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif +#include "internal/DMFFForceImpl.h" +#include "DMFFKernels.h" +#include "openmm/OpenMMException.h" +#include "openmm/internal/ContextImpl.h" +#include +#include +#include +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + +DMFFForceImpl::DMFFForceImpl(const DMFFForce& owner) : owner(owner) { +} + +DMFFForceImpl::~DMFFForceImpl() { +} + +void DMFFForceImpl::initialize(ContextImpl& context) { + kernel = context.getPlatform().createKernel(CalcDMFFForceKernel::Name(), context); + kernel.getAs().initialize(context.getSystem(), owner); +} + +double DMFFForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) { + if ((groups&(1<().execute(context, includeForces, includeEnergy); + return 0.0; +} + +std::vector DMFFForceImpl::getKernelNames() { + std::vector names; + names.push_back(CalcDMFFForceKernel::Name()); + return names; +} + + diff --git a/backend/openmm_dmff_plugin/platforms/cuda/CMakeLists.txt b/backend/openmm_dmff_plugin/platforms/cuda/CMakeLists.txt new file mode 100644 index 000000000..6d1d97d73 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/CMakeLists.txt @@ -0,0 +1,79 @@ +#--------------------------------------------------- +# OpenMM DMFF Plugin CUDA Platform +#---------------------------------------------------- + +# Collect information about the version of the OpenMM library we're building +# and make it available to the code so it can be built into the binaries. + +SET(PLUGIN_CUDA_LIBRARY_NAME OpenMMDMFFCUDA) + +SET(SHARED_TARGET ${PLUGIN_CUDA_LIBRARY_NAME}) + + +# These are all the places to search for header files which are +# to be part of the API. +SET(API_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/include/internal") + +# Locate header files. +SET(API_INCLUDE_FILES) +FOREACH(dir ${API_INCLUDE_DIRS}) + FILE(GLOB fullpaths ${dir}/*.h) + SET(API_INCLUDE_FILES ${API_INCLUDE_FILES} ${fullpaths}) +ENDFOREACH(dir) + +# collect source files +SET(SOURCE_FILES) # empty +SET(SOURCE_INCLUDE_FILES) + +FILE(GLOB_RECURSE src_files ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/src/*.c) +FILE(GLOB incl_files ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h) +SET(SOURCE_FILES ${SOURCE_FILES} ${src_files}) #append +SET(SOURCE_INCLUDE_FILES ${SOURCE_INCLUDE_FILES} ${incl_files}) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/include) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/src) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_BINARY_DIR}/platforms/cuda/src) + +# Set variables needed for encoding kernel sources into a C++ class + +SET(CUDA_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) +SET(CUDA_SOURCE_CLASS CudaDMFFKernelSources) +SET(CUDA_KERNELS_CPP ${CMAKE_CURRENT_BINARY_DIR}/src/${CUDA_SOURCE_CLASS}.cpp) +SET(CUDA_KERNELS_H ${CMAKE_CURRENT_BINARY_DIR}/src/${CUDA_SOURCE_CLASS}.h) +SET(SOURCE_FILES ${SOURCE_FILES} ${CUDA_KERNELS_CPP} ${CUDA_KERNELS_H}) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src) + +# Create the library + +INCLUDE_DIRECTORIES(${CUDA_TOOLKIT_INCLUDE}) + +FILE(GLOB CUDA_KERNELS ${CUDA_SOURCE_DIR}/kernels/*.cu) +ADD_CUSTOM_COMMAND(OUTPUT ${CUDA_KERNELS_CPP} ${CUDA_KERNELS_H} + COMMAND ${CMAKE_COMMAND} + ARGS -D CUDA_SOURCE_DIR=${CUDA_SOURCE_DIR} -D CUDA_KERNELS_CPP=${CUDA_KERNELS_CPP} -D CUDA_KERNELS_H=${CUDA_KERNELS_H} -D CUDA_SOURCE_CLASS=${CUDA_SOURCE_CLASS} -P ${CMAKE_SOURCE_DIR}/platforms/cuda/EncodeCUDAFiles.cmake + DEPENDS ${CUDA_KERNELS} +) +SET_SOURCE_FILES_PROPERTIES(${CUDA_KERNELS_CPP} ${CUDA_KERNELS_H} PROPERTIES GENERATED TRUE) +ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_INCLUDE_FILES}) + +TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${CUDA_LIBRARIES}) +TARGET_LINK_LIBRARIES(${SHARED_TARGET} OpenMM) +TARGET_LINK_LIBRARIES(${SHARED_TARGET} OpenMMCUDA) +TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${SHARED_DMFF_TARGET}) +SET_TARGET_PROPERTIES(${SHARED_TARGET} PROPERTIES + COMPILE_FLAGS "-DOPENMM_BUILDING_SHARED_LIBRARY ${EXTRA_COMPILE_FLAGS}" + LINK_FLAGS "${EXTRA_COMPILE_FLAGS}") +IF (APPLE) + SET_TARGET_PROPERTIES(${SHARED_TARGET} PROPERTIES LINK_FLAGS "-F/Library/Frameworks -framework CUDA ${EXTRA_COMPILE_FLAGS}") +ENDIF (APPLE) + +INSTALL(TARGETS ${SHARED_TARGET} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/plugins) +# Ensure that links to the main library will be resolved. +IF (APPLE) + INSTALL(CODE "EXECUTE_PROCESS(COMMAND install_name_tool -add_rpath @loader_path/.. ${CMAKE_INSTALL_PREFIX}/lib/plugins/lib${SHARED_TARGET}.dylib)") +ENDIF (APPLE) + + +SUBDIRS (tests) diff --git a/backend/openmm_dmff_plugin/platforms/cuda/EncodeCUDAFiles.cmake b/backend/openmm_dmff_plugin/platforms/cuda/EncodeCUDAFiles.cmake new file mode 100644 index 000000000..58285b088 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/EncodeCUDAFiles.cmake @@ -0,0 +1,27 @@ +FILE(GLOB CUDA_KERNELS ${CUDA_SOURCE_DIR}/kernels/*.cu) +SET(CUDA_FILE_DECLARATIONS) +SET(CUDA_FILE_DEFINITIONS) +CONFIGURE_FILE(${CUDA_SOURCE_DIR}/${CUDA_SOURCE_CLASS}.cpp.in ${CUDA_KERNELS_CPP}) +FOREACH(file ${CUDA_KERNELS}) + # Load the file contents and process it. + FILE(STRINGS ${file} file_content NEWLINE_CONSUME) + # Replace all backslashes by double backslashes as they are being put in a C string. + # Be careful not to replace the backslash before a semicolon as that is the CMAKE + # internal escaping of a semicolon to prevent it from acting as a list seperator. + STRING(REGEX REPLACE "\\\\([^;])" "\\\\\\\\\\1" file_content "${file_content}") + # Escape double quotes as being put in a C string. + STRING(REPLACE "\"" "\\\"" file_content "${file_content}") + # Split in separate C strings for each line. + STRING(REPLACE "\n" "\\n\"\n\"" file_content "${file_content}") + + # Determine a name for the variable that will contain this file's contents + FILE(RELATIVE_PATH filename ${CUDA_SOURCE_DIR}/kernels ${file}) + STRING(LENGTH ${filename} filename_length) + MATH(EXPR filename_length ${filename_length}-3) + STRING(SUBSTRING ${filename} 0 ${filename_length} variable_name) + + # Record the variable declaration and definition. + SET(CUDA_FILE_DECLARATIONS ${CUDA_FILE_DECLARATIONS}static\ const\ std::string\ ${variable_name};\n) + FILE(APPEND ${CUDA_KERNELS_CPP} const\ string\ ${CUDA_SOURCE_CLASS}::${variable_name}\ =\ \"${file_content}\"\;\n) +ENDFOREACH(file) +CONFIGURE_FILE(${CUDA_SOURCE_DIR}/${CUDA_SOURCE_CLASS}.h.in ${CUDA_KERNELS_H}) diff --git a/backend/openmm_dmff_plugin/platforms/cuda/include/CudaDMFFKernelFactory.h b/backend/openmm_dmff_plugin/platforms/cuda/include/CudaDMFFKernelFactory.h new file mode 100644 index 000000000..b4c728e28 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/include/CudaDMFFKernelFactory.h @@ -0,0 +1,50 @@ +#ifndef OPENMM_CUDA_DMFF_KERNEL_FACTORY_H_ +#define OPENMM_CUDA_DMFF_KERNEL_FACTORY_H_ + +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2018 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "openmm/KernelFactory.h" + +namespace OpenMM { + +/** + * This KernelFactory creates kernels for the CUDA implementation of the DMFF plugin. + */ + +class CudaDMFFKernelFactory : public KernelFactory { +public: + KernelImpl* createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const; +}; + +} // namespace OpenMM + +#endif /*OPENMM_CUDA_DMFF_KERNEL_FACTORY_H_*/ \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/cuda/include/CudaDMFFKernels.h b/backend/openmm_dmff_plugin/platforms/cuda/include/CudaDMFFKernels.h new file mode 100644 index 000000000..2cdf81ceb --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/include/CudaDMFFKernels.h @@ -0,0 +1,87 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2018 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ +#ifndef CUDA_DMFF_KERNELS_H_ +#define CUDA_DMFF_KERNELS_H_ + +#include "DMFFKernels.h" +#include "openmm/cuda/CudaContext.h" +#include "openmm/cuda/CudaArray.h" +#include "openmm/reference/ReferenceNeighborList.h" + + +namespace DMFFPlugin { + +/** + * This kernel is invoked by DMFFForceImpl to calculate the forces acting on the system and the energy of the system. + */ +class CudaCalcDMFFForceKernel : public CalcDMFFForceKernel{ +public: + CudaCalcDMFFForceKernel(std::string name, const OpenMM::Platform& platform, OpenMM::CudaContext& cu):CalcDMFFForceKernel(name, platform), cu(cu){}; + ~CudaCalcDMFFForceKernel(); + void initialize(const OpenMM::System& system, const DMFFForce& force); + double execute(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy); +private: + // Used for CUDA Platform. + bool hasInitialized; + OpenMM::CudaContext& cu; + OpenMM::CudaArray dmffForces; + CUfunction addForcesKernel; + + std::string graph_file; + cppflow::model jax_model; + vector coord_shape = vector(2); + vector box_shape{3, 3}; + vector pair_shape = vector(2); + vector pairs_v; + cppflow::tensor coord_tensor, box_tensor, pair_tensor; + vector output_tensors; + vector operations; + vector input_node_names = vector(3); + + OpenMM::NeighborList neighborList; + vector> exclusions; + + int natoms; + double cutoff; + ENERGYTYPE dener; + vector dforce; + vector dcoord; + vector dbox; + double forceUnitCoeff, energyUnitCoeff, coordUnitCoeff; + vector AddedForces; + +}; + + +} // namespace DMFFPlugin + + +#endif /*CUDA_DMFF_KERNELS_H_*/ \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelFactory.cpp b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelFactory.cpp new file mode 100644 index 000000000..aad51deca --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelFactory.cpp @@ -0,0 +1,76 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2018 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include + +#include "CudaDMFFKernelFactory.h" +#include "CudaDMFFKernels.h" +#include "openmm/internal/windowsExport.h" +#include "openmm/internal/ContextImpl.h" +#include "openmm/OpenMMException.h" +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + +extern "C" OPENMM_EXPORT void registerPlatforms() { +} + +extern "C" OPENMM_EXPORT void registerKernelFactories() { + try { + int argc = 0; + vector argv = {NULL}; + Platform& platform = Platform::getPlatformByName("CUDA"); + CudaDMFFKernelFactory* factory = new CudaDMFFKernelFactory(); + platform.registerKernelFactory(CalcDMFFForceKernel::Name(), factory); + } + catch (std::exception ex) { + // Ignore + } +} + +extern "C" OPENMM_EXPORT void registerDMFFCudaKernelFactories() { + try { + Platform::getPlatformByName("CUDA"); + } + catch (...) { + Platform::registerPlatform(new CudaPlatform()); + } + registerKernelFactories(); +} + +KernelImpl* CudaDMFFKernelFactory::createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const { + CudaContext& cu = *static_cast(context.getPlatformData())->contexts[0]; + if (name == CalcDMFFForceKernel::Name()) + return new CudaCalcDMFFForceKernel(name, platform, cu); + throw OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str()); +} \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelSources.cpp.in b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelSources.cpp.in new file mode 100644 index 000000000..c6e9da1dd --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelSources.cpp.in @@ -0,0 +1,35 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2018 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "CudaDMFFKernelSources.h" + +using namespace DMFFPlugin; +using namespace std; \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelSources.h.in b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelSources.h.in new file mode 100644 index 000000000..abc0db566 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernelSources.h.in @@ -0,0 +1,52 @@ +#ifndef OPENMM_CUDA_DMFF_KERNEL_SOURCES_H_ +#define OPENMM_CUDA_DMFF_KERNEL_SOURCES_H_ + +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2018 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include + +namespace DMFFPlugin { + +/** + * This class is a central holding place for the source code of CUDA kernels. + * The CMake build script inserts declarations into it based on the .cu files in the + * kernels subfolder. + */ + +class CudaDMFFKernelSources { +public: +@CUDA_FILE_DECLARATIONS@ +}; + +} // namespace DMFFPlugin + +#endif /*OPENMM_CUDA_DMFF_KERNEL_SOURCES_H_*/ \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernels.cpp b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernels.cpp new file mode 100644 index 000000000..7867d1f41 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/src/CudaDMFFKernels.cpp @@ -0,0 +1,178 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2018 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "CudaDMFFKernels.h" +#include "CudaDMFFKernelSources.h" +#include "openmm/internal/ContextImpl.h" +#include +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + + +CudaCalcDMFFForceKernel::~CudaCalcDMFFForceKernel(){ + return; +} + +void CudaCalcDMFFForceKernel::initialize(const System& system, const DMFFForce& force){ + graph_file = force.getDMFFGraphFile(); + forceUnitCoeff = force.getForceUnitCoefficient(); + energyUnitCoeff = force.getEnergyUnitCoefficient(); + coordUnitCoeff = force.getCoordUnitCoefficient(); + cutoff = force.getCutoff(); + + natoms = system.getNumParticles(); + coord_shape[0] = natoms; + coord_shape[1] = 3; + exclusions.resize(natoms); + + // Load the ordinary graph firstly. + jax_model.init(graph_file); + + operations = jax_model.get_operations(); + for (int ii = 0; ii < operations.size(); ii++){ + if (operations[ii].find("serving")!= std::string::npos){ + if (operations[ii].find("0")!= std::string::npos){ + input_node_names[0] = operations[ii] + ":0"; + } else if (operations[ii].find("1") != std::string::npos){ + input_node_names[1] = operations[ii] + ":0"; + } else if (operations[ii].find("2") != std::string::npos){ + input_node_names[2] = operations[ii] + ":0"; + } + } + } + + // Initialize the ordinary input and output array. + // Initialize the input tensor. + dener = 0.; + dforce = vector(natoms * 3, 0.); + dcoord = vector(natoms * 3, 0.); + dbox = vector(9, 0.); + + AddedForces = vector(natoms * 3, 0.0); + // Set for CUDA context. + cu.setAsCurrent(); + map defines; + defines["FORCES_TYPE"] = "double"; + dmffForces.initialize(cu, 3*natoms, sizeof(double), "dmffForces"); + CUmodule module = cu.createModule(CudaDMFFKernelSources::DMFFForce, defines); + addForcesKernel = cu.getKernel(module, "addForces"); +} + + +double CudaCalcDMFFForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { + vector pos; + context.getPositions(pos); + Vec3 box[3]; + + // Set box size. + if ( !context.getSystem().usesPeriodicBoundaryConditions() ){ + dbox = {}; // No PBC. + throw OpenMMException("DMFFForce requires periodic boundary conditions."); + } + + cu.getPeriodicBoxVectors(box[0], box[1], box[2]); + // Transform unit from nanometers to the required units in DMFF input. + dbox[0] = box[0][0] * coordUnitCoeff; + dbox[1] = box[0][1] * coordUnitCoeff; + dbox[2] = box[0][2] * coordUnitCoeff; + dbox[3] = box[1][0] * coordUnitCoeff; + dbox[4] = box[1][1] * coordUnitCoeff; + dbox[5] = box[1][2] * coordUnitCoeff; + dbox[6] = box[2][0] * coordUnitCoeff; + dbox[7] = box[2][1] * coordUnitCoeff; + dbox[8] = box[2][2] * coordUnitCoeff; + cppflow::tensor box_tensor = cppflow::tensor(dbox, box_shape); + + // Set input coord. + for(int ii = 0; ii < natoms; ++ii){ + // Multiply by coordUnitCoeff to transform unit from nanometers to input units for DMFF model. + dcoord[ii * 3 + 0] = pos[ii][0] * coordUnitCoeff; + dcoord[ii * 3 + 1] = pos[ii][1] * coordUnitCoeff; + dcoord[ii * 3 + 2] = pos[ii][2] * coordUnitCoeff; + } + coord_tensor = cppflow::tensor(dcoord, coord_shape); + + // Fetch the neighbor list for input pairs tensor. + computeNeighborListVoxelHash( + neighborList, + natoms, + pos, + exclusions, + box, + true, + cutoff, + 0.0 + ); + int totpairs = neighborList.size(); + pairs_v = vector(totpairs * 2); + for (int ii = 0; ii < totpairs; ii ++){ + pairs_v[ ii * 2 + 0 ] = neighborList[ii].second; + pairs_v[ ii * 2 + 1 ] = neighborList[ii].first; + } + pair_shape[0] = totpairs; + pair_shape[1] = 2; + pair_tensor = cppflow::tensor(pairs_v, pair_shape); + + // Calculate the energy and forces. + output_tensors = jax_model({{input_node_names[0], coord_tensor}, {input_node_names[1], box_tensor}, {input_node_names[2], pair_tensor}}, {"PartitionedCall:0", "PartitionedCall:1"}); + + dener = output_tensors[0].get_data()[0]; + dforce = output_tensors[1].get_data(); + + + // Transform the unit from eV/A to KJ/(mol*nm) + for(int ii = 0; ii < natoms; ii ++){ + AddedForces[ii * 3 + 0] = - dforce[ii * 3 + 0] * forceUnitCoeff; + AddedForces[ii * 3 + 1] = - dforce[ii * 3 + 1] * forceUnitCoeff; + AddedForces[ii * 3 + 2] = - dforce[ii * 3 + 2] * forceUnitCoeff; + } + // Transform the unit from eV to KJ/mol + dener = dener * energyUnitCoeff; + + if (includeForces) { + // Change to OpenMM CUDA context. + cu.setAsCurrent(); + dmffForces.upload(AddedForces); + int paddedNumAtoms = cu.getPaddedNumAtoms(); + void* args[] = {&dmffForces.getDevicePointer(), &cu.getForce().getDevicePointer(), &cu.getAtomIndexArray().getDevicePointer(), &natoms, &paddedNumAtoms}; + cu.executeKernel(addForcesKernel, args, natoms); + } + if (!includeEnergy){ + dener = 0.0; + } + return dener; +} + + + diff --git a/backend/openmm_dmff_plugin/platforms/cuda/src/kernels/DMFFForce.cu b/backend/openmm_dmff_plugin/platforms/cuda/src/kernels/DMFFForce.cu new file mode 100644 index 000000000..0a5543c34 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/src/kernels/DMFFForce.cu @@ -0,0 +1,10 @@ +extern "C" __global__ +void addForces(const FORCES_TYPE* __restrict__ forces, long long* __restrict__ forceBuffers, int* __restrict__ atomIndex, int numAtoms, int paddedNumAtoms) { + for (int atom = blockIdx.x*blockDim.x+threadIdx.x; atom < numAtoms; atom += blockDim.x*gridDim.x) { + int index = atomIndex[atom]; + forceBuffers[atom] += (long long) (forces[3*index]*0x100000000); + forceBuffers[atom+paddedNumAtoms] += (long long) (forces[3*index+1]*0x100000000); + forceBuffers[atom+2*paddedNumAtoms] += (long long) (forces[3*index+2]*0x100000000); + } +} + diff --git a/backend/openmm_dmff_plugin/platforms/cuda/tests/CMakeLists.txt b/backend/openmm_dmff_plugin/platforms/cuda/tests/CMakeLists.txt new file mode 100644 index 000000000..e4a4c1bf8 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/tests/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Testing +# + +INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR}) + +# Automatically create tests using files named "Test*.cpp" +FILE(GLOB TEST_PROGS "*Test*.cpp") +FOREACH(TEST_PROG ${TEST_PROGS}) + GET_FILENAME_COMPONENT(TEST_ROOT ${TEST_PROG} NAME_WE) + + # Link with shared library + ADD_EXECUTABLE(${TEST_ROOT} ${TEST_PROG}) + TARGET_LINK_LIBRARIES(${TEST_ROOT} ${SHARED_DMFF_TARGET} ${SHARED_TARGET}) + IF (APPLE) + SET_TARGET_PROPERTIES(${TEST_ROOT} PROPERTIES LINK_FLAGS "${EXTRA_COMPILE_FLAGS} -F/Library/Frameworks -framework CUDA" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}") + ELSE (APPLE) + SET_TARGET_PROPERTIES(${TEST_ROOT} PROPERTIES LINK_FLAGS "${EXTRA_COMPILE_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}") + ENDIF (APPLE) + ADD_TEST(NAME ${TEST_ROOT}Single COMMAND ${EXECUTABLE_OUTPUT_PATH}/${TEST_ROOT} single WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME ${TEST_ROOT}Mixed COMMAND ${EXECUTABLE_OUTPUT_PATH}/${TEST_ROOT} mixed WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME ${TEST_ROOT}Double COMMAND ${EXECUTABLE_OUTPUT_PATH}/${TEST_ROOT} double WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +ENDFOREACH(TEST_PROG ${TEST_PROGS}) \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/cuda/tests/TestDMFFPlugin4CUDA.cpp b/backend/openmm_dmff_plugin/platforms/cuda/tests/TestDMFFPlugin4CUDA.cpp new file mode 100644 index 000000000..295ff71a5 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/cuda/tests/TestDMFFPlugin4CUDA.cpp @@ -0,0 +1,231 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2008-2016 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForce.h" +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "openmm/Platform.h" +#include "openmm/reference/ReferenceNeighborList.h" +#include +#include +#include +#include +#include + + +using namespace OpenMM; +using namespace DMFFPlugin; +using namespace std; + +extern "C" OPENMM_EXPORT void registerDMFFCudaKernelFactories(); + +const double TOL = 1e-5; +const string graph = "../python/OpenMMDMFFPlugin/data/lj_fluid_gpu"; +const double coordUnitCoeff = 1; +const double forceUnitCoeff = 1; +const double energyUnitCoeff = 1; +const double temperature = 100; +const int randomSeed = 123456; + +vector coord_shape = vector(2); +vector box_shape{3, 3}; +vector pair_shape = vector(2); +vector pairs_v; +OpenMM::NeighborList neighborList; +vector> exclusions; + +cppflow::tensor coord_tensor, box_tensor, pair_tensor; +vector output_tensors; +vector operations; +vector input_node_names = vector(3); + + +void referenceDMFFForce(vector positions, vector box, vector& force, double& energy, cppflow::model dmff_model){ + int natoms = positions.size(); + vector input_coords(natoms*3); + vector input_box(9); + vector dmff_force(natoms*3); + ENERGYTYPE dmff_energy; + + // Set box and coordinates input for dmff jax model. + for (int ii = 0; ii < natoms; ++ii){ + input_coords[ii * 3 + 0] = positions[ii][0] * coordUnitCoeff; + input_coords[ii * 3 + 1] = positions[ii][1] * coordUnitCoeff; + input_coords[ii * 3 + 2] = positions[ii][2] * coordUnitCoeff; + } + input_box[0] = box[0][0] * coordUnitCoeff; + input_box[1] = box[0][1] * coordUnitCoeff; + input_box[2] = box[0][2] * coordUnitCoeff; + input_box[3] = box[1][0] * coordUnitCoeff; + input_box[4] = box[1][1] * coordUnitCoeff; + input_box[5] = box[1][2] * coordUnitCoeff; + input_box[6] = box[2][0] * coordUnitCoeff; + input_box[7] = box[2][1] * coordUnitCoeff; + input_box[8] = box[2][2] * coordUnitCoeff; + + // Evaluate and get DMFF forces and energy. + //nnp_inter.compute (nnp_energy, dmff_force, nnp_virial, input_coords, types, input_box); + box_tensor = cppflow::tensor(input_box, box_shape); + coord_tensor = cppflow::tensor(input_coords, coord_shape); + + + computeNeighborListVoxelHash( + neighborList, + natoms, + positions, + exclusions, + box.data(), + true, + 1.2, + 0.0 + ); + int totpairs = neighborList.size(); + pairs_v = vector(totpairs * 2); + for (int ii = 0; ii < totpairs; ii ++){ + pairs_v[ ii * 2 + 0 ] = neighborList[ii].second; + pairs_v[ ii * 2 + 1 ] = neighborList[ii].first; + } + pair_shape[0] = totpairs; + pair_shape[1] = 2; + pair_tensor = cppflow::tensor(pairs_v, pair_shape); + + output_tensors = dmff_model({{input_node_names[0], coord_tensor}, {input_node_names[1], box_tensor}, {input_node_names[2], pair_tensor}}, {"PartitionedCall:0", "PartitionedCall:1"}); + + dmff_energy = output_tensors[0].get_data()[0]; + dmff_force = output_tensors[1].get_data(); + + + // Assign the energy and forces as return values. + energy = static_cast(dmff_energy) * energyUnitCoeff; + for(int ii = 0; ii < natoms; ++ii){ + force[ii][0] = - dmff_force[ii * 3 + 0] * forceUnitCoeff; + force[ii][1] = - dmff_force[ii * 3 + 1] * forceUnitCoeff; + force[ii][2] = - dmff_force[ii * 3 + 2] * forceUnitCoeff; + } +} + +void testDMFFDynamics(int natoms, vector coord, vector box, vector mass, int nsteps=100){ + System system; + VerletIntegrator integrator(0.0002); // Time step is 0.2 fs here. + DMFFForce* dmff_force = new DMFFForce(graph); + + // Convert the units of coordinates and box from angstrom to nanometers. + vector omm_coord; + vector omm_box; + for(int ii = 0; ii < 3; ii++){ + omm_box.push_back(Vec3(box[ii * 3 + 0] / coordUnitCoeff, box[ii * 3 + 1] / coordUnitCoeff, box[ii * 3 + 2] / coordUnitCoeff)); + } + for (int ii = 0; ii < natoms; ++ii){ + system.addParticle(mass[ii]); + omm_coord.push_back(Vec3(coord[ii * 3 + 0], coord[ii * 3 + 1], coord[ii * 3 + 2])); + } + dmff_force->setUnitTransformCoefficients(coordUnitCoeff, forceUnitCoeff, energyUnitCoeff); + system.addForce(dmff_force); + + Platform& platform = Platform::getPlatformByName("CUDA"); + Context context(system, integrator, platform); + context.setPositions(omm_coord); + context.setPeriodicBoxVectors(omm_box[0], omm_box[1], omm_box[2]); + context.setVelocitiesToTemperature(temperature, randomSeed); + + // Initialize the jax_model for comparision. + cppflow::model jax_model = cppflow::model(graph); + + operations = jax_model.get_operations(); + for (int ii = 0; ii < operations.size(); ii++){ + if (operations[ii].find("serving")!= std::string::npos){ + if (operations[ii].find("0")!= std::string::npos){ + input_node_names[0] = operations[ii] + ":0"; + } else if (operations[ii].find("1") != std::string::npos){ + input_node_names[1] = operations[ii] + ":0"; + } else if (operations[ii].find("2") != std::string::npos){ + input_node_names[2] = operations[ii] + ":0"; + } + } + } + + coord_shape[0] = natoms; + coord_shape[1] = 3; + exclusions.resize(natoms); + + for (int ii = 0; ii < nsteps; ++ii){ + // Running 1 step dynamics. + integrator.step(1); + // Get the forces and energy from openmm context state. + State state = context.getState(State::Forces | State::Energy | State::Positions); + const vector& omm_forces = state.getForces(); + const double& omm_energy = state.getPotentialEnergy(); + + // Calculate the force from jax model directly. + std::vector forces(natoms, Vec3(0,0,0)); + double energy; + referenceDMFFForce(state.getPositions(), omm_box, forces, energy, jax_model); + + for (int jj = 0; jj < natoms; ++jj){ + ASSERT_EQUAL_VEC(omm_forces[jj], forces[jj], TOL); + } + ASSERT_EQUAL_TOL(energy, omm_energy, TOL); + } +} + + +int main(int argc, char* argv[]) { + // Initialize positions, unit is nanometer. + std::vector coord = { + 1.4869,1.4417,1.8370000000000002,0.4282,1.2164000000000001,2.3527,0.24500000000000002,1.4031000000000002,0.8695,1.658,0.4821,1.0031,1.1704,1.4292,0.0907,2.3001,1.2364000000000002,0.7593000000000001,2.3508,1.5238,1.5395,0.6515,1.2797,1.1300000000000001,1.3238,1.0387000000000002,0.6028,1.0313,2.3941,1.1909,1.3783,2.2266,1.5460000000000003,2.1957,1.0599,1.455,0.11530000000000001,1.4707000000000001,2.1146000000000003,0.3065,0.5774,1.8188,-0.0494,1.832,2.3497,1.8178999999999998,1.1692,2.0008,1.8654000000000002,0.343,1.8725000000000003,0.4292,1.5221,1.4368,1.3570000000000002,2.0981,1.103,1.4098000000000002,0.2258,0.32630000000000003,0.21230000000000004,0.9242000000000001,2.1351,1.252,0.6546000000000001,1.545,2.4359,1.4137000000000002,0.09910000000000001,0.662,1.3891,0.24460000000000004,2.1807,1.0765,0.3568,1.0917000000000001,0.7743000000000001,2.2414,0.4378,2.1796,0.9539,1.2263000000000002,1.6801,1.136,2.3466,1.5591,1.103,1.2570000000000001,1.1877000000000002,2.164,0.49570000000000003,1.658,0.5198,1.3144,1.4976000000000003,0.7143,1.0516,0.0978,1.6482,2.1533,2.2135000000000002,2.1415,1.9163000000000001,1.5897000000000001,1.2458,1.8677000000000001,0.8567,1.7155000000000002,2.1512000000000002,0.5445000000000001,1.576,1.5814000000000001,1.9201000000000001,1.7932,1.9875,0.7042,2.1085000000000003,1.8557,1.843,2.1122,1.9743,2.0838,1.7328000000000001,1.4769,2.0688,2.3225000000000002,0.15880000000000002,1.8634000000000002,1.31,1.9523000000000001,1.4241000000000001,0.2902,1.7763000000000002,1.2461000000000002,1.5118,2.2309,0.6424000000000001,0.4232,2.0509,0.19720000000000001,2.2418,0.7959,2.2298,1.8864999999999998,0.6643,2.4145000000000003,1.4313000000000002,0.9792000000000001,1.2498,0.5067,1.1904000000000001,1.7758,1.6664000000000003,0.29700000000000004,0.4565000000000001,2.2786000000000004,0.9821,1.8803999999999998,2.061,0.2198,1.2162000000000002,1.7406,0.1378,0.1044,0.9499000000000001,0.20390000000000003,0.5397000000000001,1.0388,1.8989000000000003,1.6082,1.7350000000000003,0.18600000000000003,1.8321000000000003,0.8019000000000001,0.8502000000000001,0.31880000000000003,2.4162,2.0214,0.8935000000000001,0.7367,2.1347,2.326,1.3818000000000001,0.994,0.2096,0.4845,0.2175,2.3638000000000003,1.3552,1.0178,0.08750000000000001,2.1046,0.2683,0.1509,0.2312,0.49800000000000005,1.9023,2.1448,1.2019000000000002,0.6935,1.0732,2.4222,2.1601,1.046,1.5106000000000002,0.9357,1.3374000000000001,1.7486000000000002,0.0001,1.5913000000000002,1.3398,1.6791,2.1634,0.3709,0.9591,0.9917,1.9379000000000002,0.7608,1.2121000000000002,0.25070000000000003,1.2747000000000002,0.42880000000000007,2.3371,0.8711000000000001,1.8224,1.185,1.9267,0.7294,0.7635000000000001,1.5939,2.3087,0.5569000000000001,0.8128000000000001,2.3936,1.5107,0.621,1.8996,0.26110000000000005,1.7603000000000002,1.7589,0.8151,0.8802,0.9716,1.0201,2.1419,0.40990000000000004,1.6098,1.3719000000000001,2.3480000000000003,0.8929,1.5590000000000002,0.8311000000000001,1.3937,0.23870000000000002,1.4025,1.2885,0.2555,0.9979,0.5136999999999999,0.9361000000000002,0.39740000000000003,0.1281,0.862,0.6312000000000001,1.7553999999999998,1.2711000000000001,0.6960000000000001,1.5184,2.2293,0.3469,2.3319,0.4435,1.979,1.0995,0.5888,0.2383,0.0459,0.0884,2.2377,0.7851,2.2165,2.3288,1.6031,0.9092000000000001,0.9029,1.5514000000000001,1.3294000000000001,1.0917000000000001,0.8621000000000001,1.6037,1.361,1.3277,0.5452,0.6697000000000001,0.7398,1.2445000000000002,1.5919,0.12330000000000002,0.9811000000000001,0.1521,1.7182,0.9617000000000001,0.405,2.381,1.586,0.5104000000000001,0.6341000000000001,1.9363000000000001,0.1958,0.48150000000000004,0.9375,1.4548,0.6653,0.5055,0.3047,2.0997,1.8672000000000002,0.21680000000000002,1.9649999999999999,1.1833,1.0909000000000002,1.3763,1.8358,0.33340000000000003,0.6167,0.5750000000000001,1.2102000000000002,2.1995999999999998,1.3109000000000002,1.9009,0.5614,0.1795,1.0621,1.5168,0.6135,0.16970000000000002,0.9818,0.37210000000000004,1.3101000000000003,1.6585999999999999,2.1465,0.77,1.2604,2.2049,1.9687000000000001,1.9338000000000002,0.6234000000000001,0.0946,2.1932,0.5114,0.9361000000000002,0.5063,0.0862,2.1896999999999998,0.49570000000000003,0.20779999999999998,0.6381000000000001,0.23290000000000002,0.5797,0.2647,0.15910000000000002,1.2245,1.2844,1.6597000000000002,2.4419000000000004,1.1129,1.2369,1.3273000000000001,1.4671,0.5469,1.9987,1.3801,1.979,2.2589,0.4699,1.8303000000000003,0.21030000000000004,0.21800000000000003,0.9397000000000001,1.6920000000000002,0.4039,1.4287,0.1847,1.8767,1.5318,1.4136,0.3267,0.3819,2.2102,0.5225,0.9017,0.9943,0.1343,0.0959,0.7195,1.4226,1.8988,1.0612000000000001,0.011000000000000001,0.5231,1.6952000000000003,1.0156,0.15810000000000002,0.13970000000000002,1.7762000000000002,1.3682,1.029,0.17070000000000002,0.5629,0.9455,1.8879000000000001,0.8945000000000001,1.9775,1.088,1.5278,1.645,1.4302000000000001,1.1055,0.4757,1.9054,0.6253000000000001,0.20270000000000002,1.7903,0.7812000000000001,0.6088,1.625,1.6886,0.5251,1.5066000000000002,2.0992,2.4409,0.9244,1.2841,2.3567,0.6889000000000001,0.9853000000000001,0.9608000000000001,1.3817000000000002,0.6080000000000001,1.203,0.6994,1.6666,0.15900000000000003,0.6957,0.5502,1.4368,1.9486999999999999,1.7292000000000003,2.061,1.3492000000000002,1.2589000000000001,0.38680000000000003,2.3253,1.7936,1.8175999999999999,0.5237,0.399,2.1877,1.7484000000000002,1.7109000000000003,1.7693000000000003,0.06530000000000001,0.1459,2.1296,2.0946000000000002,0.3396,2.2007000000000003,0.04000000000000001,0.9349000000000001,0.7859,0.5703,2.2681,1.0914,2.2751,2.2311,1.9684000000000001,0.6532,0.7358,1.9657,0.683,0.8435000000000001,2.3908,0.7913000000000001,2.2823,1.8032000000000001,1.9242000000000001,0.6987000000000001,2.4374000000000002,0.2751,0.12380000000000001,1.9288,0.31520000000000004,0.37660000000000005,0.3412,1.4505000000000001,1.7479,2.3245,2.0271000000000003,0.8131,1.149,2.1734000000000004,1.0833000000000002,1.8968,0.039200000000000006,2.3826,0.2848,1.3407,2.0369,1.5881,0.8055,2.0751000000000004,0.24700000000000003,0.5736,1.129,2.4050000000000002,0.10800000000000001,2.1736999999999997,0.053200000000000004,1.8006000000000002,1.5141,0.0407,2.3854,2.4202000000000004,2.1236,1.6792000000000002,0.9624000000000001,2.0857,1.5029000000000001,1.0552,1.4344000000000001,1.8936000000000002,2.3468,0.6714000000000001,2.3607,1.6348,1.7348,0.9441000000000002,1.9555,0.27740000000000004,1.2697,2.3304,2.2686,0.1339,1.5751,0.8855000000000001,2.2264,1.7631000000000001,0.5546000000000001,0.5404,2.3537,0.8901,1.0565,1.4367,1.0164,1.7736999999999998,1.02,0.9386,1.8329000000000002,0.8833000000000001,0.4201,0.8357,2.4159,2.3893,0.5675,2.1608,1.8838000000000001,1.4112,0.7187000000000001,1.7854,1.7442000000000002,0.34600000000000003,1.6451000000000002,0.042300000000000004,1.8826,2.222,0.052300000000000006,2.2824000000000004,0.2641,0.17490000000000003,1.6754000000000002,0.4199,2.2403,0.0853,0.3877,0.6189,0.7160000000000001,0.5518,2.0741,2.0256000000000003,1.5051,2.2686,0.49340000000000006,0.6245,0.7081000000000001,2.0069,2.0260000000000002,1.0139,1.1265,1.2039,1.013 + }; + std::vector box = { + 2.4413, 0., 0., 0., 2.4413, 0., 0., 0., 2.4413 + }; + + std::vector mass; + int nsteps = 100; + int natoms = coord.size() / 3; + for(int ii = 0; ii < natoms; ++ii){ + mass.push_back(15.99943); + } + + // Test the single point energy and dynamics of DMFF Plugin. + try{ + registerDMFFCudaKernelFactories(); + if (argc > 1) + Platform::getPlatformByName("CUDA").setPropertyDefaultValue("CudaPrecision", string(argv[1])); + testDMFFDynamics(natoms, coord, box, mass, nsteps); + } + catch(const OpenMM::OpenMMException& e) { + cout << "OpenMMException: "< +#include + +namespace DMFFPlugin { + +/** + * This kernel is invoked by DMFFForceImpl to calculate the forces acting on the system and the energy of the system. + */ +class ReferenceCalcDMFFForceKernel : public CalcDMFFForceKernel { +public: + ReferenceCalcDMFFForceKernel(std::string name, const OpenMM::Platform& platform) : CalcDMFFForceKernel(name, platform) { + } + /** + * Initialize the kernel. + * + * @param system the System this kernel will be applied to + * @param force the DMFFForce this kernel will be used for + */ + ~ReferenceCalcDMFFForceKernel(); + void initialize(const OpenMM::System& system, const DMFFForce& force); + /** + * Execute the kernel to calculate the forces and/or energy. + * + * @param context the context in which to execute this kernel + * @param includeForces true if forces should be calculated + * @param includeEnergy true if the energy should be calculated + * @return the potential energy due to the force + */ + double execute(OpenMM::ContextImpl& context, bool includeForces, bool includeEnergy); + /** + * Copy changed parameters over to a context. + * + * @param context the context to copy parameters to + * @param force the DMFFForce to copy the parameters from + */ +private: + std::string graph_file; + cppflow::model jax_model; + + std::vector coord_shape = vector(2); + std::vector coord_shape_1 = vector(2); + std::vector coord_shape_2 = vector(2); + std::vector box_shape{3, 3}; + std::vector pair_shape = vector(2); + + std::vector output; + cppflow::tensor coord_tensor, box_tensor, pair_tensor; + vector operations; + vector input_node_names = vector(3); + + OpenMM::NeighborList neighborList; + std::vector> exclusions; + + int natoms; + double cutoff; + ENERGYTYPE dener; + vector dforce; + vector dcoord; + vector dbox; + std::vector dpairs; + + double forceUnitCoeff, energyUnitCoeff, coordUnitCoeff; + vector AddedForces; +}; + +} // namespace DMFFPlugin + +#endif /*REFERENCE_DMFF_KERNELS_H_*/ diff --git a/backend/openmm_dmff_plugin/platforms/reference/src/ReferenceDMFFKernelFactory.cpp b/backend/openmm_dmff_plugin/platforms/reference/src/ReferenceDMFFKernelFactory.cpp new file mode 100644 index 000000000..add9af7d9 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/reference/src/ReferenceDMFFKernelFactory.cpp @@ -0,0 +1,63 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "ReferenceDMFFKernelFactory.h" +#include "ReferenceDMFFKernels.h" +#include "openmm/reference/ReferencePlatform.h" +#include "openmm/internal/ContextImpl.h" +#include "openmm/OpenMMException.h" + +using namespace DMFFPlugin; +using namespace OpenMM; + +extern "C" OPENMM_EXPORT void registerPlatforms() { +} + +extern "C" OPENMM_EXPORT void registerKernelFactories() { + for (int i = 0; i < Platform::getNumPlatforms(); i++) { + Platform& platform = Platform::getPlatform(i); + if (dynamic_cast(&platform) != NULL) { + ReferenceDMFFKernelFactory* factory = new ReferenceDMFFKernelFactory(); + platform.registerKernelFactory(CalcDMFFForceKernel::Name(), factory); + } + } +} + +extern "C" OPENMM_EXPORT void registerDMFFReferenceKernelFactories() { + registerKernelFactories(); +} + +KernelImpl* ReferenceDMFFKernelFactory::createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const { + ReferencePlatform::PlatformData& data = *static_cast(context.getPlatformData()); + if (name == CalcDMFFForceKernel::Name()) + return new ReferenceCalcDMFFForceKernel(name, platform); + throw OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str()); +} diff --git a/backend/openmm_dmff_plugin/platforms/reference/src/ReferenceDMFFKernels.cpp b/backend/openmm_dmff_plugin/platforms/reference/src/ReferenceDMFFKernels.cpp new file mode 100644 index 000000000..f73979fc8 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/reference/src/ReferenceDMFFKernels.cpp @@ -0,0 +1,189 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "ReferenceDMFFKernels.h" +#include "DMFFForce.h" +#include "openmm/OpenMMException.h" +#include "openmm/internal/ContextImpl.h" +#include "openmm/reference/RealVec.h" +#include "openmm/reference/ReferencePlatform.h" +#include +#include +#include +#include +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + +static vector& extractPositions(ContextImpl& context) { + ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); + return *((vector*) data->positions); +} + +static vector& extractForces(ContextImpl& context) { + ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); + return *((vector*) data->forces); +} + +static Vec3* extractBoxVectors(ContextImpl& context) { + ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); + return (Vec3*) data->periodicBoxVectors; +} + +ReferenceCalcDMFFForceKernel::~ReferenceCalcDMFFForceKernel(){ + return; +} + +void ReferenceCalcDMFFForceKernel::initialize(const System& system, const DMFFForce& force) { + graph_file = force.getDMFFGraphFile(); + forceUnitCoeff = force.getForceUnitCoefficient(); + energyUnitCoeff = force.getEnergyUnitCoefficient(); + coordUnitCoeff = force.getCoordUnitCoefficient(); + cutoff = force.getCutoff(); + + natoms = system.getNumParticles(); + coord_shape[0] = natoms; + coord_shape[1] = 3; + exclusions.resize(natoms); + + // Load the ordinary graph firstly. + jax_model.init(graph_file); + + operations = jax_model.get_operations(); + for (int ii = 0; ii < operations.size(); ii++){ + if (operations[ii].find("serving")!= std::string::npos){ + if (operations[ii].find("0")!= std::string::npos){ + input_node_names[0] = operations[ii]+":0"; + } else if (operations[ii].find("1") != std::string::npos){ + input_node_names[1] = operations[ii]+":0"; + } else if (operations[ii].find("2") != std::string::npos){ + input_node_names[2] = operations[ii]+":0"; + } else { + std::cout << "Warning: Unknown input node name: " << operations[ii] << std::endl; + } + } + } + + // Initialize the ordinary input and output array. + // Initialize the input tensor. + dener = 0.; + dforce = vector(natoms * 3, 0.); + dcoord = vector(natoms * 3, 0.); + dbox = vector(9, 0.); + + AddedForces = vector(natoms * 3, 0.0); +} + +double ReferenceCalcDMFFForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { + vector& pos = extractPositions(context); + vector& force = extractForces(context); + // Extract the box size. + if ( ! context.getSystem().usesPeriodicBoundaryConditions()){ + dbox = {}; // No PBC. + throw OpenMMException("No PBC is not supported yet."); + } + Vec3* box = extractBoxVectors(context); + // Transform unit from nanometers to required units for DMFF model input. + dbox[0] = box[0][0] * coordUnitCoeff; + dbox[1] = box[0][1] * coordUnitCoeff; + dbox[2] = box[0][2] * coordUnitCoeff; + dbox[3] = box[1][0] * coordUnitCoeff; + dbox[4] = box[1][1] * coordUnitCoeff; + dbox[5] = box[1][2] * coordUnitCoeff; + dbox[6] = box[2][0] * coordUnitCoeff; + dbox[7] = box[2][1] * coordUnitCoeff; + dbox[8] = box[2][2] * coordUnitCoeff; + box_tensor = cppflow::tensor(dbox, box_shape); + + // Set input coord. + for(int ii = 0; ii < natoms; ++ii){ + // Multiply by coordUnitCoeff means the transformation of the unit from nanometers to input units. + dcoord[ii * 3 + 0] = pos[ii][0] * coordUnitCoeff; + dcoord[ii * 3 + 1] = pos[ii][1] * coordUnitCoeff; + dcoord[ii * 3 + 2] = pos[ii][2] * coordUnitCoeff; + } + coord_tensor = cppflow::tensor(dcoord, coord_shape); + + // Set input pairs. + computeNeighborListVoxelHash( + neighborList, + natoms, + pos, + exclusions, + box, + true, + cutoff, + 0.0 + ); + int totpairs = neighborList.size(); + dpairs = vector(totpairs * 2); + for (int ii = 0; ii < totpairs; ii++) + { + int32_t i1 = neighborList[ii].second; + int32_t i2 = neighborList[ii].first; + dpairs[ii * 2 + 0 ] = i1; + dpairs[ii * 2 + 1 ] = i2; + } + pair_shape[0] = totpairs; + pair_shape[1] = 2; + cppflow::tensor pair_tensor = cppflow::tensor(dpairs, pair_shape); + + output = jax_model({{input_node_names[0], coord_tensor}, {input_node_names[1], box_tensor}, {input_node_names[2], pair_tensor}}, {"PartitionedCall:0", "PartitionedCall:1"}); + + dener = output[0].get_data()[0]; + dforce = output[1].get_data(); + + // Transform the unit from output units to KJ/(mol*nm) + for(int ii = 0; ii < natoms; ii ++){ + AddedForces[ii * 3 + 0] = - dforce[ii * 3 + 0] * forceUnitCoeff; + AddedForces[ii * 3 + 1] = - dforce[ii * 3 + 1] * forceUnitCoeff; + AddedForces[ii * 3 + 2] = - dforce[ii * 3 + 2] * forceUnitCoeff; + } + // Transform the unit from output units to KJ/mol + dener = dener * energyUnitCoeff; + + if(includeForces){ + for(int ii = 0; ii < natoms; ii ++){ + force[ii][0] += AddedForces[ii * 3 + 0]; + force[ii][1] += AddedForces[ii * 3 + 1]; + force[ii][2] += AddedForces[ii * 3 + 2]; + } + } + if (!includeEnergy){ + dener = 0.0; + } + // Return energy. + return dener; +} + + diff --git a/backend/openmm_dmff_plugin/platforms/reference/tests/CMakeLists.txt b/backend/openmm_dmff_plugin/platforms/reference/tests/CMakeLists.txt new file mode 100644 index 000000000..1976ba067 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/reference/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Testing +# + +# Automatically create tests using files named "Test*.cpp" +FILE(GLOB TEST_PROGS "*Test*.cpp") +FOREACH(TEST_PROG ${TEST_PROGS}) + GET_FILENAME_COMPONENT(TEST_ROOT ${TEST_PROG} NAME_WE) + + # Link with shared library + ADD_EXECUTABLE(${TEST_ROOT} ${TEST_PROG}) + TARGET_LINK_LIBRARIES(${TEST_ROOT} ${SHARED_DMFF_TARGET} ${SHARED_TARGET}) + SET_TARGET_PROPERTIES(${TEST_ROOT} PROPERTIES LINK_FLAGS "${EXTRA_COMPILE_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}") + ADD_TEST(NAME ${TEST_ROOT} COMMAND ${EXECUTABLE_OUTPUT_PATH}/${TEST_ROOT} single WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +ENDFOREACH(TEST_PROG ${TEST_PROGS}) \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/platforms/reference/tests/TestDMFFPlugin4Reference.cpp b/backend/openmm_dmff_plugin/platforms/reference/tests/TestDMFFPlugin4Reference.cpp new file mode 100644 index 000000000..962fa41b2 --- /dev/null +++ b/backend/openmm_dmff_plugin/platforms/reference/tests/TestDMFFPlugin4Reference.cpp @@ -0,0 +1,227 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2008-2016 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForce.h" +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "openmm/Platform.h" +#include "openmm/reference/ReferenceNeighborList.h" +#include +#include +#include + + +using namespace OpenMM; +using namespace DMFFPlugin; +using namespace std; + +extern "C" OPENMM_EXPORT void registerDMFFReferenceKernelFactories(); + +const double TOL = 1e-5; +const string graph = "../python/OpenMMDMFFPlugin/data/lj_fluid_gpu"; +const double coordUnitCoeff = 1; +const double forceUnitCoeff = 1; +const double energyUnitCoeff = 1; +const double temperature = 100; +const int randomSeed = 123456; + +vector coord_shape = vector(2); +vector box_shape{3, 3}; +vector pair_shape = vector(2); +vector pairs_v; +OpenMM::NeighborList neighborList; +vector> exclusions; + +cppflow::tensor coord_tensor, box_tensor, pair_tensor; +vector output_tensors; +vector operations; +vector input_node_names = vector(3); + + +void referenceDMFFForce(vector positions, vector box, vector& force, double& energy, cppflow::model dmff_model){ + int natoms = positions.size(); + vector input_coords(natoms*3); + vector input_box(9); + vector dmff_force(natoms*3); + ENERGYTYPE dmff_energy; + + // Set box and coordinates input for dmff jax model. + for (int ii = 0; ii < natoms; ++ii){ + input_coords[ii * 3 + 0] = positions[ii][0] * coordUnitCoeff; + input_coords[ii * 3 + 1] = positions[ii][1] * coordUnitCoeff; + input_coords[ii * 3 + 2] = positions[ii][2] * coordUnitCoeff; + } + input_box[0] = box[0][0] * coordUnitCoeff; + input_box[1] = box[0][1] * coordUnitCoeff; + input_box[2] = box[0][2] * coordUnitCoeff; + input_box[3] = box[1][0] * coordUnitCoeff; + input_box[4] = box[1][1] * coordUnitCoeff; + input_box[5] = box[1][2] * coordUnitCoeff; + input_box[6] = box[2][0] * coordUnitCoeff; + input_box[7] = box[2][1] * coordUnitCoeff; + input_box[8] = box[2][2] * coordUnitCoeff; + + // Evaluate and get DMFF forces and energy. + //nnp_inter.compute (nnp_energy, dmff_force, nnp_virial, input_coords, types, input_box); + box_tensor = cppflow::tensor(input_box, box_shape); + coord_tensor = cppflow::tensor(input_coords, coord_shape); + + + computeNeighborListVoxelHash( + neighborList, + natoms, + positions, + exclusions, + box.data(), + true, + 1.2, + 0.0 + ); + int totpairs = neighborList.size(); + pairs_v = vector(totpairs * 2); + for (int ii = 0; ii < totpairs; ii ++){ + pairs_v[ ii * 2 + 0 ] = neighborList[ii].second; + pairs_v[ ii * 2 + 1 ] = neighborList[ii].first; + } + pair_shape[0] = totpairs; + pair_shape[1] = 2; + pair_tensor = cppflow::tensor(pairs_v, pair_shape); + + output_tensors = dmff_model({{input_node_names[0], coord_tensor}, {input_node_names[1], box_tensor}, {input_node_names[2], pair_tensor}}, {"PartitionedCall:0", "PartitionedCall:1"}); + + dmff_energy = output_tensors[0].get_data()[0]; + dmff_force = output_tensors[1].get_data(); + + + // Assign the energy and forces as return values. + energy = static_cast(dmff_energy) * energyUnitCoeff; + for(int ii = 0; ii < natoms; ++ii){ + force[ii][0] = - dmff_force[ii * 3 + 0] * forceUnitCoeff; + force[ii][1] = - dmff_force[ii * 3 + 1] * forceUnitCoeff; + force[ii][2] = - dmff_force[ii * 3 + 2] * forceUnitCoeff; + } +} + +void testDMFFDynamics(int natoms, vector coord, vector box, vector mass, int nsteps=100){ + System system; + VerletIntegrator integrator(0.0002); // Time step is 0.2 fs here. + DMFFForce* dmff_force = new DMFFForce(graph); + + // Convert the units of coordinates and box from angstrom to nanometers. + vector omm_coord; + vector omm_box; + for(int ii = 0; ii < 3; ii++){ + omm_box.push_back(Vec3(box[ii * 3 + 0] / coordUnitCoeff, box[ii * 3 + 1] / coordUnitCoeff, box[ii * 3 + 2] / coordUnitCoeff)); + } + for (int ii = 0; ii < natoms; ++ii){ + system.addParticle(mass[ii]); + omm_coord.push_back(Vec3(coord[ii * 3 + 0], coord[ii * 3 + 1], coord[ii * 3 + 2])); + } + dmff_force->setUnitTransformCoefficients(coordUnitCoeff, forceUnitCoeff, energyUnitCoeff); + system.addForce(dmff_force); + + Platform& platform = Platform::getPlatformByName("Reference"); + Context context(system, integrator, platform); + context.setPositions(omm_coord); + context.setPeriodicBoxVectors(omm_box[0], omm_box[1], omm_box[2]); + context.setVelocitiesToTemperature(temperature, randomSeed); + + // Initialize the jax_model for comparision. + cppflow::model jax_model = cppflow::model(graph); + + operations = jax_model.get_operations(); + for (int ii = 0; ii < operations.size(); ii++){ + if (operations[ii].find("serving")!= std::string::npos){ + if (operations[ii].find("0")!= std::string::npos){ + input_node_names[0] = operations[ii] + ":0"; + } else if (operations[ii].find("1") != std::string::npos){ + input_node_names[1] = operations[ii] + ":0"; + } else if (operations[ii].find("2") != std::string::npos){ + input_node_names[2] = operations[ii] + ":0"; + } + } + } + + coord_shape[0] = natoms; + coord_shape[1] = 3; + exclusions.resize(natoms); + + + for (int ii = 0; ii < nsteps; ++ii){ + // Running 1 step dynamics. + integrator.step(1); + // Get the forces and energy from openmm context state. + State state = context.getState(State::Forces | State::Energy | State::Positions); + const vector& omm_forces = state.getForces(); + const double& omm_energy = state.getPotentialEnergy(); + + // Calculate the force from jax model directly. + std::vector forces(natoms, Vec3(0,0,0)); + double energy; + referenceDMFFForce(state.getPositions(), omm_box, forces, energy, jax_model); + + for (int jj = 0; jj < natoms; ++jj){ + ASSERT_EQUAL_VEC(omm_forces[jj], forces[jj], TOL); + } + ASSERT_EQUAL_TOL(energy, omm_energy, TOL); + } +} + + +int main() { + // Initialize positions, unit is nanometer. + std::vector coord = { + 1.4869,1.4417,1.8370000000000002,0.4282,1.2164000000000001,2.3527,0.24500000000000002,1.4031000000000002,0.8695,1.658,0.4821,1.0031,1.1704,1.4292,0.0907,2.3001,1.2364000000000002,0.7593000000000001,2.3508,1.5238,1.5395,0.6515,1.2797,1.1300000000000001,1.3238,1.0387000000000002,0.6028,1.0313,2.3941,1.1909,1.3783,2.2266,1.5460000000000003,2.1957,1.0599,1.455,0.11530000000000001,1.4707000000000001,2.1146000000000003,0.3065,0.5774,1.8188,-0.0494,1.832,2.3497,1.8178999999999998,1.1692,2.0008,1.8654000000000002,0.343,1.8725000000000003,0.4292,1.5221,1.4368,1.3570000000000002,2.0981,1.103,1.4098000000000002,0.2258,0.32630000000000003,0.21230000000000004,0.9242000000000001,2.1351,1.252,0.6546000000000001,1.545,2.4359,1.4137000000000002,0.09910000000000001,0.662,1.3891,0.24460000000000004,2.1807,1.0765,0.3568,1.0917000000000001,0.7743000000000001,2.2414,0.4378,2.1796,0.9539,1.2263000000000002,1.6801,1.136,2.3466,1.5591,1.103,1.2570000000000001,1.1877000000000002,2.164,0.49570000000000003,1.658,0.5198,1.3144,1.4976000000000003,0.7143,1.0516,0.0978,1.6482,2.1533,2.2135000000000002,2.1415,1.9163000000000001,1.5897000000000001,1.2458,1.8677000000000001,0.8567,1.7155000000000002,2.1512000000000002,0.5445000000000001,1.576,1.5814000000000001,1.9201000000000001,1.7932,1.9875,0.7042,2.1085000000000003,1.8557,1.843,2.1122,1.9743,2.0838,1.7328000000000001,1.4769,2.0688,2.3225000000000002,0.15880000000000002,1.8634000000000002,1.31,1.9523000000000001,1.4241000000000001,0.2902,1.7763000000000002,1.2461000000000002,1.5118,2.2309,0.6424000000000001,0.4232,2.0509,0.19720000000000001,2.2418,0.7959,2.2298,1.8864999999999998,0.6643,2.4145000000000003,1.4313000000000002,0.9792000000000001,1.2498,0.5067,1.1904000000000001,1.7758,1.6664000000000003,0.29700000000000004,0.4565000000000001,2.2786000000000004,0.9821,1.8803999999999998,2.061,0.2198,1.2162000000000002,1.7406,0.1378,0.1044,0.9499000000000001,0.20390000000000003,0.5397000000000001,1.0388,1.8989000000000003,1.6082,1.7350000000000003,0.18600000000000003,1.8321000000000003,0.8019000000000001,0.8502000000000001,0.31880000000000003,2.4162,2.0214,0.8935000000000001,0.7367,2.1347,2.326,1.3818000000000001,0.994,0.2096,0.4845,0.2175,2.3638000000000003,1.3552,1.0178,0.08750000000000001,2.1046,0.2683,0.1509,0.2312,0.49800000000000005,1.9023,2.1448,1.2019000000000002,0.6935,1.0732,2.4222,2.1601,1.046,1.5106000000000002,0.9357,1.3374000000000001,1.7486000000000002,0.0001,1.5913000000000002,1.3398,1.6791,2.1634,0.3709,0.9591,0.9917,1.9379000000000002,0.7608,1.2121000000000002,0.25070000000000003,1.2747000000000002,0.42880000000000007,2.3371,0.8711000000000001,1.8224,1.185,1.9267,0.7294,0.7635000000000001,1.5939,2.3087,0.5569000000000001,0.8128000000000001,2.3936,1.5107,0.621,1.8996,0.26110000000000005,1.7603000000000002,1.7589,0.8151,0.8802,0.9716,1.0201,2.1419,0.40990000000000004,1.6098,1.3719000000000001,2.3480000000000003,0.8929,1.5590000000000002,0.8311000000000001,1.3937,0.23870000000000002,1.4025,1.2885,0.2555,0.9979,0.5136999999999999,0.9361000000000002,0.39740000000000003,0.1281,0.862,0.6312000000000001,1.7553999999999998,1.2711000000000001,0.6960000000000001,1.5184,2.2293,0.3469,2.3319,0.4435,1.979,1.0995,0.5888,0.2383,0.0459,0.0884,2.2377,0.7851,2.2165,2.3288,1.6031,0.9092000000000001,0.9029,1.5514000000000001,1.3294000000000001,1.0917000000000001,0.8621000000000001,1.6037,1.361,1.3277,0.5452,0.6697000000000001,0.7398,1.2445000000000002,1.5919,0.12330000000000002,0.9811000000000001,0.1521,1.7182,0.9617000000000001,0.405,2.381,1.586,0.5104000000000001,0.6341000000000001,1.9363000000000001,0.1958,0.48150000000000004,0.9375,1.4548,0.6653,0.5055,0.3047,2.0997,1.8672000000000002,0.21680000000000002,1.9649999999999999,1.1833,1.0909000000000002,1.3763,1.8358,0.33340000000000003,0.6167,0.5750000000000001,1.2102000000000002,2.1995999999999998,1.3109000000000002,1.9009,0.5614,0.1795,1.0621,1.5168,0.6135,0.16970000000000002,0.9818,0.37210000000000004,1.3101000000000003,1.6585999999999999,2.1465,0.77,1.2604,2.2049,1.9687000000000001,1.9338000000000002,0.6234000000000001,0.0946,2.1932,0.5114,0.9361000000000002,0.5063,0.0862,2.1896999999999998,0.49570000000000003,0.20779999999999998,0.6381000000000001,0.23290000000000002,0.5797,0.2647,0.15910000000000002,1.2245,1.2844,1.6597000000000002,2.4419000000000004,1.1129,1.2369,1.3273000000000001,1.4671,0.5469,1.9987,1.3801,1.979,2.2589,0.4699,1.8303000000000003,0.21030000000000004,0.21800000000000003,0.9397000000000001,1.6920000000000002,0.4039,1.4287,0.1847,1.8767,1.5318,1.4136,0.3267,0.3819,2.2102,0.5225,0.9017,0.9943,0.1343,0.0959,0.7195,1.4226,1.8988,1.0612000000000001,0.011000000000000001,0.5231,1.6952000000000003,1.0156,0.15810000000000002,0.13970000000000002,1.7762000000000002,1.3682,1.029,0.17070000000000002,0.5629,0.9455,1.8879000000000001,0.8945000000000001,1.9775,1.088,1.5278,1.645,1.4302000000000001,1.1055,0.4757,1.9054,0.6253000000000001,0.20270000000000002,1.7903,0.7812000000000001,0.6088,1.625,1.6886,0.5251,1.5066000000000002,2.0992,2.4409,0.9244,1.2841,2.3567,0.6889000000000001,0.9853000000000001,0.9608000000000001,1.3817000000000002,0.6080000000000001,1.203,0.6994,1.6666,0.15900000000000003,0.6957,0.5502,1.4368,1.9486999999999999,1.7292000000000003,2.061,1.3492000000000002,1.2589000000000001,0.38680000000000003,2.3253,1.7936,1.8175999999999999,0.5237,0.399,2.1877,1.7484000000000002,1.7109000000000003,1.7693000000000003,0.06530000000000001,0.1459,2.1296,2.0946000000000002,0.3396,2.2007000000000003,0.04000000000000001,0.9349000000000001,0.7859,0.5703,2.2681,1.0914,2.2751,2.2311,1.9684000000000001,0.6532,0.7358,1.9657,0.683,0.8435000000000001,2.3908,0.7913000000000001,2.2823,1.8032000000000001,1.9242000000000001,0.6987000000000001,2.4374000000000002,0.2751,0.12380000000000001,1.9288,0.31520000000000004,0.37660000000000005,0.3412,1.4505000000000001,1.7479,2.3245,2.0271000000000003,0.8131,1.149,2.1734000000000004,1.0833000000000002,1.8968,0.039200000000000006,2.3826,0.2848,1.3407,2.0369,1.5881,0.8055,2.0751000000000004,0.24700000000000003,0.5736,1.129,2.4050000000000002,0.10800000000000001,2.1736999999999997,0.053200000000000004,1.8006000000000002,1.5141,0.0407,2.3854,2.4202000000000004,2.1236,1.6792000000000002,0.9624000000000001,2.0857,1.5029000000000001,1.0552,1.4344000000000001,1.8936000000000002,2.3468,0.6714000000000001,2.3607,1.6348,1.7348,0.9441000000000002,1.9555,0.27740000000000004,1.2697,2.3304,2.2686,0.1339,1.5751,0.8855000000000001,2.2264,1.7631000000000001,0.5546000000000001,0.5404,2.3537,0.8901,1.0565,1.4367,1.0164,1.7736999999999998,1.02,0.9386,1.8329000000000002,0.8833000000000001,0.4201,0.8357,2.4159,2.3893,0.5675,2.1608,1.8838000000000001,1.4112,0.7187000000000001,1.7854,1.7442000000000002,0.34600000000000003,1.6451000000000002,0.042300000000000004,1.8826,2.222,0.052300000000000006,2.2824000000000004,0.2641,0.17490000000000003,1.6754000000000002,0.4199,2.2403,0.0853,0.3877,0.6189,0.7160000000000001,0.5518,2.0741,2.0256000000000003,1.5051,2.2686,0.49340000000000006,0.6245,0.7081000000000001,2.0069,2.0260000000000002,1.0139,1.1265,1.2039,1.013 + }; + std::vector box = { + 2.4413, 0., 0., 0., 2.4413, 0., 0., 0., 2.4413 + }; + + std::vector mass; + int nsteps = 100; + int natoms = coord.size() / 3; + for(int ii = 0; ii < natoms; ++ii){ + mass.push_back(15.99943); + } + + try{ + registerDMFFReferenceKernelFactories(); + testDMFFDynamics(natoms, coord, box, mass, nsteps); + } + catch(const std::exception& e) { + std::cout << "exception: "< +%include +%include + +%inline %{ +using namespace std; +%} + +namespace std { + %template(IntVector) vector; + %template(DoubleVector) vector; + %template(StringVector) vector; + %template(ConstCharVector) vector; +} + +%{ +#include "DMFFForce.h" +#include "OpenMM.h" +#include "OpenMMAmoeba.h" +#include "OpenMMDrude.h" +#include "openmm/RPMDIntegrator.h" +#include "openmm/RPMDMonteCarloBarostat.h" +#include +%} + + +/* + * Convert C++ exceptions to Python exceptions. +*/ +%exception { + try { + $action + } catch (std::exception &e) { + PyErr_SetString(PyExc_Exception, const_cast(e.what())); + return NULL; + } +} + +namespace DMFFPlugin { + +class DMFFForce : public OpenMM::Force { +public: + DMFFForce(const string& GraphFile); + + void setUnitTransformCoefficients(const double coordCoefficient, const double forceCoefficient, const double energyCoefficient); + + /* + * Add methods for casting a Force to a DMFFForce. + */ + %extend { + static DMFFPlugin::DMFFForce& cast(OpenMM::Force& force) { + return dynamic_cast(force); + } + + static bool isinstance(OpenMM::Force& force) { + return (dynamic_cast(&force) != NULL); + } + } +}; + +} diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/__init__.py b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/__init__.py new file mode 100644 index 000000000..6b282b924 --- /dev/null +++ b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/__init__.py @@ -0,0 +1,15 @@ +"""OpenMM is a toolkit for molecular simulation. It can be used either as a +stand-alone application for running simulations, or as a library you call +from your own code. It provides a combination of extreme flexibility +(through custom forces and integrators), openness, and high performance +(especially on recent GPUs) that make it truly unique among simulation codes. +""" +from __future__ import absolute_import +__author__ = "Ye Ding" +__mail__ = "dingye@westlake.edu.cn" +__version__ = "@GIT_HASH@" + +import os, os.path +import sys +from .tools import DMFFModel +from .OpenMMDMFFPlugin import DMFFForce diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid.pdb b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid.pdb new file mode 100644 index 000000000..bdbca18eb --- /dev/null +++ b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid.pdb @@ -0,0 +1,204 @@ +REMARK 1 CREATED WITH OPENMM 7.7, 2022-11-03 +CRYST1 24.413 24.413 24.413 90.00 90.00 90.00 P 1 1 +HETATM 1 ATM LJP A 1 14.869 14.417 18.370 1.00 0.00 O +HETATM 2 ATM LJP A 2 4.282 12.164 23.527 1.00 0.00 O +HETATM 3 ATM LJP A 3 2.450 14.031 8.695 1.00 0.00 O +HETATM 4 ATM LJP A 4 16.580 4.821 10.031 1.00 0.00 O +HETATM 5 ATM LJP A 5 11.704 14.292 0.907 1.00 0.00 O +HETATM 6 ATM LJP A 6 23.001 12.364 7.593 1.00 0.00 O +HETATM 7 ATM LJP A 7 23.508 15.238 15.395 1.00 0.00 O +HETATM 8 ATM LJP A 8 6.515 12.797 11.300 1.00 0.00 O +HETATM 9 ATM LJP A 9 13.238 10.387 6.028 1.00 0.00 O +HETATM 10 ATM LJP A 10 10.313 23.941 11.909 1.00 0.00 O +HETATM 11 ATM LJP A 11 13.783 22.266 15.460 1.00 0.00 O +HETATM 12 ATM LJP A 12 21.957 10.599 14.550 1.00 0.00 O +HETATM 13 ATM LJP A 13 1.153 14.707 21.146 1.00 0.00 O +HETATM 14 ATM LJP A 14 3.065 5.774 18.188 1.00 0.00 O +HETATM 15 ATM LJP A 15 -0.494 18.320 23.497 1.00 0.00 O +HETATM 16 ATM LJP A 16 18.179 11.692 20.008 1.00 0.00 O +HETATM 17 ATM LJP A 17 18.654 3.430 18.725 1.00 0.00 O +HETATM 18 ATM LJP A 18 4.292 15.221 14.368 1.00 0.00 O +HETATM 19 ATM LJP A 19 13.570 20.981 11.030 1.00 0.00 O +HETATM 20 ATM LJP A 20 14.098 2.258 3.263 1.00 0.00 O +HETATM 21 ATM LJP A 21 2.123 9.242 21.351 1.00 0.00 O +HETATM 22 ATM LJP A 22 12.520 6.546 15.450 1.00 0.00 O +HETATM 23 ATM LJP A 23 24.359 14.137 0.991 1.00 0.00 O +HETATM 24 ATM LJP A 24 6.620 13.891 2.446 1.00 0.00 O +HETATM 25 ATM LJP A 25 21.807 10.765 3.568 1.00 0.00 O +HETATM 26 ATM LJP A 26 10.917 7.743 22.414 1.00 0.00 O +HETATM 27 ATM LJP A 27 4.378 21.796 9.539 1.00 0.00 O +HETATM 28 ATM LJP A 28 12.263 16.801 11.360 1.00 0.00 O +HETATM 29 ATM LJP A 29 23.466 15.591 11.030 1.00 0.00 O +HETATM 30 ATM LJP A 30 12.570 11.877 21.640 1.00 0.00 O +HETATM 31 ATM LJP A 31 4.957 16.580 5.198 1.00 0.00 O +HETATM 32 ATM LJP A 32 13.144 14.976 7.143 1.00 0.00 O +HETATM 33 ATM LJP A 33 10.516 0.978 16.482 1.00 0.00 O +HETATM 34 ATM LJP A 34 21.533 22.135 21.415 1.00 0.00 O +HETATM 35 ATM LJP A 35 19.163 15.897 12.458 1.00 0.00 O +HETATM 36 ATM LJP A 36 18.677 8.567 17.155 1.00 0.00 O +HETATM 37 ATM LJP A 37 21.512 5.445 15.760 1.00 0.00 O +HETATM 38 ATM LJP A 38 15.814 19.201 17.932 1.00 0.00 O +HETATM 39 ATM LJP A 39 19.875 7.042 21.085 1.00 0.00 O +HETATM 40 ATM LJP A 40 18.557 18.430 21.122 1.00 0.00 O +HETATM 41 ATM LJP A 41 19.743 20.838 17.328 1.00 0.00 O +HETATM 42 ATM LJP A 42 14.769 20.688 23.225 1.00 0.00 O +HETATM 43 ATM LJP A 43 1.588 18.634 13.100 1.00 0.00 O +HETATM 44 ATM LJP A 44 19.523 14.241 2.902 1.00 0.00 O +HETATM 45 ATM LJP A 45 17.763 12.461 15.118 1.00 0.00 O +HETATM 46 ATM LJP A 46 22.309 6.424 4.232 1.00 0.00 O +HETATM 47 ATM LJP A 47 20.509 1.972 22.418 1.00 0.00 O +HETATM 48 ATM LJP A 48 7.959 22.298 18.865 1.00 0.00 O +HETATM 49 ATM LJP A 49 6.643 24.145 14.313 1.00 0.00 O +HETATM 50 ATM LJP A 50 9.792 12.498 5.067 1.00 0.00 O +HETATM 51 ATM LJP A 51 11.904 17.758 16.664 1.00 0.00 O +HETATM 52 ATM LJP A 52 2.970 4.565 22.786 1.00 0.00 O +HETATM 53 ATM LJP A 53 9.821 18.804 20.610 1.00 0.00 O +HETATM 54 ATM LJP A 54 2.198 12.162 17.406 1.00 0.00 O +HETATM 55 ATM LJP A 55 1.378 1.044 9.499 1.00 0.00 O +HETATM 56 ATM LJP A 56 2.039 5.397 10.388 1.00 0.00 O +HETATM 57 ATM LJP A 57 18.989 16.082 17.350 1.00 0.00 O +HETATM 58 ATM LJP A 58 1.860 18.321 8.019 1.00 0.00 O +HETATM 59 ATM LJP A 59 8.502 3.188 24.162 1.00 0.00 O +HETATM 60 ATM LJP A 60 20.214 8.935 7.367 1.00 0.00 O +HETATM 61 ATM LJP A 61 21.347 23.260 13.818 1.00 0.00 O +HETATM 62 ATM LJP A 62 9.940 2.096 4.845 1.00 0.00 O +HETATM 63 ATM LJP A 63 2.175 23.638 13.552 1.00 0.00 O +HETATM 64 ATM LJP A 64 10.178 0.875 21.046 1.00 0.00 O +HETATM 65 ATM LJP A 65 2.683 1.509 2.312 1.00 0.00 O +HETATM 66 ATM LJP A 66 4.980 19.023 21.448 1.00 0.00 O +HETATM 67 ATM LJP A 67 12.019 6.935 10.732 1.00 0.00 O +HETATM 68 ATM LJP A 68 24.222 21.601 10.460 1.00 0.00 O +HETATM 69 ATM LJP A 69 15.106 9.357 13.374 1.00 0.00 O +HETATM 70 ATM LJP A 70 17.486 0.001 15.913 1.00 0.00 O +HETATM 71 ATM LJP A 71 13.398 16.791 21.634 1.00 0.00 O +HETATM 72 ATM LJP A 72 3.709 9.591 9.917 1.00 0.00 O +HETATM 73 ATM LJP A 73 19.379 7.608 12.121 1.00 0.00 O +HETATM 74 ATM LJP A 74 2.507 12.747 4.288 1.00 0.00 O +HETATM 75 ATM LJP A 75 23.371 8.711 18.224 1.00 0.00 O +HETATM 76 ATM LJP A 76 11.850 19.267 7.294 1.00 0.00 O +HETATM 77 ATM LJP A 77 7.635 15.939 23.087 1.00 0.00 O +HETATM 78 ATM LJP A 78 5.569 8.128 23.936 1.00 0.00 O +HETATM 79 ATM LJP A 79 15.107 6.210 18.996 1.00 0.00 O +HETATM 80 ATM LJP A 80 2.611 17.603 17.589 1.00 0.00 O +HETATM 81 ATM LJP A 81 8.151 8.802 9.716 1.00 0.00 O +HETATM 82 ATM LJP A 82 10.201 21.419 4.099 1.00 0.00 O +HETATM 83 ATM LJP A 83 16.098 13.719 23.480 1.00 0.00 O +HETATM 84 ATM LJP A 84 8.929 15.590 8.311 1.00 0.00 O +HETATM 85 ATM LJP A 85 13.937 2.387 14.025 1.00 0.00 O +HETATM 86 ATM LJP A 86 12.885 2.555 9.979 1.00 0.00 O +HETATM 87 ATM LJP A 87 5.137 9.361 3.974 1.00 0.00 O +HETATM 88 ATM LJP A 88 1.281 8.620 6.312 1.00 0.00 O +HETATM 89 ATM LJP A 89 17.554 12.711 6.960 1.00 0.00 O +HETATM 90 ATM LJP A 90 15.184 22.293 3.469 1.00 0.00 O +HETATM 91 ATM LJP A 91 23.319 4.435 19.790 1.00 0.00 O +HETATM 92 ATM LJP A 92 10.995 5.888 2.383 1.00 0.00 O +HETATM 93 ATM LJP A 93 0.459 0.884 22.377 1.00 0.00 O +HETATM 94 ATM LJP A 94 7.851 22.165 23.288 1.00 0.00 O +HETATM 95 ATM LJP A 95 16.031 9.092 9.029 1.00 0.00 O +HETATM 96 ATM LJP A 96 15.514 13.294 10.917 1.00 0.00 O +HETATM 97 ATM LJP A 97 8.621 16.037 13.610 1.00 0.00 O +HETATM 98 ATM LJP A 98 13.277 5.452 6.697 1.00 0.00 O +HETATM 99 ATM LJP A 99 7.398 12.445 15.919 1.00 0.00 O +HETATM 100 ATM LJP A 100 1.233 9.811 1.521 1.00 0.00 O +HETATM 101 ATM LJP A 101 17.182 9.617 4.050 1.00 0.00 O +HETATM 102 ATM LJP A 102 23.810 15.860 5.104 1.00 0.00 O +HETATM 103 ATM LJP A 103 6.341 19.363 1.958 1.00 0.00 O +HETATM 104 ATM LJP A 104 4.815 9.375 14.548 1.00 0.00 O +HETATM 105 ATM LJP A 105 6.653 5.055 3.047 1.00 0.00 O +HETATM 106 ATM LJP A 106 20.997 18.672 2.168 1.00 0.00 O +HETATM 107 ATM LJP A 107 19.650 11.833 10.909 1.00 0.00 O +HETATM 108 ATM LJP A 108 13.763 18.358 3.334 1.00 0.00 O +HETATM 109 ATM LJP A 109 6.167 5.750 12.102 1.00 0.00 O +HETATM 110 ATM LJP A 110 21.996 13.109 19.009 1.00 0.00 O +HETATM 111 ATM LJP A 111 5.614 1.795 10.621 1.00 0.00 O +HETATM 112 ATM LJP A 112 15.168 6.135 1.697 1.00 0.00 O +HETATM 113 ATM LJP A 113 9.818 3.721 13.101 1.00 0.00 O +HETATM 114 ATM LJP A 114 16.586 21.465 7.700 1.00 0.00 O +HETATM 115 ATM LJP A 115 12.604 22.049 19.687 1.00 0.00 O +HETATM 116 ATM LJP A 116 19.338 6.234 0.946 1.00 0.00 O +HETATM 117 ATM LJP A 117 21.932 5.114 9.361 1.00 0.00 O +HETATM 118 ATM LJP A 118 5.063 0.862 21.897 1.00 0.00 O +HETATM 119 ATM LJP A 119 4.957 2.078 6.381 1.00 0.00 O +HETATM 120 ATM LJP A 120 2.329 5.797 2.647 1.00 0.00 O +HETATM 121 ATM LJP A 121 1.591 12.245 12.844 1.00 0.00 O +HETATM 122 ATM LJP A 122 16.597 24.419 11.129 1.00 0.00 O +HETATM 123 ATM LJP A 123 12.369 13.273 14.671 1.00 0.00 O +HETATM 124 ATM LJP A 124 5.469 19.987 13.801 1.00 0.00 O +HETATM 125 ATM LJP A 125 19.790 22.589 4.699 1.00 0.00 O +HETATM 126 ATM LJP A 126 18.303 2.103 2.180 1.00 0.00 O +HETATM 127 ATM LJP A 127 9.397 16.920 4.039 1.00 0.00 O +HETATM 128 ATM LJP A 128 14.287 1.847 18.767 1.00 0.00 O +HETATM 129 ATM LJP A 129 15.318 14.136 3.267 1.00 0.00 O +HETATM 130 ATM LJP A 130 3.819 22.102 5.225 1.00 0.00 O +HETATM 131 ATM LJP A 131 9.017 9.943 1.343 1.00 0.00 O +HETATM 132 ATM LJP A 132 0.959 7.195 14.226 1.00 0.00 O +HETATM 133 ATM LJP A 133 18.988 10.612 0.110 1.00 0.00 O +HETATM 134 ATM LJP A 134 5.231 16.952 10.156 1.00 0.00 O +HETATM 135 ATM LJP A 135 1.581 1.397 17.762 1.00 0.00 O +HETATM 136 ATM LJP A 136 13.682 10.290 1.707 1.00 0.00 O +HETATM 137 ATM LJP A 137 5.629 9.455 18.879 1.00 0.00 O +HETATM 138 ATM LJP A 138 8.945 19.775 10.880 1.00 0.00 O +HETATM 139 ATM LJP A 139 15.278 16.450 14.302 1.00 0.00 O +HETATM 140 ATM LJP A 140 11.055 4.757 19.054 1.00 0.00 O +HETATM 141 ATM LJP A 141 6.253 2.027 17.903 1.00 0.00 O +HETATM 142 ATM LJP A 142 7.812 6.088 16.250 1.00 0.00 O +HETATM 143 ATM LJP A 143 16.886 5.251 15.066 1.00 0.00 O +HETATM 144 ATM LJP A 144 20.992 24.409 9.244 1.00 0.00 O +HETATM 145 ATM LJP A 145 12.841 23.567 6.889 1.00 0.00 O +HETATM 146 ATM LJP A 146 9.853 9.608 13.817 1.00 0.00 O +HETATM 147 ATM LJP A 147 6.080 12.030 6.994 1.00 0.00 O +HETATM 148 ATM LJP A 148 16.666 1.590 6.957 1.00 0.00 O +HETATM 149 ATM LJP A 149 5.502 14.368 19.487 1.00 0.00 O +HETATM 150 ATM LJP A 150 17.292 20.610 13.492 1.00 0.00 O +HETATM 151 ATM LJP A 151 12.589 3.868 23.253 1.00 0.00 O +HETATM 152 ATM LJP A 152 17.936 18.176 5.237 1.00 0.00 O +HETATM 153 ATM LJP A 153 3.990 21.877 17.484 1.00 0.00 O +HETATM 154 ATM LJP A 154 17.109 17.693 0.653 1.00 0.00 O +HETATM 155 ATM LJP A 155 1.459 21.296 20.946 1.00 0.00 O +HETATM 156 ATM LJP A 156 3.396 22.007 0.400 1.00 0.00 O +HETATM 157 ATM LJP A 157 9.349 7.859 5.703 1.00 0.00 O +HETATM 158 ATM LJP A 158 22.681 10.914 22.751 1.00 0.00 O +HETATM 159 ATM LJP A 159 22.311 19.684 6.532 1.00 0.00 O +HETATM 160 ATM LJP A 160 7.358 19.657 6.830 1.00 0.00 O +HETATM 161 ATM LJP A 161 8.435 23.908 7.913 1.00 0.00 O +HETATM 162 ATM LJP A 162 22.823 18.032 19.242 1.00 0.00 O +HETATM 163 ATM LJP A 163 6.987 24.374 2.751 1.00 0.00 O +HETATM 164 ATM LJP A 164 1.238 19.288 3.152 1.00 0.00 O +HETATM 165 ATM LJP A 165 3.766 3.412 14.505 1.00 0.00 O +HETATM 166 ATM LJP A 166 17.479 23.245 20.271 1.00 0.00 O +HETATM 167 ATM LJP A 167 8.131 11.490 21.734 1.00 0.00 O +HETATM 168 ATM LJP A 168 10.833 18.968 0.392 1.00 0.00 O +HETATM 169 ATM LJP A 169 23.826 2.848 13.407 1.00 0.00 O +HETATM 170 ATM LJP A 170 20.369 15.881 8.055 1.00 0.00 O +HETATM 171 ATM LJP A 171 20.751 2.470 5.736 1.00 0.00 O +HETATM 172 ATM LJP A 172 11.290 24.050 1.080 1.00 0.00 O +HETATM 173 ATM LJP A 173 21.737 0.532 18.006 1.00 0.00 O +HETATM 174 ATM LJP A 174 15.141 0.407 23.854 1.00 0.00 O +HETATM 175 ATM LJP A 175 24.202 21.236 16.792 1.00 0.00 O +HETATM 176 ATM LJP A 176 9.624 20.857 15.029 1.00 0.00 O +HETATM 177 ATM LJP A 177 10.552 14.344 18.936 1.00 0.00 O +HETATM 178 ATM LJP A 178 23.468 6.714 23.607 1.00 0.00 O +HETATM 179 ATM LJP A 179 16.348 17.348 9.441 1.00 0.00 O +HETATM 180 ATM LJP A 180 19.555 2.774 12.697 1.00 0.00 O +HETATM 181 ATM LJP A 181 23.304 22.686 1.339 1.00 0.00 O +HETATM 182 ATM LJP A 182 15.751 8.855 22.264 1.00 0.00 O +HETATM 183 ATM LJP A 183 17.631 5.546 5.404 1.00 0.00 O +HETATM 184 ATM LJP A 184 23.537 8.901 10.565 1.00 0.00 O +HETATM 185 ATM LJP A 185 14.367 10.164 17.737 1.00 0.00 O +HETATM 186 ATM LJP A 186 10.200 9.386 18.329 1.00 0.00 O +HETATM 187 ATM LJP A 187 8.833 4.201 8.357 1.00 0.00 O +HETATM 188 ATM LJP A 188 24.159 23.893 5.675 1.00 0.00 O +HETATM 189 ATM LJP A 189 21.608 18.838 14.112 1.00 0.00 O +HETATM 190 ATM LJP A 190 7.187 17.854 17.442 1.00 0.00 O +HETATM 191 ATM LJP A 191 3.460 16.451 0.423 1.00 0.00 O +HETATM 192 ATM LJP A 192 18.826 22.220 0.523 1.00 0.00 O +HETATM 193 ATM LJP A 193 22.824 2.641 1.749 1.00 0.00 O +HETATM 194 ATM LJP A 194 16.754 4.199 22.403 1.00 0.00 O +HETATM 195 ATM LJP A 195 0.853 3.877 6.189 1.00 0.00 O +HETATM 196 ATM LJP A 196 7.160 5.518 20.741 1.00 0.00 O +HETATM 197 ATM LJP A 197 20.256 15.051 22.686 1.00 0.00 O +HETATM 198 ATM LJP A 198 4.934 6.245 7.081 1.00 0.00 O +HETATM 199 ATM LJP A 199 20.069 20.260 10.139 1.00 0.00 O +HETATM 200 ATM LJP A 200 11.265 12.039 10.134 1.00 0.00 O +TER 201 LJP A 200 +END diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/fingerprint.pb b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/fingerprint.pb new file mode 100644 index 000000000..a71b9d584 --- /dev/null +++ b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/fingerprint.pb @@ -0,0 +1 @@ +ӊݖۆq љ(ۄ2 \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/saved_model.pb b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/saved_model.pb new file mode 100644 index 000000000..c1a96e44a Binary files /dev/null and b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/saved_model.pb differ diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/variables/variables.data-00000-of-00001 b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/variables/variables.data-00000-of-00001 new file mode 100644 index 000000000..b98b2b29c Binary files /dev/null and b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/variables/variables.data-00000-of-00001 differ diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/variables/variables.index b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/variables/variables.index new file mode 100644 index 000000000..1d14dfb86 Binary files /dev/null and b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/data/lj_fluid_gpu/variables/variables.index differ diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/tests/test_dmff_plugin_nve.py b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/tests/test_dmff_plugin_nve.py new file mode 100644 index 000000000..dd6dd53e5 --- /dev/null +++ b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/tests/test_dmff_plugin_nve.py @@ -0,0 +1,101 @@ +import os +import numpy as np +import time +import argparse + +try: + import openmm as mm + from openmm import unit as u + from openmm.app import PDBFile, StateDataReporter, DCDReporter, Simulation +except: + import simtk.openmm as mm + from simtk import unit as u + from simtk.openmm.app import PDBFile, StateDataReporter, DCDReporter, Simulation + +from OpenMMDMFFPlugin import DMFFModel + + +def test_dmff_nve(nsteps = 1000, time_step = 0.2, platform_name = "Reference", output_temp_dir = "/tmp/openmm_dmff_plugin_test_nve_output", energy_std_tol = 0.0005 ): + if not os.path.exists(output_temp_dir): + os.mkdir(output_temp_dir) + + pdb_file = os.path.join(os.path.dirname(__file__), "../data", "lj_fluid.pdb") + if platform_name == "Reference": + dmff_model_file = os.path.join(os.path.dirname(__file__), "../data", "lj_fluid_gpu") + elif platform_name == "CUDA": + dmff_model_file = os.path.join(os.path.dirname(__file__), "../data", "lj_fluid_gpu") + + output_dcd = os.path.join(output_temp_dir, "lj_fluid_test.nve.dcd") + output_log = os.path.join(output_temp_dir, "lj_fluid_test.nve.log") + + # Set up the simulation parameters. + nsteps = nsteps + time_step = time_step # unit is femtosecond. + report_frequency = 10 + box = [24.413, 0, 0, 0, 24.413, 0, 0, 0, 24.413] + box = [mm.Vec3(box[0], box[1], box[2]), mm.Vec3(box[3], box[4], box[5]), mm.Vec3(box[6], box[7], box[8])] * u.angstroms + + liquid_water = PDBFile(pdb_file) + topology = liquid_water.topology + positions = liquid_water.getPositions() + num_atoms = topology.getNumAtoms() + + # Set up the dmff_system with the dmff_model. + dmff_model = DMFFModel(dmff_model_file) + dmff_model.setUnitTransformCoefficients(1, 1, 1) + dmff_system = dmff_model.createSystem(topology) + + integrator = mm.VerletIntegrator(time_step*u.femtoseconds) + platform = mm.Platform.getPlatformByName(platform_name) + + # Build up the simulation object. + sim = Simulation(topology, dmff_system, integrator, platform) + sim.context.setPeriodicBoxVectors(box[0], box[1], box[2]) + sim.context.setPositions(positions) + + # Add state reporters + sim.reporters.append(DCDReporter(output_dcd, report_frequency, enforcePeriodicBox=False)) + sim.reporters.append( + StateDataReporter(output_log, report_frequency, step=True, time=True, totalEnergy=True, kineticEnergy=True, potentialEnergy=True, temperature=True, progress=True, + remainingTime=True, speed=True, density=True,totalSteps=nsteps, separator='\t') + ) + + # Run dynamics + print("Running dynamics") + start_time = time.time() + sim.step(nsteps) + end_time = time.time() + cost_time = end_time - start_time + print("Running on %s platform, time cost: %.4f s"%(platform_name, cost_time)) + + # Fetch the total energy from the log file. + total_energy = [] + tot_energy_index = -5 + with open(output_log, "r") as f: + log_content = f.readlines() + for ii , line in enumerate(log_content): + if ii == 0: + continue + temp = line.split() + total_energy.append(float(temp[tot_energy_index])) + total_energy = np.array(total_energy) + + # Check the total energy fluctuations over # of atoms is smaller than energy_std_tol, unit in kJ/mol. + print("Total energy std: %.4f kJ/mol"%(np.std(total_energy))) + print("Mean total energy: %.4f kJ/mol"%(np.mean(total_energy))) + #assert(np.std(total_energy) / num_atoms < energy_std_tol) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-n', '--nsteps', type = int, dest='nsteps', help='Number of steps', default=100) + parser.add_argument('--dt', type = float, dest='timestep', help='Time step for simulation, unit is femtosecond', default=0.2) + parser.add_argument('--platform', type = str, dest='platform', help='Platform for simulation.', default="Reference") + + args = parser.parse_args() + + nsteps = args.nsteps + time_step = args.timestep + platform_name = args.platform + + test_dmff_nve(nsteps=nsteps, time_step=time_step, platform_name=platform_name) + diff --git a/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/tools.py b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/tools.py new file mode 100644 index 000000000..d86804eaf --- /dev/null +++ b/backend/openmm_dmff_plugin/python/OpenMMDMFFPlugin/tools.py @@ -0,0 +1,88 @@ +from __future__ import absolute_import +try: + from openmm import app, KcalPerKJ + import openmm as mm + from openmm import unit as u + from openmm.app import * + import openmm.unit as unit +except: + from simtk import unit as u + import simtk.openmm as mm + from simtk.openmm.app import * + import simtk.openmm as mm + import simtk.unit as unit + +import sys +from datetime import datetime, timedelta +import numpy as np + +try: + string_types = (unicode, str) +except NameError: + string_types = (str,) + +from .OpenMMDMFFPlugin import DMFFForce + +class ForceReporter(object): + def __init__(self, file, group_num, reportInterval): + self.group_num = group_num + if self.group_num is None: + self._out = open(file, 'w') + #self._out.write("Get the forces of all components"+"\n") + else: + self._out = open(file, 'w') + #self._out.write("Get the forces of group "+str(self.group_num) + "\n") + self._reportInterval = reportInterval + + def __del__(self): + self._out.close() + + def describeNextReport(self, simulation): + steps = self._reportInterval - simulation.currentStep%self._reportInterval + # return (steps, positions, velocities, forces, energies) + return (steps, False, False, True, False) + + def report(self, simulation, state): + if self.group_num is not None: + state = simulation.context.getState(getForces=True, groups={self.group_num}) + else: + state = simulation.context.getState(getForces=True) + forces = state.getForces().value_in_unit(u.kilojoules_per_mole/u.nanometers) + self._out.write(str(forces)+"\n") + + + +class DMFFModel(): + def __init__(self, model_file) -> None: + self.model_file = model_file + self.dmff_force = DMFFForce(model_file) + return + + def setUnitTransformCoefficients(self, coordinatesCoefficient, forceCoefficient, energyCoefficient): + """Set the unit transform coefficients for the DMFF model. + Within the OpenMM context, the units for coordinates/forces/energy are restricted to nm and kJ/(mol * nm) and kJ/mol, respectively. + + Args: + coordinatesCoefficient (float): Coefficient for input coordinates that transforms the units of the coordinates from nanometers to the units required by the DMFF model. + forceCoefficient (float): Coefficient for forces that transforms the units of the DMFF calculated forces to the units used by OpenMM (kJ/(mol * nm)). + energyCoefficient (float): Coefficient for energy that transforms the units of the DMFF calculated energy to the units used by OpenMM (kJ/mol). + """ + self.dmff_force.setUnitTransformCoefficients(coordinatesCoefficient, forceCoefficient, energyCoefficient) + return + + def createSystem(self, topology): + """Create the OpenMM System object for the DMFF model. + + Args: + topology (_type_): OpenMM Topology object + + """ + dmff_system = mm.System() + + # Add particles into force. + for atom in topology.atoms(): + dmff_system.addParticle(atom.element.mass) + + dmff_system.addForce(self.dmff_force) + + return dmff_system \ No newline at end of file diff --git a/backend/openmm_dmff_plugin/python/setup.py b/backend/openmm_dmff_plugin/python/setup.py new file mode 100644 index 000000000..df4518358 --- /dev/null +++ b/backend/openmm_dmff_plugin/python/setup.py @@ -0,0 +1,40 @@ +from distutils.core import setup +from distutils.extension import Extension +import os +import platform + +openmm_dir = '@OPENMM_DIR@' +CPPFLOW_DIR = '@CPPFLOW_DIR@' +TENSORFLOW_DIR = '@TENSORFLOW_DIR@' +DMFFPlugin_header_dir = '@DMFFPLUGIN_HEADER_DIR@' +DMFFPlugin_library_dir = '@DMFFPLUGIN_LIBRARY_DIR@' + +os.environ["CC"] = "@CMAKE_C_COMPILER@" +os.environ["CXX"] = "@CMAKE_CXX_COMPILER@" + +extra_compile_args = ["-std=c++17", "-fPIC"] +extra_link_args = [] + + +# setup extra compile and link arguments on Mac +if platform.system() == 'Darwin': + extra_compile_args += ['-stdlib=libc++', '-mmacosx-version-min=10.7'] + extra_link_args += ['-stdlib=libc++', '-mmacosx-version-min=10.7', '-Wl', '-rpath', openmm_dir+'/lib'] + +extension = Extension(name='OpenMMDMFFPlugin._OpenMMDMFFPlugin', + sources=['OpenMMDMFFPluginWrapper.cpp'], + libraries=['OpenMM', 'OpenMMDMFF'], + include_dirs=[os.path.join(openmm_dir, 'include'), os.path.join(CPPFLOW_DIR, 'include'), os.path.join(TENSORFLOW_DIR, 'include'), DMFFPlugin_header_dir], + library_dirs=[os.path.join(openmm_dir, 'lib'), os.path.join(CPPFLOW_DIR, 'lib'), os.path.join(TENSORFLOW_DIR, 'lib'), DMFFPlugin_library_dir], + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args + ) + + + +setup(name='OpenMMDMFFPlugin', + version="@GIT_HASH@", + ext_modules=[extension], + packages=['OpenMMDMFFPlugin', "OpenMMDMFFPlugin.tests"], + package_data={"OpenMMDMFFPlugin":['data/lj_fluid/*.pb', 'data/lj_fluid/variables/variables.index', 'data/lj_fluid/variables/variables.data-00000-of-00001', 'data/lj_fluid_gpu/*.pb', 'data/lj_fluid_gpu/variables/variables.index', 'data/lj_fluid_gpu/variables/variables.data-00000-of-00001', 'data/*.pdb']}, + ) diff --git a/backend/openmm_dmff_plugin/python/tests/test_dmff_plugin_nve.py b/backend/openmm_dmff_plugin/python/tests/test_dmff_plugin_nve.py new file mode 100644 index 000000000..21a16ca79 --- /dev/null +++ b/backend/openmm_dmff_plugin/python/tests/test_dmff_plugin_nve.py @@ -0,0 +1,101 @@ +import os +import numpy as np +import time +import argparse + +try: + import openmm as mm + from openmm import unit as u + from openmm.app import PDBFile, StateDataReporter, DCDReporter, Simulation +except: + import simtk.openmm as mm + from simtk import unit as u + from simtk.openmm.app import PDBFile, StateDataReporter, DCDReporter, Simulation + +from OpenMMDMFFPlugin import DMFFModel + + +def test_dmff_nve(nsteps = 1000, time_step = 0.2, platform_name = "Reference", output_temp_dir = "/tmp/openmm_dmff_plugin_test_nve_output", energy_std_tol = 0.005 ): + if not os.path.exists(output_temp_dir): + os.mkdir(output_temp_dir) + + pdb_file = os.path.join(os.path.dirname(__file__), "../data", "lj_fluid.pdb") + if platform_name == "Reference": + dmff_model_file = os.path.join(os.path.dirname(__file__), "../data", "lj_fluid_gpu") + elif platform_name == "CUDA": + dmff_model_file = os.path.join(os.path.dirname(__file__), "../data", "lj_fluid_gpu") + + output_dcd = os.path.join(output_temp_dir, "lj_fluid_test.nve.dcd") + output_log = os.path.join(output_temp_dir, "lj_fluid_test.nve.log") + + # Set up the simulation parameters. + nsteps = nsteps + time_step = time_step # unit is femtosecond. + report_frequency = 10 + box = [24.413, 0, 0, 0, 24.413, 0, 0, 0, 24.413] + box = [mm.Vec3(box[0], box[1], box[2]), mm.Vec3(box[3], box[4], box[5]), mm.Vec3(box[6], box[7], box[8])] * u.angstroms + + liquid_water = PDBFile(pdb_file) + topology = liquid_water.topology + positions = liquid_water.getPositions() + num_atoms = topology.getNumAtoms() + + # Set up the dmff_system with the dmff_model. + dmff_model = DMFFModel(dmff_model_file) + dmff_model.setUnitTransformCoefficients(1, 1, 1) + dmff_system = dmff_model.createSystem(topology) + + integrator = mm.VerletIntegrator(time_step*u.femtoseconds) + platform = mm.Platform.getPlatformByName(platform_name) + + # Build up the simulation object. + sim = Simulation(topology, dmff_system, integrator, platform) + sim.context.setPeriodicBoxVectors(box[0], box[1], box[2]) + sim.context.setPositions(positions) + + # Add state reporters + sim.reporters.append(DCDReporter(output_dcd, report_frequency, enforcePeriodicBox=False)) + sim.reporters.append( + StateDataReporter(output_log, report_frequency, step=True, time=True, totalEnergy=True, kineticEnergy=True, potentialEnergy=True, temperature=True, progress=True, + remainingTime=True, speed=True, density=True,totalSteps=nsteps, separator='\t') + ) + + # Run dynamics + print("Running dynamics") + start_time = time.time() + sim.step(nsteps) + end_time = time.time() + cost_time = end_time - start_time + print("Running on %s platform, time cost: %.4f s"%(platform_name, cost_time)) + + # Fetch the total energy from the log file. + total_energy = [] + tot_energy_index = -5 + with open(output_log, "r") as f: + log_content = f.readlines() + for ii , line in enumerate(log_content): + if ii == 0: + continue + temp = line.split() + total_energy.append(float(temp[tot_energy_index])) + total_energy = np.array(total_energy) + + # Check the total energy fluctuations over # of atoms is smaller than energy_std_tol, unit in kJ/mol. + print("Total energy std: %.4f kJ/mol"%(np.std(total_energy))) + print("Mean total energy: %.4f kJ/mol"%(np.mean(total_energy))) + assert(np.std(total_energy) / num_atoms < energy_std_tol) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-n', '--nsteps', type = int, dest='nsteps', help='Number of steps', default=100) + parser.add_argument('--dt', type = float, dest='timestep', help='Time step for simulation, unit is femtosecond', default=0.2) + parser.add_argument('--platform', type = str, dest='platform', help='Platform for simulation.', default="Reference") + + args = parser.parse_args() + + nsteps = args.nsteps + time_step = args.timestep + platform_name = args.platform + + test_dmff_nve(nsteps=nsteps, time_step=time_step, platform_name=platform_name) + diff --git a/backend/openmm_dmff_plugin/serialization/include/DMFFForceProxy.h b/backend/openmm_dmff_plugin/serialization/include/DMFFForceProxy.h new file mode 100644 index 000000000..e22e03a07 --- /dev/null +++ b/backend/openmm_dmff_plugin/serialization/include/DMFFForceProxy.h @@ -0,0 +1,53 @@ +#ifndef OPENMM_DMFF_FORCE_PROXY_H_ +#define OPENMM_DMFF_FORCE_PROXY_H_ + +/* -------------------------------------------------------------------------- * + * OpenMM-DMF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "internal/windowsExportDMFF.h" +#include "openmm/serialization/SerializationProxy.h" + +namespace OpenMM { + +/** + * This is a proxy for serializing DMFFForce objects. + */ + +class OPENMM_EXPORT_DMFF DMFFForceProxy : public SerializationProxy { +public: + DMFFForceProxy(); + void serialize(const void* object, SerializationNode& node) const; + void* deserialize(const SerializationNode& node) const; +}; + +} // namespace OpenMM + +#endif /*OPENMM_DMFF_FORCE_PROXY_H_*/ diff --git a/backend/openmm_dmff_plugin/serialization/src/DMFFForceProxy.cpp b/backend/openmm_dmff_plugin/serialization/src/DMFFForceProxy.cpp new file mode 100644 index 000000000..b593fc07f --- /dev/null +++ b/backend/openmm_dmff_plugin/serialization/src/DMFFForceProxy.cpp @@ -0,0 +1,57 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForceProxy.h" +#include "DMFFForce.h" +#include "openmm/serialization/SerializationNode.h" +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + +// TODO: Serialization of DMFFForce is not implemented rigourously. +// More work is needed to make sure that the serialization is correct. +DMFFForceProxy::DMFFForceProxy() : SerializationProxy("DMFFForce") { +} + +void DMFFForceProxy::serialize(const void* object, SerializationNode& node) const { + node.setIntProperty("version", 0); + const DMFFForce& force = *reinterpret_cast(object); + node.setStringProperty("file", force.getDMFFGraphFile()); +} + +void* DMFFForceProxy::deserialize(const SerializationNode& node) const { + if (node.getIntProperty("version") != 0) + throw OpenMMException("Unsupported version number"); + DMFFForce* force = new DMFFForce(node.getStringProperty("file")); + return force; +} diff --git a/backend/openmm_dmff_plugin/serialization/src/DMFFSerializationProxyRegistration.cpp b/backend/openmm_dmff_plugin/serialization/src/DMFFSerializationProxyRegistration.cpp new file mode 100644 index 000000000..2a68a3f79 --- /dev/null +++ b/backend/openmm_dmff_plugin/serialization/src/DMFFSerializationProxyRegistration.cpp @@ -0,0 +1,62 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#ifdef WIN32 +#include +#include +#else +#include +#include +#include +#endif + +#include "DMFFForce.h" +#include "DMFFForceProxy.h" +#include "openmm/serialization/SerializationProxy.h" + +#if defined(WIN32) + #include + extern "C" OPENMM_EXPORT_DMFF void registerDMFFSerializationProxies(); + BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + if (ul_reason_for_call == DLL_PROCESS_ATTACH) + registerDMFFSerializationProxies(); + return TRUE; + } +#else + extern "C" void __attribute__((constructor)) registerDMFFSerializationProxies(); +#endif + +using namespace DMFFPlugin; +using namespace OpenMM; + +extern "C" OPENMM_EXPORT_DMFF void registerDMFFSerializationProxies() { + SerializationProxy::registerProxy(typeid(DMFFForce), new DMFFForceProxy()); +} diff --git a/backend/openmm_dmff_plugin/serialization/tests/CMakeLists.txt b/backend/openmm_dmff_plugin/serialization/tests/CMakeLists.txt new file mode 100644 index 000000000..048f048f9 --- /dev/null +++ b/backend/openmm_dmff_plugin/serialization/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Testing +# + +# Automatically create tests using files named "Test*.cpp" +FILE(GLOB TEST_PROGS "*Test*.cpp") +FOREACH(TEST_PROG ${TEST_PROGS}) + GET_FILENAME_COMPONENT(TEST_ROOT ${TEST_PROG} NAME_WE) + + # Link with shared library + + ADD_EXECUTABLE(${TEST_ROOT} ${TEST_PROG}) + TARGET_LINK_LIBRARIES(${TEST_ROOT} ${SHARED_DMFF_TARGET}) + SET_TARGET_PROPERTIES(${TEST_ROOT} PROPERTIES LINK_FLAGS "${EXTRA_COMPILE_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}") + ADD_TEST(NAME ${TEST_ROOT} COMMAND ${EXECUTABLE_OUTPUT_PATH}/${TEST_ROOT} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +ENDFOREACH(TEST_PROG ${TEST_PROGS}) diff --git a/backend/openmm_dmff_plugin/serialization/tests/TestSerializeDMFFForce.cpp b/backend/openmm_dmff_plugin/serialization/tests/TestSerializeDMFFForce.cpp new file mode 100644 index 000000000..fd4963e90 --- /dev/null +++ b/backend/openmm_dmff_plugin/serialization/tests/TestSerializeDMFFForce.cpp @@ -0,0 +1,75 @@ +/* -------------------------------------------------------------------------- * + * OpenMM-DMFF * + * -------------------------------------------------------------------------- * + * This is part of the OpenMM molecular simulation toolkit originating from * + * Simbios, the NIH National Center for Physics-Based Simulation of * + * Biological Structures at Stanford, funded under the NIH Roadmap for * + * Medical Research, grant U54 GM072970. See https://simtk.org. * + * * + * Portions copyright (c) 2014 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "DMFFForce.h" +#include "openmm/Platform.h" +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/serialization/XmlSerializer.h" +#include +#include + +using namespace DMFFPlugin; +using namespace OpenMM; +using namespace std; + +extern "C" void registerDMFFSerializationProxies(); + + +void testSerialization() { + const double TOL = 1e-5; + const string graph = "../python/OpenMMDMFFPlugin/data/lj_fluid_gpu"; + const double temperature = 300; + + // Create a Force. + DMFFForce dmff_force = DMFFForce(graph); + + stringstream buffer; + XmlSerializer::serialize(&dmff_force, "Force", buffer); + DMFFForce* copy = XmlSerializer::deserialize(buffer); + + // Compare the two forces to see if they are identical. + DMFFForce& dmff_force2 = *copy; + ASSERT_EQUAL(dmff_force2.getDMFFGraphFile(), dmff_force.getDMFFGraphFile()); + return; +} + +int main() { + try { + registerDMFFSerializationProxies(); + testSerialization(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/backend/openmm_dmff_plugin/tests/cppflow_empty_constructor.patch b/backend/openmm_dmff_plugin/tests/cppflow_empty_constructor.patch new file mode 100644 index 000000000..bd4430cf9 --- /dev/null +++ b/backend/openmm_dmff_plugin/tests/cppflow_empty_constructor.patch @@ -0,0 +1,75 @@ +diff --git a/include/cppflow/model.h b/include/cppflow/model.h +index 368e145..88e47e6 100644 +--- a/include/cppflow/model.h ++++ b/include/cppflow/model.h +@@ -68,6 +68,8 @@ class model { + const TYPE type = TYPE::SAVED_MODEL); + model(const model &model) = default; + model(model &&model) = default; ++ model(); ++ void init(const std::string& filename, const TYPE type = TYPE::SAVED_MODEL); + + ~model() = default; + +@@ -144,6 +146,61 @@ inline model::model(const std::string &filename, const TYPE type) { + status_check(this->status.get()); + } + ++inline model::model(){ ++} ++ ++inline void model::init(const std::string &filename, const TYPE type){ ++ this->status = {TF_NewStatus(), &TF_DeleteStatus}; ++ this->graph = {TF_NewGraph(), TF_DeleteGraph}; ++ ++ // Create the session. ++ std::unique_ptr ++ session_options = {TF_NewSessionOptions(), TF_DeleteSessionOptions}; ++ ++ auto session_deleter = [this](TF_Session* sess) { ++ TF_DeleteSession(sess, this->status.get()); ++ status_check(this->status.get()); ++ }; ++ ++ if (type == TYPE::SAVED_MODEL) { ++ std::unique_ptr run_options = { ++ TF_NewBufferFromString("", 0), TF_DeleteBuffer}; ++ std::unique_ptr meta_graph = { ++ TF_NewBuffer(), TF_DeleteBuffer}; ++ ++ int tag_len = 1; ++ const char* tag = "serve"; ++ this->session = { ++ TF_LoadSessionFromSavedModel(session_options.get(), run_options.get(), ++ filename.c_str(), &tag, tag_len, ++ this->graph.get(), meta_graph.get(), ++ this->status.get()), session_deleter}; ++ } else if (type == TYPE::FROZEN_GRAPH) { ++ this->session = {TF_NewSession(this->graph.get(), session_options.get(), ++ this->status.get()), ++ session_deleter}; ++ status_check(this->status.get()); ++ ++ // Import the graph definition ++ TF_Buffer* def = readGraph(filename); ++ if (def == nullptr) { ++ throw std::runtime_error("Failed to import graph def from file"); ++ } ++ ++ std::unique_ptr graph_opts = { ++ TF_NewImportGraphDefOptions(), TF_DeleteImportGraphDefOptions}; ++ TF_GraphImportGraphDef(this->graph.get(), def, graph_opts.get(), ++ this->status.get()); ++ TF_DeleteBuffer(def); ++ } else { ++ throw std::runtime_error("Model type unknown"); ++ } ++ ++ status_check(this->status.get()); ++ ++} ++ + inline std::vector model::get_operations() const { + std::vector result; + size_t pos = 0; diff --git a/backend/save_dmff2tf.py b/backend/save_dmff2tf.py index f56ba3f0b..fac1741d3 100644 --- a/backend/save_dmff2tf.py +++ b/backend/save_dmff2tf.py @@ -3,11 +3,9 @@ import jax import jax.numpy as jnp from jax.experimental import jax2tf -# The model is saved in double precision by default. -# Since forces accuracy in double precision is needed in molecular dynamics simulations, -# we need to enable double precision in JAX. -from jax import config -config.update("jax_enable_x64", True) +# The model is saved in float32 precision by default. +#from jax import config +#config.update("jax_enable_x64", True) import openmm.app as app import openmm.unit as unit import tensorflow as tf @@ -71,6 +69,6 @@ def potential_engrad(positions, box, pairs): ) dmff_model = tf.Module() dmff_model.f = tf.function(f_tf, autograph=False, - input_signature=[tf.TensorSpec(shape=[natoms,3], dtype=tf.float64), tf.TensorSpec(shape=[3,3], dtype=tf.float64), tf.TensorSpec(shape=tf.TensorShape([None, 2]), dtype=tf.int32)]) + input_signature=[tf.TensorSpec(shape=[natoms,3], dtype=tf.float32), tf.TensorSpec(shape=[3,3], dtype=tf.float32), tf.TensorSpec(shape=tf.TensorShape([None, 2]), dtype=tf.int32)]) tf.saved_model.save(dmff_model, output_dir, options=tf.saved_model.SaveOptions(experimental_custom_gradients=True))