Commit 2e451b9d authored by Peter Eastman's avatar Peter Eastman
Browse files

Deleted the old CUDA platform

parent 352e2fc7
// ORIGIN:
// http://sites.google.com/site/jivsoft/Home/a-c---random-number-generator-class
#ifndef _RNG_OPENMM_H_
#define _RNG_OPENMM_H_
// __________________________________________________________________________
// rng.h - a Random Number Generator Class
// rng.C - contains the non-inline class methods
// __________________________________________________________________________
// CAUTIONS:
// 1. Some of this code might not work correctly on 64-bit machines. I
// have hacked the 32 bit version try and make it work, but the 64-bit
// version is not extensively tested.
//
// 2. This generator should NOT be used as in the following line.
// for (int i = 0; i < 100; ++i) { RNG x; cout << x.uniform() << endl; }
// The problem is that each time through the loop, a new RNG 'x' is
// created, and that RNG is used to generate exactly one random number.
// While the results may be satisfactory, the class is designed to
// produce quality random numbers by having a single (or a few) RNGs
// called repeatedly.
// The better way to do the above loop is:
// RNG x; for (int i = 0; i < 100; ++i) { cout << x.uniform() << endl; }
// __________________________________________________________________________
// This C++ code uses the simple, fast "KISS" (Keep It Simple Stupid)
// random number generator suggested by George Marsaglia in a Usenet
// posting from 1999. He describes it as "one of my favorite
// generators". It generates high-quality random numbers that
// apparently pass all commonly used tests for randomness. In fact, it
// generates random numbers by combining the results of three simple
// random number generators that have different periods and are
// constructed from completely different algorithms. It does not have
// the ultra-long period of some other generators - a "problem" that can
// be fixed fairly easily - but that seems to be its only potential
// problem. The period is about 2^123.
// The KISS algorithm is only used directly in the function rand_int32.
// rand_int32 is then used (directly or indirectly) by every other
// member function of the class that generates random numbers. For
// faster random numbers, one can redefine rand_int32 to return either
// WMC(), CONG(), or SHR3(). The speed will be two to three times
// faster, and the quality of the random numbers should be sufficient
// for many purposes. The three alternatives are comparable in terms of
// both speed and quality.
// The ziggurat method of Marsaglia is used to generate exponential and
// normal variates. The method as well as source code can be found in
// the article "The Ziggurat Method for Generating Random Variables" by
// Marsaglia and Tsang, Journal of Statistical Software 5, 2000.
// The method for generating gamma variables appears in "A Simple Method
// for Generating Gamma Variables" by Marsaglia and Tsang, ACM
// Transactions on Mathematical Software, Vol. 26, No 3, Sep 2000, pages
// 363-372.
// __________________________________________________________________________
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifdef _MSC_VER
#include "windowsStdInt.h"
#else
#include <stdint.h> // Use the C99 official header
#ifndef UINT32_MAX
#define UINT32_MAX 0xffffffff
#endif
#endif
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <climits>
#include <vector>
using std::vector;
//static const double PI = 3.1415926535897932;
static const double AD_l = 0.6931471805599453;
static const double AD_a = 5.7133631526454228;
static const double AD_b = 3.4142135623730950;
static const double AD_c = -1.6734053240284925;
static const double AD_p = 0.9802581434685472;
static const double AD_A = 5.6005707569738080;
static const double AD_B = 3.3468106480569850;
static const double AD_H = 0.0026106723602095;
static const double AD_D = 0.0857864376269050;
typedef int32_t sint;
typedef uint32_t uint;
typedef int32_t slong;
typedef uint32_t ulong32;
inline slong UL32toSL32(ulong32 x) { return (slong(x)); }
class RNG
{
private:
ulong32 z, w, jsr, jcong; // Seeds
static ulong32 tm; // Used to ensure different RNGs have different seeds.
static ulong32 kn[128], ke[256];
static double wn[128], fn[128], we[256],fe[256];
public:
RNG() { init(); zigset(); }
RNG(ulong32 x_) :
z(x_), w(x_), jsr(x_), jcong(x_) { zigset(); }
RNG(ulong32 z_, ulong32 w_, ulong32 jsr_, ulong32 jcong_ ) :
z(z_), w(w_), jsr(jsr_), jcong(jcong_) { zigset(); }
~RNG() { }
// Get and set seeds (for allowing resumption).
void getSeed(ulong32 & z_, ulong32 & w_, ulong32 & jsr_, ulong32 & jcong_)
{ z_ = z; w_ = w; jsr_ = jsr; jcong_ = jcong; }
void setSeed(ulong32 & z_, ulong32 & w_, ulong32 & jsr_, ulong32 & jcong_)
{ z = z_; w = w_; jsr = jsr_; jcong = jcong_; zigset(); }
// 32 bit unsigned longs
ulong32 znew()
{ return (z = 36969 * (z & 0xfffful) + (z >> 16)); }
ulong32 wnew()
{ return (w = 18000 * (w & 0xfffful) + (w >> 16)); }
ulong32 MWC()
{ return ((znew() << 16) + wnew()); }
ulong32 SHR3()
{ jsr ^= (jsr << 17); jsr ^= (jsr >> 13); return (jsr ^= (jsr << 5)); }
ulong32 CONG()
{ return (jcong = 69069 * jcong + 1234567); }
ulong32 rand_int32() // [0,2^32-1]
{ return ((MWC() ^ CONG()) + SHR3()); }
ulong32 rand_int() // [0,2^32-1]
{ return ((MWC() ^ CONG()) + SHR3()); }
double RNOR() {
slong h = UL32toSL32(rand_int32()), i = h & 127;
return (((ulong32)std::abs(h) < kn[i]) ? h * wn[i] : nfix(h, i));
}
double REXP() {
ulong32 j = rand_int32(), i = j & 255;
return ((j < ke[i]) ? j * we[i] : efix(j, i));
}
double nfix(slong h, ulong32 i);
double efix(ulong32 j, ulong32 i);
void zigset();
void init()
{ z = w = jsr = jcong = ulong32(time(0)) + tm; tm += 123457; }
void init(ulong32 z_, ulong32 w_, ulong32 jsr_, ulong32 jcong_ )
{ z = z_; w = w_; jsr = jsr_; jcong = jcong_; }
// For a faster but lower quality RNG, uncomment the following
// line, and comment out the original definition of rand_int above.
// In practice, the faster RNG will be fine for simulations
// that do not simulate more than a few billion random numbers.
// ulong32 rand_int() { return SHR3(); }
long rand_int31() // [0,2^31-1]
{ return ((long) rand_int32() >> 1);}
double rand_closed01() // [0,1]
{ return ((double) rand_int() / double(UINT32_MAX)); }
double rand_open01() // (0,1)
{ return (((double) rand_int() + 1.0) / (UINT32_MAX + 2.0)); }
double rand_halfclosed01() // [0,1)
{ return ((double) rand_int() / (UINT32_MAX + 1.0)); }
double rand_halfopen01() // (0,1]
{ return (((double) rand_int() + 1.0) / (UINT32_MAX + 1.0)); }
// Continuous Distributions
double uniform(double x = 0.0, double y = 1.0)
{ return rand_closed01() * (y - x) + x; }
double normal(double mu = 0.0, double sd = 1.0)
{ return RNOR() * sd + mu; }
double exponential(double lambda = 1)
{ return REXP() / lambda; }
double gamma(double shape = 1, double scale = 1);
double chi_square(double df)
{ return gamma(df / 2.0, 0.5); }
double beta(double a1, double a2)
{ const double x1 = gamma(a1, 1); return (x1 / (x1 + gamma(a2, 1))); }
void uniform(vector<double>& res, double x = 0.0, double y = 1.0) {
for (vector<double>::iterator i = res.begin(); i != res.end(); ++i)
*i = uniform(x, y);
}
void normal(vector<double>& res, double mu = 0.0, double sd = 1.0) {
for (vector<double>::iterator i = res.begin(); i != res.end(); ++i)
*i = normal(mu, sd);
}
void exponential(vector<double>& res, double lambda = 1) {
for (vector<double>::iterator i = res.begin(); i != res.end(); ++i)
*i = exponential(lambda);
}
void gamma(vector<double>& res, double shape = 1, double scale = 1) {
for (vector<double>::iterator i = res.begin(); i != res.end(); ++i)
*i = gamma(shape, scale);
}
void chi_square(vector<double>& res, double df) {
for (vector<double>::iterator i = res.begin(); i != res.end(); ++i)
*i = chi_square(df);
}
void beta(vector<double>& res, double a1, double a2) {
for (vector<double>::iterator i = res.begin(); i != res.end(); ++i)
*i = beta(a1, a2);
}
// Discrete Distributions
int poisson(double mu);
int binomial(double p, int n);
void multinom(unsigned int n, const vector<double>& probs, vector<uint>& samp);
void multinom(unsigned int n, const double* prob, uint K, uint* samp);
void poisson(vector<int>& res, double lambda) {
for (vector<int>::iterator i = res.begin(); i != res.end(); ++i)
*i = poisson(lambda);
}
void binomial(vector<int>& res, double p, int n) {
for (vector<int>::iterator i = res.begin(); i != res.end(); ++i)
*i = binomial(p, n);
}
}; // class RNG
#undef UINT32_MAX
#endif // RNG_H
//
// http://msinttypes.googlecode.com/svn/trunk/stdint.h
//
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2008 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_STDINT_H_ // [
#define _MSC_STDINT_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include <limits.h>
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus
extern "C" {
#endif
# include <wchar.h>
#ifdef __cplusplus
}
#endif
// Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
// realize that, e.g. char has the same size as __int8
// so we give up on __intX for them.
#if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
#define INTMAX_C INT64_C
#define UINTMAX_C UINT64_C
#endif // __STDC_CONSTANT_MACROS ]
#endif // _MSC_STDINT_H_ ]
#
# Include CUDA related files.
#
#INCLUDE(${FINDCUDA_DIR}/FindCuda.cmake)
INCLUDE_DIRECTORIES(${CUDA_INCLUDE})
LINK_DIRECTORIES(${CUDA_TARGET_LINK})
FOREACH(subdir ${OPENMM_SOURCE_SUBDIRS})
FILE(GLOB src_files ${CMAKE_SOURCE_DIR}/platforms/cuda/${subdir}/src/*.cu ${CMAKE_SOURCE_DIR}/platforms/cuda/${subdir}/src/*/*.cu)
SET(SOURCE_FILES ${SOURCE_FILES} ${src_files})
CUDA_INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/${subdir}/include)
CUDA_INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/${subdir}/src)
ENDFOREACH(subdir)
CUDA_INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/jama/include)
CUDA_ADD_LIBRARY(${STATIC_TARGET} STATIC ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES})
# required for getting OPENMM_EXPORT to be set correctly in 'class OPENMM_EXPORT CudaStreamFactory', ...
# see OpenMM/openmmapi/include/internal/windowsExport.h for details
SET(CUDA_STATIC_COMPILE_FLAG "-DOPENMMCUDA_BUILDING_STATIC_LIBRARY -DOPENMMCUDA_USE_STATIC_LIBRARIES")
SET_TARGET_PROPERTIES(${STATIC_TARGET} PROPERTIES COMPILE_FLAGS ${CUDA_STATIC_COMPILE_FLAG})
TARGET_LINK_LIBRARIES(${STATIC_TARGET} optimized ${OPENMM_LIBRARY_NAME}_static)
TARGET_LINK_LIBRARIES(${STATIC_TARGET} debug ${OPENMM_LIBRARY_NAME}_static_d optimized ${OPENMM_LIBRARY_NAME}_static ${CUFFT_TARGET_LINK})
#INSTALL_TARGETS(/lib/plugins RUNTIME_DIRECTORY /lib/plugins ${STATIC_TARGET})
#
# Testing
#
ENABLE_TESTING()
# INCLUDE(${CMAKE_SOURCE_DIR}/platforms/cuda/cuda-cmake/FindCuda.cmake)
INCLUDE_DIRECTORIES(${CUDA_INCLUDE})
SET( INCLUDE_SERIALIZATION FALSE )
#SET( INCLUDE_SERIALIZATION TRUE )
IF( INCLUDE_SERIALIZATION )
INCLUDE_DIRECTORIES(${OPENMM_DIR}/serialization/include)
SET( SHARED_OPENMM_SERIALIZATION OpenMMSerialization )
ENDIF( INCLUDE_SERIALIZATION )
# Automatically create tests using files named "Test*.cpp"
FILE(GLOB TEST_PROGS "*Test*.cpp")
# TestCudaRandom has never worked on windows, so let's stop polluting the dashboard with it.
IF (${CMAKE_GENERATOR} MATCHES "Visual Studio")
FILE(GLOB TEST_CUDA_RANDOM_PROG "*TestCudaRandom.cpp")
LIST(REMOVE_ITEM TEST_PROGS "${TEST_CUDA_RANDOM_PROG}")
ENDIF (${CMAKE_GENERATOR} MATCHES "Visual Studio")
FOREACH(TEST_PROG ${TEST_PROGS})
GET_FILENAME_COMPONENT(TEST_ROOT ${TEST_PROG} NAME_WE)
# Link with shared library
CUDA_ADD_EXECUTABLE(${TEST_ROOT} ${TEST_PROG})
TARGET_LINK_LIBRARIES(${TEST_ROOT} ${SHARED_TARGET})
# Three tests are created from the file TestCudaGBVIForce2.cpp by
# setting preprocessor definitions
# TestCudaNonbondForce2
# TestCudaGBSAOBCForce2
# TestCudaGBVIForce2
IF( ${TEST_ROOT} STREQUAL "TestCudaGBVIForce2" )
# serialize
SET(DEFINE_STRING "-DTEST_PLATFORM=0 ")
IF( INCLUDE_SERIALIZATION )
SET(DEFINE_STRING "${DEFINE_STRING} -DOPENMM_SERIALIZE ")
ENDIF( INCLUDE_SERIALIZATION )
# obc
SET(OBC_DEFINE_STRING "${DEFINE_STRING} -DIMPLICIT_SOLVENT=1")
SET(OBC_TEST "TestCudaGBSAOBCForce2")
CUDA_ADD_EXECUTABLE(${OBC_TEST} ${TEST_PROG})
SET_TARGET_PROPERTIES(${OBC_TEST} PROPERTIES COMPILE_FLAGS ${OBC_DEFINE_STRING} )
ADD_TEST(${OBC_TEST} ${EXECUTABLE_OUTPUT_PATH}/${OBC_TEST})
# nonbond
SET(NONBOND_DEFINE_STRING "${DEFINE_STRING} -DIMPLICIT_SOLVENT=0")
SET(NONBOND_TEST "TestCudaNonbondForce2")
CUDA_ADD_EXECUTABLE(${NONBOND_TEST} ${TEST_PROG})
SET_TARGET_PROPERTIES(${NONBOND_TEST} PROPERTIES COMPILE_FLAGS ${NONBOND_DEFINE_STRING} )
ADD_TEST(${NONBOND_TEST} ${EXECUTABLE_OUTPUT_PATH}/${NONBOND_TEST})
# gbvi
SET(DEFINE_STRING "${DEFINE_STRING} -DIMPLICIT_SOLVENT=2")
SET_TARGET_PROPERTIES(${TEST_ROOT} PROPERTIES COMPILE_FLAGS ${DEFINE_STRING} )
# libs
IF( INCLUDE_SERIALIZATION )
TARGET_LINK_LIBRARIES(${OBC_TEST} ${SHARED_TARGET} ${SHARED_OPENMM_SERIALIZATION} )
TARGET_LINK_LIBRARIES(${NONBOND_TEST} ${SHARED_TARGET} ${SHARED_OPENMM_SERIALIZATION} )
TARGET_LINK_LIBRARIES(${TEST_ROOT} ${SHARED_TARGET} ${SHARED_OPENMM_SERIALIZATION} )
ELSE( INCLUDE_SERIALIZATION )
TARGET_LINK_LIBRARIES(${OBC_TEST} ${SHARED_TARGET})
TARGET_LINK_LIBRARIES(${NONBOND_TEST} ${SHARED_TARGET})
TARGET_LINK_LIBRARIES(${TEST_ROOT} ${SHARED_TARGET})
ENDIF( INCLUDE_SERIALIZATION )
ENDIF( ${TEST_ROOT} STREQUAL "TestCudaGBVIForce2" )
#MESSAGE( "vcm ${TEST_ROOT} ${DEFINE_STRING}" )
ADD_TEST(${TEST_ROOT} ${EXECUTABLE_OUTPUT_PATH}/${TEST_ROOT})
# Link with static library
# SET(TEST_STATIC ${TEST_ROOT}Static)
# CUDA_ADD_EXECUTABLE(${TEST_STATIC} ${TEST_PROG})
# SET_TARGET_PROPERTIES(${TEST_STATIC}
# PROPERTIES
# COMPILE_FLAGS "-DOPENMM_USE_STATIC_LIBRARIES"
# )
# TARGET_LINK_LIBRARIES(${TEST_STATIC} ${STATIC_TARGET})
# ADD_TEST(${TEST_STATIC} ${EXECUTABLE_OUTPUT_PATH}/${TEST_STATIC})
ENDFOREACH(TEST_PROG ${TEST_PROGS})
install(TARGETS TestCudaHarmonicBondForce
RUNTIME DESTINATION bin)
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of AndersenThermostat.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/AndersenThermostat.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void testTemperature() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
const int numSteps = 10000;
CudaPlatform platform;
System system;
VerletIntegrator integrator(0.005);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
AndersenThermostat* thermstat = new AndersenThermostat(temp, collisionFreq);
system.addForce(thermstat);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
for (int i = 0; i < numParticles; ++i)
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the temperature is correct.
double ke = 0.0;
for (int i = 0; i < numSteps; ++i) {
State state = context.getState(State::Energy);
ke += state.getKineticEnergy();
integrator.step(1);
}
ke /= numSteps;
double expected = 0.5*numParticles*3*BOLTZ*temp;
ASSERT_EQUAL_TOL(expected, ke, 6/std::sqrt((double) numSteps));
}
void testConstraints() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
const int numSteps = 10000;
CudaPlatform platform;
System system;
VerletIntegrator integrator(0.005);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
system.addConstraint(0, 1, 1);
system.addConstraint(1, 2, 1);
system.addConstraint(2, 3, 1);
system.addConstraint(3, 0, 1);
system.addConstraint(4, 5, 1);
system.addConstraint(5, 6, 1);
system.addConstraint(6, 7, 1);
system.addConstraint(7, 4, 1);
AndersenThermostat* thermstat = new AndersenThermostat(temp, collisionFreq);
system.addForce(thermstat);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(1, 0, 0);
positions[2] = Vec3(1, 1, 0);
positions[3] = Vec3(0, 1, 0);
positions[4] = Vec3(1, 0, 1);
positions[5] = Vec3(1, 1, 1);
positions[6] = Vec3(0, 1, 1);
positions[7] = Vec3(0, 0, 1);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the temperature is correct.
double ke = 0.0;
for (int i = 0; i < numSteps; ++i) {
State state = context.getState(State::Energy);
ke += state.getKineticEnergy();
integrator.step(1);
}
ke /= numSteps;
double expected = 0.5*(numParticles*3-system.getNumConstraints())*BOLTZ*temp;
ASSERT_EQUAL_TOL(expected, ke, 6/std::sqrt((double) numSteps));
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
CudaPlatform platform;
System system;
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
AndersenThermostat* thermostat = new AndersenThermostat(temp, collisionFreq);
system.addForce(thermostat);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
thermostat->setRandomNumberSeed(5);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
thermostat->setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() {
try {
testTemperature();
testConstraints();
testRandomSeed();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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/System.h"
/**
* This tests the Cuda implementation of BrownianIntegrator.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/BrownianIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleBond() {
CudaPlatform platform;
System system;
system.addParticle(2.0);
system.addParticle(2.0);
double dt = 0.01;
BrownianIntegrator integrator(0, 0.1, dt);
HarmonicBondForce* forceField = new HarmonicBondForce();
forceField->addBond(0, 1, 1.5, 1);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// This is simply an overdamped harmonic oscillator, so compare it to the analytical solution.
double rate = 2*1.0/(0.1*2.0);
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Velocities);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::exp(-rate*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
if (i > 0) {
double expectedSpeed = -0.5*rate*std::exp(-rate*(time-0.5*dt));
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.11);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.11);
}
integrator.step(1);
}
}
void testTemperature() {
const int numParticles = 8;
const int numBonds = numParticles-1;
const double temp = 10.0;
CudaPlatform platform;
System system;
BrownianIntegrator integrator(temp, 2.0, 0.01);
HarmonicBondForce* forceField = new HarmonicBondForce();
for (int i = 0; i < numParticles; ++i)
system.addParticle(2.0);
for (int i = 0; i < numBonds; ++i)
forceField->addBond(i, i+1, 1.0, 5.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
for (int i = 0; i < numParticles; ++i)
positions[i] = Vec3(i, 0, 0);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the temperature is correct.
double pe = 0.0;
const int steps = 50000;
for (int i = 0; i < steps; ++i) {
State state = context.getState(State::Energy);
pe += state.getPotentialEnergy();
integrator.step(1);
}
pe /= steps;
double expected = 0.5*numBonds*BOLTZ*temp;
ASSERT_USUALLY_EQUAL_TOL(expected, pe, 0.1*expected);
}
void testConstraints() {
const int numParticles = 8;
const int numConstraints = 5;
const double temp = 20.0;
CudaPlatform platform;
System system;
BrownianIntegrator integrator(temp, 2.0, 0.001);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
system.addConstraint(0, 1, 1.0);
system.addConstraint(1, 2, 1.0);
system.addConstraint(2, 3, 1.0);
system.addConstraint(4, 5, 1.0);
system.addConstraint(6, 7, 1.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3(i, 0, 0);
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions);
for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4);
}
integrator.step(1);
}
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
CudaPlatform platform;
System system;
BrownianIntegrator integrator(temp, 2.0, 0.001);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() {
try {
testSingleBond();
testTemperature();
testConstraints();
testRandomSeed();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2010 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of CMAPTorsionForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CMAPTorsionForce.h"
#include "openmm/PeriodicTorsionForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testCMAPTorsions() {
const int mapSize = 36;
// Create two systems: one with a pair of periodic torsions, and one with a CMAP torsion
// that approximates the same force.
CudaPlatform platform;
System system1;
for (int i = 0; i < 5; i++)
system1.addParticle(1.0);
PeriodicTorsionForce* periodic = new PeriodicTorsionForce();
periodic->addTorsion(0, 1, 2, 3, 2, M_PI/4, 1.5);
periodic->addTorsion(1, 2, 3, 4, 3, M_PI/3, 2.0);
system1.addForce(periodic);
System system2;
for (int i = 0; i < 5; i++)
system2.addParticle(1.0);
CMAPTorsionForce* cmap = new CMAPTorsionForce();
vector<double> mapEnergy(mapSize*mapSize);
for (int i = 0; i < mapSize; i++) {
double angle1 = i*2*M_PI/mapSize;
double energy1 = 1.5*(1+cos(2*angle1-M_PI/4));
for (int j = 0; j < mapSize; j++) {
double angle2 = j*2*M_PI/mapSize;
double energy2 = 2.0*(1+cos(3*angle2-M_PI/3));
mapEnergy[i+j*mapSize] = energy1+energy2;
}
}
cmap->addMap(mapSize, mapEnergy);
cmap->addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4);
system2.addForce(cmap);
// Set the atoms in various positions, and verify that both systems give equal forces and energy.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(5);
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
vector<Vec3> f1, f2;
double energy1, energy2;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < (int) positions.size(); j++)
positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt));
{
Context context(system1, integrator1, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
f1 = state.getForces();
energy1 = state.getPotentialEnergy();
}
{
Context context(system2, integrator2, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
f2 = state.getForces();
energy2 = state.getPotentialEnergy();
}
for (int i = 0; i < system1.getNumParticles(); i++)
ASSERT_EQUAL_VEC(f1[i], f2[i], 0.05);
ASSERT_EQUAL_TOL(energy1, energy2, 1e-3);
}
}
int main() {
try {
testCMAPTorsions();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of AndersenThermostat.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/VerletIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
Vec3 calcCM(const vector<Vec3>& values, System& system) {
Vec3 cm;
for (int j = 0; j < system.getNumParticles(); ++j) {
cm[0] += values[j][0]*system.getParticleMass(j);
cm[1] += values[j][1]*system.getParticleMass(j);
cm[2] += values[j][2]*system.getParticleMass(j);
}
return cm;
}
void testMotionRemoval(Integrator& integrator) {
const int numParticles = 8;
CudaPlatform platform;
System system;
HarmonicBondForce* bonds = new HarmonicBondForce();
bonds->addBond(2, 3, 2.0, 0.5);
system.addForce(bonds);
NonbondedForce* nonbonded = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(i+1);
nonbonded->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(nonbonded);
CMMotionRemover* remover = new CMMotionRemover();
system.addForce(remover);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Now run it for a while and see if the center of mass remains fixed.
Vec3 cmPos = calcCM(context.getState(State::Positions).getPositions(), system);
for (int i = 0; i < 1000; ++i) {
integrator.step(1);
State state = context.getState(State::Positions | State::Velocities);
Vec3 pos = calcCM(state.getPositions(), system);
ASSERT_EQUAL_VEC(cmPos, pos, 1e-2);
Vec3 vel = calcCM(state.getVelocities(), system);
if (i > 0) {
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), vel, 1e-2);
}
}
}
int main() {
try {
LangevinIntegrator langevin(0.0, 1e-5, 0.01);
testMotionRemoval(langevin);
VerletIntegrator verlet(0.01);
testMotionRemoval(verlet);
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2010 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the CUDA implementation of CustomAngleForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CustomAngleForce.h"
#include "openmm/HarmonicAngleForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testAngles() {
CudaPlatform platform;
// Create a system using a CustomAngleForce.
System customSystem;
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
CustomAngleForce* custom = new CustomAngleForce("scale*k*(theta-theta0)^2");
custom->addPerAngleParameter("theta0");
custom->addPerAngleParameter("k");
custom->addGlobalParameter("scale", 0.5);
vector<double> parameters(2);
parameters[0] = 1.5;
parameters[1] = 0.8;
custom->addAngle(0, 1, 2, parameters);
parameters[0] = 2.0;
parameters[1] = 0.5;
custom->addAngle(1, 2, 3, parameters);
customSystem.addForce(custom);
// Create an identical system using a HarmonicAngleForce.
System harmonicSystem;
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
HarmonicAngleForce* harmonic = new HarmonicAngleForce();
harmonic->addAngle(0, 1, 2, 1.5, 0.8);
harmonic->addAngle(1, 2, 3, 2.0, 0.5);
harmonicSystem.addForce(harmonic);
// Set the atoms in various positions, and verify that both systems give identical forces and energy.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(4);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < (int) positions.size(); j++)
positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt));
double energy1, energy2;
vector<Vec3> forces1, forces2;
{
VerletIntegrator integrator(0.01);
Context c(customSystem, integrator, platform);
c.setPositions(positions);
State s = c.getState(State::Forces | State::Energy);
energy1 = s.getPotentialEnergy();
forces1 = s.getForces();
}
{
VerletIntegrator integrator(0.01);
Context c(harmonicSystem, integrator, platform);
c.setPositions(positions);
State s = c.getState(State::Forces | State::Energy);
energy2 = s.getPotentialEnergy();
forces2 = s.getForces();
}
for (int i = 0; i < customSystem.getNumParticles(); i++)
ASSERT_EQUAL_VEC(forces2[i], forces1[i], TOL);
ASSERT_EQUAL_TOL(energy2, energy1, TOL);
}
}
int main() {
try {
testAngles();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of CustomBondForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CustomBondForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testBonds() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomBondForce* forceField = new CustomBondForce("scale*k*(r-r0)^2");
forceField->addPerBondParameter("r0");
forceField->addPerBondParameter("k");
forceField->addGlobalParameter("scale", 0.5);
vector<double> parameters(2);
parameters[0] = 1.5;
parameters[1] = 0.8;
forceField->addBond(0, 1, parameters);
parameters[0] = 1.2;
parameters[1] = 0.7;
forceField->addBond(1, 2, parameters);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 2, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(0, -0.8*0.5, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0.7*0.2, 0, 0), forces[2], TOL);
ASSERT_EQUAL_VEC(Vec3(-forces[0][0]-forces[2][0], -forces[0][1]-forces[2][1], -forces[0][2]-forces[2][2]), forces[1], TOL);
ASSERT_EQUAL_TOL(0.5*0.8*0.5*0.5 + 0.5*0.7*0.2*0.2, state.getPotentialEnergy(), TOL);
}
int main() {
try {
testBonds();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of CustomExternalForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CustomExternalForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testForce() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomExternalForce* forceField = new CustomExternalForce("scale*(x+yscale*(y-y0)^2)");
forceField->addPerParticleParameter("y0");
forceField->addPerParticleParameter("yscale");
forceField->addGlobalParameter("scale", 0.5);
vector<double> parameters(2);
parameters[0] = 0.5;
parameters[1] = 2.0;
forceField->addParticle(0, parameters);
parameters[0] = 1.5;
parameters[1] = 3.0;
forceField->addParticle(2, parameters);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 2, 0);
positions[1] = Vec3(0, 0, 1);
positions[2] = Vec3(1, 0, 1);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(-0.5, -0.5*2.0*2.0*1.5, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(-0.5, 0.5*3.0*2.0*1.5, 0), forces[2], TOL);
ASSERT_EQUAL_TOL(0.5*(1.0 + 2.0*1.5*1.5 + 3.0*1.5*1.5), state.getPotentialEnergy(), TOL);
}
int main() {
try {
testForce();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests all the different force terms in the Cuda implementation of CustomNonbondedForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "sfmt/SFMT.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSimpleExpression() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomNonbondedForce* forceField = new CustomNonbondedForce("-0.1*r^3");
forceField->addParticle(vector<double>());
forceField->addParticle(vector<double>());
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double force = 0.1*3*(2*2);
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(-0.1*(2*2*2), state.getPotentialEnergy(), TOL);
}
void testParameters() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomNonbondedForce* forceField = new CustomNonbondedForce("scale*a*(r*b)^3; a=a1*a2; b=c+b1+b2");
forceField->addPerParticleParameter("a");
forceField->addPerParticleParameter("b");
forceField->addGlobalParameter("scale", 3.0);
forceField->addGlobalParameter("c", -1.0);
vector<double> params(2);
params[0] = 1.5;
params[1] = 2.0;
forceField->addParticle(params);
params[0] = 2.0;
params[1] = 3.0;
forceField->addParticle(params);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
context.setPositions(positions);
context.setParameter("scale", 1.0);
context.setParameter("c", 0.0);
State state = context.getState(State::Forces | State::Energy);
vector<Vec3> forces = state.getForces();
double force = -3.0*3*5.0*(10*10);
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(3.0*(10*10*10), state.getPotentialEnergy(), TOL);
context.setParameter("scale", 1.5);
context.setParameter("c", 1.0);
state = context.getState(State::Forces | State::Energy);
forces = state.getForces();
force = -1.5*3.0*3*6.0*(12*12);
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(1.5*3.0*(12*12*12), state.getPotentialEnergy(), TOL);
}
void testExclusions() {
CudaPlatform platform;
System system;
VerletIntegrator integrator(0.01);
CustomNonbondedForce* nonbonded = new CustomNonbondedForce("a*r; a=a1+a2");
nonbonded->addPerParticleParameter("a");
vector<double> params(1);
vector<Vec3> positions(4);
for (int i = 0; i < 4; i++) {
system.addParticle(1.0);
params[0] = i+1;
nonbonded->addParticle(params);
positions[i] = Vec3(i, 0, 0);
}
nonbonded->addExclusion(0, 1);
nonbonded->addExclusion(1, 2);
nonbonded->addExclusion(2, 3);
nonbonded->addExclusion(0, 2);
nonbonded->addExclusion(1, 3);
system.addForce(nonbonded);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(1+4, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL);
ASSERT_EQUAL_VEC(Vec3(-(1+4), 0, 0), forces[3], TOL);
ASSERT_EQUAL_TOL((1+4)*3.0, state.getPotentialEnergy(), TOL);
}
void testCutoff() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomNonbondedForce* forceField = new CustomNonbondedForce("r");
forceField->addParticle(vector<double>());
forceField->addParticle(vector<double>());
forceField->addParticle(vector<double>());
forceField->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic);
forceField->setCutoffDistance(2.5);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 2, 0);
positions[2] = Vec3(0, 3, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(0, 1, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, -1, 0), forces[2], TOL);
ASSERT_EQUAL_TOL(2.0+1.0, state.getPotentialEnergy(), TOL);
}
void testPeriodic() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomNonbondedForce* forceField = new CustomNonbondedForce("r");
forceField->addParticle(vector<double>());
forceField->addParticle(vector<double>());
forceField->addParticle(vector<double>());
forceField->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic);
forceField->setCutoffDistance(2.0);
system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4));
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 2.1, 0);
positions[2] = Vec3(0, 3, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(0, -2, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 2, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL);
ASSERT_EQUAL_TOL(1.9+1+0.9, state.getPotentialEnergy(), TOL);
}
void testTabulatedFunction() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1");
forceField->addParticle(vector<double>());
forceField->addParticle(vector<double>());
vector<double> table;
for (int i = 0; i < 21; i++)
table.push_back(std::sin(0.25*i));
forceField->addFunction("fn", table, 1.0, 6.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
double tol = 0.01;
for (int i = 1; i < 30; i++) {
double x = (7.0/30.0)*i;
positions[1] = Vec3(x, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double force = (x < 1.0 || x > 6.0 ? 0.0 : -std::cos(x-1.0));
double energy = (x < 1.0 || x > 6.0 ? 0.0 : std::sin(x-1.0))+1.0;
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], 0.1);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], 0.1);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02);
}
for (int i = 1; i < 20; i++) {
double x = 0.25*i+1.0;
positions[1] = Vec3(x, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Energy);
double energy = (x < 1.0 || x > 6.0 ? 0.0 : std::sin(x-1.0))+1.0;
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4);
}
}
void testCoulombLennardJones() {
const int numMolecules = 300;
const int numParticles = numMolecules*2;
const double boxSize = 20.0;
CudaPlatform platform;
// Create two systems: one with a NonbondedForce, and one using a CustomNonbondedForce to implement the same interaction.
System standardSystem;
System customSystem;
for (int i = 0; i < numParticles; i++) {
standardSystem.addParticle(1.0);
customSystem.addParticle(1.0);
}
NonbondedForce* standardNonbonded = new NonbondedForce();
CustomNonbondedForce* customNonbonded = new CustomNonbondedForce("4*eps*((sigma/r)^12-(sigma/r)^6)+138.935456*q/r; q=q1*q2; sigma=0.5*(sigma1+sigma2); eps=sqrt(eps1*eps2)");
customNonbonded->addPerParticleParameter("q");
customNonbonded->addPerParticleParameter("sigma");
customNonbonded->addPerParticleParameter("eps");
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<double> params(3);
for (int i = 0; i < numMolecules; i++) {
if (i < numMolecules/2) {
standardNonbonded->addParticle(1.0, 0.2, 0.1);
params[0] = 1.0;
params[1] = 0.2;
params[2] = 0.1;
customNonbonded->addParticle(params);
standardNonbonded->addParticle(-1.0, 0.1, 0.1);
params[0] = -1.0;
params[1] = 0.1;
customNonbonded->addParticle(params);
}
else {
standardNonbonded->addParticle(1.0, 0.2, 0.2);
params[0] = 1.0;
params[1] = 0.2;
params[2] = 0.2;
customNonbonded->addParticle(params);
standardNonbonded->addParticle(-1.0, 0.1, 0.2);
params[0] = -1.0;
params[1] = 0.1;
customNonbonded->addParticle(params);
}
positions[2*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt));
positions[2*i+1] = Vec3(positions[2*i][0]+1.0, positions[2*i][1], positions[2*i][2]);
velocities[2*i] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt));
velocities[2*i+1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt));
standardNonbonded->addException(2*i, 2*i+1, 0.0, 1.0, 0.0);
customNonbonded->addExclusion(2*i, 2*i+1);
}
standardNonbonded->setNonbondedMethod(NonbondedForce::NoCutoff);
customNonbonded->setNonbondedMethod(CustomNonbondedForce::NoCutoff);
standardSystem.addForce(standardNonbonded);
customSystem.addForce(customNonbonded);
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
double energy1, energy2;
vector<Vec3> forces1, forces2;
{
Context context(standardSystem, integrator1, platform);
context.setPositions(positions);
context.setVelocities(velocities);
State state = context.getState(State::Forces | State::Energy);
energy1 = state.getPotentialEnergy();
forces1 = state.getForces();
}
{
Context context(customSystem, integrator2, platform);
context.setPositions(positions);
context.setVelocities(velocities);
State state = context.getState(State::Forces | State::Energy);
energy2 = state.getPotentialEnergy();
forces2 = state.getForces();
}
ASSERT_EQUAL_TOL(energy1, energy2, 1e-4);
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(forces1[i], forces2[i], 1e-4);
}
}
int main() {
try {
testSimpleExpression();
testParameters();
testExclusions();
testCutoff();
testPeriodic();
testTabulatedFunction();
testCoulombLennardJones();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2010 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the CUDA implementation of CustomTorsionForce.
*/
#ifdef WIN32
#define _USE_MATH_DEFINES // Needed to get M_PI
#endif
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CustomTorsionForce.h"
#include "openmm/PeriodicTorsionForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testTorsions() {
CudaPlatform platform;
// Create a system using a CustomTorsionForce.
System customSystem;
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
customSystem.addParticle(1.0);
CustomTorsionForce* custom = new CustomTorsionForce("k*(1+cos(n*theta-theta0))");
custom->addPerTorsionParameter("theta0");
custom->addPerTorsionParameter("n");
custom->addGlobalParameter("k", 0.5);
vector<double> parameters(2);
parameters[0] = 1.5;
parameters[1] = 1;
custom->addTorsion(0, 1, 2, 3, parameters);
parameters[0] = 2.0;
parameters[1] = 2;
custom->addTorsion(1, 2, 3, 4, parameters);
customSystem.addForce(custom);
// Create an identical system using a PeriodicTorsionForce.
System harmonicSystem;
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
harmonicSystem.addParticle(1.0);
VerletIntegrator integrator(0.01);
PeriodicTorsionForce* periodic = new PeriodicTorsionForce();
periodic->addTorsion(0, 1, 2, 3, 1, 1.5, 0.5);
periodic->addTorsion(1, 2, 3, 4, 2, 2.0, 0.5);
harmonicSystem.addForce(periodic);
// Set the atoms in various positions, and verify that both systems give identical forces and energy.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(5);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < (int) positions.size(); j++)
positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt));
double energy1, energy2;
vector<Vec3> forces1, forces2;
{
VerletIntegrator integrator(0.01);
Context c(customSystem, integrator, platform);
c.setPositions(positions);
State s = c.getState(State::Forces | State::Energy);
energy1 = s.getPotentialEnergy();
forces1 = s.getForces();
}
{
VerletIntegrator integrator(0.01);
Context c(harmonicSystem, integrator, platform);
c.setPositions(positions);
State s = c.getState(State::Forces | State::Energy);
energy2 = s.getPotentialEnergy();
forces2 = s.getForces();
}
for (int i = 0; i < customSystem.getNumParticles(); i++)
ASSERT_EQUAL_VEC(forces2[i], forces1[i], TOL);
ASSERT_EQUAL_TOL(energy2, energy1, TOL);
}
}
void testRange() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
CustomTorsionForce* custom = new CustomTorsionForce("theta");
custom->addTorsion(0, 1, 2, 3, vector<double>());
system.addForce(custom);
// Set the atoms in various positions, and verify that the angle is always in the expected range.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(4);
VerletIntegrator integrator(0.01);
double minAngle = 1000;
double maxAngle = -1000;
Context context(system, integrator, platform);
for (int i = 0; i < 100; i++) {
for (int j = 0; j < (int) positions.size(); j++)
positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt));
context.setPositions(positions);
double angle = context.getState(State::Energy).getPotentialEnergy();
if (angle < minAngle)
minAngle = angle;
if (angle > maxAngle)
maxAngle = angle;
}
ASSERT(minAngle >= -M_PI);
ASSERT(maxAngle <= M_PI);
}
int main() {
try {
testTorsions();
testRange();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2010 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Ewald summation method cuda implementation of NonbondedForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "ReferencePlatform.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/internal/ContextImpl.h"
#include "kernels/gputypes.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testEwaldPME(bool includeExceptions) {
// Use amorphous NaCl system for the tests
const int numParticles = 894;
const double cutoff = 1.2;
const double boxSize = 3.00646;
double tol = 1e-5;
CudaPlatform cuda;
ReferencePlatform reference;
System system;
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
nonbonded->setCutoffDistance(cutoff);
nonbonded->setEwaldErrorTolerance(tol);
for (int i = 0; i < numParticles/2; i++)
system.addParticle(22.99);
for (int i = 0; i < numParticles/2; i++)
system.addParticle(35.45);
for (int i = 0; i < numParticles/2; i++)
nonbonded->addParticle(1.0, 1.0,0.0);
for (int i = 0; i < numParticles/2; i++)
nonbonded->addParticle(-1.0, 1.0,0.0);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(nonbonded);
vector<Vec3> positions(numParticles);
#include "nacl_amorph.dat"
if (includeExceptions) {
// Add some exclusions.
for (int i = 0; i < numParticles-1; i++) {
Vec3 delta = positions[i]-positions[i+1];
if (sqrt(delta.dot(delta)) < 0.5*cutoff)
nonbonded->addException(i, i+1, i%2 == 0 ? 0.0 : 0.5, 1.0, 0.0);
}
}
// (1) Check whether the Reference and Cuda platforms agree when using Ewald Method
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
Context cudaContext(system, integrator1, cuda);
Context referenceContext(system, integrator2, reference);
cudaContext.setPositions(positions);
referenceContext.setPositions(positions);
State cudaState = cudaContext.getState(State::Forces | State::Energy);
State referenceState = referenceContext.getState(State::Forces | State::Energy);
tol = 1e-2;
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(referenceState.getForces()[i], cudaState.getForces()[i], tol);
}
tol = 1e-5;
ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cudaState.getPotentialEnergy(), tol);
// (2) Check whether Ewald method in Cuda is self-consistent
double norm = 0.0;
for (int i = 0; i < numParticles; ++i) {
Vec3 f = cudaState.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
}
norm = std::sqrt(norm);
const double delta = 5e-3;
double step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = cudaState.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
cudaContext.reinitialize();
cudaContext.setPositions(positions);
tol = 1e-2;
State cudaState2 = cudaContext.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (cudaState2.getPotentialEnergy()-cudaState.getPotentialEnergy())/delta, tol)
// (3) Check whether the Reference and Cuda platforms agree when using PME
nonbonded->setNonbondedMethod(NonbondedForce::PME);
cudaContext.reinitialize();
referenceContext.reinitialize();
cudaContext.setPositions(positions);
referenceContext.setPositions(positions);
cudaState = cudaContext.getState(State::Forces | State::Energy);
referenceState = referenceContext.getState(State::Forces | State::Energy);
tol = 1e-2;
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(referenceState.getForces()[i], cudaState.getForces()[i], tol);
}
tol = 1e-5;
ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cudaState.getPotentialEnergy(), tol);
// (4) Check whether PME method in Cuda is self-consistent
norm = 0.0;
for (int i = 0; i < numParticles; ++i) {
Vec3 f = cudaState.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
}
norm = std::sqrt(norm);
step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = cudaState.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
cudaContext.reinitialize();
cudaContext.setPositions(positions);
tol = 1e-2;
State cudaState3 = cudaContext.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (cudaState3.getPotentialEnergy()-cudaState.getPotentialEnergy())/delta, tol)
}
void testEwald2Ions() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->addParticle(1.0, 1, 0);
nonbonded->addParticle(-1.0, 1, 0);
nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
const double cutoff = 2.0;
nonbonded->setCutoffDistance(cutoff);
nonbonded->setEwaldErrorTolerance(TOL);
system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6));
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(3.048000,2.764000,3.156000);
positions[1] = Vec3(2.809000,2.888000,2.571000);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 123.711, -64.1877, 302.716), forces[1], 10*TOL);
ASSERT_EQUAL_TOL(-217.276, state.getPotentialEnergy(), 0.01/*10*TOL*/);
}
void testErrorTolerance(NonbondedForce::NonbondedMethod method) {
// Create a cloud of random point charges.
const int numParticles = 51;
const double boxWidth = 5.0;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
force->addParticle(-1.0+i*2.0/(numParticles-1), 1.0, 0.0);
positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
}
force->setNonbondedMethod(method);
CudaPlatform platform;
// For various values of the cutoff and error tolerance, see if the actual error is reasonable.
for (double cutoff = 1.0; cutoff < boxWidth/2; cutoff *= 1.2) {
force->setCutoffDistance(cutoff);
vector<Vec3> refForces;
double norm = 0.0;
for (double tol = 5e-5; tol < 1e-3; tol *= 2.0) {
force->setEwaldErrorTolerance(tol);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces);
if (refForces.size() == 0) {
refForces = state.getForces();
for (int i = 0; i < numParticles; i++)
norm += refForces[i].dot(refForces[i]);
norm = sqrt(norm);
}
else {
double diff = 0.0;
for (int i = 0; i < numParticles; i++) {
Vec3 delta = refForces[i]-state.getForces()[i];
diff += delta.dot(delta);
}
diff = sqrt(diff)/norm;
ASSERT(diff < 2*tol);
}
}
}
}
int main() {
try {
testEwaldPME(false);
testEwaldPME(true);
// testEwald2Ions();
testErrorTolerance(NonbondedForce::Ewald);
testErrorTolerance(NonbondedForce::PME);
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of GBSAOBCForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "ReferencePlatform.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include "openmm/NonbondedForce.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleParticle() {
CudaPlatform platform;
System system;
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBSAOBCForce* gbsa = new GBSAOBCForce();
NonbondedForce* nonbonded = new NonbondedForce();
gbsa->addParticle( 0.5, 0.15, 1);
nonbonded->addParticle(0.5, 1, 0);
system.addForce(gbsa);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(1);
positions[0] = Vec3(0, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Energy);
double bornRadius = 0.15-0.009; // dielectric offset
double eps0 = EPSILON0;
double bornEnergy = (-0.5*0.5/(8*PI_M*eps0))*(1.0/gbsa->getSoluteDielectric()-1.0/gbsa->getSolventDielectric())/bornRadius;
double extendedRadius = bornRadius+0.14; // probe radius
double nonpolarEnergy = CAL2JOULE*PI_M*0.0216*(10*extendedRadius)*(10*extendedRadius)*std::pow(0.15/bornRadius, 6.0); // Where did this formula come from? Just copied it from CpuImplicitSolvent.cpp
ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01);
}
void testCutoffAndPeriodic() {
CudaPlatform cuda;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBSAOBCForce* gbsa = new GBSAOBCForce();
NonbondedForce* nonbonded = new NonbondedForce();
gbsa->addParticle(-1, 0.15, 1);
nonbonded->addParticle(-1, 1, 0);
gbsa->addParticle(1, 0.15, 1);
nonbonded->addParticle(1, 1, 0);
const double cutoffDistance = 3.0;
const double boxSize = 10.0;
nonbonded->setCutoffDistance(cutoffDistance);
gbsa->setCutoffDistance(cutoffDistance);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(gbsa);
system.addForce(nonbonded);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
// Calculate the forces for both cutoff and periodic with two different atom positions.
nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
Context context(system, integrator, cuda);
context.setPositions(positions);
State state1 = context.getState(State::Forces);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
context.reinitialize();
context.setPositions(positions);
State state2 = context.getState(State::Forces);
positions[1][0]+= boxSize;
nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
context.reinitialize();
context.setPositions(positions);
State state3 = context.getState(State::Forces);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
context.reinitialize();
context.setPositions(positions);
State state4 = context.getState(State::Forces);
// All forces should be identical, exception state3 which should be zero.
ASSERT_EQUAL_VEC(state1.getForces()[0], state2.getForces()[0], 0.01);
ASSERT_EQUAL_VEC(state1.getForces()[1], state2.getForces()[1], 0.01);
ASSERT_EQUAL_VEC(state1.getForces()[0], state4.getForces()[0], 0.01);
ASSERT_EQUAL_VEC(state1.getForces()[1], state4.getForces()[1], 0.01);
ASSERT_EQUAL_VEC(state3.getForces()[0], Vec3(0, 0, 0), 0.01);
ASSERT_EQUAL_VEC(state3.getForces()[1], Vec3(0, 0, 0), 0.01);
}
void testForce(int numParticles, NonbondedForce::NonbondedMethod method, GBSAOBCForce::NonbondedMethod method2) {
CudaPlatform cuda;
ReferencePlatform reference;
System system;
GBSAOBCForce* gbsa = new GBSAOBCForce();
NonbondedForce* nonbonded = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
double charge = i%2 == 0 ? -1 : 1;
gbsa->addParticle(charge, 0.15, 1);
nonbonded->addParticle(charge, 1, 0);
}
nonbonded->setNonbondedMethod(method);
gbsa->setNonbondedMethod(method2);
nonbonded->setCutoffDistance(3.0);
gbsa->setCutoffDistance(3.0);
int grid = (int) floor(0.5+pow(numParticles, 1.0/3.0));
if (method == NonbondedForce::CutoffPeriodic) {
double boxSize = (grid+1)*1.1;
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
}
system.addForce(gbsa);
system.addForce(nonbonded);
LangevinIntegrator integrator1(0, 0.1, 0.01);
LangevinIntegrator integrator2(0, 0.1, 0.01);
Context context(system, integrator1, cuda);
Context refContext(system, integrator2, reference);
// Set random (but uniformly distributed) positions for all the particles.
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < grid; i++)
for (int j = 0; j < grid; j++)
for (int k = 0; k < grid; k++)
positions[i*grid*grid+j*grid+k] = Vec3(i*1.1, j*1.1, k*1.1);
for (int i = 0; i < numParticles; ++i)
positions[i] = positions[i] + Vec3(0.5*genrand_real2(sfmt), 0.5*genrand_real2(sfmt), 0.5*genrand_real2(sfmt));
context.setPositions(positions);
refContext.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
State refState = refContext.getState(State::Forces | State::Energy);
// Make sure the Cuda and Reference platforms agree.
double norm = 0.0;
double diff = 0.0;
for (int i = 0; i < numParticles; ++i) {
Vec3 f = state.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
Vec3 delta = f-refState.getForces()[i];
diff += delta[0]*delta[0] + delta[1]*delta[1] + delta[2]*delta[2];
}
norm = std::sqrt(norm);
diff = std::sqrt(diff);
ASSERT_EQUAL_TOL(0.0, diff, 0.001*norm);
ASSERT_EQUAL_TOL(state.getPotentialEnergy(), refState.getPotentialEnergy(), 1e-3);
// Take a small step in the direction of the energy gradient. (This doesn't work with cutoffs, since the energy
// changes discontinuously at the cutoff distance.)
if (method == NonbondedForce::NoCutoff)
{
const double delta = 1e-2;
double step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = state.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
context.setPositions(positions);
// See whether the potential energy changed by the expected amount.
State state2 = context.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/delta, 1e-3*abs(state.getPotentialEnergy()));
}
}
int main() {
try {
testSingleParticle();
testCutoffAndPeriodic();
for (int i = 5; i < 11; i++) {
testForce(i*i*i, NonbondedForce::NoCutoff, GBSAOBCForce::NoCutoff);
testForce(i*i*i, NonbondedForce::CutoffNonPeriodic, GBSAOBCForce::CutoffNonPeriodic);
testForce(i*i*i, NonbondedForce::CutoffPeriodic, GBSAOBCForce::CutoffPeriodic);
}
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of GBVIForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "CudaPlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/GBVIForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/NonbondedForce.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleParticle() {
const int log = 0;
CudaPlatform platform;
System system;
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBVIForce* forceField = new GBVIForce();
double charge = -1.0;
double radius = 0.15;
double gamma = 1.0;
forceField->addParticle(charge, radius, gamma);
system.addForce(forceField);
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::NoCutoff);
nonbonded->addParticle( charge, 1.0, 0.0);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(1);
positions[0] = Vec3(0, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Energy);
double bornRadius = radius;
double eps0 = EPSILON0;
double tau = (1.0/forceField->getSoluteDielectric()-1.0/forceField->getSolventDielectric());
double bornEnergy = (-charge*charge/(8*PI_M*eps0))*tau/bornRadius;
double nonpolarEnergy = -gamma*tau*std::pow( radius/bornRadius, 3.0);
double expectedE = (bornEnergy+nonpolarEnergy);
double obtainedE = state.getPotentialEnergy();
double diff = fabs( (obtainedE - expectedE)/expectedE );
if( log ){
(void) fprintf( stderr, "testSingleParticle expected=%14.6e obtained=%14.6e diff=%14.6e breakdown:[%14.6e %14.6e]\n",
expectedE, obtainedE, diff, bornEnergy, nonpolarEnergy );
}
ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01);
}
void testEnergyEthane( int applySwitch ) {
//ReferencePlatform platform;
CudaPlatform platform;
const int numParticles = 8;
const int log = 0;
System system;
LangevinIntegrator integrator(0, 0.1, 0.01);
// harmonic bond
double C_HBondDistance = 0.1097;
double C_CBondDistance = 0.1504;
HarmonicBondForce* bonds = new HarmonicBondForce();
bonds->addBond(0, 1, C_HBondDistance, 0.0);
bonds->addBond(2, 1, C_HBondDistance, 0.0);
bonds->addBond(3, 1, C_HBondDistance, 0.0);
bonds->addBond(1, 4, C_CBondDistance, 0.0);
bonds->addBond(5, 4, C_HBondDistance, 0.0);
bonds->addBond(6, 4, C_HBondDistance, 0.0);
bonds->addBond(7, 4, C_HBondDistance, 0.0);
system.addForce(bonds);
double C_radius, C_gamma, C_charge, H_radius, H_gamma, H_charge;
int AM1_BCC = 1;
H_charge = -0.053;
C_charge = -3.0*H_charge;
if( AM1_BCC ){
C_radius = 0.180;
C_gamma = -0.2863;
H_radius = 0.125;
H_gamma = 0.2437;
} else {
C_radius = 0.215;
C_gamma = -1.1087;
H_radius = 0.150;
H_gamma = 0.1237;
}
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::NoCutoff);
if( log ){
(void) fprintf( stderr, "Applying GB/VI\n" );
}
GBVIForce* forceField = new GBVIForce();
if( applySwitch ){
forceField->setBornRadiusScalingMethod( GBVIForce::QuinticSpline );
} else {
forceField->setBornRadiusScalingMethod( GBVIForce::NoScaling );
}
for( int i = 0; i < numParticles; i++ ){
system.addParticle(1.0);
forceField->addParticle( H_charge, H_radius, H_gamma);
nonbonded->addParticle( H_charge, H_radius, 0.0);
}
forceField->setParticleParameters( 1, C_charge, C_radius, C_gamma);
forceField->setParticleParameters( 4, C_charge, C_radius, C_gamma);
nonbonded->setParticleParameters( 1, C_charge, C_radius, 0.0);
nonbonded->setParticleParameters( 4, C_charge, C_radius, 0.0);
forceField->addBond( 0, 1, C_HBondDistance );
forceField->addBond( 2, 1, C_HBondDistance );
forceField->addBond( 3, 1, C_HBondDistance );
forceField->addBond( 1, 4, C_CBondDistance );
forceField->addBond( 5, 4, C_HBondDistance );
forceField->addBond( 6, 4, C_HBondDistance );
forceField->addBond( 7, 4, C_HBondDistance );
std::vector<pair<int, int> > bondExceptions;
std::vector<double> bondDistances;
bondExceptions.push_back(pair<int, int>(0, 1));
bondDistances.push_back( C_HBondDistance );
bondExceptions.push_back(pair<int, int>(2, 1));
bondDistances.push_back( C_HBondDistance );
bondExceptions.push_back(pair<int, int>(3, 1));
bondDistances.push_back( C_HBondDistance );
bondExceptions.push_back(pair<int, int>(1, 4));
bondDistances.push_back( C_CBondDistance );
bondExceptions.push_back(pair<int, int>(5, 4));
bondDistances.push_back( C_HBondDistance );
bondExceptions.push_back(pair<int, int>(6, 4));
bondDistances.push_back( C_HBondDistance );
bondExceptions.push_back(pair<int, int>(7, 4));
bondDistances.push_back( C_HBondDistance );
nonbonded->createExceptionsFromBonds(bondExceptions, 0.0, 0.0);
system.addForce(forceField);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
positions[0] = Vec3(0.5480, 1.7661, 0.0000);
positions[1] = Vec3(0.7286, 0.8978, 0.6468);
positions[2] = Vec3(0.4974, 0.0000, 0.0588);
positions[3] = Vec3(0.0000, 0.9459, 1.4666);
positions[4] = Vec3(2.1421, 0.8746, 1.1615);
positions[5] = Vec3(2.3239, 0.0050, 1.8065);
positions[6] = Vec3(2.8705, 0.8295, 0.3416);
positions[7] = Vec3(2.3722, 1.7711, 1.7518);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
if( log ){
(void) fprintf( stderr, "Energy %.4e\n", state.getPotentialEnergy() );
}
// Take a small step in the direction of the energy gradient.
double norm = 0.0;
double forceSum[3] = { 0.0, 0.0, 0.0 };
for (int i = 0; i < numParticles; ++i) {
Vec3 f = state.getForces()[i];
if( log ){
(void) fprintf( stderr, "F %d [%14.6e %14.6e %14.6e]\n", i, f[0], f[1], f[2] );
}
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
forceSum[0] += f[0];
forceSum[1] += f[1];
forceSum[2] += f[2];
}
norm = std::sqrt(norm);
if( log ){
(void) fprintf( stderr, "Fsum [%14.6e %14.6e %14.6e] norm=%14.6e\n", forceSum[0], forceSum[1], forceSum[2], norm );
}
const double delta = 1e-4;
double step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = state.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
context.setPositions(positions);
State state2 = context.getState(State::Energy);
if( log ){
double deltaE = fabs( state.getPotentialEnergy() - state2.getPotentialEnergy() )/delta;
double diff = (deltaE - norm)/norm;
(void) fprintf( stderr, "Energies %.8e %.8e deltaE=%14.7e %14.7e diff=%14.7e\n", state.getPotentialEnergy(), state2.getPotentialEnergy(), deltaE, norm, diff );
}
// See whether the potential energy changed by the expected amount.
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/delta, 0.01)
}
int main() {
try {
testSingleParticle();
int applySwitch = 0;
testEnergyEthane( applySwitch );
applySwitch = 1;
testEnergyEthane( applySwitch );
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementations of GBVIForce, GBSAOBCForce and the softcore versions of
* these forces.
*/
#define TEST_NONBONDED 0
#define TEST_OBC 1
#define TEST_GBVI 2
#define TEST_CUDA_PLATFORM 0
#define TEST_OPENCL_PLATFORM 1
#include "openmm/GBVIForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/NonbondedForce.h"
#ifdef USE_SOFTCORE
#include "openmm/GBVISoftcoreForce.h"
#include "openmm/GBSAOBCSoftcoreForce.h"
#include "openmm/NonbondedSoftcoreForce.h"
#endif
/**
* Utility methods shared across unit tests
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/System.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "OpenMM.h"
#if TEST_PLATFORM == TEST_OPENCL_PLATFORM
#include "ReferencePlatform.h"
#include "OpenCLPlatform.h"
#endif
#if TEST_PLATFORM == TEST_CUDA_PLATFORM
#include "ReferencePlatform.h"
#include "CudaPlatform.h"
#endif
#ifdef USE_SOFTCORE
#include "OpenMMFreeEnergy.h"
#include "openmm/freeEnergyKernels.h"
#endif
#include "sfmt/SFMT.h"
#include "openmm/VerletIntegrator.h"
#ifdef OPENMM_SERIALIZE
#include "openmm/serialization/SerializationProxy.h"
#include "openmm/serialization/SerializationNode.h"
#include "openmm/serialization/XmlSerializer.h"
#endif
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <typeinfo>
#include <iomanip>
extern "C" void registerFreeEnergyCudaKernelFactories();
using namespace OpenMM;
using namespace std;
static const int NoCutoff_OpenMMTest = 0;
static const int CutoffNonPeriodic_OpenMMTest = 1;
static const int CutoffPeriodic_OpenMMTest = 2;
static const int Ewald_OpenMMTest = 3;
static const int PME_OpenMMTest = 4;
static const int ChargeIndex_OpenMMTest = 0;
static const int SigmaIndex_OpenMMTest = 1;
static const int EpsIndex_OpenMMTest = 2;
static const int GammaIndex_OpenMMTest = 3;
static const int LambdaIndex_OpenMMTest = 4;
static const int Reference_OpenMMTest = 0;
static const int Cuda_OpenMMTest = 1;
static const int OpenCL_OpenMMTest = 2;
class BondInfo_OpenMMTest {
public:
BondInfo_OpenMMTest( int particle1, int particle2, double distance );
int _particle1;
int _particle2;
double _distance;
};
BondInfo_OpenMMTest::BondInfo_OpenMMTest( int particle1, int particle2, double distance ){
_particle1 = particle1;
_particle2 = particle2;
_distance = distance;
}
typedef std::vector<std::string> StringVector;
typedef StringVector::iterator StringVectorI;
typedef StringVector::const_iterator StringVectorCI;
typedef std::vector<StringVector> StringVectorVector;
typedef std::vector<int> IntVector;
typedef IntVector::iterator IntVectorI;
typedef IntVector::const_iterator IntVectorCI;
typedef std::vector<IntVector> IntVectorVector;
typedef std::vector<double> DoubleVector;
typedef DoubleVector::iterator DoubleVectorI;
typedef DoubleVector::const_iterator DoubleVectorCI;
typedef std::vector<DoubleVector> DoubleVectorVector;
// the following are used in parsing parameter file
typedef std::vector<std::string> StringVector;
typedef StringVector::iterator StringVectorI;
typedef StringVector::const_iterator StringVectorCI;
typedef std::vector<StringVector> VectorStringVector;
typedef VectorStringVector::iterator VectorStringVectorI;
typedef VectorStringVector::const_iterator VectorStringVectorCI;
typedef std::vector<std::vector<double> > VectorOfDoubleVectors;
typedef VectorOfDoubleVectors::iterator VectorOfDoubleVectorsI;
typedef VectorOfDoubleVectors::const_iterator VectorOfDoubleVectorsCI;
typedef std::map< int, int> MapIntInt;
typedef MapIntInt::iterator MapIntIntI;
typedef MapIntInt::const_iterator MapIntIntCI;
typedef std::map< double, int> MapDoubleToInt;
typedef MapDoubleToInt::iterator MapDoubleToIntI;
typedef MapDoubleToInt::const_iterator MapDoubleToIntCI;
typedef std::map< std::string, VectorOfDoubleVectors > MapStringVectorOfDoubleVectors;
typedef MapStringVectorOfDoubleVectors::iterator MapStringVectorOfDoubleVectorsI;
typedef MapStringVectorOfDoubleVectors::const_iterator MapStringVectorOfDoubleVectorsCI;
typedef std::map< std::string, StringVector > MapStringStringVector;
typedef MapStringStringVector::iterator MapStringStringVectorI;
typedef MapStringStringVector::const_iterator MapStringStringVectorCI;
typedef std::map< std::string, std::string > MapStringString;
typedef MapStringString::iterator MapStringStringI;
typedef MapStringString::const_iterator MapStringStringCI;
typedef std::map< std::string, std::string > MapStringToInt;
typedef MapStringToInt::iterator MapStringToIntI;
typedef MapStringToInt::const_iterator MapStringToIntCI;
typedef std::vector< std::map< std::string, std::string > > VectorMapStringString;
typedef VectorMapStringString::iterator VectorMapStringStringI;
typedef VectorMapStringString::const_iterator VectorMapStringStringCI;
typedef std::map< std::string, int > MapStringInt;
typedef MapStringInt::iterator MapStringIntI;
typedef MapStringInt::const_iterator MapStringIntCI;
typedef std::map< std::string, std::vector<OpenMM::Vec3> > MapStringVec3;
typedef MapStringVec3::iterator MapStringVec3I;
typedef MapStringVec3::const_iterator MapStringVec3CI;
typedef std::map< std::string, double > MapStringToDouble;
typedef MapStringToDouble::iterator MapStringToDoubleI;
typedef MapStringToDouble::const_iterator MapStringToDoubleCI;
typedef std::vector< MapStringToDouble > VectorOfMapStringToDouble;
typedef std::map< std::string, DoubleVector> MapStringToDoubleVector;
typedef MapStringToDoubleVector::iterator MapStringToDoubleVectorI;
typedef MapStringToDoubleVector::const_iterator MapStringToDoubleVectorCI;
typedef std::map< std::string, DoubleVector > MapStringToDoubleVector;
typedef std::map< std::string, Force*> MapStringForce;
typedef MapStringForce::iterator MapStringForceI;
typedef MapStringForce::const_iterator MapStringForceCI;
typedef std::map< int, IntVector> MapIntIntVector;
typedef MapIntIntVector::const_iterator MapIntIntVectorCI;
typedef std::pair<int, int> IntIntPair;
typedef std::vector<IntIntPair> IntIntPairVector;
typedef IntIntPairVector::iterator IntIntPairVectorI;
typedef IntIntPairVector::const_iterator IntIntPairVectorCI;
typedef std::pair<int, double> IntDoublePair;
typedef std::vector<IntDoublePair> IntDoublePairVector;
typedef IntDoublePairVector::iterator IntDoublePairVectorI;
typedef IntDoublePairVector::const_iterator IntDoublePairVectorCI;
/**
* Predicate for sorting <int,double> pair
*
* @param d1 first IntDoublePair to compare
* @param d2 second IntDoublePair to compare
*
*/
bool TestIntDoublePair( const IntDoublePair& d1, const IntDoublePair& d2 ){
return d1.second < d2.second;
}
class PositionGenerator {
public:
enum GenerationMethod {
/**
* Random positions
*/
Random = 0,
/**
* On grid
*/
SimpleGrid = 1,
};
PositionGenerator( int numMolecules, int numParticlesPerMolecule, double boxSize );
~PositionGenerator( );
/**
* Set logging file reference
*
* @param log log
*
*/
void setLog( FILE* log );
/**
* Set positions
*
* @param method method placement
* @param positions output vector of positions
*
* @return nonzero if error detected; 0 otherwise
*/
int setPositions( GenerationMethod method, std::vector<Vec3>& positions ) const;
/**
* Set positions
*
* @param method method placement
* @param sfmt input random number generator
* @param positions output vector of positions
*
* @return nonzero if error detected; 0 otherwise
*/
int setPositions( GenerationMethod method, OpenMM_SFMT::SFMT& sfmt, std::vector<Vec3>& positions ) const;
/**
* Place particles on a grid
*
* @param origin origin
* @param boxDimensions box dimensions
* @param spacing spacing
* @param sfmt input random number generator
* @param bondDistance input bond distance
* @param array output vector of grid values
*
* @return -1 if particles will not fit on grid; 0 if they do
*/
int setParticlesOnGrid( const Vec3& origin, const Vec3& boxDimensions, const Vec3& spacing,
OpenMM_SFMT::SFMT& sfmt, double bondDistance, std::vector<Vec3>& array ) const;
/**
* Set bond distance
*
* @param bondDistance bond distance
*/
void setBondDistance( double bondDistance );
/**
* Get bond distance
*
* @return bond distance
*/
double getBondDistance( void ) const;
/**
* Get distance
*
* @param index1 index of first particle
* @param index2 index of second particle
* @param positions particle positions
*
* @return distance
*/
double getDistance( int index1, int index2, const std::vector<Vec3>& positions ) const;
/**
* Get distance assumming periodic boundary conditions
*
* @param index1 index of first particle
* @param index2 index of second particle
* @param positions particle positions
*
* @return distance
*/
double getPeriodicDistance( int index1, int index2, const std::vector<Vec3>& positions ) const;
/**
* Get settings
*
* @return info string
*/
std::string getSettings( void ) const;
/**
* Get enclosing box
*
* @param positions input vector of positions
* @param enclosingBox output vector of enclosing box dimensions
*
*/
void getEnclosingBox( const std::vector<Vec3>& positions, Vec3 enclosingBox[2] ) const;
/**
* Get sorted distances from particular position
*
* @param periodicBoundaryConditions if set, apply PBC
* @param positionIndex input position index
* @param positions input vector of positions
* @param sortVector on output sorted IntDoublePairVector
*
*/
void getSortedDistances( int periodicBoundaryConditions, int positionIndex, const std::vector<Vec3>& positions, IntDoublePairVector& sortVector ) const;
/**
* Show min/max distances between all positions
*
* @param positions input vector of positions
* @param periodicBoundaryConditions if set, use PBC in calculating distances
* @param showIndex number of min/maxentries to show
*
*/
void showMinMaxDistances( const std::vector<Vec3>& positions,
int periodicBoundaryConditions, int showIndex );
/**
* Show min/max distances between a single position and all remaining positions
*
* @param positions input vector of positions
* @param periodicBoundaryConditions if set, use PBC in calculating distances
* @param showIndex number of min/maxentries to show
* @param positionIndexVector list of entries to show min/max distances from
*
*/
void showMinMaxDistances( const std::vector<Vec3>& positions,
int periodicBoundaryConditions, int showIndex,
const IntVector& positionIndexVector );
/**
* Show distances between positions
*
* @param pairs particle indcies for which distance is to be reported
* @param positions input vector of positions
*
*/
void showDistances( const IntIntPairVector& pairs, const std::vector<Vec3>& positions ) const;
/**
* Show particles within a specified distance of a given particle
*
* @param positions input vector of positions
* @param periodicBoundaryConditions if set, use PBC in calculating distances
* @param particleIndex particle to check
* @param distanceToCheckFor distance to check for
* @param tolerance distance tolerance
*
*/
void showParticlesWithinDistance( const std::vector<Vec3>& positions,
int periodicBoundaryConditions, unsigned int particleIndex,
double distanceToCheckFor, double tolerance);
private:
int _numMolecules;
int _numParticlesPerMolecule;
int _numParticles;
int _seed;
double _boxSize;
double _bondDistance;
Vec3 _origin;
Vec3 _boxDimensions;
Vec3 _spacing;
FILE* _log;
};
PositionGenerator::PositionGenerator( int numMolecules, int numParticlesPerMolecule, double boxSize ) :
_numMolecules(numMolecules),
_seed(0),
_log(NULL),
_bondDistance(0.1),
_numParticlesPerMolecule(numParticlesPerMolecule),
_numParticles(numMolecules*numParticlesPerMolecule),
_boxSize(boxSize),
_boxDimensions(Vec3(boxSize,boxSize,boxSize)),
_origin(Vec3(0.0,0.0,0.0)) {
double particlesPerDimension = pow( static_cast<double>(_numParticles), (1.0/3.0) );
int particlesPerDimensionI = static_cast<int>(particlesPerDimension+0.999999);
double spacingPerDimension = _boxSize/particlesPerDimension;
_spacing[0] = spacingPerDimension;
_spacing[1] = spacingPerDimension;
_spacing[2] = spacingPerDimension;
}
PositionGenerator::~PositionGenerator( ){};
void PositionGenerator::setBondDistance( double bondDistance ){
_bondDistance = bondDistance;
}
void PositionGenerator::setLog( FILE* log ){
_log = log;
}
double PositionGenerator::getBondDistance( void ) const {
return _bondDistance;
}
double PositionGenerator::getDistance( int index1, int index2, const std::vector<Vec3>& positions ) const {
Vec3 delta = positions[index2] - positions[index1];
return sqrt( delta.dot( delta ) );
}
double PositionGenerator::getPeriodicDistance( int index1, int index2, const std::vector<Vec3>& positions ) const {
Vec3 delta = positions[index2] - positions[index1];
if( _boxSize > 0.0 ){
delta[0] -= floor(delta[0]/_boxSize+0.5f)*_boxSize;
delta[1] -= floor(delta[1]/_boxSize+0.5f)*_boxSize;
delta[2] -= floor(delta[2]/_boxSize+0.5f)*_boxSize;
}
return sqrt( delta.dot( delta ) );
}
/**
* Get positions
*
* @param method method placement
* @param positions output vector of positions
*
* @return nonzero if error detected; 0 otherwise
*/
int PositionGenerator::setPositions( GenerationMethod method, std::vector<Vec3>& positions ) const {
OpenMM_SFMT::SFMT sfmt;
init_gen_rand( _seed, sfmt);
return setPositions( method, sfmt, positions );
}
/**
* Get settings
*
* @return info string
*/
std::string PositionGenerator::getSettings( void ) const {
std::stringstream msg;
msg << "numMolecules " << _numMolecules << std::endl;
msg << "numParticlesPerMolecule " << _numParticlesPerMolecule << std::endl;
msg << "boxSize " << _boxSize << std::endl;
msg << "spacing " << _spacing[0] << std::endl;
msg << "seed " << _seed << std::endl;
return msg.str();
}
/**
* Get positions
*
* @param method method placement
* @param sfmt input random number generator
* @param positions output vector of positions
*
* @return nonzero if error detected; 0 otherwise
*/
int PositionGenerator::setPositions( GenerationMethod method, OpenMM_SFMT::SFMT& sfmt, std::vector<Vec3>& positions ) const {
int errorFlag = 0;
positions.resize( _numParticles );
if( method == Random ){
for( unsigned int ii = 0; ii < static_cast<unsigned int>(_numParticles); ii += _numParticlesPerMolecule ){
positions[ii] = Vec3(_boxSize*genrand_real2(sfmt), _boxSize*genrand_real2(sfmt), _boxSize*genrand_real2(sfmt));
for( unsigned int jj = 1; jj < static_cast<unsigned int>(_numParticlesPerMolecule); jj++) {
positions[ii+jj] = positions[ii] + Vec3(_bondDistance*genrand_real2(sfmt), _bondDistance*genrand_real2(sfmt), _bondDistance*genrand_real2(sfmt));
}
}
} else if( method == SimpleGrid ){
Vec3 origin, boxDimensions, spacing;
std::stringstream msg;
if( _numParticlesPerMolecule > 1 && _bondDistance > 0.0 ){
origin = Vec3(_bondDistance, _bondDistance, _bondDistance );
double particlesPerDimension = pow( static_cast<double>(_numMolecules), (1.0/3.0) );
int particlesPerDimensionI = static_cast<int>(particlesPerDimension+0.999999);
double boxSize = _boxSize;
double spacingPerDimension = (boxSize-_bondDistance)/(particlesPerDimension+1.0);
spacing = Vec3(spacingPerDimension, spacingPerDimension, spacingPerDimension );
boxDimensions = Vec3(boxSize, boxSize, boxSize );
msg << "Bond distance " << _bondDistance << std::endl;
msg << "particlesPerDimension " << particlesPerDimension << std::endl;
msg << "boxSize " << boxSize << std::endl;
msg << "spacingPerDimension " << spacingPerDimension << std::endl;
} else {
origin = _origin;
spacing = _spacing;
boxDimensions = _boxDimensions;
}
msg << getSettings() << std::endl;
if( _log ){
(void) fprintf( _log, "SimpleGrid %s\n", msg.str().c_str() );
}
errorFlag = setParticlesOnGrid( origin, boxDimensions, spacing, sfmt, _bondDistance, positions );
}
return errorFlag;
}
/**
* Place particles on a grid
*
* @param origin origin
* @param boxDimensions box dimensions
* @param spacing spacing
* @param array output vector of grid values
*
* @return -1 if particles will not fit on grid; 0 if they do
*/
int PositionGenerator::setParticlesOnGrid( const Vec3& origin, const Vec3& boxDimensions, const Vec3& spacing, OpenMM_SFMT::SFMT& sfmt,
double bondDistance, std::vector<Vec3>& array ) const {
const double pi = 3.14159265358979323846;
const double pi2 = 2.0*pi;
Vec3 start(origin);
if( array.size() != _numParticles ){
std::stringstream msg;
msg << "PositionGenerator::setParticlesOnGrid position vector size=" << array.size() << " != numParticles=" << _numParticles;
msg << getSettings();
throw OpenMMException( msg.str() );
}
// place molecule centers on grid
for( unsigned int ii = 0; ii < static_cast<unsigned int>(_numParticles); ii += _numParticlesPerMolecule ){
array[ii] = Vec3(start);
bool done = false;
for( unsigned int jj = 0; jj < 3 && !done; jj++ ){
start[jj] += spacing[jj];
if( (start[jj]+4.0*bondDistance) > boxDimensions[jj] ){
start[jj] = origin[jj];
} else {
done = true;
}
}
if( !done ){
std::stringstream msg;
msg << "PositionGenerator::setParticlesOnGrid error in grid settings at molecule=" << ii;
throw OpenMMException( msg.str() );
}
}
// add molecule atoms
for( unsigned int ii = 0; ii < static_cast<unsigned int>(_numMolecules); ii++ ){
int molecularIndex = ii*_numParticlesPerMolecule;
for( unsigned int jj = 1; jj < static_cast<unsigned int>(_numParticlesPerMolecule); jj++ ){
double theta = genrand_real2(sfmt)*pi2;
double phi = genrand_real2(sfmt)*pi;
array[molecularIndex+jj] = array[molecularIndex] + Vec3(_bondDistance*cos(theta)*cos(phi), _bondDistance*cos(theta)*sin(phi), _bondDistance*sin(theta) );
}
}
return 0;
}
/**
* Get enclosing box
*
* @param positions input vector of positions
* @param enclosingBox output Vec3[2] of minimum enclosing box ranges
*
*/
void PositionGenerator::getEnclosingBox( const std::vector<Vec3>& positions, Vec3 enclosingBox[2] ) const {
enclosingBox[0][0] = enclosingBox[1][0] = positions[0][0];
enclosingBox[0][1] = enclosingBox[1][1] = positions[0][1];
enclosingBox[0][2] = enclosingBox[1][2] = positions[0][2];
for( unsigned int ii = 1; ii < positions.size(); ii++ ){
if( enclosingBox[0][0] > positions[ii][0] ){
enclosingBox[0][0] = positions[ii][0];
}
if( enclosingBox[1][0] < positions[ii][0] ){
enclosingBox[1][0] = positions[ii][0];
}
if( enclosingBox[0][1] > positions[ii][1] ){
enclosingBox[0][1] = positions[ii][1];
}
if( enclosingBox[1][1] < positions[ii][1] ){
enclosingBox[1][1] = positions[ii][1];
}
if( enclosingBox[0][2] > positions[ii][2] ){
enclosingBox[0][2] = positions[ii][2];
}
if( enclosingBox[1][2] < positions[ii][2] ){
enclosingBox[1][2] = positions[ii][2];
}
}
return;
}
/**
* Show min/max distances between positions
*
* @param positions input vector of positions
* @param periodicBoundaryConditions if set, use PBC in calculating distances
* @param showIndex number of min/maxentries to show
* @param positionIndexVector list of entries to show min/max distances from
*
*/
void PositionGenerator::showMinMaxDistances( const std::vector<Vec3>& positions,
int periodicBoundaryConditions, int showIndex,
const IntVector& positionIndexVector ){
if( !_log )return;
Vec3 box[2];
getEnclosingBox( positions, box );
(void) fprintf( _log, "Enclosing Box (in A): [%15.7e %15.7e] [%15.7e %15.7e] [%15.7e %15.7e] [%15.7e %15.7e %15.7e]\n",
box[0][0], box[1][0], box[0][1], box[1][1], box[0][2], box[1][2],
(box[1][0] - box[0][0]), (box[1][1] - box[0][1]), (box[1][2] - box[0][2]) );
for( unsigned int ii = 0; ii < positionIndexVector.size(); ii++ ){
if( positionIndexVector[ii] < static_cast<int>(positions.size()) ){
int positionIndex = positionIndexVector[ii];
IntDoublePairVector sortVector;
getSortedDistances( periodicBoundaryConditions, positionIndex, positions, sortVector );
(void) fprintf( _log, "Min/max distance from %6d:\n ", positionIndex );
for( unsigned int jj = 0; jj < sortVector.size() && jj < static_cast<unsigned int>(showIndex); jj++ ){
IntDoublePair pair = sortVector[jj];
(void) fprintf( _log, "[%6d %15.7e] ", pair.first, pair.second);
}
(void) fprintf( _log, "\n " );
for( unsigned int jj = (sortVector.size() - showIndex); jj < sortVector.size() && jj >= 0; jj++ ){
IntDoublePair pair = sortVector[jj];
(void) fprintf( _log, "[%6d %15.7e] ", pair.first, pair.second);
}
(void) fprintf( _log, "\n" );
}
}
return;
}
/**
* Show min/max distances between positions
*
* @param positions input vector of positions
* @param periodicBoundaryConditions if set, use PBC in calculating distances
* @param showIndex number of min/maxentries to show
*
*/
void PositionGenerator::showMinMaxDistances( const std::vector<Vec3>& positions,
int periodicBoundaryConditions, int showIndex ){
if( !_log )return;
Vec3 box[2];
getEnclosingBox( positions, box );
(void) fprintf( _log, "Enclosing Box (in A): [%15.7e %15.7e] [%15.7e %15.7e] [%15.7e %15.7e] [%15.7e %15.7e %15.7e]\n",
box[0][0], box[1][0], box[0][1], box[1][1], box[0][2], box[1][2],
(box[1][0] - box[0][0]), (box[1][1] - box[0][1]), (box[1][2] - box[0][2]) );
IntDoublePairVector hitVector;
double minDistance = 1.0e+30;
double minDistanceCutoff = minDistance*1.1;
for( unsigned int ii = 0; ii < positions.size(); ii++ ){
for( unsigned int jj = ii+1; jj < positions.size(); jj++ ){
double distance = periodicBoundaryConditions ? getPeriodicDistance( jj, ii, positions) :
getDistance( jj, ii, positions);
if( distance < minDistanceCutoff ){
if( distance < minDistance ){
minDistance = distance;
minDistanceCutoff = minDistance*1.1;
}
hitVector.push_back( IntDoublePair(ii*positions.size()+jj,distance ) );
}
}
}
std::sort( hitVector.begin(), hitVector.end(), TestIntDoublePair );
(void) fprintf( _log, "Min distances pbc=%d\n", periodicBoundaryConditions );
for( unsigned int jj = 0; jj < hitVector.size() && jj < static_cast<unsigned int>(showIndex); jj++ ){
IntDoublePair pair = hitVector[jj];
int index = pair.first;
int iIndex = static_cast<int>(index/positions.size());
int jIndex = index - iIndex*positions.size();
(void) fprintf( _log, " [%6d %6d %15.7e]\n", iIndex, jIndex, pair.second);
}
return;
}
/**
* Show particles within a specified distance of a given particle
*
* @param positions input vector of positions
* @param periodicBoundaryConditions if set, use PBC in calculating distances
* @param particleIndex particle to check
* @param distanceToCheckFor distance to check for
* @param tolerance distance tolerance
*
*/
void PositionGenerator::showParticlesWithinDistance( const std::vector<Vec3>& positions,
int periodicBoundaryConditions, unsigned int particleIndex,
double distanceToCheckFor, double tolerance){
if( !_log || particleIndex >= positions.size() )return;
for( unsigned int ii = 0; ii < positions.size(); ii++ ){
double distance = periodicBoundaryConditions ? getPeriodicDistance( particleIndex, ii, positions) :
getDistance( particleIndex, ii, positions);
double delta = fabs( distanceToCheckFor - distance );
if( ii != particleIndex && delta < tolerance ){
(void) fprintf( _log, "Distance=%15.7e between particles %u %u.\n", distance, particleIndex, ii);
}
}
return;
}
/**
* Show distances between positions
*
* @param pairs particle indcies for which distance is to be reported
* @param positions input vector of positions
*
*/
void PositionGenerator::showDistances( const IntIntPairVector& pairs, const std::vector<Vec3>& positions ) const {
for( IntIntPairVectorCI ii = pairs.begin(); ii != pairs.end(); ii++ ){
if( ii->first < static_cast<int>(positions.size()) && ii->second < static_cast<int>(positions.size()) ){
double d = getDistance( ii->first, ii->second, positions );
(void) fprintf( _log, "Distance %6d %6d %15.7e d2=%15.7e\n", ii->first, ii->second, d, d*d );
}
}
return;
}
/**
* Get sorted distances from particular position
*
* @param periodicBoundaryConditions if set, apply PBC
* @param positionIndex input position index
* @param positions input vector of positions
* @param sortVector on output sorted IntDoublePairVector
*
*/
void PositionGenerator::getSortedDistances( int periodicBoundaryConditions, int positionIndex, const std::vector<Vec3>& positions,
IntDoublePairVector& sortVector ) const {
sortVector.resize( 0 );
for( unsigned int ii = 0; ii < positions.size(); ii++ ){
if( ii == positionIndex )continue;
double distance = periodicBoundaryConditions ? getPeriodicDistance( positionIndex, ii, positions) : getDistance( positionIndex, ii, positions);
sortVector.push_back( IntDoublePair( ii, distance ) );
}
std::sort( sortVector.begin(), sortVector.end(), TestIntDoublePair );
return;
}
/**---------------------------------------------------------------------------------------
*
* Set string field if in map
*
* @param argumentMap map to check
* @param fieldToCheck key
* @param fieldToSet field to set
*
* @return 1 if argument set, else 0
*
--------------------------------------------------------------------------------------- */
static int setStringFromMap( MapStringString& argumentMap, std::string fieldToCheck, std::string& fieldToSet ){
MapStringStringCI check = argumentMap.find( fieldToCheck );
if( check != argumentMap.end() ){
fieldToSet = (*check).second;
return 1;
}
return 0;
}
/**---------------------------------------------------------------------------------------
*
* Set int field if in map
*
* @param argumentMap map to check
* @param fieldToCheck key
* @param fieldToSet field to set
*
* @return 1 if argument set, else 0
*
--------------------------------------------------------------------------------------- */
static int setIntFromMap( MapStringString& argumentMap, std::string fieldToCheck, int& fieldToSet ){
MapStringStringCI check = argumentMap.find( fieldToCheck );
if( check != argumentMap.end() ){
fieldToSet = atoi( (*check).second.c_str() );
return 1;
}
return 0;
}
/**---------------------------------------------------------------------------------------
*
* Set int field if in map
*
* @param argumentMap map to check
* @param fieldToCheck key
* @param fieldToSet field to set
*
* @return 1 if argument set, else 0
*
--------------------------------------------------------------------------------------- */
static int setIntFromMapStringToDouble( MapStringToDouble& argumentMap, std::string fieldToCheck, int& fieldToSet ){
// ---------------------------------------------------------------------------------------
MapStringToDoubleCI check = argumentMap.find( fieldToCheck );
if( check != argumentMap.end() ){
fieldToSet = static_cast<int>(check->second+0.0000001);
return 1;
}
return 0;
}
/**---------------------------------------------------------------------------------------
* Set float field if in map
*
* @param argumentMap map to check
* @param fieldToCheck key
* @param fieldToSet field to set
*
* @return 1 if argument set, else 0
*
--------------------------------------------------------------------------------------- */
static int setFloatFromMap( MapStringString& argumentMap, std::string fieldToCheck, float& fieldToSet ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "setFloatFromMap";
// ---------------------------------------------------------------------------------------
MapStringStringCI check = argumentMap.find( fieldToCheck );
if( check != argumentMap.end() ){
fieldToSet = static_cast<float>(atof( (*check).second.c_str() ));
return 1;
}
return 0;
}
/**---------------------------------------------------------------------------------------
*
* Set double field if in map
*
* @param argumentMap map to check
* @param fieldToCheck key
* @param fieldToSet field to set
*
* @return 1 if argument set, else 0
*
--------------------------------------------------------------------------------------- */
static int setDoubleFromMap( MapStringString& argumentMap, std::string fieldToCheck, double& fieldToSet ){
// ---------------------------------------------------------------------------------------
MapStringStringCI check = argumentMap.find( fieldToCheck );
if( check != argumentMap.end() ){
fieldToSet = atof( (*check).second.c_str() );
return 1;
}
return 0;
}
/**---------------------------------------------------------------------------------------
*
* Set double field if in map
*
* @param argumentMap map to check
* @param fieldToCheck key
* @param fieldToSet field to set
*
* @return 1 if argument set, else 0
*
--------------------------------------------------------------------------------------- */
static int setDoubleFromMapStringToDouble( MapStringToDouble& argumentMap, std::string fieldToCheck, double& fieldToSet ){
// ---------------------------------------------------------------------------------------
MapStringToDoubleCI check = argumentMap.find( fieldToCheck );
if( check != argumentMap.end() ){
fieldToSet = check->second;
return 1;
}
return 0;
}
/**---------------------------------------------------------------------------------------
*
* Get relative difference between two forces
*
* @param f1 force1
* @param f2 force2
* @param forceNorm1 output norm of force1
* @param forceNorm2 output norm of force2
* @param relativeDiff output relative difference between force norms
* @param log if set, output forces
*
*
--------------------------------------------------------------------------------------- */
static void getForceRelativeDifference( const Vec3& f1, const Vec3& f2, double& forceNorm1, double& forceNorm2,
double& relativeDiff, FILE* log ) {
double diff = (f1[0] - f2[0])*(f1[0] - f2[0]) +
(f1[1] - f2[1])*(f1[1] - f2[1]) +
(f1[2] - f2[2])*(f1[2] - f2[2]);
forceNorm1 = sqrt( f1[0]*f1[0] + f1[1]*f1[1] + f1[2]*f1[2] );
forceNorm2 = sqrt( f2[0]*f2[0] + f2[1]*f2[1] + f2[2]*f2[2] );
if( forceNorm1 > 0.0 || forceNorm2 > 0.0 ){
relativeDiff = 2.0*sqrt( diff )/(forceNorm1+forceNorm2);
} else {
relativeDiff = 0.0;
}
return;
}
/**---------------------------------------------------------------------------------------
*
* Compare forces from two states
*
* @param state1 state1
* @param state2 state2
* @param relativeTolerance relative tolerance
* @param log if set, output forces
*
* @return number of entries with relative difference > tolerance
*
--------------------------------------------------------------------------------------- */
int compareForcesOfTwoStates( State& state1, State& state2, double relativeTolerance,
DoubleVector& stats, FILE* log ) {
int error = 0;
vector<Vec3> force1 = state1.getForces();
vector<Vec3> force2 = state2.getForces();
double averageRelativeDifference = 0.0;
double count = 0.0;
DoubleVector medians1( force1.size() );
DoubleVector medians2( force1.size() );
IntDoublePairVector relativeDifferences;
for( unsigned int ii = 0; ii < force1.size(); ii++ ){
double forceNorm1;
double forceNorm2;
double relativeDiff;
getForceRelativeDifference( force1[ii], force2[ii], forceNorm1, forceNorm2, relativeDiff, log );
medians1[ii] = forceNorm1;
medians2[ii] = forceNorm2;
relativeDifferences.push_back( IntDoublePair(ii, relativeDiff ) );
averageRelativeDifference += relativeDiff;
count += 1.0;
if( relativeDiff > relativeTolerance ){
error++;
}
if( log ){
(void) fprintf( log, "F %6u %15.7e [%15.7e %15.7e %15.7e] [%15.7e %15.7e %15.7e] %15.7e %15.7e %s\n", static_cast<unsigned int>(ii),
relativeDiff, force1[ii][0], force1[ii][1], force1[ii][2], force2[ii][0], force2[ii][1], force2[ii][2],
forceNorm1, forceNorm2, (relativeDiff < relativeTolerance ? "":"XXXXXX") );
}
}
// sort relative differences
std::sort( relativeDifferences.begin(), relativeDifferences.end(), TestIntDoublePair );
if( log ){
(void) fprintf( log, "\nEntries w/ largest relative differences.\n" );
for( unsigned int ii = relativeDifferences.size()-1; ii >= relativeDifferences.size()-10 && ii >= 0; ii-- ){
double forceNorm1;
double forceNorm2;
double relativeDiff;
int index = relativeDifferences[ii].first;
getForceRelativeDifference( force1[index], force2[index], forceNorm1, forceNorm2, relativeDiff, log );
(void) fprintf( log, "Fs %6u %15.7e [%15.7e %15.7e %15.7e] [%15.7e %15.7e %15.7e] %15.7e %15.7e %s\n",
static_cast<unsigned int>(index), relativeDiff,
force1[index][0], force1[index][1], force1[index][2],
force2[index][0], force2[index][1], force2[index][2],
forceNorm1, forceNorm2, (relativeDiff < relativeTolerance ? "":"XXXXXX") );
}
}
if( count > 0.0 ){
averageRelativeDifference /= count;
}
std::sort( medians1.begin(), medians1.end() );
std::sort( medians2.begin(), medians2.end() );
double median1 = medians1[medians1.size()/2];
double median2 = medians2[medians2.size()/2];
stats.resize( 4 );
stats[0] = averageRelativeDifference;
IntDoublePair pair = relativeDifferences[relativeDifferences.size()-1];
stats[1] = pair.second;
stats[2] = static_cast<double>(pair.first);
stats[3] = median1 < median2 ? median1 : median2;
return error;
}
/**
* Create nonbonded force and set some parameters
*
* @param nonbondedMethod nonbonded method
* @param cutoffDistance cutoff distance
* @param reactionFieldDielectric reaction field dielectric
* @param parameterList list of parameters -- used via addParticle()
* @param bonds list of BondInfo_OpenMMTest containing info for exceptions
* @param log logging file (optional -- may be NULL)
*
*/
static NonbondedForce* getNonbondedForce( int nonbondedMethod, double cutoffDistance, double reactionFieldDielectric,
VectorOfDoubleVectors& parameterList, std::vector< BondInfo_OpenMMTest >& bonds, FILE* log ){
NonbondedForce* nonbondedForce = new NonbondedForce();
NonbondedForce::NonbondedMethod method;
switch( nonbondedMethod ){
case NoCutoff_OpenMMTest:
method = NonbondedForce::NoCutoff;
break;
case CutoffNonPeriodic_OpenMMTest:
method = NonbondedForce::CutoffNonPeriodic;
break;
case CutoffPeriodic_OpenMMTest:
method = NonbondedForce::CutoffPeriodic;
break;
case Ewald_OpenMMTest:
method = NonbondedForce::Ewald;
break;
case PME_OpenMMTest:
method = NonbondedForce::PME;
break;
default:
method = NonbondedForce::NoCutoff;
}
nonbondedForce->setNonbondedMethod( method );
nonbondedForce->setCutoffDistance( cutoffDistance );
nonbondedForce->setReactionFieldDielectric( reactionFieldDielectric );
// load parameters
for( unsigned int ii = 0; ii < parameterList.size(); ii++ ){
DoubleVector parameters = parameterList[ii];
nonbondedForce->addParticle( parameters[ChargeIndex_OpenMMTest], parameters[SigmaIndex_OpenMMTest], parameters[EpsIndex_OpenMMTest] );
}
// add exceptions
for( unsigned int ii = 0; ii < bonds.size(); ii++ ){
BondInfo_OpenMMTest bond = bonds[ii];
nonbondedForce->addException( bond._particle1, bond._particle2, 0.0f, 1.0, 0.0f );
}
return nonbondedForce;
}
/**
* Create GBVI force and set some parameters
*
* @param nonbondedMethod nonbonded method
* @param cutoffDistance cutoff distance
* @param useQuinticSpline if set use quintic spline for Born radii scaling; else use no scaling
* @param quinticLowerLimitFactor quintic lower limit factor
* @param quinticUpperBornRadiusLimit quintic upper Born radius limit
* @param solventDielectric solvent dielectric
* @param soluteDielectric solute dielectric
* @param parameterList list of parameters -- used via addParticle()
* @param bonds list of BondInfo_OpenMMTest containing info for exceptions
* @param log logging file (optional -- may be NULL)
*
*/
static GBVIForce* getGBVIForce( int nonbondedMethod, double cutoffDistance, int useQuinticSpline,
double quinticLowerLimitFactor, double quinticUpperBornRadiusLimit,
double solventDielectric, double soluteDiecletric,
VectorOfDoubleVectors& parameterList, std::vector< BondInfo_OpenMMTest >& bonds, FILE* log ){
GBVIForce* gbviForce = new GBVIForce();
GBVIForce::NonbondedMethod method;
switch( nonbondedMethod ){
case NoCutoff_OpenMMTest:
method = GBVIForce::NoCutoff;
break;
case CutoffNonPeriodic_OpenMMTest:
method = GBVIForce::CutoffNonPeriodic;
break;
case CutoffPeriodic_OpenMMTest:
method = GBVIForce::CutoffPeriodic;
break;
default:
method = GBVIForce::NoCutoff;
}
gbviForce->setNonbondedMethod( method );
gbviForce->setCutoffDistance( cutoffDistance );
gbviForce->setSolventDielectric( solventDielectric );
gbviForce->setSoluteDielectric( soluteDiecletric );
if( useQuinticSpline ){
gbviForce->setBornRadiusScalingMethod( GBVIForce::QuinticSpline );
gbviForce->setQuinticLowerLimitFactor( quinticLowerLimitFactor );
gbviForce->setQuinticUpperBornRadiusLimit( quinticUpperBornRadiusLimit );
} else {
gbviForce->setBornRadiusScalingMethod( GBVIForce::NoScaling );
}
// load parameters
for( unsigned int ii = 0; ii < parameterList.size(); ii++ ){
DoubleVector parameters = parameterList[ii];
gbviForce->addParticle( parameters[ChargeIndex_OpenMMTest], parameters[SigmaIndex_OpenMMTest], parameters[GammaIndex_OpenMMTest] );
}
// add exceptions
for( unsigned int ii = 0; ii < bonds.size(); ii++ ){
BondInfo_OpenMMTest bond = bonds[ii];
gbviForce->addBond( bond._particle1, bond._particle2, bond._distance);
}
return gbviForce;
}
/**
* Create OBC force and set some parameters
*
* @param nonbondedMethod nonbonded method
* @param cutoffDistance cutoff distance
* @param solventDielectric solvent dielectric
* @param soluteDielectric solute dielectric
* @param parameterList list of parameters -- used via addParticle()
* @param log logging file (optional -- may be NULL)
*
*/
static GBSAOBCForce* getGBSAOBCForce( int nonbondedMethod, double cutoffDistance, double solventDielectric, double soluteDiecletric,
VectorOfDoubleVectors& parameterList, FILE* log ){
GBSAOBCForce* obcForce = new GBSAOBCForce();
GBSAOBCForce::NonbondedMethod method;
switch( nonbondedMethod ){
case NoCutoff_OpenMMTest:
method = GBSAOBCForce::NoCutoff;
break;
case CutoffNonPeriodic_OpenMMTest:
method = GBSAOBCForce::CutoffNonPeriodic;
break;
case CutoffPeriodic_OpenMMTest:
method = GBSAOBCForce::CutoffPeriodic;
break;
default:
method = GBSAOBCForce::NoCutoff;
}
obcForce->setNonbondedMethod( method );
obcForce->setCutoffDistance( cutoffDistance );
obcForce->setSolventDielectric( solventDielectric );
obcForce->setSoluteDielectric( soluteDiecletric );
// load parameters
for( unsigned int ii = 0; ii < parameterList.size(); ii++ ){
DoubleVector parameters = parameterList[ii];
obcForce->addParticle( parameters[ChargeIndex_OpenMMTest], parameters[SigmaIndex_OpenMMTest], parameters[GammaIndex_OpenMMTest] );
}
return obcForce;
}
/**
* Create nonbonded softcore force and set some parameters
*
* @param nonbondedMethod nonbonded method
* @param cutoffDistance cutoff distance
* @param reactionFieldDielectric reaction field dielectric
* @param log logging file (optional -- may be NULL)
*
*/
#ifdef USE_SOFTCORE
static NonbondedSoftcoreForce* getNonbondedSoftcoreForce( int nonbondedMethod, double cutoffDistance, double reactionFieldDielectric, FILE* log ){
NonbondedSoftcoreForce* nonbondedForce = new NonbondedSoftcoreForce();
NonbondedSoftcoreForce::NonbondedMethod method;
switch( nonbondedMethod ){
case NoCutoff_OpenMMTest:
method = NonbondedSoftcoreForce::NoCutoff;
break;
case CutoffNonPeriodic_OpenMMTest:
method = NonbondedSoftcoreForce::CutoffNonPeriodic;
break;
case CutoffPeriodic_OpenMMTest:
method = NonbondedSoftcoreForce::CutoffPeriodic;
break;
default:
method = NonbondedSoftcoreForce::NoCutoff;
}
nonbondedForce->setNonbondedMethod( method );
nonbondedForce->setCutoffDistance( cutoffDistance );
nonbondedForce->setReactionFieldDielectric( reactionFieldDielectric );
return nonbondedForce;
}
/**
* Create GBVI softcore force and set some parameters
*
* @param nonbondedMethod nonbonded method
* @param cutoffDistance cutoff distance
* @param useQuinticSpline if set use quintic spline for Born radii scaling; else use no scaling
* @param quinticLowerLimitFactor quintic lower limit factor
* @param quinticUpperBornRadiusLimit quintic upper Born radius limit
* @param solventDielectric solvent dielectric
* @param soluteDielectric solute dielectric
* @param log logging file (optional -- may be NULL)
*
*/
static GBVISoftcoreForce* getGBVISoftcoreForce( int nonbondedMethod, double cutoffDistance, int useQuinticSpline,
double quinticLowerLimitFactor, double quinticUpperBornRadiusLimit,
double solventDielectric, double soluteDiecletric, FILE* log ){
GBVISoftcoreForce* gbviForce = new GBVISoftcoreForce();
GBVISoftcoreForce::NonbondedMethod method;
switch( gbviMethod ){
case NoCutoff_OpenMMTest:
method = GBVISoftcoreForce::NoCutoff;
break;
case CutoffNonPeriodic_OpenMMTest:
method = GBVISoftcoreForce::CutoffNonPeriodic;
break;
case CutoffPeriodic_OpenMMTest:
method = GBVISoftcoreForce::CutoffPeriodic;
break;
default:
method = GBVISoftcoreForce::NoCutoff;
}
gbviForce->setNonbondedMethod( method );
gbviForce->setCutoffDistance( cutoffDistance );
gbviForce->setSolventDielectric( solventDielectric );
gbviForce->setSoluteDielectric( soluteDiecletric );
if( useQuinticSpline ){
gbviForce->setBornRadiusScalingMethod( GBVISoftcoreForce::QuinticSpline );
gbviForce->setQuinticLowerLimitFactor( quinticLowerLimitFactor );
gbviForce->setQuinticUpperBornRadiusLimit( quinticUpperBornRadiusLimit );
} else {
gbviForce->setBornRadiusScalingMethod( GBVISoftcoreForce::NoScaling );
}
return gbviForce;
}
/**
* Create OBC softcore force and set some parameters
*
* @param nonbondedMethod nonbonded method
* @param cutoffDistance cutoff distance
* @param solventDielectric solvent dielectric
* @param soluteDielectric solute dielectric
* @param log logging file (optional -- may be NULL)
*
*/
static GBSAOBCSoftcoreForce* getGBSAOBCSoftcoreForce( int nonbondedMethod, double cutoffDistance,
double solventDielectric, double soluteDiecletric, FILE* log ){
GBSAOBCSoftcoreForce* obcForce = new GBSAOBCSoftcoreForce();
GBSAOBCSoftcoreForce::NonbondedMethod method;
switch( gbviMethod ){
case NoCutoff_OpenMMTest:
method = GBSAOBCSoftcoreForce::NoCutoff;
break;
case CutoffNonPeriodic_OpenMMTest:
method = GBSAOBCSoftcoreForce::CutoffNonPeriodic;
break;
case CutoffPeriodic_OpenMMTest:
method = GBSAOBCSoftcoreForce::CutoffPeriodic;
break;
default:
method = GBSAOBCSoftcoreForce::NoCutoff;
}
obcForce->setNonbondedMethod( method );
obcForce->setCutoffDistance( cutoffDistance );
obcForce->setSolventDielectric( solventDielectric );
obcForce->setSoluteDielectric( soluteDiecletric );
return obcForce;
}
#endif
/**
* Get forces in system
*
* @param system system to serialize
* @param stringForceVector output stringForceVector[forceName] = force index
* @param log logging file (optional -- may be NULL)
*
*/
static void getStringForceMap( System& system, MapStringInt& stringForceVector, FILE* log ){
// print active forces and relevant parameters
for( int ii = 0; ii < system.getNumForces(); ii++ ) {
int hit = 0;
Force& force = system.getForce(ii);
if( !hit ){
try {
CMAPTorsionForce& castForce = dynamic_cast<CMAPTorsionForce&>(force);
stringForceVector["CMAPTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomAngleForce& castForce = dynamic_cast<CustomAngleForce&>(force);
stringForceVector["CustomAngle"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomBondForce& castForce = dynamic_cast<CustomBondForce&>(force);
stringForceVector["CustomBond"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomExternalForce& castForce = dynamic_cast<CustomExternalForce&>(force);
stringForceVector["CustomExternal"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomGBForce& castForce = dynamic_cast<CustomGBForce&>(force);
stringForceVector["CustomGB"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomHbondForce& castForce = dynamic_cast<CustomHbondForce&>(force);
stringForceVector["CustomHbond"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomNonbondedForce& castForce = dynamic_cast<CustomNonbondedForce&>(force);
stringForceVector["CustomNonbonded"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
CustomTorsionForce& castForce = dynamic_cast<CustomTorsionForce&>(force);
stringForceVector["CustomTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
GBSAOBCForce& castForce = dynamic_cast<GBSAOBCForce&>(force);
stringForceVector["GBSAOBC"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
GBVIForce& castForce = dynamic_cast<GBVIForce&>(force);
stringForceVector["GBVI"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
HarmonicAngleForce& castForce = dynamic_cast<HarmonicAngleForce&>(force);
stringForceVector["HarmonicAngle"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
HarmonicBondForce& castForce = dynamic_cast<HarmonicBondForce&>(force);
stringForceVector["HarmonicBond"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
NonbondedForce& castForce = dynamic_cast<NonbondedForce&>(force);
stringForceVector["Nonbonded"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
PeriodicTorsionForce& castForce = dynamic_cast<PeriodicTorsionForce&>(force);
stringForceVector["PeriodicTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
RBTorsionForce& castForce = dynamic_cast<RBTorsionForce&>(force);
stringForceVector["RBTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
MonteCarloBarostat& castForce = dynamic_cast<MonteCarloBarostat&>(force);
stringForceVector["MonteCarloBarostat"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AndersenThermostat& castForce = dynamic_cast<AndersenThermostat&>(force);
stringForceVector["AndersenThermostat"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
#ifdef USE_SOFTCORE
if( !hit ){
try {
GBSAOBCSoftcoreForce& castForce = dynamic_cast<GBSAOBCSoftcoreForce&>(force);
stringForceVector["GBSAOBCSoftcore"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
GBVISoftcoreForce& castForce = dynamic_cast<GBVISoftcoreForce&>(force);
stringForceVector["GBVISoftcore"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
NonbondedSoftcoreForce& castForce = dynamic_cast<NonbondedSoftcoreForce&>(force);
stringForceVector["NonbondedSoftcore"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
#endif
#ifdef INCLUDE_AMOEBA_FORCES
if( !hit ){
try {
AmoebaHarmonicBondForce& castForce = dynamic_cast<AmoebaHarmonicBondForce&>(force);
stringForceVector["AmoebaHarmonicBond"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaHarmonicAngleForce& castForce = dynamic_cast<AmoebaHarmonicAngleForce&>(force);
stringForceVector["AmoebaHarmonicAngle"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaHarmonicInPlaneAngleForce& castForce = dynamic_cast<AmoebaHarmonicInPlaneAngleForce&>(force);
stringForceVector["AmoebaHarmonicInPlaneAngle"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaMultipoleForce& castForce = dynamic_cast<AmoebaMultipoleForce&>(force);
stringForceVector["AmoebaMultipole"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaOutOfPlaneBendForce& castForce = dynamic_cast<AmoebaOutOfPlaneBendForce&>(force);
stringForceVector["AmoebaOutOfPlaneBend"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaPiTorsionForce& castForce = dynamic_cast<AmoebaPiTorsionForce&>(force);
stringForceVector["AmoebaPiTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaStretchBendForce& castForce = dynamic_cast<AmoebaStretchBendForce&>(force);
stringForceVector["AmoebaStretchBend"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaTorsionForce& castForce = dynamic_cast<AmoebaTorsionForce&>(force);
stringForceVector["AmoebaTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaTorsionTorsionForce& castForce = dynamic_cast<AmoebaTorsionTorsionForce&>(force);
stringForceVector["AmoebaTorsionTorsion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaUreyBradleyForce& castForce = dynamic_cast<AmoebaUreyBradleyForce&>(force);
stringForceVector["AmoebaUreyBradley"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaVdwForce& castForce = dynamic_cast<AmoebaVdwForce&>(force);
stringForceVector["AmoebaVdw"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaWcaDispersionForce& castForce = dynamic_cast<AmoebaWcaDispersionForce&>(force);
stringForceVector["AmoebaWcaDispersion"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaGeneralizedKirkwoodForce& castForce = dynamic_cast<AmoebaGeneralizedKirkwoodForce&>(force);
stringForceVector["AmoebaGeneralizedKirkwood"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
if( !hit ){
try {
AmoebaTorsionTorsionForce& castForce = dynamic_cast<AmoebaTorsionTorsionForce&>(force);
stringForceVector["AmoebaTorsionTorsionForce"] = ii;
hit++;
} catch( std::bad_cast ){
}
}
#endif
// COM
if( !hit ){
try {
CMMotionRemover& cMMotionRemover = dynamic_cast<CMMotionRemover&>(force);
hit++;
} catch( std::bad_cast ){
}
}
if( !hit && log ){
(void) fprintf( log, " entry=%2d force not recognized.\n", ii );
}
}
}
/**
* Get forces in system
*
* @param system system to serialize
* @param stringForceVector output stringForceVector[forceName] = force index
* @param log logging file (optional -- may be NULL)
*
*/
static Force* copyForce( const Force& force, FILE* log ){
// print active forces and relevant parameters
Force* forceCopy = NULL;
try {
const CMAPTorsionForce& castForce = dynamic_cast<const CMAPTorsionForce&>(force);
forceCopy = new CMAPTorsionForce( castForce );
} catch( std::bad_cast ){
}
if( forceCopy == NULL ){
try {
const CustomAngleForce& castForce = dynamic_cast<const CustomAngleForce&>(force);
forceCopy = new CustomAngleForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const CustomBondForce& castForce = dynamic_cast<const CustomBondForce&>(force);
forceCopy = new CustomBondForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const CustomExternalForce& castForce = dynamic_cast<const CustomExternalForce&>(force);
forceCopy = new CustomExternalForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const CustomGBForce& castForce = dynamic_cast<const CustomGBForce&>(force);
forceCopy = new CustomGBForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const CustomHbondForce& castForce = dynamic_cast<const CustomHbondForce&>(force);
forceCopy = new CustomHbondForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const CustomNonbondedForce& castForce = dynamic_cast<const CustomNonbondedForce&>(force);
forceCopy = new CustomNonbondedForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const CustomTorsionForce& castForce = dynamic_cast<const CustomTorsionForce&>(force);
forceCopy = new CustomTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const GBSAOBCForce& castForce = dynamic_cast<const GBSAOBCForce&>(force);
forceCopy = new GBSAOBCForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const GBVIForce& castForce = dynamic_cast<const GBVIForce&>(force);
forceCopy = new GBVIForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const HarmonicAngleForce& castForce = dynamic_cast<const HarmonicAngleForce&>(force);
forceCopy = new HarmonicAngleForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const HarmonicBondForce& castForce = dynamic_cast<const HarmonicBondForce&>(force);
forceCopy = new HarmonicBondForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const NonbondedForce& castForce = dynamic_cast<const NonbondedForce&>(force);
forceCopy = new NonbondedForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const PeriodicTorsionForce& castForce = dynamic_cast<const PeriodicTorsionForce&>(force);
forceCopy = new PeriodicTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const RBTorsionForce& castForce = dynamic_cast<const RBTorsionForce&>(force);
forceCopy = new RBTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const MonteCarloBarostat& castForce = dynamic_cast<const MonteCarloBarostat&>(force);
forceCopy = new MonteCarloBarostat( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AndersenThermostat& castForce = dynamic_cast<const AndersenThermostat&>(force);
forceCopy = new AndersenThermostat( castForce );
} catch( std::bad_cast ){
}
}
#ifdef USE_SOFTCORE
if( forceCopy == NULL ){
try {
const GBSAOBCSoftcoreForce& castForce = dynamic_cast<const GBSAOBCSoftcoreForce&>(force);
forceCopy = new GBSAOBCSoftcoreForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const GBVISoftcoreForce& castForce = dynamic_cast<const GBVISoftcoreForce&>(force);
forceCopy = new GBVISoftcoreForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const NonbondedSoftcoreForce& castForce = dynamic_cast<const NonbondedSoftcoreForce&>(force);
forceCopy = new NonbondedSoftcoreForce( castForce );
} catch( std::bad_cast ){
}
}
#endif
#ifdef INCLUDE_AMOEBA_FORCES
if( forceCopy == NULL ){
try {
const AmoebaHarmonicBondForce& castForce = dynamic_cast<const AmoebaHarmonicBondForce&>(force);
forceCopy = new AmoebaHarmonicBondForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaHarmonicAngleForce& castForce = dynamic_cast<const AmoebaHarmonicAngleForce&>(force);
forceCopy = new AmoebaHarmonicAngleForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaHarmonicInPlaneAngleForce& castForce = dynamic_cast<const AmoebaHarmonicInPlaneAngleForce&>(force);
forceCopy = new AmoebaHarmonicInPlaneAngleForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaMultipoleForce& castForce = dynamic_cast<const AmoebaMultipoleForce&>(force);
forceCopy = new AmoebaMultipoleForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaOutOfPlaneBendForce& castForce = dynamic_cast<const AmoebaOutOfPlaneBendForce&>(force);
forceCopy = new AmoebaOutOfPlaneBendForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaPiTorsionForce& castForce = dynamic_cast<const AmoebaPiTorsionForce&>(force);
forceCopy = new AmoebaPiTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaStretchBendForce& castForce = dynamic_cast<const AmoebaStretchBendForce&>(force);
forceCopy = new AmoebaStretchBendForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaTorsionForce& castForce = dynamic_cast<const AmoebaTorsionForce&>(force);
forceCopy = new AmoebaTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaTorsionTorsionForce& castForce = dynamic_cast<const AmoebaTorsionTorsionForce&>(force);
forceCopy = new AmoebaTorsionTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaUreyBradleyForce& castForce = dynamic_cast<const AmoebaUreyBradleyForce&>(force);
forceCopy = new AmoebaUreyBradleyForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaVdwForce& castForce = dynamic_cast<const AmoebaVdwForce&>(force);
forceCopy = new AmoebaVdwForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaWcaDispersionForce& castForce = dynamic_cast<const AmoebaWcaDispersionForce&>(force);
forceCopy = new AmoebaWcaDispersionForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaGeneralizedKirkwoodForce& castForce = dynamic_cast<const AmoebaGeneralizedKirkwoodForce&>(force);
forceCopy = new AmoebaGeneralizedKirkwoodForce( castForce );
} catch( std::bad_cast ){
}
}
if( forceCopy == NULL ){
try {
const AmoebaTorsionTorsionForce& castForce = dynamic_cast<const AmoebaTorsionTorsionForce&>(force);
forceCopy = new AmoebaTorsionTorsionForce( castForce );
} catch( std::bad_cast ){
}
}
#endif
if( log && forceCopy == NULL ){
(void) fprintf( log, " force not recognized.\n" );
}
return forceCopy;
}
/**
* Return copy of system (but not forces)
*
* @param inputSystem system to copy
*
* @return system copy
*
*/
static void copySystem( const System& inputSystem, System& systemCopy, FILE* log ){
// add particle/mass
for( unsigned int ii = 0; ii < static_cast<unsigned int>(inputSystem.getNumParticles()); ii++ ){
systemCopy.addParticle( inputSystem.getParticleMass( static_cast<int>(ii) ) );
}
// box
Vec3 a;
Vec3 b;
Vec3 c;
inputSystem.getDefaultPeriodicBoxVectors( a, b, c );
systemCopy.setDefaultPeriodicBoxVectors( a, b, c );
// copy constraints
for( unsigned int ii = 0; ii < static_cast<unsigned int>(inputSystem.getNumConstraints()); ii++ ){
int particle1, particle2;
double distance;
inputSystem.getConstraintParameters( ii, particle1, particle2, distance);
systemCopy.addConstraint( particle1, particle2, distance);
}
// copy forces
for( unsigned int ii = 0; ii < static_cast<unsigned int>(inputSystem.getNumForces()); ii++ ){
systemCopy.addForce( copyForce( inputSystem.getForce(ii), log) );
}
return;
}
/**
* Randomize parameters
*
* @param parametersLowerBound vector of parameter lower bounds
* @param parametersUpperBound vector of parameter upper bounds
* @param sfmt SFMT random number generator
* @param parameters output vector of randomized parameter values
*
*/
static void randomizeParameters( const std::vector<double>& parametersLowerBound,
const std::vector<double>& parametersUpperBound,
OpenMM_SFMT::SFMT& sfmt, std::vector<double>& parameters ){
if( parametersLowerBound.size() != parametersUpperBound.size() ){
std::stringstream msg;
msg << " randomizeParameters parametersLowerBound size=" << parametersLowerBound.size() << " != parametersUpperBound size=" << parametersUpperBound.size();
throw OpenMMException( msg.str() );
}
if( parametersLowerBound.size() != parameters.size() ){
std::stringstream msg;
msg << " randomizeParameters parametersLowerBound size=" << parametersLowerBound.size() << " != parameter size=" << parameters.size();
throw OpenMMException( msg.str() );
}
for( unsigned int ii = 0; ii < parametersLowerBound.size(); ii++ ){
parameters[ii] = parametersLowerBound[ii] + (parametersUpperBound[ii] - parametersLowerBound[ii])*(genrand_real2(sfmt));
}
return;
}
/**
* Randomize Vec3 vector
*
* @param average mean value
* @param range +/- range
* @param sfmt SFMT random number generator
* @param array output vector of randomized values
*
*/
static void randomizeVec3( double average, double range,
OpenMM_SFMT::SFMT& sfmt, std::vector<Vec3>& array ){
range *= 2.0;
for( unsigned int ii = 0; ii < array.size(); ii++ ){
array[ii] = Vec3( average + range*(genrand_real2(sfmt) - 0.5),
average + range*(genrand_real2(sfmt) - 0.5),
average + range*(genrand_real2(sfmt) - 0.5) );
}
return;
}
/**
* Output contents of MapStringString
*
* @param inputArgumentMap map to output
* @param outputStream output stream
*
*/
static void streamArgumentMap( const MapStringString& inputArgumentMap, std::stringstream& outputStream ){
char buffer[2048];
for( MapStringStringCI ii = inputArgumentMap.begin(); ii != inputArgumentMap.end(); ii++ ){
std::string key = ii->first;
std::string value = ii->second;
(void) sprintf( buffer, " %30s %40s\n", key.c_str(), value.c_str() );
outputStream << buffer;
}
return;
}
/**
* Format argument/value
*
* @param buffer formatted output
* @param key argument name
* @param value argument value
* @param format format string
* @param call if call > 0, skip key name
* @param type type == 0, then use int value; else double
*
*/
static void formatArgument( char* buffer, const std::string& key, double value, const char* format, int call, int type ){
// if call > 0, skip key name
unsigned int index = 0;
while( index < key.size() ){
buffer[index] = call ? ' ' : key[index];
index++;
}
// add blank
buffer[index++] = ' ';
buffer[index] = static_cast<char>(NULL);
if( type == 0 ){
int valueInt = static_cast<int>(value+0.00001);
(void) sprintf( buffer + index, format, valueInt );
} else {
(void) sprintf( buffer + index, format, value );
}
return;
}
/**
* Output contents of MapStringString w/ all argument on one line
*
* @param inputArgumentMap map to output
* @param exclude map of keys to exclude from output
* @param outputStream output stream
*
*/
static void streamArgumentMapOneLine( const MapStringToDouble& inputArgumentMap, const MapStringToInt& exclude,
const StringVector& printFirst, int callId, std::stringstream& outputStream ){
char buffer[2048];
MapStringToInt excludeAll(exclude);
for( unsigned int ii = 0; ii < printFirst.size(); ii++ ){
MapStringToDoubleCI iter = inputArgumentMap.find( printFirst[ii] );
if( iter != inputArgumentMap.end() ){
std::string key = iter->first;
if( exclude.find( key ) == exclude.end() ){
double value = iter->second;
if( key == "numMolecules" ){
formatArgument( buffer, key, value, "%6d ", callId, 0 );
} else if( key == "nonbondedMethod" ){
formatArgument( buffer, key, value, "%1d ", callId, 0 );
} else if( key == "lambda1" || key == "lambda2" ){
formatArgument( buffer, key, value, "%4.2f ", callId, 1 );
} else if( key == "boxSize" ){
formatArgument( buffer, key, value, "%6.2f ", callId, 1 );
} else if( key == "cutoffDistance" ){
formatArgument( buffer, key, value, "%7.3f ", callId, 1 );
} else if( key == "relativeTolerance" ){
formatArgument( buffer, key, value, "%8.1e ", callId, 1 );
} else if( key == "positionPlacementMethod" || key == "applyAssert" || key == "serialize" ){
formatArgument( buffer, key, value, "%1d ", callId, 1 );
} else {
formatArgument( buffer, key, value, "%15.7e ", callId, 1 );
}
outputStream << buffer;
excludeAll[key] = 1;
}
}
}
for( MapStringToDoubleCI ii = inputArgumentMap.begin(); ii != inputArgumentMap.end(); ii++ ){
std::string key = ii->first;
if( excludeAll.find( key ) == excludeAll.end() ){
double value = ii->second;
int valueInt = static_cast<int>(value+0.00001);
double valueDouble = static_cast<double>(valueInt);
if( key == "numMolecules" ){
(void) sprintf( buffer, "%s=%6d ", key.c_str(), valueInt );
} else if( key == "nonbondedMethod" || key == "positionPlacementMethod" || key == "applyAssert" || key == "serialize" ){
(void) sprintf( buffer, "%s=%1d ", key.c_str(), valueInt );
} else if( key == "lambda1" || key == "lambda2" ){
(void) sprintf( buffer, "%s=%4.2f ", key.c_str(), value );
} else if( key == "boxSize" || key == "cutoffDistance" ){
(void) sprintf( buffer, "%s=%6.2f ", key.c_str(), value );
} else if( key == "relativeTolerance" ){
(void) sprintf( buffer, "%s=%8.1e ", key.c_str(), value );
} else if( valueDouble == value ){
(void) sprintf( buffer, "%s=%6d ", key.c_str(), valueInt );
} else {
(void) sprintf( buffer, "%s=%15.7e ", key.c_str(), value );
}
outputStream << buffer;
}
}
outputStream << std::endl;
return;
}
/**
* Get signature of a MapStringToDouble object
*
* @param inputArgumentMap map
* @return signature
*
*/
static double getMapStringToDoubleSignature( const MapStringToDouble& inputArgumentMap ){
double signature = 0.0;
double offset = 0.1;
for( MapStringToDoubleCI ii = inputArgumentMap.begin(); ii != inputArgumentMap.end(); ii++ ){
signature += (offset + ii->second);
offset += 0.1;
}
return signature;
}
/**
* Compare two MapStringToDouble to see if they have the same (key,value) pairs
*
* @param inputArgumentMap1 map 1
* @param inputArgumentMap2 map 2
*
* @return true if maps have same (key,value) pairs; otherwise false
*
*/
static bool compareMapStringToDoubles( const MapStringToDouble& inputArgumentMap1, const MapStringToDouble& inputArgumentMap2 ){
if( inputArgumentMap1.size() != inputArgumentMap1.size() ){
return false;
}
for( MapStringToDoubleCI ii = inputArgumentMap1.begin(); ii != inputArgumentMap1.end(); ii++ ){
MapStringToDoubleCI jj = inputArgumentMap2.find( (*ii).first );
if( jj == inputArgumentMap2.end() || jj->second != ii->second ){
return false;
}
}
return true;
}
/**
* Generate collection of inputArguments maps given
* list of DoubleVectors for each argument
*
* @param inputArguments map[argumentKey] = vector of double parameter values
* @param argumentMaps output vector of generated maps
*
*/
static void generateInputArgumentMapsFromStringVectors( const MapStringToDoubleVector& inputArguments,
VectorOfMapStringToDouble& argumentMaps ){
for( MapStringToDoubleVectorCI ii = inputArguments.begin(); ii != inputArguments.end(); ii++ ){
std::string argumentName = (*ii).first;
DoubleVector arguments = (*ii).second;
unsigned int initialArgumentMapSize = argumentMaps.size();
// generate signature map for each argument map
MapDoubleToInt signatures;
for( unsigned int kk = 0; kk < initialArgumentMapSize; kk++ ){
double signature = getMapStringToDoubleSignature( argumentMaps[kk] );
signatures[signature] = 1;
}
// for each current argumment map, add a new argument map w/ (key,value)
// check that no existing map has the same arguments before adding to the
// vector of argument maps
for( unsigned int kk = 0; kk < initialArgumentMapSize; kk++ ){
for( unsigned int jj = 0; jj < arguments.size(); jj++ ){
MapStringToDouble inputArgumentMap = MapStringToDouble(argumentMaps[kk]);
inputArgumentMap[argumentName] = arguments[jj];
double signature = getMapStringToDoubleSignature( inputArgumentMap );
if( signatures.find( signature ) == signatures.end() ){
argumentMaps.push_back( inputArgumentMap );
} else {
bool match = 0;
for( unsigned int mm = 0; mm < initialArgumentMapSize && !match; mm++ ){
match = compareMapStringToDoubles( inputArgumentMap, argumentMaps[mm] );
}
if( !match ){
argumentMaps.push_back( inputArgumentMap );
}
}
}
}
}
return;
}
/**
* Predicate for sorting map[string] = double
*
* @param d1 first MapStringToDouble to compare
* @param d2 second MapStringToDouble to compare
*
*/
bool TestMapSortPredicate( const MapStringToDouble& d1, const MapStringToDouble& d2 ){
StringVector sortOrder;
sortOrder.push_back( "numMolecules" );
sortOrder.push_back( "nonbondedMethod" );
sortOrder.push_back( "lambda2" );
sortOrder.push_back( "boxSize" );
for( unsigned int ii = 0; ii < sortOrder.size(); ii++ ){
if( d1.find( sortOrder[ii] ) != d1.end() &&
d2.find( sortOrder[ii] ) != d2.end() ){
MapStringToDoubleCI d1i = d1.find( sortOrder[ii] );
MapStringToDoubleCI d2i = d2.find( sortOrder[ii] );
if( d1i->second != d2i->second ){
return d1i->second < d2i->second;
}
}
}
return false;
}
#ifdef USE_SOFTCORE
static CustomNonbondedForce* buildCustomNonbondedSoftcoreForce( const NonbondedSoftcoreForce& nonbondedSoftcoreForce ){
CustomNonbondedForce* customNonbonded;
if( nonbondedSoftcoreForce.getNonbondedMethod() == NoCutoff ){
customNonbonded = new CustomNonbondedForce("lambda*4*eps*(dem^2-dem)+138.935456*q/r;"
"q=q1*q2;"
"dem=1.0/(soft+rsig);"
"rsig=(r/sigma)^6;"
"rsig=(r/sigma)^6;"
"soft=0.5*(1.0-lambda);"
"sigma=0.5*(sigma1+sigma2);"
"eps=sqrt(eps1*eps2);"
"lambda=min(lambda1,lambda2)");
customNonbonded->setNonbondedMethod( CustomNonbondedForce::NoCutoff );
} else {
customNonbonded = new CustomNonbondedForce("lambda*4*eps*(dem^2-dem)+138.935456*q*(1.0/r+(krf*r*r)-crf);"
"q=q1*q2;"
"dem=1.0/(soft+rsig);"
"rsig=(r/sigma)^6;"
"rsig=(r/sigma)^6;"
"soft=0.5*(1.0-lambda);"
"sigma=0.5*(sigma1+sigma2);"
"eps=sqrt(eps1*eps2);"
"lambda=min(lambda1,lambda2)");
customNonbonded->setCutoffDistance( nonbondedSoftcoreForce.getCutoffDistance() );
if( nonbondedSoftcoreForce.getNonbondedMethod() == CutoffNonPeriodic ){
customNonbonded->setNonbondedMethod( CustomNonbondedForce::CutoffNonPeriodic );
} else {
customNonbonded->setNonbondedMethod( CustomNonbondedForce::CutoffPeriodic );
}
double cutoffDistance = nonbondedSoftcoreForce.getCutoffDistance();
double reactionFieldDielectric = nonbondedSoftcoreForce.getReactionFieldDielectric();
double eps2 = (reactionFieldDielectric - 1.0)/(2.0*reactionFieldDielectric+1.0);
double kValue = eps2/(cutoffDistance*cutoffDistance*cutoffDistance);
customNonbonded->addGlobalParameter("krf", kValue );
double cValue = (1.0/cutoffDistance)*(3.0*reactionFieldDielectric)/(2.0*reactionFieldDielectric + 1.0);
customNonbonded->addGlobalParameter("crf", cValue );
}
customNonbonded->addPerParticleParameter("q");
customNonbonded->addPerParticleParameter("sigma");
customNonbonded->addPerParticleParameter("eps");
customNonbonded->addPerParticleParameter("lambda");
vector<double> nonbondedParams(4);
for( unsigned int ii = 0; ii < nonbondedSoftcoreForce.getNumParticles(); ii++ ){
double charge;
double sigma;
double epsilon;
double softcoreLJLambda;
nonbondedSoftcoreForce.getParticleParameters(ii, charge, sigma, epsilon, softcoreLJLambda);
nonbondedParams[0] = charge;
nonbondedParams[1] = sigma;
nonbondedParams[2] = epsilon;
nonbondedParams[3] = softcoreLJLambda;
customNonbonded->addParticle( nonbondedParams );
}
return customNonbonded;
}
CustomBondForce* buildCustomBondForceForNonbondedExceptions( const NonbondedSoftcoreForce& nonbondedSoftcoreForce ){
CustomBondForce* customBond;
if( nonbondedSoftcoreForce.getNonbondedMethod() == NoCutoff ){
customBond = new CustomBondForce("lambda*4*eps*(dem^2-dem)+138.935456*q/r;"
"dem=1.0/(soft+rsig);"
"rsig=(r/sigma)^6;"
"soft=0.5*(1.0-lambda)");
} else {
customBond = new CustomBondForce("withinCutoff*(lambda*4*eps*(dem^2-dem)+138.935456*q*(1.0/r+(krf*r*r)-crf));"
"withinCutoff=step(cutoff-r);"
"dem=1.0/(soft+rsig);"
"rsig=(r/sigma)^6;"
"soft=0.5*(1.0-lambda)");
double cutoffDistance = nonbondedSoftcoreForce.getCutoffDistance();
double reactionFieldDielectric = nonbondedSoftcoreForce.getReactionFieldDielectric();
double eps2 = (reactionFieldDielectric - 1.0)/(2.0*reactionFieldDielectric+1.0);
double kValue = eps2/(cutoffDistance*cutoffDistance*cutoffDistance);
customBond->addGlobalParameter("krf", kValue );
double cValue = (1.0/cutoffDistance)*(3.0*reactionFieldDielectric)/(2.0*reactionFieldDielectric + 1.0);
customBond->addGlobalParameter("crf", cValue );
customBond->addGlobalParameter("cutoff", cutoffDistance );
}
customBond->addPerBondParameter("q");
customBond->addPerBondParameter("sigma");
customBond->addPerBondParameter("eps");
customBond->addPerBondParameter("lambda");
for( unsigned int ii = 0; ii < nonbondedSoftcoreForce.getNumExceptions(); ii++ ){
int particle1, particle2;
double chargeProd;
double sigma;
double epsilon;
double softcoreLJLambda;
nonbondedSoftcoreForce.getExceptionParameters( ii, particle1, particle2, chargeProd, sigma, epsilon, softcoreLJLambda );
vector<double> bondParams(4);
bondParams[0] = chargeProd;
bondParams[1] = sigma;
bondParams[2] = epsilon;
bondParams[3] = softcoreLJLambda;
customBond->addBond( particle1, particle2, bondParams );
}
return customBond;
}
#endif
/**
* Load plugins
*
* @param pluginDirectory plugin directory; if OPENMM_PLUGIN_DIR use ENV variable
* @param log logging file (optional -- may be NULL)
*
*/
static int loadPlugins( const std::string& pluginDirectory, std::vector<std::string>& loaded, FILE* log ){
const char* openmmPluginDirectory;
int envVariableIsSet = 0;
if( pluginDirectory.compare( "OPENMM_PLUGIN_DIR") == 0 ){
openmmPluginDirectory = getenv( "OPENMM_PLUGIN_DIR" );
} else {
openmmPluginDirectory = pluginDirectory.c_str();
}
try {
if( openmmPluginDirectory ){
envVariableIsSet = 1;
if( log ){
(void) fprintf( log, "openmmPluginDirectory=%s\n", openmmPluginDirectory );
(void) fflush( log );
}
loaded = Platform::loadPluginsFromDirectory( openmmPluginDirectory );
if( log ){
(void) fprintf( log, "\nLoaded following %u lib(s) from %s:\n", static_cast<unsigned int>(loaded.size()), openmmPluginDirectory ); (void) fflush( log );
for( unsigned int ii = 0; ii < loaded.size(); ii++ ){
(void) fprintf( log, " %s\n", loaded[ii].c_str() );
}
(void) fprintf( log, "\n" ); (void) fflush( log );
}
} else {
if( log && pluginDirectory == "OPENMM_PLUGIN_DIR" ){
(void) fprintf( log, "Env variable OPENMM_PLUGIN_DIR is not set.\n" );
(void) fflush( log );
}
}
} catch(const exception& e) {
(void) fprintf( log, "Exception: %s\n", e.what() );
(void) fflush( log );
}
return envVariableIsSet;
}
/**
* Set device id
*
* @param platform platform
* @param deviceId device id
* @param log logging file (optional -- may be NULL)
*
*/
static void setDeviceId( Platform& platform, int deviceId, FILE* log ){
std::stringstream deviceIdStr;
deviceIdStr << deviceId;
int wasSet = 0;
if( platform.getName().compare( "Cuda" ) == 0 ){
platform.setPropertyDefaultValue( "CudaDevice", deviceIdStr.str() );
wasSet = 1;
} else if( platform.getName().compare( "OpenCL" ) == 0 ){
platform.setPropertyDefaultValue( "OpenCLDeviceIndex", deviceIdStr.str());
wasSet = 1;
}
if( log && wasSet ){
(void) fprintf( log, "Set deviceId to %d\n", deviceId );
(void) fflush( log );
}
return;
}
/**
* Set device id
*
* @param platform platform
* @param deviceId device id
* @param log logging file (optional -- may be NULL)
*
*/
static void setDeviceIdUsingEnvVariable( Platform& platform, FILE* log ){
const char* deviceId = getenv( "GPU_DEVICE_ID" );
if( deviceId == NULL ){
return;
}
int wasSet = 0;
if( platform.getName().compare( "Cuda" ) == 0 ){
platform.setPropertyDefaultValue( "CudaDevice", deviceId );
wasSet = 1;
} else if( platform.getName().compare( "OpenCL" ) == 0 ){
platform.setPropertyDefaultValue( "OpenCLDeviceIndex", deviceId);
wasSet = 1;
}
if( log && wasSet ){
(void) fprintf( log, "Set deviceId to %s based on env variable GPU_DEVICE_ID setting.\n", deviceId );
(void) fflush( log );
}
return;
}
/**
* Get platform name
*
* @param platformId platformId( 0=Reference, 1=Cuda, 2=OpenCL)
* @param platformName output platform name
*
*/
static void getPlatformName( int platformId, std::string& platformName ){
switch( platformId ){
case Reference_OpenMMTest:
platformName = "Reference";
break;
case Cuda_OpenMMTest:
platformName = "Cuda";
break;
case OpenCL_OpenMMTest:
platformName = "OpenCL";
break;
default:
platformName = "NA";
break;
}
return;
}
/**
* Get lib name
*
* @param libPrefix lib prefix (lib or "")
* @param libSuffix lib suffix (.so, .dylib, .dll)
* @param baseName base name
*
* @return libname
*
*/
static std::string getLibName( const std::string& libPrefix, const std::string& libSuffix, const std::string& baseName ){
std::string fullName = libPrefix;
fullName.append( baseName );
fullName.append( libSuffix );
return fullName;
}
/**
* Get nonbonded method name
*
* @param nonbondedMethod nonbonded method flag
* @return nonbonded method name
*
*/
static std::string getNonbondedMethodName( int nonbondedMethod ){
switch( nonbondedMethod ){
case NoCutoff_OpenMMTest:
return "NoCutoff";
case CutoffNonPeriodic_OpenMMTest:
return "CutoffNonPeriodic";
case CutoffPeriodic_OpenMMTest:
return "CutoffPeriodic";
case Ewald_OpenMMTest:
return "Ewald";
case PME_OpenMMTest:
return "PME";
default:
return "NA";
}
}
/**
* Check if required libs are available
*
* @param requiredLibs list of required libs
* @param loadedLibs list of available libs
* @param log optional logging reference
*
* @return 1 if all required libs are loaded; else 0
*
*/
static int checkRequiredLibsAreAvailable( const StringVector& requiredLibs, const StringVector& loadedLibs, FILE* log ){
unsigned int matchCount = 0;
for( unsigned int kk = 0; kk < requiredLibs.size(); kk++ ){
unsigned int match = 0;
for( unsigned int ii = 0; ii < loadedLibs.size() && match == 0; ii++ ){
if( loadedLibs[ii].compare( requiredLibs[kk] ) == 0 ){
match = 1;
}
}
if( log && !match ){
(void) fprintf( log, "Missing lib %s\n", requiredLibs[kk].c_str() );
}
matchCount += match;
}
int allPresent;
if( matchCount < requiredLibs.size() ){
allPresent = 0;
if( log ){
(void) fprintf( log, "Aborting tests due to missing libs.\n" );
}
} else {
allPresent = 1;
}
return allPresent;
}
/**
* Perform comparison of energies/forces for two systems
*
* @param system1 first system
* @param system2 second system
* @param platform1 first platform name (Reference, Cuda, OpenCL)
* @param platform2 second platform name (Reference, Cuda, OpenCL)
* @param positions positions
* @param inputArgumentMap arguments/flags (relativeTolerance, applyAssert, ...)
* @param idString id string
* @param log logging file (optional -- may be NULL)
*
*/
void runSystemComparisonTest( System& system1, System& system2,
const std::vector<Vec3>& positions, MapStringToDouble& inputArgumentMap,
const std::string& idString, FILE* log ){
int applyAssert = 0;
int platformId1 = 0;
int platformId2 = 0;
int deviceId1 = 0;
int deviceId2 = 0;
double relativeTolerance = 1.0e-04;
setDoubleFromMapStringToDouble( inputArgumentMap, "relativeTolerance", relativeTolerance );
setIntFromMapStringToDouble( inputArgumentMap, "applyAssert", applyAssert ) ;
setIntFromMapStringToDouble( inputArgumentMap, "platformId1", platformId1 ) ;
setIntFromMapStringToDouble( inputArgumentMap, "platformId2", platformId2 ) ;
setIntFromMapStringToDouble( inputArgumentMap, "deviceId1", deviceId1 ) ;
setIntFromMapStringToDouble( inputArgumentMap, "deviceId2", deviceId2 ) ;
std::string platformName1;
std::string platformName2;
getPlatformName( platformId1, platformName1 );
getPlatformName( platformId2, platformName2 );
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
if( log ){
(void) fprintf( log, "System1: particles=%d forces=%d System2: particles=%d forces=%d\n",
system1.getNumParticles(), system1.getNumForces(),
system2.getNumParticles(), system2.getNumForces() );
(void) fprintf( log, "Positions=%u\n", static_cast<unsigned int>(positions.size()) );
(void) fprintf( log, "Platform1=%s Platform2=%s\n", platformName1.c_str(), platformName2.c_str() );
(void) fprintf( log, "deviceId1=%d deviceId2=%d\n", deviceId1, deviceId2 );
(void) fprintf( log, "relativeTolerance=%8.2e applyAssert=%d\n", relativeTolerance, applyAssert );
MapStringInt stringForceVector1;
MapStringInt stringForceVector2;
getStringForceMap( system1, stringForceVector1, log );
(void) fprintf( log, "Forces in system 1: [" );
for( MapStringIntCI ii = stringForceVector1.begin(); ii != stringForceVector1.end(); ii++ ){
(void) fprintf( log, " %s ", ii->first.c_str() );
}
getStringForceMap( system2, stringForceVector2, log );
(void) fprintf( log, "]\nForces in system 2: [" );
for( MapStringIntCI ii = stringForceVector2.begin(); ii != stringForceVector2.end(); ii++ ){
(void) fprintf( log, " %s ", ii->first.c_str() );
}
(void) fprintf( log, "]\n" );
}
if( system1.getNumParticles() != system2.getNumParticles() ){
std::stringstream msg;
msg << "Number of particles for systems to be compared are unequal: " << system1.getNumParticles() << " != " << system2.getNumParticles();
throw OpenMMException( msg.str() );
}
if( system1.getNumParticles() != static_cast<int>(positions.size()) ){
std::stringstream msg;
msg << "Number of particles for system does not equal size of position array: " << system1.getNumParticles() << " != " << positions.size();
throw OpenMMException( msg.str() );
}
#if TEST_PLATFORM == TEST_OPENCL_PLATFORM
ReferencePlatform platform1;
OpenCLPlatform platform2;
#elif TEST_PLATFORM == TEST_CUDA_PLATFORM
ReferencePlatform platform1;
CudaPlatform platform2;
#else
Platform& platform1 = Platform::getPlatformByName( platformName1 );
if( deviceId1 ){
setDeviceId( platform1, deviceId1, log );
}
setDeviceIdUsingEnvVariable( platform1, log );
Platform& platform2 = Platform::getPlatformByName( platformName2 );
if( deviceId2 ){
setDeviceId( platform2, deviceId2, log );
}
setDeviceIdUsingEnvVariable( platform2, log );
#endif
Context context1( system1, integrator1, platform1 );
context1.setPositions(positions);
State state1 = context1.getState(State::Forces | State::Energy);
Context context2( system2, integrator2, platform2 );
context2.setPositions(positions);
State state2 = context2.getState(State::Forces | State::Energy);
double energyDiff = 0.0;
if( fabs( state1.getPotentialEnergy() ) > 0.0 || fabs( state2.getPotentialEnergy()) > 0.0 ){
energyDiff = fabs( state1.getPotentialEnergy() - state2.getPotentialEnergy() )/( fabs( state1.getPotentialEnergy() ) + fabs( state2.getPotentialEnergy() ) );
}
if( log ){
DoubleVector stats;
compareForcesOfTwoStates( state1, state2, relativeTolerance, stats, log );
(void) fprintf( log, "%s %6d eDff=%15.7e fMx=%15.7e fAvg=%15.7e fMed=%15.7e eCd=%15.7e eRf=%15.7e mxFIdx=%d\n",
idString.c_str(), system1.getNumParticles(), energyDiff,
stats[1], stats[0], stats[3], state1.getPotentialEnergy(), state2.getPotentialEnergy(), static_cast<int>(stats[2]+0.0001));
(void) fflush( log );
}
if( applyAssert ){
ASSERT( energyDiff < relativeTolerance );
for( int ii = 0; ii < system1.getNumParticles(); ii++ ){
Vec3 f1 = state1.getForces()[ii];
Vec3 f2 = state2.getForces()[ii];
double f1N = sqrt( (f1[0]*f1[0]) + (f1[1]*f1[1]) + (f1[2]*f1[2]) );
double f2N = sqrt( (f2[0]*f2[0]) + (f2[1]*f2[1]) + (f2[2]*f2[2]) );
double diff = (f1[0]-f2[0])*(f1[0]-f2[0]) +
(f1[1]-f2[1])*(f1[1]-f2[1]) +
(f1[2]-f2[2])*(f1[2]-f2[2]);
if( f1N > 0.0 || f1N > 0.0 ){
diff = 2.0*sqrt( diff )/(f1N + f2N);
}
ASSERT( diff < relativeTolerance );
}
}
}
/**
* Serialize system
*
* @param system system to serialize
* @param serializeFileName file name for xml output
* @param log logging file (optional -- may be NULL)
*
*/
void serializeSystem( System& system, const std::string& serializeFileName, FILE* log ){
#ifdef OPENMM_SERIALIZE
//registerAmoebaSerializationProxies();
std::stringstream buffer;
XmlSerializer::serialize<System>(&system, "System", buffer);
FILE* filePtr = fopen( serializeFileName.c_str(), "w" );
if( filePtr == NULL ){
if( log ){
(void) fprintf( log, "Unable to open xml file %s\n", serializeFileName.c_str() );
return;
}
}
(void) fprintf( filePtr, "%s", buffer.str().c_str() );
(void) fclose( filePtr );
if( log ){
(void) fprintf( log, "Wrote system to xml file %s\n", serializeFileName.c_str() );
}
#endif
return;
}
/**
* Output vector of Vec3 to file
*
* @param positions system to serialize
* @param fileName file name for output
* @param log logging file (optional -- may be NULL)
*
*/
void serializeVectorOfVec3( const std::vector<Vec3>& positions, std::string fileName, FILE* log ){
#ifdef OPENMM_SERIALIZE
FILE* filePtr = fopen( fileName.c_str(), "w" );
if( filePtr == NULL ){
if( log ){
(void) fprintf( log, "Unable to open Vec3 file %s\n", fileName.c_str() );
return;
}
}
(void) fprintf( filePtr, "Positions %u\n", static_cast<unsigned int>(positions.size()) );
for( unsigned int ii = 0; ii < positions.size(); ii++ ){
(void) fprintf( filePtr, "%9u %17.10e %17.10e %17.10e\n", ii, positions[ii][0], positions[ii][1], positions[ii][2] );
}
(void) fclose( filePtr );
if( log ){
(void) fprintf( log, "Wrote to file %s\n", fileName.c_str() );
}
#endif
return;
}
/**
* Serialize system and positions
*
* @param system system to serialize
* @param positions positions to output
* @param baseFileName base file name for xml/txt output
* @param log logging file (optional -- may be NULL)
*
*/
void serializeSystemAndPositions( System& system, const std::vector<Vec3>& positions, const std::string& baseFileName, FILE* log ){
std::stringstream xmlfileName;
xmlfileName << baseFileName << ".xml";
serializeSystem( system, xmlfileName.str(), log );
std::stringstream posfileName;
posfileName << baseFileName << ".txt";
serializeVectorOfVec3( positions, posfileName.str(), log );
return;
}
void runTests( MapStringToDouble& inputArgumentMap, FILE* log ){
double lambda1 = 1.0;
double lambda2 = 1.0;
int nonbondedMethod = 0;
int numMolecules = 1;
int numParticlesPerMolecule = 2;
int useQuinticSpline = 1;
int applyAssert = 1;
int positionPlacementMethod = 0;
int serialize = 0;
double boxSize = 10.0;
double relativeTolerance = 1.0e-04;
double quinticLowerLimitFactor = 0.8;
double quinticUpperBornRadiusLimit = 2.0;
std::stringstream baseFileName;
setDoubleFromMapStringToDouble( inputArgumentMap, "lambda1", lambda1 );
setDoubleFromMapStringToDouble( inputArgumentMap, "lambda2", lambda2 );
setDoubleFromMapStringToDouble( inputArgumentMap, "boxSize", boxSize );
double cutoffDistance = boxSize*0.4;
setDoubleFromMapStringToDouble( inputArgumentMap, "cutoffDistance", cutoffDistance);
setDoubleFromMapStringToDouble( inputArgumentMap, "relativeTolerance", relativeTolerance );
baseFileName << "Nb";
#if IMPLICIT_SOLVENT == TEST_GBVI
setDoubleFromMapStringToDouble( inputArgumentMap, "quinticLowerLimitFactor", quinticLowerLimitFactor );
setDoubleFromMapStringToDouble( inputArgumentMap, "quinticUpperBornRadiusLimit", quinticUpperBornRadiusLimit );
baseFileName << "Gbvi";
#endif
#if IMPLICIT_SOLVENT == TEST_OBC
baseFileName << "Obc";
#endif
setIntFromMapStringToDouble( inputArgumentMap, "positionPlacementMethod", positionPlacementMethod ) ;
setIntFromMapStringToDouble( inputArgumentMap, "nonbondedMethod", nonbondedMethod );
setIntFromMapStringToDouble( inputArgumentMap, "numMolecules", numMolecules );
setIntFromMapStringToDouble( inputArgumentMap, "numParticlesPerMolecule", numParticlesPerMolecule );
setIntFromMapStringToDouble( inputArgumentMap, "serialize", serialize );
setIntFromMapStringToDouble( inputArgumentMap, "applyAssert", applyAssert );
double bondDistance = 0.1;
double minDistance = 0.1;
double cellSize = 2.0*bondDistance + minDistance;
double boxLength = cellSize*pow( static_cast<double>(numMolecules), 0.333333 );
if( positionPlacementMethod == 1 && boxLength > boxSize ){
boxSize = boxLength;
if( log ){
// (void) fprintf( log, "Updated box size: bL=%6.3f cell=%6.2e bond=%5.2f separation=%5.2f\n", boxLength, cellSize, bondDistance, minDistance );
}
}
if( nonbondedMethod >= 2 && cutoffDistance > boxSize*0.5 ){
cutoffDistance = boxSize*0.49;
}
int numParticles = numMolecules*numParticlesPerMolecule;
int includeGbvi = 1;
double reactionFieldDielectric = 80.0;
if( log ){
double particleDensity = static_cast<double>(numParticles)/(boxSize*boxSize*boxSize);
double particleCube = pow( particleDensity, (-1.0/3.0) );
(void) fprintf( log, "\n--------------------------------------------------------------------------------------\n" );
(void) fprintf( log, "Input arguments\n" );
(void) fflush( log );
//(void) fprintf( log, " includeGbvi %d\n", includeGbvi );
(void) fprintf( log, " nonbondedMethod %d\n", nonbondedMethod );
(void) fprintf( log, " numParticles %d\n", numParticles );
(void) fprintf( log, " numMolecules %d\n", numMolecules );
(void) fprintf( log, " numParticlesPerMolecule %d\n", numParticlesPerMolecule );
(void) fprintf( log, " positionPlacementMethod %d\n", positionPlacementMethod);
(void) fprintf( log, " boxSize %8.3f\n", boxSize );
(void) fprintf( log, " cutoffDistance %15.7e\n", cutoffDistance );
(void) fprintf( log, " reactionFieldDielectric %8.3f\n", reactionFieldDielectric );
#if IMPLICIT_SOLVENT == TEST_GBVI
(void) fprintf( log, " useQuinticSpline %d\n", useQuinticSpline );
(void) fprintf( log, " quinticLowerLimitFactor %8.3f\n", quinticLowerLimitFactor );
(void) fprintf( log, " quinticUpperBornRadiusLimit %8.3f\n", quinticUpperBornRadiusLimit );
#endif
#ifdef USE_SOFTCORE
(void) fprintf( log, " lambda1 %8.3f\n", lambda1 );
(void) fprintf( log, " lambda2 %8.3f\n", lambda2 );
#endif
(void) fprintf( log, " relativeTolerance %8.1e\n", relativeTolerance );
(void) fprintf( log, " particleDensity %8.2e\n", particleDensity );
(void) fprintf( log, " particleCube %8.2e\n", particleCube );
}
// Create two systems: one with GbviSoftcoreForce NonbondedSoftcoreForce forces, and one using a CustomNonbondedForce, CustomGBVI force to implement the same interaction.
System standardSystem;
for (int i = 0; i < numParticles; i++) {
standardSystem.addParticle(1.0);
}
standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
double solventDielectric = 78.3; // 1.0 or 1.0e+10
double soluteDiecletric = 1.0;
std::vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
PositionGenerator positionGenerator( numMolecules, numParticlesPerMolecule, boxSize );
if( log ){
positionGenerator.setLog( log );
}
if( positionPlacementMethod == 1 ){
positionGenerator.setPositions( PositionGenerator::SimpleGrid, sfmt, positions );
} else {
positionGenerator.setBondDistance( 0.3 );
positionGenerator.setPositions( PositionGenerator::Random, sfmt, positions );
}
// show info on particle positions
if( log ){
int periodicBoundaryConditions = (nonbondedMethod > CutoffNonPeriodic_OpenMMTest) ? 1 : 0;
int showIndex = 5;
double distanceTolerance = 1.0e-04;
IntVector positionIndexVector;
positionIndexVector.push_back( 0 );
positionIndexVector.push_back( 5713 );
positionIndexVector.push_back( 6291 );
positionIndexVector.push_back( 3191 );
positionIndexVector.push_back( 3769 );
positionIndexVector.push_back( static_cast<int>(positions.size())-1 );
positionGenerator.showMinMaxDistances( positions, periodicBoundaryConditions, showIndex, positionIndexVector);
positionGenerator.showMinMaxDistances( positions, periodicBoundaryConditions, showIndex );
positionGenerator.showParticlesWithinDistance( positions, periodicBoundaryConditions, 5713, cutoffDistance, distanceTolerance );
positionGenerator.showParticlesWithinDistance( positions, periodicBoundaryConditions, 6291, cutoffDistance, distanceTolerance );
IntIntPairVector pairs;
pairs.push_back( IntIntPair( 5713, 6291 ) );
pairs.push_back( IntIntPair( 5713, 3191 ) );
pairs.push_back( IntIntPair( 5713, 3769 ) );
pairs.push_back( IntIntPair( 6291, 3191 ) );
positionGenerator.showDistances( pairs, positions );
}
const int numberOfParameters = 5;
std::vector<double> parameterLowerBound( numberOfParameters, 0.0 );
double fixedCharge = 0.1;
parameterLowerBound[ChargeIndex_OpenMMTest] = fixedCharge; // charge
parameterLowerBound[SigmaIndex_OpenMMTest] = 0.1; // sigma
parameterLowerBound[EpsIndex_OpenMMTest] = 0.5; // eps
parameterLowerBound[GammaIndex_OpenMMTest] = 0.1; // gamma
parameterLowerBound[LambdaIndex_OpenMMTest] = lambda1; // lambda
std::vector<double> parameterUpperBound( parameterLowerBound );
parameterUpperBound[ChargeIndex_OpenMMTest] = fixedCharge; // charge
parameterUpperBound[SigmaIndex_OpenMMTest] = 0.3; // sigma
parameterUpperBound[EpsIndex_OpenMMTest] = 40.0; // eps
parameterUpperBound[GammaIndex_OpenMMTest] = 40.0; // gamma
#if IMPLICIT_SOLVENT == TEST_OBC
parameterLowerBound[GammaIndex_OpenMMTest] = 0.1; // overlap factor
parameterUpperBound[GammaIndex_OpenMMTest] = 1.5;
#endif
std::vector<double> parameters( numberOfParameters );
VectorOfDoubleVectors parameterList;
std::vector< BondInfo_OpenMMTest > bonds;
double charge = fixedCharge;
for( int ii = 0; ii < numMolecules; ii++) {
charge *= -1.0;
double lambda = ii < (numMolecules/2) ? lambda1 : lambda2;
randomizeParameters( parameterLowerBound, parameterUpperBound, sfmt, parameters );
parameters[ChargeIndex_OpenMMTest] = charge;
parameters[LambdaIndex_OpenMMTest] = lambda;
parameterList.push_back( parameters );
int baseParticleIndex = ii*numParticlesPerMolecule;
for( int jj = 1; jj < numParticlesPerMolecule; jj++) {
// alternate charges
charge *= -1.0;
randomizeParameters( parameterLowerBound, parameterUpperBound, sfmt, parameters );
parameters[ChargeIndex_OpenMMTest] = charge;
parameters[LambdaIndex_OpenMMTest] = lambda;
parameterList.push_back( parameters );
double bondDistance = positionGenerator.getDistance( baseParticleIndex, baseParticleIndex+jj, positions );
bonds.push_back( BondInfo_OpenMMTest( baseParticleIndex, baseParticleIndex+jj, bondDistance ) );
}
// alternate charge if numParticlesPerMolecule is odd
if( (numParticlesPerMolecule % 2) ){
charge *= -1.0;
}
}
#ifdef USE_SOFTCORE
baseFileName << "Softcore";
NonbondedSoftcoreForce* nonbondedSoftcoreForce = getNonbondedSoftcoreForce( nonbondedMethod, cutoffDistance, reactionFieldDielectric,
parameterList, bonds, log);
#if IMPLICIT_SOLVENT == TEST_GBVI
GBVISoftcoreForce* gbviSoftcoreForce = getGBVISoftcoreForce( nonbondedMethod, nonbondedSoftcoreForce->getCutoffDistance(),
useQuinticSpline, quinticLowerLimitFactor, quinticUpperBornRadiusLimit,
solventDielectric, soluteDiecletric,
parameterList, bonds, log );
#endif
#if IMPLICIT_SOLVENT == TEST_OBC
GBSAOBCSoftcoreForce* gbviSoftcoreForce = getGBSAOBCSoftcoreForce( nonbondedMethod, nonbondedSoftcoreForce->getCutoffDistance(),
solventDielectric, soluteDiecletric,
parameterList, log );
#endif
#else
NonbondedForce* nonbondedSoftcoreForce = getNonbondedForce( nonbondedMethod, cutoffDistance, reactionFieldDielectric,
parameterList, bonds, log);
#if IMPLICIT_SOLVENT == TEST_GBVI
GBVIForce* gbviSoftcoreForce = getGBVIForce( nonbondedMethod, nonbondedSoftcoreForce->getCutoffDistance(),
useQuinticSpline, quinticLowerLimitFactor, quinticUpperBornRadiusLimit,
solventDielectric, soluteDiecletric, parameterList, bonds, log );
#endif
#if IMPLICIT_SOLVENT == TEST_OBC
GBSAOBCForce* gbviSoftcoreForce = getGBSAOBCForce( nonbondedMethod, nonbondedSoftcoreForce->getCutoffDistance(),
solventDielectric, soluteDiecletric, parameterList, log );
#endif
#endif
standardSystem.addForce(nonbondedSoftcoreForce);
#if IMPLICIT_SOLVENT > 0
if( includeGbvi ){
standardSystem.addForce(gbviSoftcoreForce);
}
#endif
// copy system and forces
System systemCopy;
copySystem( standardSystem, systemCopy, log );
// serialize
baseFileName << "_N" << positions.size();
baseFileName << "_Nb" << nonbondedMethod;
serializeSystemAndPositions( standardSystem, positions, baseFileName.str(), log);
// perform comparison
std::stringstream idString;
idString << "Nb " << nonbondedMethod << " l2 " << std::fixed << setprecision(2) << lambda2;
runSystemComparisonTest( standardSystem, systemCopy, positions, inputArgumentMap, idString.str(), log );
}
int main() {
try {
#ifdef USE_SOFTCORE
registerFreeEnergyCudaKernelFactories( );
#endif
VectorOfMapStringToDouble vectorOfMapStringToDouble;
MapStringToDouble inputArgumentMap;
MapStringToDoubleVector generativeArgumentMaps;
//FILE* log = stderr;
FILE* log = NULL;
std::vector<std::string> loadedLibs;
int envVariableIsSet = loadPlugins( "OPENMM_PLUGIN_DIR", loadedLibs, log );
inputArgumentMap["platformId1"] = 0;
inputArgumentMap["platformId2"] = 1;
inputArgumentMap["deviceId1"] = 0;
inputArgumentMap["deviceId2"] = 0;
inputArgumentMap["lambda2"] = 1.0;
inputArgumentMap["nonbondedMethod"] = 0;
inputArgumentMap["numMolecules"] = 10;
inputArgumentMap["boxSize"] = 5.0;
inputArgumentMap["positionPlacementMethod"] = 1;
inputArgumentMap["cutoffDistance"] = 0.301*inputArgumentMap["boxSize"];
//inputArgumentMap["cutoffDistance"] = 1.0;
inputArgumentMap["relativeTolerance"] = 5.0e-04;
inputArgumentMap["applyAssert"] = 1;
inputArgumentMap["serialize"] = 1;
inputArgumentMap["numParticlesPerMolecule"] = 2;
#ifdef USE_SOFTCORE
DoubleVector lamda2;
lamda2.push_back( 1.0 );
lamda2.push_back( 0.5 );
lamda2.push_back( 0.0 );
if( lamda2.size() > 0 ){
generativeArgumentMaps["lambda2"] = lamda2;
inputArgumentMap["lambda2"] = lamda2[0];
}
#endif
DoubleVector numberOfMolecules;
numberOfMolecules.push_back( 10 );
numberOfMolecules.push_back( 100 );
numberOfMolecules.push_back( 1000 );
numberOfMolecules.push_back( 2000 );
numberOfMolecules.push_back( 4000 );
//numberOfMolecules.push_back( 8000 );
if( numberOfMolecules.size() > 0 ){
generativeArgumentMaps["numMolecules"] = numberOfMolecules;
inputArgumentMap["numMolecules"] = numberOfMolecules[0];
}
DoubleVector nonbondedMethod;
nonbondedMethod.push_back( NoCutoff_OpenMMTest );
nonbondedMethod.push_back( CutoffNonPeriodic_OpenMMTest );
nonbondedMethod.push_back( CutoffPeriodic_OpenMMTest );
#if IMPLICIT_SOLVENT == TEST_NONBONDED
nonbondedMethod.push_back( Ewald_OpenMMTest );
nonbondedMethod.push_back( PME_OpenMMTest );
#endif
if( nonbondedMethod.size() > 0 ){
generativeArgumentMaps["nonbondedMethod"] = nonbondedMethod;
inputArgumentMap["nonbondedMethod"] = nonbondedMethod[0];
}
DoubleVector platformId2s;
#if TEST_PLATFORM == TEST_OPENCL_PLATFORM
platformId2s.push_back( OpenCL_OpenMMTest );
#elif TEST_PLATFORM == TEST_CUDA_PLATFORM
platformId2s.push_back( Cuda_OpenMMTest );
#else
platformId2s.push_back( Cuda_OpenMMTest );
#endif
// check that required libs are available for platform to be tested
// if unavailable, skip tests
std::string libPrefix = "lib";
std::string libSuffix = ".so";
#ifdef _MSC_VER
libPrefix = "";
libSuffix = ".dll";
#endif
#ifdef __APPLE__
libSuffix = ".dylib";
#endif
StringVector requiredLibs;
for( unsigned int kk = 0; kk < platformId2s.size(); kk++ ){
if( platformId2s[kk] == OpenCL_OpenMMTest ){
requiredLibs.push_back( getLibName( libPrefix, libSuffix, "OpenMMOpenCL" ) );
}
if( platformId2s[kk] == Cuda_OpenMMTest ){
requiredLibs.push_back( getLibName( libPrefix, libSuffix, "OpenMMCuda") );
#ifdef USE_SOFTCORE
requiredLibs.push_back( getLibName( libPrefix, libSuffix, "OpenMMFreeEnergy" ) );
requiredLibs.push_back( getLibName( libPrefix, libSuffix, "OpenMMFreeEnergyCuda" ) );
#endif
}
}
// if TEST_PLATFORM is not set, then check that required libs are available
#if TEST_PLATFORM != TEST_OPENCL_PLATFORM && TEST_PLATFORM != TEST_CUDA_PLATFORM
envVariableIsSet = checkRequiredLibsAreAvailable( requiredLibs, loadedLibs, log );
if( envVariableIsSet == 0 && log ){
(void) fprintf( log, "Aborting tests due to missing libs.\n" );
}
#else
// unit test path: force tests to run
envVariableIsSet = 1;
#endif
if( platformId2s.size() > 0 ){
generativeArgumentMaps["platformId2"] = platformId2s;
inputArgumentMap["platformId2"] = platformId2s[0];
}
vectorOfMapStringToDouble.push_back( inputArgumentMap );
generateInputArgumentMapsFromStringVectors( generativeArgumentMaps, vectorOfMapStringToDouble );
// modify relative tolerance for large systems
// case: Distance 433 669 1.5000001e+00 d2= 2.2500002e+00 w/ cutoff=1.500
for( unsigned int kk = 0; kk < vectorOfMapStringToDouble.size(); kk++ ){
int numMolecules = 0;
int numParticlesPerMolecule = 2;
setIntFromMapStringToDouble( vectorOfMapStringToDouble[kk], "numMolecules", numMolecules );
setIntFromMapStringToDouble( vectorOfMapStringToDouble[kk], "numParticlesPerMolecule", numParticlesPerMolecule );
if( numMolecules*numParticlesPerMolecule > 1000 ){
vectorOfMapStringToDouble[kk]["relativeTolerance"] = 6.0e-03;
}
}
if( log ){
MapStringToInt exclude;
exclude["lambda1"] = 1;
exclude["platformId1"] = 1;
exclude["platformId2"] = 1;
exclude["deviceId1"] = 1;
exclude["deviceId2"] = 1;
exclude["numParticlesPerMolecule"] = 1;
std::stringstream outputStream;
std::sort( vectorOfMapStringToDouble.begin(), vectorOfMapStringToDouble.end(), TestMapSortPredicate);
StringVector printOrder;
printOrder.push_back( "numMolecules" );
printOrder.push_back( "nonbondedMethod" );
printOrder.push_back( "lambda2" );
printOrder.push_back( "boxSize" );
for( unsigned int kk = 0; kk < vectorOfMapStringToDouble.size(); kk++ ){
streamArgumentMapOneLine( vectorOfMapStringToDouble[kk], exclude, printOrder, kk, outputStream );
}
(void) fprintf( log, "Initial argument maps: %u\n%s", static_cast<unsigned int>(vectorOfMapStringToDouble.size()), outputStream.str().c_str() );
}
// run tests
if( envVariableIsSet ){
int wasException = 0;
for( unsigned int kk = 0; kk < vectorOfMapStringToDouble.size() && wasException < 3; kk++ ){
try {
runTests( vectorOfMapStringToDouble[kk], log );
} catch(const exception& e) {
std::stringstream msg;
#if IMPLICIT_SOLVENT == TEST_NONBONDED
msg << "Nonbonded";
#elif IMPLICIT_SOLVENT == TEST_OBC
msg << "GBSAOBC";
#elif IMPLICIT_SOLVENT == TEST_GBVI
msg << "GBVI";
#endif
int numMolecules = 0;
int numParticlesPerMolecule = 0;
int nonbondedMethod = 0;
setIntFromMapStringToDouble( vectorOfMapStringToDouble[kk], "numMolecules", numMolecules );
setIntFromMapStringToDouble( vectorOfMapStringToDouble[kk], "numParticlesPerMolecule", numParticlesPerMolecule );
setIntFromMapStringToDouble( vectorOfMapStringToDouble[kk], "nonbondedMethod", nonbondedMethod);
msg << " test: system size=" << numMolecules*numParticlesPerMolecule << " nonbonded method=" << getNonbondedMethodName( nonbondedMethod );
msg << " exception: " << e.what() << endl;
// msg << "Note cases have been encountered for nonbonded methods with cutoffs where the error was due to particles being within 1.0e-05 of the cutoff." << endl;
cout << msg.str();
wasException += 1;
}
}
if( wasException ){
return 1;
}
}
} catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of HarmonicAngleForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/HarmonicAngleForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testAngles() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
HarmonicAngleForce* forceField = new HarmonicAngleForce();
forceField->addAngle(0, 1, 2, PI_M/3, 1.1);
forceField->addAngle(1, 2, 3, PI_M/2, 1.2);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(4);
positions[0] = Vec3(0, 1, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
positions[3] = Vec3(2, 1, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double torque1 = 1.1*PI_M/6;
double torque2 = 1.2*PI_M/4;
ASSERT_EQUAL_VEC(Vec3(torque1, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(-0.5*torque2, 0.5*torque2, 0), forces[3], TOL); // reduced by sqrt(2) due to the bond length, another sqrt(2) due to the angle
ASSERT_EQUAL_VEC(Vec3(forces[0][0]+forces[1][0]+forces[2][0]+forces[3][0], forces[0][1]+forces[1][1]+forces[2][1]+forces[3][1], forces[0][2]+forces[1][2]+forces[2][2]+forces[3][2]), Vec3(0, 0, 0), TOL);
ASSERT_EQUAL_TOL(0.5*1.1*(PI_M/6)*(PI_M/6) + 0.5*1.2*(PI_M/4)*(PI_M/4), state.getPotentialEnergy(), TOL);
}
void testCollinear() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
HarmonicAngleForce* forceField = new HarmonicAngleForce();
forceField->addAngle(0, 1, 2, M_PI * 120. / 180., 10.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(3);
for (int a = 0; a < 3; ++a)
{
positions[a] = OpenMM::Vec3(0.5*a,0,0); // location, nm
}
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double expectedEnergy = 10.0*0.5*(PI_M/3.0)*(PI_M/3.0);
#if 0
{
(void) fprintf( stderr, "testCollinear: E=%12.5f %12.5f\n", state.getPotentialEnergy(), expectedEnergy );
for (int a = 0; a < 3; ++a) {
(void) fprintf( stderr, "%3d F[%12.5f %12.5f %12.5f]\n", a, forces[a][0], forces[a][1], forces[a][2] );
}
}
#endif
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], TOL);
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), TOL);
}
int main() {
try {
testAngles();
testCollinear();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the Cuda implementation of HarmonicBondForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testBonds() {
CudaPlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
HarmonicBondForce* forceField = new HarmonicBondForce();
forceField->addBond(0, 1, 1.5, 0.8);
forceField->addBond(1, 2, 1.2, 0.7);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 2, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(0, -0.8*0.5, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0.7*0.2, 0, 0), forces[2], TOL);
ASSERT_EQUAL_VEC(Vec3(-forces[0][0]-forces[2][0], -forces[0][1]-forces[2][1], -forces[0][2]-forces[2][2]), forces[1], TOL);
ASSERT_EQUAL_TOL(0.5*0.8*0.5*0.5 + 0.5*0.7*0.2*0.2, state.getPotentialEnergy(), TOL);
}
int main() {
try {
cout << "Running test..." << endl;
testBonds();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
cout << "FAIL - ERROR. Test failed." << endl;
return 1;
}
cout << "PASS - Test succeeded." << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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-2009 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of LangevinIntegrator.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleBond() {
CudaPlatform platform;
System system;
system.addParticle(2.0);
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
HarmonicBondForce* forceField = new HarmonicBondForce();
forceField->addBond(0, 1, 1.5, 1);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// This is simply a damped harmonic oscillator, so compare it to the analytical solution.
double freq = std::sqrt(1-0.05*0.05);
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Velocities);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::exp(-0.05*time)*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
double expectedSpeed = -0.5*std::exp(-0.05*time)*(0.05*std::cos(freq*time)+freq*std::sin(freq*time));
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.02);
integrator.step(1);
}
// Not set the friction to a tiny value and see if it conserves energy.
integrator.setFriction(5e-5);
context.setPositions(positions);
State state = context.getState(State::Energy);
double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy();
for (int i = 0; i < 1000; ++i) {
state = context.getState(State::Energy);
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1);
}
}
void testTemperature() {
const int numParticles = 8;
const double temp = 100.0;
CudaPlatform platform;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.01);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
for (int i = 0; i < numParticles; ++i)
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the temperature is correct.
double ke = 0.0;
for (int i = 0; i < 10000; ++i) {
State state = context.getState(State::Energy);
ke += state.getKineticEnergy();
integrator.step(1);
}
ke /= 10000;
double expected = 0.5*numParticles*3*BOLTZ*temp;
ASSERT_USUALLY_EQUAL_TOL(expected, ke, 6/std::sqrt(10000.0));
}
void testConstraints() {
const int numParticles = 8;
const int numConstraints = 5;
const double temp = 100.0;
CudaPlatform platform;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.01);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
system.addConstraint(0, 1, 1.0);
system.addConstraint(1, 2, 1.0);
system.addConstraint(2, 3, 1.0);
system.addConstraint(4, 5, 1.0);
system.addConstraint(6, 7, 1.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3(i/2, (i+1)/2, 0);
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions);
for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4);
}
integrator.step(1);
}
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
CudaPlatform platform;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.01);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() {
try {
testSingleBond();
testTemperature();
testConstraints();
testRandomSeed();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment