From fbf13b1d5e8323491a24a1d7e8bdbfcc018005a3 Mon Sep 17 00:00:00 2001 From: Robert McGibbon Date: Tue, 1 Sep 2015 11:21:02 -0700 Subject: [PATCH 01/49] More typechecks --- .../swig_doxygen/swig_lib/python/typemaps.i | 112 +++++++++++++----- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i b/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i index 1d6a07b25..96c402422 100644 --- a/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i +++ b/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i @@ -137,6 +137,8 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { while ((item = PyIter_Next(iterator))) { item1 = Py_StripOpenMMUnits(item); if (item1 == NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); Py_DECREF(item); return SWIG_ERROR; } @@ -145,6 +147,8 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { Py_DECREF(item1); if (PyErr_Occurred() != NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); return SWIG_ERROR; } out.push_back(d); @@ -155,7 +159,51 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { } } +%fragment("Py_SequenceToVecVec3", "header", fragment="Py_SequenceToVec3") { +int Py_SequenceToVecVec3(PyObject* obj, std::vector& out) { + int ret = 0; + PyObject* stripped = NULL; + PyObject* item = NULL; + PyObject* item1 = NULL; + PyObject* iterator = NULL; + stripped = Py_StripOpenMMUnits(obj); // new reference + iterator = PyObject_GetIter(stripped); // new reference + + if (iterator == NULL) { + Py_DECREF(stripped); + return SWIG_ERROR; + } + + while ((item = PyIter_Next(iterator))) { // new reference + item1 = Py_StripOpenMMUnits(item); // new reference + if (item1 == NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); + Py_DECREF(item); + return SWIG_ERROR; + } + + OpenMM::Vec3 v = Py_SequenceToVec3(item1, ret); + Py_DECREF(item); + Py_DECREF(item1); + + if (!SWIG_IsOK(ret)) { + Py_DECREF(stripped); + Py_DECREF(iterator); + return SWIG_ERROR; + } + + out.push_back(v); + } + + Py_DECREF(iterator); + Py_DECREF(stripped); + return SWIG_OK; +} +} + +// ------ typemap for double ---- %typemap(typecheck, precedence=SWIG_TYPECHECK_DOUBLE, fragment="Py_StripOpenMMUnits") double { double argp = 0; PyObject* s = NULL; @@ -163,7 +211,6 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { $1 = (s != NULL) ? SWIG_IsOK(SWIG_AsVal_double(s, &argp)) : 0; Py_DECREF(s); } - %typemap(in, noblock=1, fragment="Py_StripOpenMMUnits") double (double argp = 0, int res = 0, PyObject* stripped = NULL) { @@ -179,6 +226,7 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { } +// ------ typemap for Vec3 %typemap(in, fragment="Py_SequenceToVec3") Vec3 (int res=0){ // typemap -- %typemap(in) Vec3 $1 = Py_SequenceToVec3($input, res); @@ -187,8 +235,14 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { SWIG_fail; } } +%typemap(typecheck, fragment="Py_SequenceToVec3") Vec3 { + int res = 0; + Py_SequenceToVec3($input, res); + $1 = SWIG_IsOK(res); +} +// typemap for const Vec3& %typemap(in, fragment="Py_SequenceToVec3") const Vec3& (OpenMM::Vec3 myVec, int res=0) { // typemap -- %typemap(in) Vec3 myVec = Py_SequenceToVec3($input, res); @@ -198,30 +252,32 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { } $1 = &myVec; } +%typemap(typecheck, fragment="Py_SequenceToVec3") const Vec3& { + int res = 0; + Py_SequenceToVec3($input, res); + $1 = SWIG_IsOK(res); +} -/* Convert python list of tuples to C++ std::vector of Vec3 objects */ -%typemap(in, fragment="Py_SequenceToVec3") const std::vector& (std::vector vVec, PyObject* s=NULL, PyObject* o=NULL) { - int i, pLength, ret; - s = Py_StripOpenMMUnits($input); - pLength = (int)PySequence_Length(s); - for (i = 0; i < pLength; i++) { - o = PySequence_GetItem(s, i); - OpenMM::Vec3 v = Py_SequenceToVec3(o, ret); - if (!SWIG_IsOK(ret)) { - Py_DECREF(s); - Py_DECREF(o); - PyErr_SetString(PyExc_ValueError, "in method $symname, argument $argnum could not be converted to type $type"); - SWIG_fail; - } - vVec.push_back(v); + +// typemap for vector +%typemap(in, fragment="Py_SequenceToVecVec3") const std::vector& (std::vector v, int res=0) { + res = Py_SequenceToVecVec3($input, v); + if (!SWIG_IsOK(res)) { + PyErr_SetString(PyExc_ValueError, "in method $symname, argument $argnum could not be converted to type $type"); + SWIG_fail; } - $1 = &vVec; - Py_DECREF(s); + $1 = &v; +} +%typemap(typecheck, precedence=SWIG_TYPECHECK_DOUBLE_ARRAY, fragment="Py_SequenceToVecVec3") const std::vector& { + std::vector v; + int res=0; + res = Py_SequenceToVecVec3($input, v); + $1 = SWIG_IsOK(res); } - +// typemap for const vector %typemap(in, fragment="Py_SequenceToVecDouble") const std::vector & (std::vector v, int res=0) { res = Py_SequenceToVecDouble($input, v); if (!SWIG_IsOK(res)) { @@ -230,6 +286,14 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { } $1 = &v; } +%typemap(typecheck, precedence=SWIG_TYPECHECK_DOUBLE_ARRAY) const std::vector & { + std::vector v; + int res = 0; + res = Py_SequenceToVecDouble($input, v); + $1 = SWIG_IsOK(res); +} + + /* The following two typemaps cause a non-const vector& to become a return value. */ %typemap(in, numinputs=0) std::vector& (std::vector temp) { @@ -260,17 +324,7 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { %typemap(argout) const std::vector& { } -/* Convert python tuple to C++ Vec3 object*/ -%typemap(typecheck) Vec3 { - // typemap -- %typemap(typecheck) Vec3 - $1 = (PySequence_Length($input) >= 3 ? 1 : 0); -} - -%typemap(typecheck) const Vec3& { - // typemap -- %typemap(typecheck) Vec3 - $1 = (PySequence_Length($input) >= 3 ? 1 : 0); -} %typemap(out) Vec3 { -- GitLab From cceb317136b392f8bc4df06bed5b05a1d89f8372 Mon Sep 17 00:00:00 2001 From: peastman Date: Fri, 18 Sep 2015 10:43:05 -0700 Subject: [PATCH 02/49] Reference implementation of periodicdistance() function for CustomExternalForce --- .../include/openmm/CustomExternalForce.h | 8 ++++ .../reference/include/ReferenceKernels.h | 13 ++++++ platforms/reference/src/ReferenceKernels.cpp | 46 ++++++++++++++++++- .../TestReferenceCustomExternalForce.cpp | 42 +++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/openmmapi/include/openmm/CustomExternalForce.h b/openmmapi/include/openmm/CustomExternalForce.h index 77be2d046..af4826322 100644 --- a/openmmapi/include/openmm/CustomExternalForce.h +++ b/openmmapi/include/openmm/CustomExternalForce.h @@ -67,6 +67,14 @@ namespace OpenMM { * force->addPerParticleParameter("z0"); * * + * Special care is needed in systems that use periodic boundary conditions. In that case, each particle really represents + * an infinite set of particles repeating through space. The variables x, y, and z contain the coordinates of one of those + * periodic copies, but there is no guarantee about which. It might even change from one time step to the next. You can handle + * this situation by using the function periodicdistance(x1, y1, z1, x2, y2, z2), which returns the minimum distance between + * periodic copies of the points (x1, y1, z1) and (x2, y2, z2). For example, the force given above would be rewritten as + * + * CustomExternalForce* force = new CustomExternalForce("k*periodicdistance(x, y, z, x0, y0, z0)^2"); + * * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. delta(x) = 1 if x is 0, 0 otherwise. diff --git a/platforms/reference/include/ReferenceKernels.h b/platforms/reference/include/ReferenceKernels.h index 5cc49a981..ca14215e9 100644 --- a/platforms/reference/include/ReferenceKernels.h +++ b/platforms/reference/include/ReferenceKernels.h @@ -37,6 +37,7 @@ #include "SimTKOpenMMRealType.h" #include "ReferenceNeighborList.h" #include "lepton/CompiledExpression.h" +#include "lepton/CustomFunction.h" #include "lepton/ExpressionProgram.h" namespace OpenMM { @@ -795,11 +796,23 @@ public: */ void copyParametersToContext(ContextImpl& context, const CustomExternalForce& force); private: + class PeriodicDistanceFunction; int numParticles; std::vector particles; RealOpenMM **particleParamArray; Lepton::CompiledExpression energyExpression, forceExpressionX, forceExpressionY, forceExpressionZ; std::vector parameterNames, globalParameterNames; + RealVec* boxVectors; +}; + +class ReferenceCalcCustomExternalForceKernel::PeriodicDistanceFunction : public Lepton::CustomFunction { +public: + RealVec** boxVectorHandle; + PeriodicDistanceFunction(RealVec** boxVectorHandle); + int getNumArguments() const; + double evaluate(const double* arguments) const; + double evaluateDerivative(const double* arguments, const int* derivOrder) const; + Lepton::CustomFunction* clone() const; }; /** diff --git a/platforms/reference/src/ReferenceKernels.cpp b/platforms/reference/src/ReferenceKernels.cpp index f9ed11daa..99b28c50e 100644 --- a/platforms/reference/src/ReferenceKernels.cpp +++ b/platforms/reference/src/ReferenceKernels.cpp @@ -1402,6 +1402,46 @@ void ReferenceCalcCustomGBForceKernel::copyParametersToContext(ContextImpl& cont } } +ReferenceCalcCustomExternalForceKernel::PeriodicDistanceFunction::PeriodicDistanceFunction(RealVec** boxVectorHandle) : boxVectorHandle(boxVectorHandle) { +} + +int ReferenceCalcCustomExternalForceKernel::PeriodicDistanceFunction::getNumArguments() const { + return 6; +} + +double ReferenceCalcCustomExternalForceKernel::PeriodicDistanceFunction::evaluate(const double* arguments) const { + RealVec* boxVectors = *boxVectorHandle; + RealVec delta = RealVec(arguments[0], arguments[1], arguments[2])-RealVec(arguments[3], arguments[4], arguments[5]); + delta -= boxVectors[2]*floor(delta[2]/boxVectors[2][2]+0.5); + delta -= boxVectors[1]*floor(delta[1]/boxVectors[1][1]+0.5); + delta -= boxVectors[0]*floor(delta[0]/boxVectors[0][0]+0.5); + return sqrt(delta.dot(delta)); +} + +double ReferenceCalcCustomExternalForceKernel::PeriodicDistanceFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const { + int argIndex = -1; + for (int i = 0; i < 6; i++) { + if (derivOrder[i] > 0) { + if (derivOrder[i] > 1 || argIndex != -1) + throw OpenMMException("Unsupported derivative of periodicdistance"); // Should be impossible for this to happen. + argIndex = i; + } + } + RealVec* boxVectors = *boxVectorHandle; + RealVec delta = RealVec(arguments[0], arguments[1], arguments[2])-RealVec(arguments[3], arguments[4], arguments[5]); + delta -= boxVectors[2]*floor(delta[2]/boxVectors[2][2]+0.5); + delta -= boxVectors[1]*floor(delta[1]/boxVectors[1][1]+0.5); + delta -= boxVectors[0]*floor(delta[0]/boxVectors[0][0]+0.5); + double r = sqrt(delta.dot(delta)); + if (argIndex < 3) + return delta[argIndex]/r; + return -delta[argIndex-3]/r; +} + +Lepton::CustomFunction* ReferenceCalcCustomExternalForceKernel::PeriodicDistanceFunction::clone() const { + return new PeriodicDistanceFunction(boxVectorHandle); +} + ReferenceCalcCustomExternalForceKernel::~ReferenceCalcCustomExternalForceKernel() { disposeRealArray(particleParamArray, numParticles); } @@ -1423,7 +1463,10 @@ void ReferenceCalcCustomExternalForceKernel::initialize(const System& system, co // Parse the expression used to calculate the force. - Lepton::ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction()).optimize(); + map functions; + PeriodicDistanceFunction periodicDistance(&boxVectors); + functions["periodicdistance"] = &periodicDistance; + Lepton::ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).optimize(); energyExpression = expression.createCompiledExpression(); forceExpressionX = expression.differentiate("x").createCompiledExpression(); forceExpressionY = expression.differentiate("y").createCompiledExpression(); @@ -1437,6 +1480,7 @@ void ReferenceCalcCustomExternalForceKernel::initialize(const System& system, co double ReferenceCalcCustomExternalForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); + boxVectors = extractBoxVectors(context); RealOpenMM energy = 0; map globalParameters; for (int i = 0; i < (int) globalParameterNames.size(); i++) diff --git a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp index e9ae2ff39..6121b3a56 100644 --- a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp @@ -101,9 +101,51 @@ void testForce() { } } +void testPeriodic() { + Vec3 vx(5, 0, 0); + Vec3 vy(0, 6, 0); + Vec3 vz(1, 2, 7); + double x0 = 51, y0 = -17, z0 = 11.2; + System system; + system.setDefaultPeriodicBoxVectors(vx, vy, vz); + system.addParticle(1.0); + CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); + force->addPerParticleParameter("x0"); + force->addPerParticleParameter("y0"); + force->addPerParticleParameter("z0"); + vector params(3); + params[0] = x0; + params[1] = y0; + params[2] = z0; + force->addParticle(0, params); + system.addForce(force); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + vector positions(1); + positions[0] = Vec3(0, 2, 0); + context.setPositions(positions); + for (int i = 0; i < 100; i++) { + State state = context.getState(State::Positions | State::Forces | State::Energy); + + // Apply periodic boundary conditions to the difference between the two positions. + + Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; + delta -= vz*floor(delta[2]/vz[2]+0.5); + delta -= vy*floor(delta[1]/vy[1]+0.5); + delta -= vx*floor(delta[0]/vx[0]+0.5); + + // Verify that the force and energy are correct. + + ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-6); + ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-6); + integrator.step(1); + } +} + int main() { try { testForce(); + testPeriodic(); } catch(const exception& e) { cout << "exception: " << e.what() << endl; -- GitLab From 0b77ab91b44e0a14b9f0822b23905aa621b70e0c Mon Sep 17 00:00:00 2001 From: peastman Date: Fri, 18 Sep 2015 11:56:25 -0700 Subject: [PATCH 03/49] Began CUDA implementation of periodicdistance() function for CustomExternalForce --- .../cuda/include/CudaExpressionUtilities.h | 10 +- .../cuda/src/CudaExpressionUtilities.cpp | 376 ++++++++++-------- platforms/cuda/src/CudaKernels.cpp | 4 +- .../tests/TestCudaCustomExternalForce.cpp | 44 +- .../TestReferenceCustomExternalForce.cpp | 2 +- 5 files changed, 265 insertions(+), 171 deletions(-) diff --git a/platforms/cuda/include/CudaExpressionUtilities.h b/platforms/cuda/include/CudaExpressionUtilities.h index fce27f54f..67e6bacc4 100644 --- a/platforms/cuda/include/CudaExpressionUtilities.h +++ b/platforms/cuda/include/CudaExpressionUtilities.h @@ -9,7 +9,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2009-2014 Stanford University and the Authors. * + * Portions copyright (c) 2009-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -89,6 +89,10 @@ public: * @param function the function for which to get a placeholder */ Lepton::CustomFunction* getFunctionPlaceholder(const TabulatedFunction& function); + /** + * Get a Lepton::CustomFunction that can be used to represent the periodicdistance() function when parsing expressions. + */ + Lepton::CustomFunction* getPeriodicDistancePlaceholder(); private: class FunctionPlaceholder : public Lepton::CustomFunction { public: @@ -114,13 +118,13 @@ private: const std::vector& functions, const std::vector >& functionNames, const std::string& prefix, const std::vector >& functionParams, const std::vector& allExpressions, const std::string& tempType); std::string getTempName(const Lepton::ExpressionTreeNode& node, const std::vector >& temps); - void findRelatedTabulatedFunctions(const Lepton::ExpressionTreeNode& node, const Lepton::ExpressionTreeNode& searchNode, + void findRelatedCustomFunctions(const Lepton::ExpressionTreeNode& node, const Lepton::ExpressionTreeNode& searchNode, std::vector& nodes); void findRelatedPowers(const Lepton::ExpressionTreeNode& node, const Lepton::ExpressionTreeNode& searchNode, std::map& powers); std::vector > computeFunctionParameters(const std::vector& functions); CudaContext& context; - FunctionPlaceholder fp1, fp2, fp3; + FunctionPlaceholder fp1, fp2, fp3, periodicDistance; }; } // namespace OpenMM diff --git a/platforms/cuda/src/CudaExpressionUtilities.cpp b/platforms/cuda/src/CudaExpressionUtilities.cpp index 1235592d4..f568159e0 100644 --- a/platforms/cuda/src/CudaExpressionUtilities.cpp +++ b/platforms/cuda/src/CudaExpressionUtilities.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2009-2014 Stanford University and the Authors. * + * Portions copyright (c) 2009-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -33,7 +33,7 @@ using namespace OpenMM; using namespace Lepton; using namespace std; -CudaExpressionUtilities::CudaExpressionUtilities(CudaContext& context) : context(context), fp1(1), fp2(2), fp3(3) { +CudaExpressionUtilities::CudaExpressionUtilities(CudaContext& context) : context(context), fp1(1), fp2(2), fp3(3), periodicDistance(6) { } string CudaExpressionUtilities::createExpressions(const map& expressions, const map& variables, @@ -79,11 +79,6 @@ void CudaExpressionUtilities::processExpression(stringstream& out, const Express throw OpenMMException("Unknown variable in expression: "+node.getOperation().getName()); case Operation::CUSTOM: { - int i; - for (i = 0; i < (int) functionNames.size() && functionNames[i].first != node.getOperation().getName(); i++) - ; - if (i == functionNames.size()) - throw OpenMMException("Unknown function in expression: "+node.getOperation().getName()); out << "0.0f;\n"; temps.push_back(make_pair(node, name)); hasRecordedNode = true; @@ -93,7 +88,7 @@ void CudaExpressionUtilities::processExpression(stringstream& out, const Express vector nodes; for (int j = 0; j < (int) allExpressions.size(); j++) - findRelatedTabulatedFunctions(node, allExpressions[j].getRootNode(), nodes); + findRelatedCustomFunctions(node, allExpressions[j].getRootNode(), nodes); vector nodeNames; nodeNames.push_back(name); for (int j = 1; j < (int) nodes.size(); j++) { @@ -103,175 +98,222 @@ void CudaExpressionUtilities::processExpression(stringstream& out, const Express temps.push_back(make_pair(*nodes[j], name2)); } out << "{\n"; - vector paramsFloat, paramsInt; - for (int j = 0; j < (int) functionParams[i].size(); j++) { - paramsFloat.push_back(context.doubleToString(functionParams[i][j])); - paramsInt.push_back(context.intToString((int) functionParams[i][j])); - } - if (dynamic_cast(functions[i]) != NULL) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "if (x >= " << paramsFloat[0] << " && x <= " << paramsFloat[1] << ") {\n"; - out << "x = (x - " << paramsFloat[0] << ")*" << paramsFloat[2] << ";\n"; - out << "int index = (int) (floor(x));\n"; - out << "index = min(index, (int) " << paramsInt[3] << ");\n"; - out << "float4 coeff = " << functionNames[i].second << "[index];\n"; - out << "real b = x-index;\n"; - out << "real a = 1.0f-b;\n"; - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0) - out << nodeNames[j] << " = a*coeff.x+b*coeff.y+((a*a*a-a)*coeff.z+(b*b*b-b)*coeff.w)/(" << paramsFloat[2] << "*" << paramsFloat[2] << ");\n"; - else - out << nodeNames[j] << " = (coeff.y-coeff.x)*" << paramsFloat[2] << "+((1.0f-3.0f*a*a)*coeff.z+(3.0f*b*b-1.0f)*coeff.w)/" << paramsFloat[2] << ";\n"; + if (node.getOperation().getName() == "periodicdistance") { + // This is the periodicdistance() function. + + out << tempType << " periodicDistance_delta = make_real3("; + for (int i = 0; i < 3; i++) { + if (i > 0) + out << ", "; + out << getTempName(node.getChildren()[i], temps) << "-" << getTempName(node.getChildren()[i+3], temps); + out << ");\n"; } - out << "}\n"; - } - else if (dynamic_cast(functions[i]) != NULL) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; - out << "if (x >= " << paramsFloat[2] << " && x <= " << paramsFloat[3] << " && y >= " << paramsFloat[4] << " && y <= " << paramsFloat[5] << ") {\n"; - out << "x = (x - " << paramsFloat[2] << ")*" << paramsFloat[6] << ";\n"; - out << "y = (y - " << paramsFloat[4] << ")*" << paramsFloat[7] << ";\n"; - out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; - out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; - out << "int coeffIndex = 4*(s+" << paramsInt[0] << "*t);\n"; - out << "float4 c[4];\n"; - for (int j = 0; j < 4; j++) - out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; - out << "real da = x-s;\n"; - out << "real db = y-t;\n"; + out << "APPLY_PERIODIC_TO_DELTA(periodicDistance_delta)\n"; + out << tempType << " periodicDistance_r = SQRT(periodicDistance_delta.x*periodicDistance_delta.x + periodicDistance_delta.y*periodicDistance_delta.y + periodicDistance_delta.z*periodicDistance_delta.z);\n"; for (int j = 0; j < nodes.size(); j++) { const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0) { - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[3].w*db + c[3].z)*db + c[3].y)*db + c[3].x;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[2].w*db + c[2].z)*db + c[2].y)*db + c[2].x;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[1].w*db + c[1].z)*db + c[1].y)*db + c[1].x;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[0].w*db + c[0].z)*db + c[0].y)*db + c[0].x;\n"; - } - else if (derivOrder[0] == 1 && derivOrder[1] == 0) { - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].w*da + 2.0f*c[2].w)*da + c[1].w;\n"; - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].z*da + 2.0f*c[2].z)*da + c[1].z;\n"; - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].y*da + 2.0f*c[2].y)*da + c[1].y;\n"; - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].x*da + 2.0f*c[2].x)*da + c[1].x;\n"; - out << nodeNames[j] << " *= " << paramsFloat[6] << ";\n"; - } - else if (derivOrder[0] == 0 && derivOrder[1] == 1) { - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[3].w*db + 2.0f*c[3].z)*db + c[3].y;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[2].w*db + 2.0f*c[2].z)*db + c[2].y;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[1].w*db + 2.0f*c[1].z)*db + c[1].y;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[0].w*db + 2.0f*c[0].z)*db + c[0].y;\n"; - out << nodeNames[j] << " *= " << paramsFloat[7] << ";\n"; + int argIndex = -1; + for (int k = 0; k < 6; k++) { + if (derivOrder[k] > 0) { + if (derivOrder[k] > 1 || argIndex != -1) + throw OpenMMException("Unsupported derivative of periodicdistance"); // Should be impossible for this to happen. + argIndex = k; + } } - else - throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); + if (argIndex == -1) + out << nodeNames[j] << " = periodicDistance_r;\n"; + else if (argIndex == 0) + out << nodeNames[j] << " = periodicDistance_delta.x/periodicDistance_r;\n"; + else if (argIndex == 1) + out << nodeNames[j] << " = periodicDistance_delta.y/periodicDistance_r;\n"; + else if (argIndex == 2) + out << nodeNames[j] << " = periodicDistance_delta.z/periodicDistance_r;\n"; + else if (argIndex == 3) + out << nodeNames[j] << " = -periodicDistance_delta.x/periodicDistance_r;\n"; + else if (argIndex == 4) + out << nodeNames[j] << " = -periodicDistance_delta.y/periodicDistance_r;\n"; + else if (argIndex == 5) + out << nodeNames[j] << " = -periodicDistance_delta.z/periodicDistance_r;\n"; } - out << "}\n"; } - else if (dynamic_cast(functions[i]) != NULL) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; - out << "real z = " << getTempName(node.getChildren()[2], temps) << ";\n"; - out << "if (x >= " << paramsFloat[3] << " && x <= " << paramsFloat[4] << " && y >= " << paramsFloat[5] << " && y <= " << paramsFloat[6] << " && z >= " << paramsFloat[7] << " && z <= " << paramsFloat[8] << ") {\n"; - out << "x = (x - " << paramsFloat[3] << ")*" << paramsFloat[9] << ";\n"; - out << "y = (y - " << paramsFloat[5] << ")*" << paramsFloat[10] << ";\n"; - out << "z = (z - " << paramsFloat[7] << ")*" << paramsFloat[11] << ";\n"; - out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; - out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; - out << "int u = min((int) floor(z), " << paramsInt[2] << ");\n"; - out << "int coeffIndex = 16*(s+" << paramsInt[0] << "*(t+" << paramsInt[1] << "*u));\n"; - out << "float4 c[16];\n"; - for (int j = 0; j < 16; j++) - out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; - out << "real da = x-s;\n"; - out << "real db = y-t;\n"; - out << "real dc = z-u;\n"; - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { - out << "real value[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = k + 4*m; - out << "value[" << m << "] = db*value[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; - } - out << nodeNames[j] << " = value[0] + dc*(value[1] + dc*(value[2] + dc*value[3]));\n"; - } - else if (derivOrder[0] == 1 && derivOrder[1] == 0 && derivOrder[2] == 0) { - out << "real derivx[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = k + 4*m; - out << "derivx[" << m << "] = db*derivx[" << m << "] + (3*c[" << base << "].w*da + 2*c[" << base << "].z)*da + c[" << base << "].y;\n"; - } - out << nodeNames[j] << " = derivx[0] + dc*(derivx[1] + dc*(derivx[2] + dc*derivx[3]));\n"; - out << nodeNames[j] << " *= " << paramsFloat[9] << ";\n"; + else { + // This is a tabulated function. + + int i; + for (i = 0; i < (int) functionNames.size() && functionNames[i].first != node.getOperation().getName(); i++) + ; + if (i == functionNames.size()) + throw OpenMMException("Unknown function in expression: "+node.getOperation().getName()); + vector paramsFloat, paramsInt; + for (int j = 0; j < (int) functionParams[i].size(); j++) { + paramsFloat.push_back(context.doubleToString(functionParams[i][j])); + paramsInt.push_back(context.intToString((int) functionParams[i][j])); + } + if (dynamic_cast(functions[i]) != NULL) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "if (x >= " << paramsFloat[0] << " && x <= " << paramsFloat[1] << ") {\n"; + out << "x = (x - " << paramsFloat[0] << ")*" << paramsFloat[2] << ";\n"; + out << "int index = (int) (floor(x));\n"; + out << "index = min(index, (int) " << paramsInt[3] << ");\n"; + out << "float4 coeff = " << functionNames[i].second << "[index];\n"; + out << "real b = x-index;\n"; + out << "real a = 1.0f-b;\n"; + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0) + out << nodeNames[j] << " = a*coeff.x+b*coeff.y+((a*a*a-a)*coeff.z+(b*b*b-b)*coeff.w)/(" << paramsFloat[2] << "*" << paramsFloat[2] << ");\n"; + else + out << nodeNames[j] << " = (coeff.y-coeff.x)*" << paramsFloat[2] << "+((1.0f-3.0f*a*a)*coeff.z+(3.0f*b*b-1.0f)*coeff.w)/" << paramsFloat[2] << ";\n"; } - else if (derivOrder[0] == 0 && derivOrder[1] == 1 && derivOrder[2] == 0) { - const string suffixes[] = {".x", ".y", ".z", ".w"}; - out << "real derivy[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = 4*m; - string suffix = suffixes[m]; - out << "derivy[" << m << "] = da*derivy[" << m << "] + (3*c[" << (base+3) << "]" << suffix << "*db + 2*c[" << (base+2) << "]" << suffix << ")*db + c[" << (base+1) << "]" << suffix << ";\n"; - } - out << nodeNames[j] << " = derivy[0] + dc*(derivy[1] + dc*(derivy[2] + dc*derivy[3]));\n"; - out << nodeNames[j] << " *= " << paramsFloat[10] << ";\n"; + out << "}\n"; + } + else if (dynamic_cast(functions[i]) != NULL) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; + out << "if (x >= " << paramsFloat[2] << " && x <= " << paramsFloat[3] << " && y >= " << paramsFloat[4] << " && y <= " << paramsFloat[5] << ") {\n"; + out << "x = (x - " << paramsFloat[2] << ")*" << paramsFloat[6] << ";\n"; + out << "y = (y - " << paramsFloat[4] << ")*" << paramsFloat[7] << ";\n"; + out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; + out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; + out << "int coeffIndex = 4*(s+" << paramsInt[0] << "*t);\n"; + out << "float4 c[4];\n"; + for (int j = 0; j < 4; j++) + out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; + out << "real da = x-s;\n"; + out << "real db = y-t;\n"; + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0) { + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[3].w*db + c[3].z)*db + c[3].y)*db + c[3].x;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[2].w*db + c[2].z)*db + c[2].y)*db + c[2].x;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[1].w*db + c[1].z)*db + c[1].y)*db + c[1].x;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[0].w*db + c[0].z)*db + c[0].y)*db + c[0].x;\n"; + } + else if (derivOrder[0] == 1 && derivOrder[1] == 0) { + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].w*da + 2.0f*c[2].w)*da + c[1].w;\n"; + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].z*da + 2.0f*c[2].z)*da + c[1].z;\n"; + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].y*da + 2.0f*c[2].y)*da + c[1].y;\n"; + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].x*da + 2.0f*c[2].x)*da + c[1].x;\n"; + out << nodeNames[j] << " *= " << paramsFloat[6] << ";\n"; + } + else if (derivOrder[0] == 0 && derivOrder[1] == 1) { + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[3].w*db + 2.0f*c[3].z)*db + c[3].y;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[2].w*db + 2.0f*c[2].z)*db + c[2].y;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[1].w*db + 2.0f*c[1].z)*db + c[1].y;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[0].w*db + 2.0f*c[0].z)*db + c[0].y;\n"; + out << nodeNames[j] << " *= " << paramsFloat[7] << ";\n"; + } + else + throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); } - else if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 1) { - out << "real derivz[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = k + 4*m; - out << "derivz[" << m << "] = db*derivz[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; - } - out << nodeNames[j] << " = derivz[1] + dc*(2*derivz[2] + dc*3*derivz[3]);\n"; - out << nodeNames[j] << " *= " << paramsFloat[11] << ";\n"; + out << "}\n"; + } + else if (dynamic_cast(functions[i]) != NULL) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; + out << "real z = " << getTempName(node.getChildren()[2], temps) << ";\n"; + out << "if (x >= " << paramsFloat[3] << " && x <= " << paramsFloat[4] << " && y >= " << paramsFloat[5] << " && y <= " << paramsFloat[6] << " && z >= " << paramsFloat[7] << " && z <= " << paramsFloat[8] << ") {\n"; + out << "x = (x - " << paramsFloat[3] << ")*" << paramsFloat[9] << ";\n"; + out << "y = (y - " << paramsFloat[5] << ")*" << paramsFloat[10] << ";\n"; + out << "z = (z - " << paramsFloat[7] << ")*" << paramsFloat[11] << ";\n"; + out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; + out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; + out << "int u = min((int) floor(z), " << paramsInt[2] << ");\n"; + out << "int coeffIndex = 16*(s+" << paramsInt[0] << "*(t+" << paramsInt[1] << "*u));\n"; + out << "float4 c[16];\n"; + for (int j = 0; j < 16; j++) + out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; + out << "real da = x-s;\n"; + out << "real db = y-t;\n"; + out << "real dc = z-u;\n"; + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { + out << "real value[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = k + 4*m; + out << "value[" << m << "] = db*value[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; + } + out << nodeNames[j] << " = value[0] + dc*(value[1] + dc*(value[2] + dc*value[3]));\n"; + } + else if (derivOrder[0] == 1 && derivOrder[1] == 0 && derivOrder[2] == 0) { + out << "real derivx[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = k + 4*m; + out << "derivx[" << m << "] = db*derivx[" << m << "] + (3*c[" << base << "].w*da + 2*c[" << base << "].z)*da + c[" << base << "].y;\n"; + } + out << nodeNames[j] << " = derivx[0] + dc*(derivx[1] + dc*(derivx[2] + dc*derivx[3]));\n"; + out << nodeNames[j] << " *= " << paramsFloat[9] << ";\n"; + } + else if (derivOrder[0] == 0 && derivOrder[1] == 1 && derivOrder[2] == 0) { + const string suffixes[] = {".x", ".y", ".z", ".w"}; + out << "real derivy[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = 4*m; + string suffix = suffixes[m]; + out << "derivy[" << m << "] = da*derivy[" << m << "] + (3*c[" << (base+3) << "]" << suffix << "*db + 2*c[" << (base+2) << "]" << suffix << ")*db + c[" << (base+1) << "]" << suffix << ";\n"; + } + out << nodeNames[j] << " = derivy[0] + dc*(derivy[1] + dc*(derivy[2] + dc*derivy[3]));\n"; + out << nodeNames[j] << " *= " << paramsFloat[10] << ";\n"; + } + else if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 1) { + out << "real derivz[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = k + 4*m; + out << "derivz[" << m << "] = db*derivz[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; + } + out << nodeNames[j] << " = derivz[1] + dc*(2*derivz[2] + dc*3*derivz[3]);\n"; + out << nodeNames[j] << " *= " << paramsFloat[11] << ";\n"; + } + else + throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); } - else - throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); + out << "}\n"; } - out << "}\n"; - } - else if (dynamic_cast(functions[i]) != NULL) { - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "if (x >= 0 && x < " << paramsInt[0] << ") {\n"; - out << "int index = (int) floor(x+0.5f);\n"; - out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; - out << "}\n"; + else if (dynamic_cast(functions[i]) != NULL) { + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "if (x >= 0 && x < " << paramsInt[0] << ") {\n"; + out << "int index = (int) floor(x+0.5f);\n"; + out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + out << "}\n"; + } } } - } - else if (dynamic_cast(functions[i]) != NULL) { - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0) { - out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; - out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; - out << "int xsize = (int) " << paramsInt[0] << ";\n"; - out << "int ysize = (int) " << paramsInt[1] << ";\n"; - out << "int index = x+y*xsize;\n"; - out << "if (index >= 0 && index < xsize*ysize)\n"; - out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + else if (dynamic_cast(functions[i]) != NULL) { + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0) { + out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; + out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; + out << "int xsize = (int) " << paramsInt[0] << ";\n"; + out << "int ysize = (int) " << paramsInt[1] << ";\n"; + out << "int index = x+y*xsize;\n"; + out << "if (index >= 0 && index < xsize*ysize)\n"; + out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + } } } - } - else if (dynamic_cast(functions[i]) != NULL) { - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { - out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; - out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; - out << "int z = (int) floor(" << getTempName(node.getChildren()[2], temps) << "+0.5f);\n"; - out << "int xsize = (int) " << paramsInt[0] << ";\n"; - out << "int ysize = (int) " << paramsInt[1] << ";\n"; - out << "int zsize = (int) " << paramsInt[2] << ";\n"; - out << "int index = x+(y+z*ysize)*xsize;\n"; - out << "if (index >= 0 && index < xsize*ysize*zsize)\n"; - out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + else if (dynamic_cast(functions[i]) != NULL) { + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { + out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; + out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; + out << "int z = (int) floor(" << getTempName(node.getChildren()[2], temps) << "+0.5f);\n"; + out << "int xsize = (int) " << paramsInt[0] << ";\n"; + out << "int ysize = (int) " << paramsInt[1] << ";\n"; + out << "int zsize = (int) " << paramsInt[2] << ";\n"; + out << "int index = x+(y+z*ysize)*xsize;\n"; + out << "if (index >= 0 && index < xsize*ysize*zsize)\n"; + out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + } } } } @@ -483,7 +525,7 @@ string CudaExpressionUtilities::getTempName(const ExpressionTreeNode& node, cons throw OpenMMException(out.str()); } -void CudaExpressionUtilities::findRelatedTabulatedFunctions(const ExpressionTreeNode& node, const ExpressionTreeNode& searchNode, +void CudaExpressionUtilities::findRelatedCustomFunctions(const ExpressionTreeNode& node, const ExpressionTreeNode& searchNode, vector& nodes) { if (searchNode.getOperation().getId() == Operation::CUSTOM && node.getOperation().getName() == searchNode.getOperation().getName()) { // Make sure the arguments are identical. @@ -504,7 +546,7 @@ void CudaExpressionUtilities::findRelatedTabulatedFunctions(const ExpressionTree } else for (int i = 0; i < (int) searchNode.getChildren().size(); i++) - findRelatedTabulatedFunctions(node, searchNode.getChildren()[i], nodes); + findRelatedCustomFunctions(node, searchNode.getChildren()[i], nodes); } void CudaExpressionUtilities::findRelatedPowers(const ExpressionTreeNode& node, const ExpressionTreeNode& searchNode, map& powers) { @@ -730,3 +772,7 @@ Lepton::CustomFunction* CudaExpressionUtilities::getFunctionPlaceholder(const Ta return &fp3; throw OpenMMException("getFunctionPlaceholder: Unknown function type"); } + +Lepton::CustomFunction* CudaExpressionUtilities::getPeriodicDistancePlaceholder() { + return &periodicDistance; +} \ No newline at end of file diff --git a/platforms/cuda/src/CudaKernels.cpp b/platforms/cuda/src/CudaKernels.cpp index 65692100b..61895fe0d 100644 --- a/platforms/cuda/src/CudaKernels.cpp +++ b/platforms/cuda/src/CudaKernels.cpp @@ -3652,7 +3652,9 @@ void CudaCalcCustomExternalForceKernel::initialize(const System& system, const C globalParamNames[i] = force.getGlobalParameterName(i); globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i); } - Lepton::ParsedExpression energyExpression = Lepton::Parser::parse(force.getEnergyFunction()).optimize(); + map customFunctions; + customFunctions["periodicdistance"] = cu.getExpressionUtilities().getPeriodicDistancePlaceholder(); + Lepton::ParsedExpression energyExpression = Lepton::Parser::parse(force.getEnergyFunction(), customFunctions).optimize(); Lepton::ParsedExpression forceExpressionX = energyExpression.differentiate("x").optimize(); Lepton::ParsedExpression forceExpressionY = energyExpression.differentiate("y").optimize(); Lepton::ParsedExpression forceExpressionZ = energyExpression.differentiate("z").optimize(); diff --git a/platforms/cuda/tests/TestCudaCustomExternalForce.cpp b/platforms/cuda/tests/TestCudaCustomExternalForce.cpp index eafdeec75..967c3b5a2 100644 --- a/platforms/cuda/tests/TestCudaCustomExternalForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomExternalForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -161,6 +161,47 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } +void testPeriodic() { + Vec3 vx(5, 0, 0); + Vec3 vy(0, 6, 0); + Vec3 vz(1, 2, 7); + double x0 = 51, y0 = -17, z0 = 11.2; + System system; + system.setDefaultPeriodicBoxVectors(vx, vy, vz); + system.addParticle(1.0); + CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); + force->addPerParticleParameter("x0"); + force->addPerParticleParameter("y0"); + force->addPerParticleParameter("z0"); + vector params(3); + params[0] = x0; + params[1] = y0; + params[2] = z0; + force->addParticle(0, params); + system.addForce(force); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + vector positions(1); + positions[0] = Vec3(0, 2, 0); + context.setPositions(positions); + for (int i = 0; i < 100; i++) { + State state = context.getState(State::Positions | State::Forces | State::Energy); + + // Apply periodic boundary conditions to the difference between the two positions. + + Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; + delta -= vz*floor(delta[2]/vz[2]+0.5); + delta -= vy*floor(delta[1]/vy[1]+0.5); + delta -= vx*floor(delta[0]/vx[0]+0.5); + + // Verify that the force and energy are correct. + + ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-6); + ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-6); + integrator.step(1); + } +} + int main(int argc, char* argv[]) { try { if (argc > 1) @@ -168,6 +209,7 @@ int main(int argc, char* argv[]) { testForce(); testManyParameters(); testParallelComputation(); + testPeriodic(); } catch(const exception& e) { cout << "exception: " << e.what() << endl; diff --git a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp index 6121b3a56..11ab9f3ff 100644 --- a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * -- GitLab From 91a8cc492283ceaee87b0267a43872a835a75103 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Fri, 18 Sep 2015 12:26:54 -0700 Subject: [PATCH 04/49] Finished CUDA implementation of periodicdistance() --- platforms/cuda/src/CudaBondedUtilities.cpp | 7 +++++- .../cuda/src/CudaExpressionUtilities.cpp | 22 +++++++++---------- .../tests/TestCudaCustomExternalForce.cpp | 4 ++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/platforms/cuda/src/CudaBondedUtilities.cpp b/platforms/cuda/src/CudaBondedUtilities.cpp index c1a353ee5..2eff4d27f 100644 --- a/platforms/cuda/src/CudaBondedUtilities.cpp +++ b/platforms/cuda/src/CudaBondedUtilities.cpp @@ -99,7 +99,7 @@ void CudaBondedUtilities::initialize(const System& system) { s<getElementSize()/4; @@ -161,6 +161,11 @@ void CudaBondedUtilities::computeInteractions(int groups) { kernelArgs.push_back(&context.getEnergyBuffer().getDevicePointer()); kernelArgs.push_back(&context.getPosq().getDevicePointer()); kernelArgs.push_back(NULL); + kernelArgs.push_back(context.getPeriodicBoxSizePointer()); + kernelArgs.push_back(context.getInvPeriodicBoxSizePointer()); + kernelArgs.push_back(context.getPeriodicBoxVecXPointer()); + kernelArgs.push_back(context.getPeriodicBoxVecYPointer()); + kernelArgs.push_back(context.getPeriodicBoxVecZPointer()); for (int i = 0; i < (int) atomIndices.size(); i++) for (int j = 0; j < (int) atomIndices[i].size(); j++) kernelArgs.push_back(&atomIndices[i][j]->getDevicePointer()); diff --git a/platforms/cuda/src/CudaExpressionUtilities.cpp b/platforms/cuda/src/CudaExpressionUtilities.cpp index f568159e0..88eb862d2 100644 --- a/platforms/cuda/src/CudaExpressionUtilities.cpp +++ b/platforms/cuda/src/CudaExpressionUtilities.cpp @@ -101,15 +101,15 @@ void CudaExpressionUtilities::processExpression(stringstream& out, const Express if (node.getOperation().getName() == "periodicdistance") { // This is the periodicdistance() function. - out << tempType << " periodicDistance_delta = make_real3("; + out << tempType << "3 periodicDistance_delta = make_real3("; for (int i = 0; i < 3; i++) { if (i > 0) out << ", "; out << getTempName(node.getChildren()[i], temps) << "-" << getTempName(node.getChildren()[i+3], temps); - out << ");\n"; } + out << ");\n"; out << "APPLY_PERIODIC_TO_DELTA(periodicDistance_delta)\n"; - out << tempType << " periodicDistance_r = SQRT(periodicDistance_delta.x*periodicDistance_delta.x + periodicDistance_delta.y*periodicDistance_delta.y + periodicDistance_delta.z*periodicDistance_delta.z);\n"; + out << tempType << " periodicDistance_rinv = RSQRT(periodicDistance_delta.x*periodicDistance_delta.x + periodicDistance_delta.y*periodicDistance_delta.y + periodicDistance_delta.z*periodicDistance_delta.z);\n"; for (int j = 0; j < nodes.size(); j++) { const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); int argIndex = -1; @@ -121,19 +121,19 @@ void CudaExpressionUtilities::processExpression(stringstream& out, const Express } } if (argIndex == -1) - out << nodeNames[j] << " = periodicDistance_r;\n"; + out << nodeNames[j] << " = RECIP(periodicDistance_rinv);\n"; else if (argIndex == 0) - out << nodeNames[j] << " = periodicDistance_delta.x/periodicDistance_r;\n"; + out << nodeNames[j] << " = periodicDistance_delta.x*periodicDistance_rinv;\n"; else if (argIndex == 1) - out << nodeNames[j] << " = periodicDistance_delta.y/periodicDistance_r;\n"; + out << nodeNames[j] << " = periodicDistance_delta.y*periodicDistance_rinv;\n"; else if (argIndex == 2) - out << nodeNames[j] << " = periodicDistance_delta.z/periodicDistance_r;\n"; + out << nodeNames[j] << " = periodicDistance_delta.z*periodicDistance_rinv;\n"; else if (argIndex == 3) - out << nodeNames[j] << " = -periodicDistance_delta.x/periodicDistance_r;\n"; + out << nodeNames[j] << " = -periodicDistance_delta.x*periodicDistance_rinv;\n"; else if (argIndex == 4) - out << nodeNames[j] << " = -periodicDistance_delta.y/periodicDistance_r;\n"; + out << nodeNames[j] << " = -periodicDistance_delta.y*periodicDistance_rinv;\n"; else if (argIndex == 5) - out << nodeNames[j] << " = -periodicDistance_delta.z/periodicDistance_r;\n"; + out << nodeNames[j] << " = -periodicDistance_delta.z*periodicDistance_rinv;\n"; } } else { @@ -775,4 +775,4 @@ Lepton::CustomFunction* CudaExpressionUtilities::getFunctionPlaceholder(const Ta Lepton::CustomFunction* CudaExpressionUtilities::getPeriodicDistancePlaceholder() { return &periodicDistance; -} \ No newline at end of file +} diff --git a/platforms/cuda/tests/TestCudaCustomExternalForce.cpp b/platforms/cuda/tests/TestCudaCustomExternalForce.cpp index 967c3b5a2..b024ab48d 100644 --- a/platforms/cuda/tests/TestCudaCustomExternalForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomExternalForce.cpp @@ -196,8 +196,8 @@ void testPeriodic() { // Verify that the force and energy are correct. - ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-6); - ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-6); + ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-5); + ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-5); integrator.step(1); } } -- GitLab From eaef52d918ba175104c331deee7f492a443a13a8 Mon Sep 17 00:00:00 2001 From: peastman Date: Fri, 18 Sep 2015 13:17:25 -0700 Subject: [PATCH 05/49] Created OpenCL implementation of periodicdistance() --- .../include/OpenCLExpressionUtilities.h | 10 +- .../opencl/src/OpenCLBondedUtilities.cpp | 21 +- .../opencl/src/OpenCLExpressionUtilities.cpp | 376 ++++++++++-------- platforms/opencl/src/OpenCLKernels.cpp | 4 +- .../tests/TestOpenCLCustomExternalForce.cpp | 44 +- 5 files changed, 282 insertions(+), 173 deletions(-) diff --git a/platforms/opencl/include/OpenCLExpressionUtilities.h b/platforms/opencl/include/OpenCLExpressionUtilities.h index a08e3f7de..834e1f7de 100644 --- a/platforms/opencl/include/OpenCLExpressionUtilities.h +++ b/platforms/opencl/include/OpenCLExpressionUtilities.h @@ -9,7 +9,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2009-2014 Stanford University and the Authors. * + * Portions copyright (c) 2009-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -89,6 +89,10 @@ public: * @param function the function for which to get a placeholder */ Lepton::CustomFunction* getFunctionPlaceholder(const TabulatedFunction& function); + /** + * Get a Lepton::CustomFunction that can be used to represent the periodicdistance() function when parsing expressions. + */ + Lepton::CustomFunction* getPeriodicDistancePlaceholder(); private: class FunctionPlaceholder : public Lepton::CustomFunction { public: @@ -114,13 +118,13 @@ private: const std::vector& functions, const std::vector >& functionNames, const std::string& prefix, const std::vector >& functionParams, const std::vector& allExpressions, const std::string& tempType); std::string getTempName(const Lepton::ExpressionTreeNode& node, const std::vector >& temps); - void findRelatedTabulatedFunctions(const Lepton::ExpressionTreeNode& node, const Lepton::ExpressionTreeNode& searchNode, + void findRelatedCustomFunctions(const Lepton::ExpressionTreeNode& node, const Lepton::ExpressionTreeNode& searchNode, std::vector& nodes); void findRelatedPowers(const Lepton::ExpressionTreeNode& node, const Lepton::ExpressionTreeNode& searchNode, std::map& powers); std::vector > computeFunctionParameters(const std::vector& functions); OpenCLContext& context; - FunctionPlaceholder fp1, fp2, fp3; + FunctionPlaceholder fp1, fp2, fp3, periodicDistance; }; } // namespace OpenMM diff --git a/platforms/opencl/src/OpenCLBondedUtilities.cpp b/platforms/opencl/src/OpenCLBondedUtilities.cpp index 59be389a9..431e4af4e 100644 --- a/platforms/opencl/src/OpenCLBondedUtilities.cpp +++ b/platforms/opencl/src/OpenCLBondedUtilities.cpp @@ -181,7 +181,7 @@ void OpenCLBondedUtilities::initialize(const System& system) { for (int i = 0; i < (int) prefixCode.size(); i++) s<(index++, context.getForceBuffers().getDeviceBuffer()); kernel.setArg(index++, context.getEnergyBuffer().getDeviceBuffer()); kernel.setArg(index++, context.getPosq().getDeviceBuffer()); - index++; + index += 6; for (int j = 0; j < (int) forceSets[i].size(); j++) { kernel.setArg(index++, atomIndices[forceSets[i][j]]->getDeviceBuffer()); kernel.setArg(index++, bufferIndices[forceSets[i][j]]->getDeviceBuffer()); @@ -277,7 +277,22 @@ void OpenCLBondedUtilities::computeInteractions(int groups) { } } for (int i = 0; i < (int) kernels.size(); i++) { - kernels[i].setArg(3, groups); + cl::Kernel& kernel = kernels[i]; + kernel.setArg(3, groups); + if (context.getUseDoublePrecision()) { + kernel.setArg(4, context.getPeriodicBoxSizeDouble()); + kernel.setArg(5, context.getInvPeriodicBoxSizeDouble()); + kernel.setArg(6, context.getPeriodicBoxVecXDouble()); + kernel.setArg(7, context.getPeriodicBoxVecYDouble()); + kernel.setArg(8, context.getPeriodicBoxVecZDouble()); + } + else { + kernel.setArg(4, context.getPeriodicBoxSize()); + kernel.setArg(5, context.getInvPeriodicBoxSize()); + kernel.setArg(6, context.getPeriodicBoxVecX()); + kernel.setArg(7, context.getPeriodicBoxVecY()); + kernel.setArg(8, context.getPeriodicBoxVecZ()); + } context.executeKernel(kernels[i], maxBonds); } } diff --git a/platforms/opencl/src/OpenCLExpressionUtilities.cpp b/platforms/opencl/src/OpenCLExpressionUtilities.cpp index 9d737d94f..ee3ae3b9e 100644 --- a/platforms/opencl/src/OpenCLExpressionUtilities.cpp +++ b/platforms/opencl/src/OpenCLExpressionUtilities.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2009-2014 Stanford University and the Authors. * + * Portions copyright (c) 2009-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -33,7 +33,7 @@ using namespace OpenMM; using namespace Lepton; using namespace std; -OpenCLExpressionUtilities::OpenCLExpressionUtilities(OpenCLContext& context) : context(context), fp1(1), fp2(2), fp3(3) { +OpenCLExpressionUtilities::OpenCLExpressionUtilities(OpenCLContext& context) : context(context), fp1(1), fp2(2), fp3(3), periodicDistance(6) { } string OpenCLExpressionUtilities::createExpressions(const map& expressions, const map& variables, @@ -79,11 +79,6 @@ void OpenCLExpressionUtilities::processExpression(stringstream& out, const Expre throw OpenMMException("Unknown variable in expression: "+node.getOperation().getName()); case Operation::CUSTOM: { - int i; - for (i = 0; i < (int) functionNames.size() && functionNames[i].first != node.getOperation().getName(); i++) - ; - if (i == functionNames.size()) - throw OpenMMException("Unknown function in expression: "+node.getOperation().getName()); out << "0.0f;\n"; temps.push_back(make_pair(node, name)); hasRecordedNode = true; @@ -93,7 +88,7 @@ void OpenCLExpressionUtilities::processExpression(stringstream& out, const Expre vector nodes; for (int j = 0; j < (int) allExpressions.size(); j++) - findRelatedTabulatedFunctions(node, allExpressions[j].getRootNode(), nodes); + findRelatedCustomFunctions(node, allExpressions[j].getRootNode(), nodes); vector nodeNames; nodeNames.push_back(name); for (int j = 1; j < (int) nodes.size(); j++) { @@ -103,175 +98,222 @@ void OpenCLExpressionUtilities::processExpression(stringstream& out, const Expre temps.push_back(make_pair(*nodes[j], name2)); } out << "{\n"; - vector paramsFloat, paramsInt; - for (int j = 0; j < (int) functionParams[i].size(); j++) { - paramsFloat.push_back(context.doubleToString(functionParams[i][j])); - paramsInt.push_back(context.intToString((int) functionParams[i][j])); - } - if (dynamic_cast(functions[i]) != NULL) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "if (x >= " << paramsFloat[0] << " && x <= " << paramsFloat[1] << ") {\n"; - out << "x = (x - " << paramsFloat[0] << ")*" << paramsFloat[2] << ";\n"; - out << "int index = (int) (floor(x));\n"; - out << "index = min(index, " << paramsInt[3] << ");\n"; - out << "float4 coeff = " << functionNames[i].second << "[index];\n"; - out << "real b = x-index;\n"; - out << "real a = 1.0f-b;\n"; - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0) - out << nodeNames[j] << " = a*coeff.x+b*coeff.y+((a*a*a-a)*coeff.z+(b*b*b-b)*coeff.w)/(" << paramsFloat[2] << "*" << paramsFloat[2] << ");\n"; - else - out << nodeNames[j] << " = (coeff.y-coeff.x)*" << paramsFloat[2] << "+((1.0f-3.0f*a*a)*coeff.z+(3.0f*b*b-1.0f)*coeff.w)/" << paramsFloat[2] << ";\n"; + if (node.getOperation().getName() == "periodicdistance") { + // This is the periodicdistance() function. + + out << tempType << "3 periodicDistance_delta = (real3) ("; + for (int i = 0; i < 3; i++) { + if (i > 0) + out << ", "; + out << getTempName(node.getChildren()[i], temps) << "-" << getTempName(node.getChildren()[i+3], temps); } - out << "}\n"; - } - else if (dynamic_cast(functions[i]) != NULL) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; - out << "if (x >= " << paramsFloat[2] << " && x <= " << paramsFloat[3] << " && y >= " << paramsFloat[4] << " && y <= " << paramsFloat[5] << ") {\n"; - out << "x = (x - " << paramsFloat[2] << ")*" << paramsFloat[6] << ";\n"; - out << "y = (y - " << paramsFloat[4] << ")*" << paramsFloat[7] << ";\n"; - out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; - out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; - out << "int coeffIndex = 4*(s+" << paramsInt[0] << "*t);\n"; - out << "float4 c[4];\n"; - for (int j = 0; j < 4; j++) - out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; - out << "real da = x-s;\n"; - out << "real db = y-t;\n"; + out << ");\n"; + out << "APPLY_PERIODIC_TO_DELTA(periodicDistance_delta)\n"; + out << tempType << " periodicDistance_rinv = RSQRT(periodicDistance_delta.x*periodicDistance_delta.x + periodicDistance_delta.y*periodicDistance_delta.y + periodicDistance_delta.z*periodicDistance_delta.z);\n"; for (int j = 0; j < nodes.size(); j++) { const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0) { - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[3].w*db + c[3].z)*db + c[3].y)*db + c[3].x;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[2].w*db + c[2].z)*db + c[2].y)*db + c[2].x;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[1].w*db + c[1].z)*db + c[1].y)*db + c[1].x;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[0].w*db + c[0].z)*db + c[0].y)*db + c[0].x;\n"; - } - else if (derivOrder[0] == 1 && derivOrder[1] == 0) { - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].w*da + 2.0f*c[2].w)*da + c[1].w;\n"; - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].z*da + 2.0f*c[2].z)*da + c[1].z;\n"; - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].y*da + 2.0f*c[2].y)*da + c[1].y;\n"; - out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].x*da + 2.0f*c[2].x)*da + c[1].x;\n"; - out << nodeNames[j] << " *= " << paramsFloat[6] << ";\n"; - } - else if (derivOrder[0] == 0 && derivOrder[1] == 1) { - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[3].w*db + 2.0f*c[3].z)*db + c[3].y;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[2].w*db + 2.0f*c[2].z)*db + c[2].y;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[1].w*db + 2.0f*c[1].z)*db + c[1].y;\n"; - out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[0].w*db + 2.0f*c[0].z)*db + c[0].y;\n"; - out << nodeNames[j] << " *= " << paramsFloat[7] << ";\n"; + int argIndex = -1; + for (int k = 0; k < 6; k++) { + if (derivOrder[k] > 0) { + if (derivOrder[k] > 1 || argIndex != -1) + throw OpenMMException("Unsupported derivative of periodicdistance"); // Should be impossible for this to happen. + argIndex = k; + } } - else - throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); + if (argIndex == -1) + out << nodeNames[j] << " = RECIP(periodicDistance_rinv);\n"; + else if (argIndex == 0) + out << nodeNames[j] << " = periodicDistance_delta.x*periodicDistance_rinv;\n"; + else if (argIndex == 1) + out << nodeNames[j] << " = periodicDistance_delta.y*periodicDistance_rinv;\n"; + else if (argIndex == 2) + out << nodeNames[j] << " = periodicDistance_delta.z*periodicDistance_rinv;\n"; + else if (argIndex == 3) + out << nodeNames[j] << " = -periodicDistance_delta.x*periodicDistance_rinv;\n"; + else if (argIndex == 4) + out << nodeNames[j] << " = -periodicDistance_delta.y*periodicDistance_rinv;\n"; + else if (argIndex == 5) + out << nodeNames[j] << " = -periodicDistance_delta.z*periodicDistance_rinv;\n"; } - out << "}\n"; } - else if (dynamic_cast(functions[i]) != NULL) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; - out << "real z = " << getTempName(node.getChildren()[2], temps) << ";\n"; - out << "if (x >= " << paramsFloat[3] << " && x <= " << paramsFloat[4] << " && y >= " << paramsFloat[5] << " && y <= " << paramsFloat[6] << " && z >= " << paramsFloat[7] << " && z <= " << paramsFloat[8] << ") {\n"; - out << "x = (x - " << paramsFloat[3] << ")*" << paramsFloat[9] << ";\n"; - out << "y = (y - " << paramsFloat[5] << ")*" << paramsFloat[10] << ";\n"; - out << "z = (z - " << paramsFloat[7] << ")*" << paramsFloat[11] << ";\n"; - out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; - out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; - out << "int u = min((int) floor(z), " << paramsInt[2] << ");\n"; - out << "int coeffIndex = 16*(s+" << paramsInt[0] << "*(t+" << paramsInt[1] << "*u));\n"; - out << "float4 c[16];\n"; - for (int j = 0; j < 16; j++) - out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; - out << "real da = x-s;\n"; - out << "real db = y-t;\n"; - out << "real dc = z-u;\n"; - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { - out << "real value[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = k + 4*m; - out << "value[" << m << "] = db*value[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; - } - out << nodeNames[j] << " = value[0] + dc*(value[1] + dc*(value[2] + dc*value[3]));\n"; - } - else if (derivOrder[0] == 1 && derivOrder[1] == 0 && derivOrder[2] == 0) { - out << "real derivx[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = k + 4*m; - out << "derivx[" << m << "] = db*derivx[" << m << "] + (3*c[" << base << "].w*da + 2*c[" << base << "].z)*da + c[" << base << "].y;\n"; - } - out << nodeNames[j] << " = derivx[0] + dc*(derivx[1] + dc*(derivx[2] + dc*derivx[3]));\n"; - out << nodeNames[j] << " *= " << paramsFloat[9] << ";\n"; + else { + // This is a tabulated function. + + int i; + for (i = 0; i < (int) functionNames.size() && functionNames[i].first != node.getOperation().getName(); i++) + ; + if (i == functionNames.size()) + throw OpenMMException("Unknown function in expression: "+node.getOperation().getName()); + vector paramsFloat, paramsInt; + for (int j = 0; j < (int) functionParams[i].size(); j++) { + paramsFloat.push_back(context.doubleToString(functionParams[i][j])); + paramsInt.push_back(context.intToString((int) functionParams[i][j])); + } + if (dynamic_cast(functions[i]) != NULL) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "if (x >= " << paramsFloat[0] << " && x <= " << paramsFloat[1] << ") {\n"; + out << "x = (x - " << paramsFloat[0] << ")*" << paramsFloat[2] << ";\n"; + out << "int index = (int) (floor(x));\n"; + out << "index = min(index, " << paramsInt[3] << ");\n"; + out << "float4 coeff = " << functionNames[i].second << "[index];\n"; + out << "real b = x-index;\n"; + out << "real a = 1.0f-b;\n"; + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0) + out << nodeNames[j] << " = a*coeff.x+b*coeff.y+((a*a*a-a)*coeff.z+(b*b*b-b)*coeff.w)/(" << paramsFloat[2] << "*" << paramsFloat[2] << ");\n"; + else + out << nodeNames[j] << " = (coeff.y-coeff.x)*" << paramsFloat[2] << "+((1.0f-3.0f*a*a)*coeff.z+(3.0f*b*b-1.0f)*coeff.w)/" << paramsFloat[2] << ";\n"; } - else if (derivOrder[0] == 0 && derivOrder[1] == 1 && derivOrder[2] == 0) { - const string suffixes[] = {".x", ".y", ".z", ".w"}; - out << "real derivy[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = 4*m; - string suffix = suffixes[m]; - out << "derivy[" << m << "] = da*derivy[" << m << "] + (3*c[" << (base+3) << "]" << suffix << "*db + 2*c[" << (base+2) << "]" << suffix << ")*db + c[" << (base+1) << "]" << suffix << ";\n"; - } - out << nodeNames[j] << " = derivy[0] + dc*(derivy[1] + dc*(derivy[2] + dc*derivy[3]));\n"; - out << nodeNames[j] << " *= " << paramsFloat[10] << ";\n"; + out << "}\n"; + } + else if (dynamic_cast(functions[i]) != NULL) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; + out << "if (x >= " << paramsFloat[2] << " && x <= " << paramsFloat[3] << " && y >= " << paramsFloat[4] << " && y <= " << paramsFloat[5] << ") {\n"; + out << "x = (x - " << paramsFloat[2] << ")*" << paramsFloat[6] << ";\n"; + out << "y = (y - " << paramsFloat[4] << ")*" << paramsFloat[7] << ";\n"; + out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; + out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; + out << "int coeffIndex = 4*(s+" << paramsInt[0] << "*t);\n"; + out << "float4 c[4];\n"; + for (int j = 0; j < 4; j++) + out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; + out << "real da = x-s;\n"; + out << "real db = y-t;\n"; + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0) { + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[3].w*db + c[3].z)*db + c[3].y)*db + c[3].x;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[2].w*db + c[2].z)*db + c[2].y)*db + c[2].x;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[1].w*db + c[1].z)*db + c[1].y)*db + c[1].x;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + ((c[0].w*db + c[0].z)*db + c[0].y)*db + c[0].x;\n"; + } + else if (derivOrder[0] == 1 && derivOrder[1] == 0) { + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].w*da + 2.0f*c[2].w)*da + c[1].w;\n"; + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].z*da + 2.0f*c[2].z)*da + c[1].z;\n"; + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].y*da + 2.0f*c[2].y)*da + c[1].y;\n"; + out << nodeNames[j] << " = db*" << nodeNames[j] << " + (3.0f*c[3].x*da + 2.0f*c[2].x)*da + c[1].x;\n"; + out << nodeNames[j] << " *= " << paramsFloat[6] << ";\n"; + } + else if (derivOrder[0] == 0 && derivOrder[1] == 1) { + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[3].w*db + 2.0f*c[3].z)*db + c[3].y;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[2].w*db + 2.0f*c[2].z)*db + c[2].y;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[1].w*db + 2.0f*c[1].z)*db + c[1].y;\n"; + out << nodeNames[j] << " = da*" << nodeNames[j] << " + (3.0f*c[0].w*db + 2.0f*c[0].z)*db + c[0].y;\n"; + out << nodeNames[j] << " *= " << paramsFloat[7] << ";\n"; + } + else + throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); } - else if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 1) { - out << "real derivz[4] = {0, 0, 0, 0};\n"; - for (int k = 3; k >= 0; k--) - for (int m = 0; m < 4; m++) { - int base = k + 4*m; - out << "derivz[" << m << "] = db*derivz[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; - } - out << nodeNames[j] << " = derivz[1] + dc*(2*derivz[2] + dc*3*derivz[3]);\n"; - out << nodeNames[j] << " *= " << paramsFloat[11] << ";\n"; + out << "}\n"; + } + else if (dynamic_cast(functions[i]) != NULL) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "real y = " << getTempName(node.getChildren()[1], temps) << ";\n"; + out << "real z = " << getTempName(node.getChildren()[2], temps) << ";\n"; + out << "if (x >= " << paramsFloat[3] << " && x <= " << paramsFloat[4] << " && y >= " << paramsFloat[5] << " && y <= " << paramsFloat[6] << " && z >= " << paramsFloat[7] << " && z <= " << paramsFloat[8] << ") {\n"; + out << "x = (x - " << paramsFloat[3] << ")*" << paramsFloat[9] << ";\n"; + out << "y = (y - " << paramsFloat[5] << ")*" << paramsFloat[10] << ";\n"; + out << "z = (z - " << paramsFloat[7] << ")*" << paramsFloat[11] << ";\n"; + out << "int s = min((int) floor(x), " << paramsInt[0] << ");\n"; + out << "int t = min((int) floor(y), " << paramsInt[1] << ");\n"; + out << "int u = min((int) floor(z), " << paramsInt[2] << ");\n"; + out << "int coeffIndex = 16*(s+" << paramsInt[0] << "*(t+" << paramsInt[1] << "*u));\n"; + out << "float4 c[16];\n"; + for (int j = 0; j < 16; j++) + out << "c[" << j << "] = " << functionNames[i].second << "[coeffIndex+" << j << "];\n"; + out << "real da = x-s;\n"; + out << "real db = y-t;\n"; + out << "real dc = z-u;\n"; + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { + out << "real value[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = k + 4*m; + out << "value[" << m << "] = db*value[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; + } + out << nodeNames[j] << " = value[0] + dc*(value[1] + dc*(value[2] + dc*value[3]));\n"; + } + else if (derivOrder[0] == 1 && derivOrder[1] == 0 && derivOrder[2] == 0) { + out << "real derivx[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = k + 4*m; + out << "derivx[" << m << "] = db*derivx[" << m << "] + (3*c[" << base << "].w*da + 2*c[" << base << "].z)*da + c[" << base << "].y;\n"; + } + out << nodeNames[j] << " = derivx[0] + dc*(derivx[1] + dc*(derivx[2] + dc*derivx[3]));\n"; + out << nodeNames[j] << " *= " << paramsFloat[9] << ";\n"; + } + else if (derivOrder[0] == 0 && derivOrder[1] == 1 && derivOrder[2] == 0) { + const string suffixes[] = {".x", ".y", ".z", ".w"}; + out << "real derivy[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = 4*m; + string suffix = suffixes[m]; + out << "derivy[" << m << "] = da*derivy[" << m << "] + (3*c[" << (base+3) << "]" << suffix << "*db + 2*c[" << (base+2) << "]" << suffix << ")*db + c[" << (base+1) << "]" << suffix << ";\n"; + } + out << nodeNames[j] << " = derivy[0] + dc*(derivy[1] + dc*(derivy[2] + dc*derivy[3]));\n"; + out << nodeNames[j] << " *= " << paramsFloat[10] << ";\n"; + } + else if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 1) { + out << "real derivz[4] = {0, 0, 0, 0};\n"; + for (int k = 3; k >= 0; k--) + for (int m = 0; m < 4; m++) { + int base = k + 4*m; + out << "derivz[" << m << "] = db*derivz[" << m << "] + ((c[" << base << "].w*da + c[" << base << "].z)*da + c[" << base << "].y)*da + c[" << base << "].x;\n"; + } + out << nodeNames[j] << " = derivz[1] + dc*(2*derivz[2] + dc*3*derivz[3]);\n"; + out << nodeNames[j] << " *= " << paramsFloat[11] << ";\n"; + } + else + throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); } - else - throw OpenMMException("Unsupported derivative order for Continuous2DFunction"); + out << "}\n"; } - out << "}\n"; - } - else if (dynamic_cast(functions[i]) != NULL) { - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0) { - out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; - out << "if (x >= 0 && x < " << paramsInt[0] << ") {\n"; - out << "int index = (int) floor(x+0.5f);\n"; - out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; - out << "}\n"; + else if (dynamic_cast(functions[i]) != NULL) { + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0) { + out << "real x = " << getTempName(node.getChildren()[0], temps) << ";\n"; + out << "if (x >= 0 && x < " << paramsInt[0] << ") {\n"; + out << "int index = (int) floor(x+0.5f);\n"; + out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + out << "}\n"; + } } } - } - else if (dynamic_cast(functions[i]) != NULL) { - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0) { - out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; - out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; - out << "int xsize = " << paramsInt[0] << ";\n"; - out << "int ysize = " << paramsInt[1] << ";\n"; - out << "int index = x+y*xsize;\n"; - out << "if (index >= 0 && index < xsize*ysize)\n"; - out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + else if (dynamic_cast(functions[i]) != NULL) { + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0) { + out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; + out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; + out << "int xsize = " << paramsInt[0] << ";\n"; + out << "int ysize = " << paramsInt[1] << ";\n"; + out << "int index = x+y*xsize;\n"; + out << "if (index >= 0 && index < xsize*ysize)\n"; + out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + } } } - } - else if (dynamic_cast(functions[i]) != NULL) { - for (int j = 0; j < nodes.size(); j++) { - const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); - if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { - out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; - out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; - out << "int z = (int) floor(" << getTempName(node.getChildren()[2], temps) << "+0.5f);\n"; - out << "int xsize = " << paramsInt[0] << ";\n"; - out << "int ysize = " << paramsInt[1] << ";\n"; - out << "int zsize = " << paramsInt[2] << ";\n"; - out << "int index = x+(y+z*ysize)*xsize;\n"; - out << "if (index >= 0 && index < xsize*ysize*zsize)\n"; - out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + else if (dynamic_cast(functions[i]) != NULL) { + for (int j = 0; j < nodes.size(); j++) { + const vector& derivOrder = dynamic_cast(&nodes[j]->getOperation())->getDerivOrder(); + if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 0) { + out << "int x = (int) floor(" << getTempName(node.getChildren()[0], temps) << "+0.5f);\n"; + out << "int y = (int) floor(" << getTempName(node.getChildren()[1], temps) << "+0.5f);\n"; + out << "int z = (int) floor(" << getTempName(node.getChildren()[2], temps) << "+0.5f);\n"; + out << "int xsize = " << paramsInt[0] << ";\n"; + out << "int ysize = " << paramsInt[1] << ";\n"; + out << "int zsize = " << paramsInt[2] << ";\n"; + out << "int index = x+(y+z*ysize)*xsize;\n"; + out << "if (index >= 0 && index < xsize*ysize*zsize)\n"; + out << nodeNames[j] << " = " << functionNames[i].second << "[index];\n"; + } } } } @@ -475,7 +517,7 @@ string OpenCLExpressionUtilities::getTempName(const ExpressionTreeNode& node, co throw OpenMMException(out.str()); } -void OpenCLExpressionUtilities::findRelatedTabulatedFunctions(const ExpressionTreeNode& node, const ExpressionTreeNode& searchNode, +void OpenCLExpressionUtilities::findRelatedCustomFunctions(const ExpressionTreeNode& node, const ExpressionTreeNode& searchNode, vector& nodes) { if (searchNode.getOperation().getId() == Operation::CUSTOM && node.getOperation().getName() == searchNode.getOperation().getName()) { // Make sure the arguments are identical. @@ -496,7 +538,7 @@ void OpenCLExpressionUtilities::findRelatedTabulatedFunctions(const ExpressionTr } else for (int i = 0; i < (int) searchNode.getChildren().size(); i++) - findRelatedTabulatedFunctions(node, searchNode.getChildren()[i], nodes); + findRelatedCustomFunctions(node, searchNode.getChildren()[i], nodes); } void OpenCLExpressionUtilities::findRelatedPowers(const ExpressionTreeNode& node, const ExpressionTreeNode& searchNode, map& powers) { @@ -722,3 +764,7 @@ Lepton::CustomFunction* OpenCLExpressionUtilities::getFunctionPlaceholder(const return &fp3; throw OpenMMException("getFunctionPlaceholder: Unknown function type"); } + +Lepton::CustomFunction* OpenCLExpressionUtilities::getPeriodicDistancePlaceholder() { + return &periodicDistance; +} diff --git a/platforms/opencl/src/OpenCLKernels.cpp b/platforms/opencl/src/OpenCLKernels.cpp index 31bddc218..5ad12bf56 100644 --- a/platforms/opencl/src/OpenCLKernels.cpp +++ b/platforms/opencl/src/OpenCLKernels.cpp @@ -3821,7 +3821,9 @@ void OpenCLCalcCustomExternalForceKernel::initialize(const System& system, const globalParamNames[i] = force.getGlobalParameterName(i); globalParamValues[i] = (cl_float) force.getGlobalParameterDefaultValue(i); } - Lepton::ParsedExpression energyExpression = Lepton::Parser::parse(force.getEnergyFunction()).optimize(); + map customFunctions; + customFunctions["periodicdistance"] = cl.getExpressionUtilities().getPeriodicDistancePlaceholder(); + Lepton::ParsedExpression energyExpression = Lepton::Parser::parse(force.getEnergyFunction(), customFunctions).optimize(); Lepton::ParsedExpression forceExpressionX = energyExpression.differentiate("x").optimize(); Lepton::ParsedExpression forceExpressionY = energyExpression.differentiate("y").optimize(); Lepton::ParsedExpression forceExpressionZ = energyExpression.differentiate("z").optimize(); diff --git a/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp b/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp index 54ce2374d..58dc7ffb4 100644 --- a/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -161,6 +161,47 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } +void testPeriodic() { + Vec3 vx(5, 0, 0); + Vec3 vy(0, 6, 0); + Vec3 vz(1, 2, 7); + double x0 = 51, y0 = -17, z0 = 11.2; + System system; + system.setDefaultPeriodicBoxVectors(vx, vy, vz); + system.addParticle(1.0); + CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); + force->addPerParticleParameter("x0"); + force->addPerParticleParameter("y0"); + force->addPerParticleParameter("z0"); + vector params(3); + params[0] = x0; + params[1] = y0; + params[2] = z0; + force->addParticle(0, params); + system.addForce(force); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + vector positions(1); + positions[0] = Vec3(0, 2, 0); + context.setPositions(positions); + for (int i = 0; i < 100; i++) { + State state = context.getState(State::Positions | State::Forces | State::Energy); + + // Apply periodic boundary conditions to the difference between the two positions. + + Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; + delta -= vz*floor(delta[2]/vz[2]+0.5); + delta -= vy*floor(delta[1]/vy[1]+0.5); + delta -= vx*floor(delta[0]/vx[0]+0.5); + + // Verify that the force and energy are correct. + + ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-5); + ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-5); + integrator.step(1); + } +} + int main(int argc, char* argv[]) { try { if (argc > 1) @@ -168,6 +209,7 @@ int main(int argc, char* argv[]) { testForce(); testManyParameters(); testParallelComputation(); + testPeriodic(); } catch(const exception& e) { cout << "exception: " << e.what() << endl; -- GitLab From 0c4537146ea95949e49d597a61bcb1cad0cd5c08 Mon Sep 17 00:00:00 2001 From: Robert McGibbon Date: Sat, 19 Sep 2015 12:54:54 -0700 Subject: [PATCH 06/49] Add typemaps --- .../swig_doxygen/swig_lib/python/typemaps.i | 113 +++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i b/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i index 96c402422..98470c801 100644 --- a/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i +++ b/wrappers/python/src/swig_doxygen/swig_lib/python/typemaps.i @@ -156,7 +156,7 @@ int Py_SequenceToVecDouble(PyObject* obj, std::vector& out) { Py_DECREF(iterator); Py_DECREF(stripped); return SWIG_OK; - } +} } %fragment("Py_SequenceToVecVec3", "header", fragment="Py_SequenceToVec3") { @@ -202,6 +202,86 @@ int Py_SequenceToVecVec3(PyObject* obj, std::vector& out) { } } +%fragment("Py_SequenceToVecVecDouble", "header", fragment="Py_SequenceToVecDouble") { +int Py_SequenceToVecVecDouble(PyObject* obj, std::vector >& out) { + PyObject* stripped = NULL; + PyObject* item = NULL; + PyObject* item1 = NULL; + PyObject* iterator = NULL; + stripped = Py_StripOpenMMUnits(obj); + iterator = PyObject_GetIter(stripped); + + if (iterator == NULL) { + Py_DECREF(stripped); + return SWIG_ERROR; + } + + while ((item = PyIter_Next(iterator))) { + item1 = Py_StripOpenMMUnits(item); + if (item1 == NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); + Py_DECREF(item); + return SWIG_ERROR; + } + std::vector v; + int r2 = Py_SequenceToVecDouble(item1, v); + Py_DECREF(item); + Py_DECREF(item1); + + if (!SWIG_IsOK(r2) || PyErr_Occurred() != NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); + return SWIG_ERROR; + } + out.push_back(v); + } + Py_DECREF(iterator); + Py_DECREF(stripped); + return SWIG_OK; +} +} + +%fragment("Py_SequenceToVecVecVecDouble", "header", fragment="Py_SequenceToVecVecDouble") { +int Py_SequenceToVecVecVecDouble(PyObject* obj, std::vector > >& out) { + PyObject* stripped = NULL; + PyObject* item = NULL; + PyObject* item1 = NULL; + PyObject* iterator = NULL; + stripped = Py_StripOpenMMUnits(obj); + iterator = PyObject_GetIter(stripped); + + if (iterator == NULL) { + Py_DECREF(stripped); + return SWIG_ERROR; + } + + while ((item = PyIter_Next(iterator))) { + item1 = Py_StripOpenMMUnits(item); + if (item1 == NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); + Py_DECREF(item); + return SWIG_ERROR; + } + std::vector >v; + int r2 = Py_SequenceToVecVecDouble(item1, v); + Py_DECREF(item); + Py_DECREF(item1); + + if (!SWIG_IsOK(r2) || PyErr_Occurred() != NULL) { + Py_DECREF(stripped); + Py_DECREF(iterator); + return SWIG_ERROR; + } + out.push_back(v); + } + Py_DECREF(iterator); + Py_DECREF(stripped); + return SWIG_OK; +} +} + // ------ typemap for double ---- %typemap(typecheck, precedence=SWIG_TYPECHECK_DOUBLE, fragment="Py_StripOpenMMUnits") double { @@ -259,6 +339,37 @@ int Py_SequenceToVecVec3(PyObject* obj, std::vector& out) { } +// typemap for const vector > +%typemap(in, fragment="Py_SequenceToVecVecDouble") const std::vector >(std::vector > v, int res=0) { + res = Py_SequenceToVecVecDouble($input, v); + if (!SWIG_IsOK(res)) { + PyErr_SetString(PyExc_ValueError, "in method $symname, argument $argnum could not be converted to type $type"); + SWIG_fail; + } + $1 = &v; +} +%typemap(typecheck, fragment="Py_SequenceToVecVecDouble") const std::vector > { + std::vector > v; + int res = Py_SequenceToVecVecDouble($input, v); + $1 = SWIG_IsOK(res); +} + + +// typemap for const vector > > +%typemap(in, fragment="Py_SequenceToVecVecVecDouble") const std::vector > >(std::vector > > v, int res=0) { + res = Py_SequenceToVecVecVecDouble($input, v); + if (!SWIG_IsOK(res)) { + PyErr_SetString(PyExc_ValueError, "in method $symname, argument $argnum could not be converted to type $type"); + SWIG_fail; + } + $1 = &v; +} +%typemap(typecheck, fragment="Py_SequenceToVecVecVecDouble") const std::vector > >{ + std::vector > > v; + int res = Py_SequenceToVecVecVecDouble($input, v); + $1 = SWIG_IsOK(res); +} + // typemap for vector %typemap(in, fragment="Py_SequenceToVecVec3") const std::vector& (std::vector v, int res=0) { -- GitLab From 9e1145ac70f00664caadd35e4488824e35e88713 Mon Sep 17 00:00:00 2001 From: peastman Date: Mon, 21 Sep 2015 11:29:32 -0700 Subject: [PATCH 07/49] Fixed CustomExternalForce::usesPeriodicBoundaryConditions() --- openmmapi/include/openmm/CustomExternalForce.h | 4 +--- openmmapi/src/CustomExternalForce.cpp | 4 ++++ .../reference/tests/TestReferenceCustomExternalForce.cpp | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openmmapi/include/openmm/CustomExternalForce.h b/openmmapi/include/openmm/CustomExternalForce.h index af4826322..e0a37d938 100644 --- a/openmmapi/include/openmm/CustomExternalForce.h +++ b/openmmapi/include/openmm/CustomExternalForce.h @@ -214,9 +214,7 @@ public: * * @returns false */ - bool usesPeriodicBoundaryConditions() const { - return false; - } + bool usesPeriodicBoundaryConditions() const; protected: ForceImpl* createImpl() const; private: diff --git a/openmmapi/src/CustomExternalForce.cpp b/openmmapi/src/CustomExternalForce.cpp index ec3b7b851..b011d06b2 100644 --- a/openmmapi/src/CustomExternalForce.cpp +++ b/openmmapi/src/CustomExternalForce.cpp @@ -119,3 +119,7 @@ ForceImpl* CustomExternalForce::createImpl() const { void CustomExternalForce::updateParametersInContext(Context& context) { dynamic_cast(getImplInContext(context)).updateParametersInContext(getContextImpl(context)); } + +bool CustomExternalForce::usesPeriodicBoundaryConditions() const { + return (energyExpression.find("periodicdistance") != string::npos); +} diff --git a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp index 11ab9f3ff..38baea675 100644 --- a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp @@ -119,6 +119,8 @@ void testPeriodic() { params[2] = z0; force->addParticle(0, params); system.addForce(force); + ASSERT(force->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); VerletIntegrator integrator(0.01); Context context(system, integrator, platform); vector positions(1); -- GitLab From a5a52dd112032c7cd50d3461565d03f5b5a54384 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Mon, 21 Sep 2015 12:02:18 -0700 Subject: [PATCH 08/49] Began refactoring of tests to eliminate duplicated code --- platforms/cpu/tests/CpuTests.h | 37 ++++++ platforms/cuda/tests/CudaTests.h | 40 ++++++ .../cuda/tests/TestCudaHarmonicAngleForce.cpp | 88 +------------- .../cuda/tests/TestCudaHarmonicBondForce.cpp | 79 +----------- platforms/opencl/tests/OpenCLTests.h | 40 ++++++ .../tests/TestOpenCLHarmonicAngleForce.cpp | 88 +------------- .../tests/TestOpenCLHarmonicBondForce.cpp | 79 +----------- platforms/reference/tests/ReferenceTests.h | 37 ++++++ .../tests/TestReferenceHarmonicAngleForce.cpp | 85 +------------ .../tests/TestReferenceHarmonicBondForce.cpp | 79 +----------- tests/TestHarmonicAngleForce.h | 114 ++++++++++++++++++ tests/TestHarmonicBondForce.h | 100 +++++++++++++++ 12 files changed, 398 insertions(+), 468 deletions(-) create mode 100644 platforms/cpu/tests/CpuTests.h create mode 100644 platforms/cuda/tests/CudaTests.h create mode 100644 platforms/opencl/tests/OpenCLTests.h create mode 100644 platforms/reference/tests/ReferenceTests.h create mode 100644 tests/TestHarmonicAngleForce.h create mode 100644 tests/TestHarmonicBondForce.h diff --git a/platforms/cpu/tests/CpuTests.h b/platforms/cpu/tests/CpuTests.h new file mode 100644 index 000000000..96cdaec4b --- /dev/null +++ b/platforms/cpu/tests/CpuTests.h @@ -0,0 +1,37 @@ +/* -------------------------------------------------------------------------- * + * 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) 2015 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 "CpuPlatform.h" + +OpenMM::CpuPlatform platform; + +void initializeTests(int argc, char* argv[]) { +} \ No newline at end of file diff --git a/platforms/cuda/tests/CudaTests.h b/platforms/cuda/tests/CudaTests.h new file mode 100644 index 000000000..c93cc424d --- /dev/null +++ b/platforms/cuda/tests/CudaTests.h @@ -0,0 +1,40 @@ +/* -------------------------------------------------------------------------- * + * 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) 2015 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 "CudaPlatform.h" +#include + +OpenMM::CudaPlatform platform; + +void initializeTests(int argc, char* argv[]) { + if (argc > 1) + platform.setPropertyDefaultValue("CudaPrecision", std::string(argv[1])); +} \ No newline at end of file diff --git a/platforms/cuda/tests/TestCudaHarmonicAngleForce.cpp b/platforms/cuda/tests/TestCudaHarmonicAngleForce.cpp index f16b49dc7..45bbd94b4 100644 --- a/platforms/cuda/tests/TestCudaHarmonicAngleForce.cpp +++ b/platforms/cuda/tests/TestCudaHarmonicAngleForce.cpp @@ -7,7 +7,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,74 +30,9 @@ * 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/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testAngles() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(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 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& 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); - } - - // Try changing the angle parameters and make sure it's still correct. - - forceField->setAngleParameters(0, 0, 1, 2, PI_M/3.1, 1.3); - forceField->setAngleParameters(1, 1, 2, 3, PI_M/2.1, 1.4); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta1 = (PI_M/2)-(PI_M/3.1); - double dtheta2 = (3*PI_M/4)-(PI_M/2.1); - double torque1 = 1.3*dtheta1; - double torque2 = 1.4*dtheta2; - 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.3*dtheta1*dtheta1 + 0.5*1.4*dtheta2*dtheta2, state.getPotentialEnergy(), TOL); - } -} +#include "CudaTests.h" +#include "TestHarmonicAngleForce.h" +#include void testParallelComputation() { System system; @@ -127,17 +62,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testAngles(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaHarmonicBondForce.cpp b/platforms/cuda/tests/TestCudaHarmonicBondForce.cpp index 0ccd2db0c..dc4c22957 100644 --- a/platforms/cuda/tests/TestCudaHarmonicBondForce.cpp +++ b/platforms/cuda/tests/TestCudaHarmonicBondForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,66 +29,9 @@ * 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/VerletIntegrator.h" -#include +#include "CudaTests.h" +#include "TestHarmonicBondForce.h" #include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testBonds() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(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 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& 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); - } - - // Try changing the bond parameters and make sure it's still correct. - - forceField->setBondParameters(0, 0, 1, 1.6, 0.9); - forceField->setBondParameters(1, 1, 2, 1.3, 0.8); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); - } -} void testParallelComputation() { System system; @@ -118,18 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testBonds(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/opencl/tests/OpenCLTests.h b/platforms/opencl/tests/OpenCLTests.h new file mode 100644 index 000000000..3652c1c1a --- /dev/null +++ b/platforms/opencl/tests/OpenCLTests.h @@ -0,0 +1,40 @@ +/* -------------------------------------------------------------------------- * + * 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) 2015 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 "OpenCLPlatform.h" +#include + +OpenMM::OpenCLPlatform platform; + +void initializeTests(int argc, char* argv[]) { + if (argc > 1) + platform.setPropertyDefaultValue("OpenCLPrecision", std::string(argv[1])); +} \ No newline at end of file diff --git a/platforms/opencl/tests/TestOpenCLHarmonicAngleForce.cpp b/platforms/opencl/tests/TestOpenCLHarmonicAngleForce.cpp index ca950a229..d3bacd908 100644 --- a/platforms/opencl/tests/TestOpenCLHarmonicAngleForce.cpp +++ b/platforms/opencl/tests/TestOpenCLHarmonicAngleForce.cpp @@ -7,7 +7,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,74 +30,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of HarmonicAngleForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testAngles() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(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 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& 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); - } - - // Try changing the angle parameters and make sure it's still correct. - - forceField->setAngleParameters(0, 0, 1, 2, PI_M/3.1, 1.3); - forceField->setAngleParameters(1, 1, 2, 3, PI_M/2.1, 1.4); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta1 = (PI_M/2)-(PI_M/3.1); - double dtheta2 = (3*PI_M/4)-(PI_M/2.1); - double torque1 = 1.3*dtheta1; - double torque2 = 1.4*dtheta2; - 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.3*dtheta1*dtheta1 + 0.5*1.4*dtheta2*dtheta2, state.getPotentialEnergy(), TOL); - } -} +#include "OpenCLTests.h" +#include "TestHarmonicAngleForce.h" +#include void testParallelComputation() { System system; @@ -127,17 +62,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testAngles(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/opencl/tests/TestOpenCLHarmonicBondForce.cpp b/platforms/opencl/tests/TestOpenCLHarmonicBondForce.cpp index 94c50c4bc..e2acdc512 100644 --- a/platforms/opencl/tests/TestOpenCLHarmonicBondForce.cpp +++ b/platforms/opencl/tests/TestOpenCLHarmonicBondForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,66 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of HarmonicBondForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include +#include "OpenCLTests.h" +#include "TestHarmonicBondForce.h" #include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testBonds() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(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 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& 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); - } - - // Try changing the bond parameters and make sure it's still correct. - - forceField->setBondParameters(0, 0, 1, 1.6, 0.9); - forceField->setBondParameters(1, 1, 2, 1.3, 0.8); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); - } -} void testParallelComputation() { System system; @@ -118,18 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testBonds(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/reference/tests/ReferenceTests.h b/platforms/reference/tests/ReferenceTests.h new file mode 100644 index 000000000..5ba196b6a --- /dev/null +++ b/platforms/reference/tests/ReferenceTests.h @@ -0,0 +1,37 @@ +/* -------------------------------------------------------------------------- * + * 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) 2015 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 "ReferencePlatform.h" + +OpenMM::ReferencePlatform platform; + +void initializeTests(int argc, char* argv[]) { +} \ No newline at end of file diff --git a/platforms/reference/tests/TestReferenceHarmonicAngleForce.cpp b/platforms/reference/tests/TestReferenceHarmonicAngleForce.cpp index c8b701725..cef07b8a0 100644 --- a/platforms/reference/tests/TestReferenceHarmonicAngleForce.cpp +++ b/platforms/reference/tests/TestReferenceHarmonicAngleForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,85 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of HarmonicAngleForce. - */ +#include "ReferenceTests.h" +#include "TestHarmonicAngleForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testAngles() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(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); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& 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); - } - - // Try changing the angle parameters and make sure it's still correct. - - forceField->setAngleParameters(0, 0, 1, 2, PI_M/3.1, 1.3); - forceField->setAngleParameters(1, 1, 2, 3, PI_M/2.1, 1.4); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta1 = (PI_M/2)-(PI_M/3.1); - double dtheta2 = (3*PI_M/4)-(PI_M/2.1); - double torque1 = 1.3*dtheta1; - double torque2 = 1.4*dtheta2; - 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.3*dtheta1*dtheta1 + 0.5*1.4*dtheta2*dtheta2, state.getPotentialEnergy(), TOL); - } -} - -int main() { - try { - testAngles(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceHarmonicBondForce.cpp b/platforms/reference/tests/TestReferenceHarmonicBondForce.cpp index cccf3c4f3..6c51f37f3 100644 --- a/platforms/reference/tests/TestReferenceHarmonicBondForce.cpp +++ b/platforms/reference/tests/TestReferenceHarmonicBondForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,79 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of HarmonicBondForce. - */ +#include "ReferenceTests.h" +#include "TestHarmonicBondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testBonds() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(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); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& 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); - } - - // Try changing the bond parameters and make sure it's still correct. - - forceField->setBondParameters(0, 0, 1, 1.6, 0.9); - forceField->setBondParameters(1, 1, 2, 1.3, 0.8); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, 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; +void runPlatformTests() { } diff --git a/tests/TestHarmonicAngleForce.h b/tests/TestHarmonicAngleForce.h new file mode 100644 index 000000000..aebeb76e3 --- /dev/null +++ b/tests/TestHarmonicAngleForce.h @@ -0,0 +1,114 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 Stanford University and the Authors.s * + * 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 reference implementation of HarmonicAngleForce. + */ + +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicAngleForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testAngles() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(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); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& 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); + } + + // Try changing the angle parameters and make sure it's still correct. + + forceField->setAngleParameters(0, 0, 1, 2, PI_M/3.1, 1.3); + forceField->setAngleParameters(1, 1, 2, 3, PI_M/2.1, 1.4); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + double dtheta1 = (PI_M/2)-(PI_M/3.1); + double dtheta2 = (3*PI_M/4)-(PI_M/2.1); + double torque1 = 1.3*dtheta1; + double torque2 = 1.4*dtheta2; + 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.3*dtheta1*dtheta1 + 0.5*1.4*dtheta2*dtheta2, state.getPotentialEnergy(), TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testAngles(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestHarmonicBondForce.h b/tests/TestHarmonicBondForce.h new file mode 100644 index 000000000..c94214a2e --- /dev/null +++ b/tests/TestHarmonicBondForce.h @@ -0,0 +1,100 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testBonds() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(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 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& 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); + } + + // Try changing the bond parameters and make sure it's still correct. + + forceField->setBondParameters(0, 0, 1, 1.6, 0.9); + forceField->setBondParameters(1, 1, 2, 1.3, 0.8); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testBonds(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + -- GitLab From a47300e6cc73ddf2592bf3ee56c93eb6c8a84861 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Mon, 21 Sep 2015 16:24:44 -0700 Subject: [PATCH 09/49] Changes to generating nonbonded kernels --- .../cuda/include/CudaNonbondedUtilities.h | 13 +++- platforms/cuda/src/CudaKernels.cpp | 2 +- platforms/cuda/src/CudaNonbondedUtilities.cpp | 17 +++-- platforms/cuda/src/kernels/nonbonded.cu | 26 ++++++-- .../opencl/include/OpenCLNonbondedUtilities.h | 13 +++- platforms/opencl/src/OpenCLKernels.cpp | 2 +- .../opencl/src/OpenCLNonbondedUtilities.cpp | 62 ++++++++++++++----- platforms/opencl/src/kernels/nonbonded.cl | 18 +++++- .../platforms/cuda/src/AmoebaCudaKernels.cpp | 2 +- 9 files changed, 118 insertions(+), 37 deletions(-) diff --git a/platforms/cuda/include/CudaNonbondedUtilities.h b/platforms/cuda/include/CudaNonbondedUtilities.h index 5b4023a42..487490664 100644 --- a/platforms/cuda/include/CudaNonbondedUtilities.h +++ b/platforms/cuda/include/CudaNonbondedUtilities.h @@ -138,8 +138,12 @@ public: void prepareInteractions(int forceGroups); /** * Compute the nonbonded interactions. + * + * @param forceGroups the flags specifying which force groups to include + * @param includeForces whether to compute forces + * @param includeEnergy whether to compute the potential energy */ - void computeInteractions(int forceGroups); + void computeInteractions(int forceGroups, bool includeForces, bool includeEnergy); /** * Check to see if the neighbor list arrays are large enough, and make them bigger if necessary. * @@ -235,8 +239,10 @@ public: * @param useExclusions specifies whether exclusions are applied to this interaction * @param isSymmetric specifies whether the interaction is symmetric * @param groups the set of force groups this kernel is for + * @param includeForces whether this kernel should compute forces + * @param includeEnergy whether this kernel should compute potential energy */ - CUfunction createInteractionKernel(const std::string& source, std::vector& params, std::vector& arguments, bool useExclusions, bool isSymmetric, int groups); + CUfunction createInteractionKernel(const std::string& source, std::vector& params, std::vector& arguments, bool useExclusions, bool isSymmetric, int groups, bool includeForces, bool includeEnergy); /** * Create the set of kernels that will be needed for a particular combination of force groups. * @@ -282,7 +288,8 @@ class CudaNonbondedUtilities::KernelSet { public: bool hasForces; double cutoffDistance; - CUfunction forceKernel; + std::string source; + CUfunction forceKernel, energyKernel, forceEnergyKernel; CUfunction findBlockBoundsKernel; CUfunction sortBoxDataKernel; CUfunction findInteractingBlocksKernel; diff --git a/platforms/cuda/src/CudaKernels.cpp b/platforms/cuda/src/CudaKernels.cpp index 61895fe0d..f92e50664 100644 --- a/platforms/cuda/src/CudaKernels.cpp +++ b/platforms/cuda/src/CudaKernels.cpp @@ -105,7 +105,7 @@ void CudaCalcForcesAndEnergyKernel::beginComputation(ContextImpl& context, bool double CudaCalcForcesAndEnergyKernel::finishComputation(ContextImpl& context, bool includeForces, bool includeEnergy, int groups, bool& valid) { cu.getBondedUtilities().computeInteractions(groups); - cu.getNonbondedUtilities().computeInteractions(groups); + cu.getNonbondedUtilities().computeInteractions(groups, includeForces, includeEnergy); double sum = 0.0; for (vector::iterator iter = cu.getPostComputations().begin(); iter != cu.getPostComputations().end(); ++iter) sum += (*iter)->computeForceAndEnergy(includeForces, includeEnergy, groups); diff --git a/platforms/cuda/src/CudaNonbondedUtilities.cpp b/platforms/cuda/src/CudaNonbondedUtilities.cpp index c94dbdeec..3b5d70abb 100644 --- a/platforms/cuda/src/CudaNonbondedUtilities.cpp +++ b/platforms/cuda/src/CudaNonbondedUtilities.cpp @@ -388,12 +388,15 @@ void CudaNonbondedUtilities::prepareInteractions(int forceGroups) { lastCutoff = kernels.cutoffDistance; } -void CudaNonbondedUtilities::computeInteractions(int forceGroups) { +void CudaNonbondedUtilities::computeInteractions(int forceGroups, bool includeForces, bool includeEnergy) { if ((forceGroups&groupFlags) == 0) return; KernelSet& kernels = groupKernels[forceGroups]; if (kernels.hasForces) { - context.executeKernel(kernels.forceKernel, &forceArgs[0], numForceThreadBlocks*forceThreadBlockSize, forceThreadBlockSize); + CUfunction& kernel = (includeForces ? (includeEnergy ? kernels.forceEnergyKernel : kernels.forceKernel) : kernels.energyKernel); + if (kernel == NULL) + kernel = createInteractionKernel(kernels.source, parameters, arguments, true, true, forceGroups, includeForces, includeEnergy); + context.executeKernel(kernel, &forceArgs[0], numForceThreadBlocks*forceThreadBlockSize, forceThreadBlockSize); } } @@ -454,8 +457,8 @@ void CudaNonbondedUtilities::createKernelsForGroups(int groups) { } kernels.hasForces = (source.size() > 0); kernels.cutoffDistance = cutoff; - if (kernels.hasForces) - kernels.forceKernel = createInteractionKernel(source, parameters, arguments, true, true, groups); + kernels.source = source; + kernels.forceKernel = kernels.energyKernel = kernels.forceEnergyKernel = NULL; if (useCutoff) { double padding = (usePadding ? 0.1*cutoff : 0.0); double paddedCutoff = cutoff+padding; @@ -478,7 +481,7 @@ void CudaNonbondedUtilities::createKernelsForGroups(int groups) { groupKernels[groups] = kernels; } -CUfunction CudaNonbondedUtilities::createInteractionKernel(const string& source, vector& params, vector& arguments, bool useExclusions, bool isSymmetric, int groups) { +CUfunction CudaNonbondedUtilities::createInteractionKernel(const string& source, vector& params, vector& arguments, bool useExclusions, bool isSymmetric, int groups, bool includeForces, bool includeEnergy) { map replacements; replacements["COMPUTE_INTERACTION"] = source; const string suffixes[] = {"x", "y", "z", "w"}; @@ -654,6 +657,10 @@ CUfunction CudaNonbondedUtilities::createInteractionKernel(const string& source, defines["USE_SYMMETRIC"] = "1"; if (useShuffle) defines["ENABLE_SHUFFLE"] = "1"; + if (includeForces) + defines["INCLUDE_FORCES"] = "1"; + if (includeEnergy) + defines["INCLUDE_ENERGY"] = "1"; defines["THREAD_BLOCK_SIZE"] = context.intToString(forceThreadBlockSize); double maxCutoff = 0.0; for (int i = 0; i < 32; i++) { diff --git a/platforms/cuda/src/kernels/nonbonded.cu b/platforms/cuda/src/kernels/nonbonded.cu index e9908f915..0c3feab19 100644 --- a/platforms/cuda/src/kernels/nonbonded.cu +++ b/platforms/cuda/src/kernels/nonbonded.cu @@ -112,7 +112,7 @@ extern "C" __global__ void computeNonbonded( const unsigned int warp = (blockIdx.x*blockDim.x+threadIdx.x)/TILE_SIZE; // global warpIndex const unsigned int tgx = threadIdx.x & (TILE_SIZE-1); // index within the warp const unsigned int tbx = threadIdx.x - tgx; // block warpIndex - real energy = 0.0f; + mixed energy = 0; // used shared memory if the device cannot shuffle #ifndef ENABLE_SHUFFLE __shared__ AtomData localData[THREAD_BLOCK_SIZE]; @@ -175,6 +175,7 @@ extern "C" __global__ void computeNonbonded( real tempEnergy = 0.0f; COMPUTE_INTERACTION energy += 0.5f*tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC force.x -= delta.x*dEdR; force.y -= delta.y*dEdR; @@ -184,6 +185,7 @@ extern "C" __global__ void computeNonbonded( force.y -= dEdR1.y; force.z -= dEdR1.z; #endif +#endif #ifdef USE_EXCLUSIONS excl >>= 1; #endif @@ -241,6 +243,7 @@ extern "C" __global__ void computeNonbonded( real tempEnergy = 0.0f; COMPUTE_INTERACTION energy += tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC delta *= dEdR; force.x -= delta.x; @@ -270,11 +273,12 @@ extern "C" __global__ void computeNonbonded( localData[tbx+tj].fz += dEdR2.z; #endif #endif // end USE_SYMMETRIC -#ifdef USE_EXCLUSIONS - excl >>= 1; -#endif #ifdef ENABLE_SHUFFLE SHUFFLE_WARP_DATA +#endif +#endif +#ifdef USE_EXCLUSIONS + excl >>= 1; #endif // cycles the indices // 0 1 2 3 4 5 6 7 -> 1 2 3 4 5 6 7 0 @@ -282,6 +286,7 @@ extern "C" __global__ void computeNonbonded( } const unsigned int offset = y*TILE_SIZE + tgx; // write results for off diagonal tiles +#ifdef INCLUDE_FORCES #ifdef ENABLE_SHUFFLE atomicAdd(&forceBuffers[offset], static_cast((long long) (shflForce.x*0x100000000))); atomicAdd(&forceBuffers[offset+PADDED_NUM_ATOMS], static_cast((long long) (shflForce.y*0x100000000))); @@ -290,13 +295,16 @@ extern "C" __global__ void computeNonbonded( atomicAdd(&forceBuffers[offset], static_cast((long long) (localData[threadIdx.x].fx*0x100000000))); atomicAdd(&forceBuffers[offset+PADDED_NUM_ATOMS], static_cast((long long) (localData[threadIdx.x].fy*0x100000000))); atomicAdd(&forceBuffers[offset+2*PADDED_NUM_ATOMS], static_cast((long long) (localData[threadIdx.x].fz*0x100000000))); +#endif #endif } // Write results for on and off diagonal tiles +#ifdef INCLUDE_FORCES const unsigned int offset = x*TILE_SIZE + tgx; atomicAdd(&forceBuffers[offset], static_cast((long long) (force.x*0x100000000))); atomicAdd(&forceBuffers[offset+PADDED_NUM_ATOMS], static_cast((long long) (force.y*0x100000000))); atomicAdd(&forceBuffers[offset+2*PADDED_NUM_ATOMS], static_cast((long long) (force.z*0x100000000))); +#endif } // Second loop: tiles without exclusions, either from the neighbor list (with cutoff) or just enumerating all @@ -441,6 +449,7 @@ extern "C" __global__ void computeNonbonded( real tempEnergy = 0.0f; COMPUTE_INTERACTION energy += tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC delta *= dEdR; force.x -= delta.x; @@ -472,6 +481,7 @@ extern "C" __global__ void computeNonbonded( #endif // end USE_SYMMETRIC #ifdef ENABLE_SHUFFLE SHUFFLE_WARP_DATA +#endif #endif tj = (tj + 1) & (TILE_SIZE - 1); } @@ -509,6 +519,7 @@ extern "C" __global__ void computeNonbonded( real tempEnergy = 0.0f; COMPUTE_INTERACTION energy += tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC delta *= dEdR; force.x -= delta.x; @@ -540,12 +551,14 @@ extern "C" __global__ void computeNonbonded( #endif // end USE_SYMMETRIC #ifdef ENABLE_SHUFFLE SHUFFLE_WARP_DATA +#endif #endif tj = (tj + 1) & (TILE_SIZE - 1); } } // Write results. +#ifdef INCLUDE_FORCES atomicAdd(&forceBuffers[atom1], static_cast((long long) (force.x*0x100000000))); atomicAdd(&forceBuffers[atom1+PADDED_NUM_ATOMS], static_cast((long long) (force.y*0x100000000))); atomicAdd(&forceBuffers[atom1+2*PADDED_NUM_ATOMS], static_cast((long long) (force.z*0x100000000))); @@ -565,8 +578,11 @@ extern "C" __global__ void computeNonbonded( atomicAdd(&forceBuffers[atom2+2*PADDED_NUM_ATOMS], static_cast((long long) (localData[threadIdx.x].fz*0x100000000))); #endif } +#endif } pos++; } - energyBuffer[blockIdx.x*blockDim.x+threadIdx.x] += energy; +#ifdef INCLUDE_ENERGY + energyBuffer[blockIdx.x*blockDim.x+threadIdx.x] += (real) energy; +#endif } \ No newline at end of file diff --git a/platforms/opencl/include/OpenCLNonbondedUtilities.h b/platforms/opencl/include/OpenCLNonbondedUtilities.h index 2aedb00e2..1e138228b 100644 --- a/platforms/opencl/include/OpenCLNonbondedUtilities.h +++ b/platforms/opencl/include/OpenCLNonbondedUtilities.h @@ -150,8 +150,12 @@ public: void prepareInteractions(int forceGroups); /** * Compute the nonbonded interactions. + * + * @param forceGroups the flags specifying which force groups to include + * @param includeForces whether to compute forces + * @param includeEnergy whether to compute the potential energy */ - void computeInteractions(int forceGroups); + void computeInteractions(int forceGroups, bool includeForces, bool includeEnergy); /** * Check to see if the neighbor list arrays are large enough, and make them bigger if necessary. * @@ -247,8 +251,10 @@ public: * @param useExclusions specifies whether exclusions are applied to this interaction * @param isSymmetric specifies whether the interaction is symmetric * @param groups the set of force groups this kernel is for + * @param includeForces whether this kernel should compute forces + * @param includeEnergy whether this kernel should compute potential energy */ - cl::Kernel createInteractionKernel(const std::string& source, const std::vector& params, const std::vector& arguments, bool useExclusions, bool isSymmetric, int groups); + cl::Kernel createInteractionKernel(const std::string& source, const std::vector& params, const std::vector& arguments, bool useExclusions, bool isSymmetric, int groups, bool includeForces, bool includeEnergy); /** * Create the set of kernels that will be needed for a particular combination of force groups. * @@ -294,7 +300,8 @@ class OpenCLNonbondedUtilities::KernelSet { public: bool hasForces; double cutoffDistance; - cl::Kernel forceKernel; + std::string source; + cl::Kernel forceKernel, energyKernel, forceEnergyKernel; cl::Kernel findBlockBoundsKernel; cl::Kernel sortBoxDataKernel; cl::Kernel findInteractingBlocksKernel; diff --git a/platforms/opencl/src/OpenCLKernels.cpp b/platforms/opencl/src/OpenCLKernels.cpp index 5ad12bf56..9c23f58a5 100644 --- a/platforms/opencl/src/OpenCLKernels.cpp +++ b/platforms/opencl/src/OpenCLKernels.cpp @@ -128,7 +128,7 @@ void OpenCLCalcForcesAndEnergyKernel::beginComputation(ContextImpl& context, boo double OpenCLCalcForcesAndEnergyKernel::finishComputation(ContextImpl& context, bool includeForces, bool includeEnergy, int groups, bool& valid) { cl.getBondedUtilities().computeInteractions(groups); - cl.getNonbondedUtilities().computeInteractions(groups); + cl.getNonbondedUtilities().computeInteractions(groups, includeForces, includeEnergy); double sum = 0.0; for (vector::iterator iter = cl.getPostComputations().begin(); iter != cl.getPostComputations().end(); ++iter) sum += (*iter)->computeForceAndEnergy(includeForces, includeEnergy, groups); diff --git a/platforms/opencl/src/OpenCLNonbondedUtilities.cpp b/platforms/opencl/src/OpenCLNonbondedUtilities.cpp index b80f4a3d5..7f6937302 100644 --- a/platforms/opencl/src/OpenCLNonbondedUtilities.cpp +++ b/platforms/opencl/src/OpenCLNonbondedUtilities.cpp @@ -373,14 +373,17 @@ void OpenCLNonbondedUtilities::prepareInteractions(int forceGroups) { lastCutoff = kernels.cutoffDistance; } -void OpenCLNonbondedUtilities::computeInteractions(int forceGroups) { +void OpenCLNonbondedUtilities::computeInteractions(int forceGroups, bool includeForces, bool includeEnergy) { if ((forceGroups&groupFlags) == 0) return; KernelSet& kernels = groupKernels[forceGroups]; if (kernels.hasForces) { + cl::Kernel& kernel = (includeForces ? (includeEnergy ? kernels.forceEnergyKernel : kernels.forceKernel) : kernels.energyKernel); + if (*reinterpret_cast(&kernel) == NULL) + kernel = createInteractionKernel(kernels.source, parameters, arguments, true, true, forceGroups, includeForces, includeEnergy); if (useCutoff) - setPeriodicBoxArgs(context, kernels.forceKernel, 9); - context.executeKernel(kernels.forceKernel, numForceThreadBlocks*forceThreadBlockSize, forceThreadBlockSize); + setPeriodicBoxArgs(context, kernel, 9); + context.executeKernel(kernel, numForceThreadBlocks*forceThreadBlockSize, forceThreadBlockSize); } } @@ -406,12 +409,25 @@ bool OpenCLNonbondedUtilities::updateNeighborListSize() { interactingTiles = OpenCLArray::create(context, maxTiles, "interactingTiles"); interactingAtoms = OpenCLArray::create(context, OpenCLContext::TileSize*maxTiles, "interactingAtoms"); for (map::iterator iter = groupKernels.begin(); iter != groupKernels.end(); ++iter) { - iter->second.forceKernel.setArg(7, interactingTiles->getDeviceBuffer()); - iter->second.forceKernel.setArg(14, maxTiles); - iter->second.forceKernel.setArg(17, interactingAtoms->getDeviceBuffer()); - iter->second.findInteractingBlocksKernel.setArg(6, interactingTiles->getDeviceBuffer()); - iter->second.findInteractingBlocksKernel.setArg(7, interactingAtoms->getDeviceBuffer()); - iter->second.findInteractingBlocksKernel.setArg(9, maxTiles); + KernelSet& kernels = iter->second; + if (*reinterpret_cast(&kernels.forceKernel) != NULL) { + kernels.forceKernel.setArg(7, interactingTiles->getDeviceBuffer()); + kernels.forceKernel.setArg(14, maxTiles); + kernels.forceKernel.setArg(17, interactingAtoms->getDeviceBuffer()); + } + if (*reinterpret_cast(&kernels.energyKernel) != NULL) { + kernels.energyKernel.setArg(7, interactingTiles->getDeviceBuffer()); + kernels.energyKernel.setArg(14, maxTiles); + kernels.energyKernel.setArg(17, interactingAtoms->getDeviceBuffer()); + } + if (*reinterpret_cast(&kernels.forceEnergyKernel) != NULL) { + kernels.forceEnergyKernel.setArg(7, interactingTiles->getDeviceBuffer()); + kernels.forceEnergyKernel.setArg(14, maxTiles); + kernels.forceEnergyKernel.setArg(17, interactingAtoms->getDeviceBuffer()); + } + kernels.findInteractingBlocksKernel.setArg(6, interactingTiles->getDeviceBuffer()); + kernels.findInteractingBlocksKernel.setArg(7, interactingAtoms->getDeviceBuffer()); + kernels.findInteractingBlocksKernel.setArg(9, maxTiles); } forceRebuildNeighborList = true; return true; @@ -432,10 +448,21 @@ void OpenCLNonbondedUtilities::setAtomBlockRange(double startFraction, double en // We are using a cutoff, and the kernels have already been created. for (map::iterator iter = groupKernels.begin(); iter != groupKernels.end(); ++iter) { - iter->second.forceKernel.setArg(5, startTileIndex); - iter->second.forceKernel.setArg(6, numTiles); - iter->second.findInteractingBlocksKernel.setArg(10, startBlockIndex); - iter->second.findInteractingBlocksKernel.setArg(11, numBlocks); + KernelSet& kernels = iter->second; + if (*reinterpret_cast(&kernels.forceKernel) != NULL) { + kernels.forceKernel.setArg(5, startTileIndex); + kernels.forceKernel.setArg(6, numTiles); + } + if (*reinterpret_cast(&kernels.energyKernel) != NULL) { + kernels.energyKernel.setArg(5, startTileIndex); + kernels.energyKernel.setArg(6, numTiles); + } + if (*reinterpret_cast(&kernels.forceEnergyKernel) != NULL) { + kernels.forceEnergyKernel.setArg(5, startTileIndex); + kernels.forceEnergyKernel.setArg(6, numTiles); + } + kernels.findInteractingBlocksKernel.setArg(10, startBlockIndex); + kernels.findInteractingBlocksKernel.setArg(11, numBlocks); } forceRebuildNeighborList = true; } @@ -453,8 +480,7 @@ void OpenCLNonbondedUtilities::createKernelsForGroups(int groups) { } kernels.hasForces = (source.size() > 0); kernels.cutoffDistance = cutoff; - if (kernels.hasForces) - kernels.forceKernel = createInteractionKernel(source, parameters, arguments, true, true, groups); + kernels.source = source; if (useCutoff) { double padding = (usePadding ? 0.1*cutoff : 0.0); double paddedCutoff = cutoff+padding; @@ -524,7 +550,7 @@ void OpenCLNonbondedUtilities::createKernelsForGroups(int groups) { groupKernels[groups] = kernels; } -cl::Kernel OpenCLNonbondedUtilities::createInteractionKernel(const string& source, const vector& params, const vector& arguments, bool useExclusions, bool isSymmetric, int groups) { +cl::Kernel OpenCLNonbondedUtilities::createInteractionKernel(const string& source, const vector& params, const vector& arguments, bool useExclusions, bool isSymmetric, int groups, bool includeForces, bool includeEnergy) { map replacements; replacements["COMPUTE_INTERACTION"] = source; const string suffixes[] = {"x", "y", "z", "w"}; @@ -623,6 +649,10 @@ cl::Kernel OpenCLNonbondedUtilities::createInteractionKernel(const string& sourc defines["USE_SYMMETRIC"] = "1"; if (useCutoff && context.getSIMDWidth() < 32) defines["PRUNE_BY_CUTOFF"] = "1"; + if (includeForces) + defines["INCLUDE_FORCES"] = "1"; + if (includeEnergy) + defines["INCLUDE_ENERGY"] = "1"; defines["FORCE_WORK_GROUP_SIZE"] = context.intToString(forceThreadBlockSize); double maxCutoff = 0.0; for (int i = 0; i < 32; i++) { diff --git a/platforms/opencl/src/kernels/nonbonded.cl b/platforms/opencl/src/kernels/nonbonded.cl index 601566905..e6688bc71 100644 --- a/platforms/opencl/src/kernels/nonbonded.cl +++ b/platforms/opencl/src/kernels/nonbonded.cl @@ -34,7 +34,7 @@ __kernel void computeNonbonded( const unsigned int warp = get_global_id(0)/TILE_SIZE; const unsigned int tgx = get_local_id(0) & (TILE_SIZE-1); const unsigned int tbx = get_local_id(0) - tgx; - real energy = 0; + mixed energy = 0; __local AtomData localData[FORCE_WORK_GROUP_SIZE]; // First loop: process tiles that contain exclusions. @@ -87,11 +87,13 @@ __kernel void computeNonbonded( real tempEnergy = 0; COMPUTE_INTERACTION energy += 0.5f*tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC force.xyz -= delta.xyz*dEdR; #else force.xyz -= dEdR1.xyz; #endif +#endif #ifdef USE_EXCLUSIONS excl >>= 1; #endif @@ -144,6 +146,7 @@ __kernel void computeNonbonded( real tempEnergy = 0; COMPUTE_INTERACTION energy += tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC delta.xyz *= dEdR; force.xyz -= delta.xyz; @@ -156,6 +159,7 @@ __kernel void computeNonbonded( localData[tbx+tj].fy += dEdR2.y; localData[tbx+tj].fz += dEdR2.z; #endif +#endif #ifdef PRUNE_BY_CUTOFF } #endif @@ -169,6 +173,7 @@ __kernel void computeNonbonded( // Write results. +#ifdef INCLUDE_FORCES #ifdef SUPPORTS_64_BIT_ATOMICS unsigned int offset = x*TILE_SIZE + tgx; atom_add(&forceBuffers[offset], (long) (force.x*0x100000000)); @@ -186,6 +191,7 @@ __kernel void computeNonbonded( forceBuffers[offset1].xyz += force.xyz; if (x != y) forceBuffers[offset2] += (real4) (localData[get_local_id(0)].fx, localData[get_local_id(0)].fy, localData[get_local_id(0)].fz, 0.0f); +#endif #endif } @@ -318,6 +324,7 @@ __kernel void computeNonbonded( real tempEnergy = 0; COMPUTE_INTERACTION energy += tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC delta.xyz *= dEdR; force.xyz -= delta.xyz; @@ -330,6 +337,7 @@ __kernel void computeNonbonded( localData[tbx+tj].fy += dEdR2.y; localData[tbx+tj].fz += dEdR2.z; #endif +#endif #ifdef PRUNE_BY_CUTOFF } #endif @@ -370,6 +378,7 @@ __kernel void computeNonbonded( real tempEnergy = 0; COMPUTE_INTERACTION energy += tempEnergy; +#ifdef INCLUDE_FORCES #ifdef USE_SYMMETRIC delta.xyz *= dEdR; force.xyz -= delta.xyz; @@ -382,6 +391,7 @@ __kernel void computeNonbonded( localData[tbx+tj].fy += dEdR2.y; localData[tbx+tj].fz += dEdR2.z; #endif +#endif #ifdef PRUNE_BY_CUTOFF } #endif @@ -392,6 +402,7 @@ __kernel void computeNonbonded( // Write results. +#ifdef INCLUDE_FORCES #ifdef USE_CUTOFF unsigned int atom2 = atomIndices[get_local_id(0)]; #else @@ -412,9 +423,12 @@ __kernel void computeNonbonded( forceBuffers[offset1].xyz += force.xyz; if (atom2 < PADDED_NUM_ATOMS) forceBuffers[offset2] += (real4) (localData[get_local_id(0)].fx, localData[get_local_id(0)].fy, localData[get_local_id(0)].fz, 0.0f); +#endif #endif } pos++; } - energyBuffer[get_global_id(0)] += energy; +#ifdef INCLUDE_ENERGY + energyBuffer[get_global_id(0)] += (real) energy; +#endif } diff --git a/plugins/amoeba/platforms/cuda/src/AmoebaCudaKernels.cpp b/plugins/amoeba/platforms/cuda/src/AmoebaCudaKernels.cpp index 0275b0897..8e6b8bebb 100644 --- a/plugins/amoeba/platforms/cuda/src/AmoebaCudaKernels.cpp +++ b/plugins/amoeba/platforms/cuda/src/AmoebaCudaKernels.cpp @@ -2407,7 +2407,7 @@ double CudaCalcAmoebaVdwForceKernel::execute(ContextImpl& context, bool includeF &bondReductionAtoms->getDevicePointer(), &bondReductionFactors->getDevicePointer()}; cu.executeKernel(prepareKernel, prepareArgs, cu.getPaddedNumAtoms()); nonbonded->prepareInteractions(1); - nonbonded->computeInteractions(1); + nonbonded->computeInteractions(1, includeForces, includeEnergy); void* spreadArgs[] = {&cu.getForce().getDevicePointer(), &tempForces->getDevicePointer(), &bondReductionAtoms->getDevicePointer(), &bondReductionFactors->getDevicePointer()}; cu.executeKernel(spreadKernel, spreadArgs, cu.getPaddedNumAtoms()); tempPosq->copyTo(cu.getPosq()); -- GitLab From ccd811da224b3cd53abcf5edc9cfb8a1f8f39abf Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Tue, 22 Sep 2015 12:38:44 -0700 Subject: [PATCH 10/49] Continuing to refactor tests --- CMakeLists.txt | 1 + platforms/cpu/tests/CpuTests.h | 2 +- platforms/cuda/tests/CudaTests.h | 2 +- .../cuda/tests/TestCudaCustomAngleForce.cpp | 120 +-- .../cuda/tests/TestCudaCustomBondForce.cpp | 125 +-- .../tests/TestCudaCustomCentroidBondForce.cpp | 245 +---- .../tests/TestCudaCustomCompoundBondForce.cpp | 304 +----- .../tests/TestCudaCustomExternalForce.cpp | 159 +--- .../cuda/tests/TestCudaCustomGBForce.cpp | 454 +-------- .../tests/TestCudaPeriodicTorsionForce.cpp | 83 +- .../cuda/tests/TestCudaRBTorsionForce.cpp | 100 +- platforms/opencl/tests/OpenCLTests.h | 2 +- .../tests/TestOpenCLCustomAngleForce.cpp | 125 +-- .../tests/TestOpenCLCustomBondForce.cpp | 126 +-- .../TestOpenCLCustomCentroidBondForce.cpp | 245 +---- .../TestOpenCLCustomCompoundBondForce.cpp | 304 +----- .../tests/TestOpenCLCustomExternalForce.cpp | 162 +--- .../opencl/tests/TestOpenCLCustomGBForce.cpp | 454 +-------- .../tests/TestOpenCLPeriodicTorsionForce.cpp | 83 +- .../opencl/tests/TestOpenCLRBTorsionForce.cpp | 100 +- platforms/reference/tests/ReferenceTests.h | 2 +- .../tests/TestReferenceCustomAngleForce.cpp | 121 +-- .../tests/TestReferenceCustomBondForce.cpp | 89 +- .../TestReferenceCustomCentroidBondForce.cpp | 244 +---- .../TestReferenceCustomCompoundBondForce.cpp | 306 +----- .../TestReferenceCustomExternalForce.cpp | 132 +-- .../tests/TestReferenceCustomGBForce.cpp | 883 +----------------- .../TestReferencePeriodicTorsionForce.cpp | 80 +- .../tests/TestReferenceRBTorsionForce.cpp | 99 +- tests/TestCustomAngleForce.h | 145 +++ tests/TestCustomBondForce.h | 149 +++ tests/TestCustomCentroidBondForce.h | 271 ++++++ tests/TestCustomCompoundBondForce.h | 332 +++++++ tests/TestCustomExternalForce.h | 188 ++++ tests/TestCustomGBForce.h | 493 ++++++++++ tests/TestHarmonicAngleForce.h | 4 - tests/TestPeriodicTorsionForce.h | 105 +++ tests/TestRBTorsionForce.h | 124 +++ 38 files changed, 1911 insertions(+), 5052 deletions(-) create mode 100644 tests/TestCustomAngleForce.h create mode 100644 tests/TestCustomBondForce.h create mode 100644 tests/TestCustomCentroidBondForce.h create mode 100644 tests/TestCustomCompoundBondForce.h create mode 100644 tests/TestCustomExternalForce.h create mode 100644 tests/TestCustomGBForce.h create mode 100644 tests/TestPeriodicTorsionForce.h create mode 100644 tests/TestRBTorsionForce.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5edc5d57f..9dc4a8861 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,6 +340,7 @@ ELSE(DL_LIBRARY) ENDIF(DL_LIBRARY) IF(BUILD_TESTING) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/tests) ADD_SUBDIRECTORY(platforms/reference/tests) ENDIF(BUILD_TESTING) diff --git a/platforms/cpu/tests/CpuTests.h b/platforms/cpu/tests/CpuTests.h index 96cdaec4b..a237e4978 100644 --- a/platforms/cpu/tests/CpuTests.h +++ b/platforms/cpu/tests/CpuTests.h @@ -34,4 +34,4 @@ OpenMM::CpuPlatform platform; void initializeTests(int argc, char* argv[]) { -} \ No newline at end of file +} diff --git a/platforms/cuda/tests/CudaTests.h b/platforms/cuda/tests/CudaTests.h index c93cc424d..db153ec62 100644 --- a/platforms/cuda/tests/CudaTests.h +++ b/platforms/cuda/tests/CudaTests.h @@ -37,4 +37,4 @@ OpenMM::CudaPlatform platform; void initializeTests(int argc, char* argv[]) { if (argc > 1) platform.setPropertyDefaultValue("CudaPrecision", std::string(argv[1])); -} \ No newline at end of file +} diff --git a/platforms/cuda/tests/TestCudaCustomAngleForce.cpp b/platforms/cuda/tests/TestCudaCustomAngleForce.cpp index 0e62d9e10..e832d1d18 100644 --- a/platforms/cuda/tests/TestCudaCustomAngleForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomAngleForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,107 +29,8 @@ * 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 -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testAngles() { - // 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 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 positions(4); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(harmonicSystem, integrator2, platform); - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the angle parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 0.9; - custom->setAngleParameters(0, 0, 1, 2, parameters); - parameters[0] = 2.1; - parameters[1] = 0.6; - custom->setAngleParameters(1, 1, 2, 3, parameters); - custom->updateParametersInContext(c1); - harmonic->setAngleParameters(0, 0, 1, 2, 1.6, 0.9); - harmonic->setAngleParameters(1, 1, 2, 3, 2.1, 0.6); - harmonic->updateParametersInContext(c2); - { - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} +#include "CudaTests.h" +#include "TestCustomAngleForce.h" void testParallelComputation() { System system; @@ -160,17 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testAngles(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaCustomBondForce.cpp b/platforms/cuda/tests/TestCudaCustomBondForce.cpp index 1d8c83434..6fadcdca6 100644 --- a/platforms/cuda/tests/TestCudaCustomBondForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomBondForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,111 +29,8 @@ * 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 "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testBonds() { - 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 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 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& 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); - } - - // Try changing the bond parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 0.9; - forceField->setBondParameters(0, 0, 1, parameters); - parameters[0] = 1.3; - parameters[1] = 0.8; - forceField->setBondParameters(1, 1, 2, parameters); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); - } -} - -void testManyParameters() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomBondForce* forceField = new CustomBondForce("(a+b+c+d+e+f+g+h+i)*r"); - forceField->addPerBondParameter("a"); - forceField->addPerBondParameter("b"); - forceField->addPerBondParameter("c"); - forceField->addPerBondParameter("d"); - forceField->addPerBondParameter("e"); - forceField->addPerBondParameter("f"); - forceField->addPerBondParameter("g"); - forceField->addPerBondParameter("h"); - forceField->addPerBondParameter("i"); - vector parameters(forceField->getNumPerBondParameters()); - for (int i = 0; i < parameters.size(); i++) - parameters[i] = i; - forceField->addBond(0, 1, parameters); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2.5, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double f = 1+2+3+4+5+6+7+8; - ASSERT_EQUAL_VEC(Vec3(0, f, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(f*2.5, state.getPotentialEnergy(), TOL); -} +#include "CudaTests.h" +#include "TestCustomBondForce.h" void testParallelComputation() { System system; @@ -164,18 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testBonds(); - testManyParameters(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp b/platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp index bd186d0dd..ac619558c 100644 --- a/platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp @@ -29,247 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomCompoundBondForce. - */ +#include "CudaTests.h" +#include "TestCustomCentroidBondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/CustomCentroidBondForce.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testHarmonicBond() { - System system; - system.addParticle(1.0); - system.addParticle(2.0); - system.addParticle(3.0); - system.addParticle(4.0); - system.addParticle(5.0); - CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "k*distance(g1,g2)^2"); - force->addPerBondParameter("k"); - vector particles1; - particles1.push_back(0); - particles1.push_back(1); - vector particles2; - particles2.push_back(2); - particles2.push_back(3); - particles2.push_back(4); - force->addGroup(particles1); - force->addGroup(particles2); - vector groups; - groups.push_back(0); - groups.push_back(1); - vector parameters; - parameters.push_back(1.0); - force->addBond(groups, parameters); - system.addForce(force); - ASSERT(!system.usesPeriodicBoundaryConditions()); - - // The center of mass of group 0 is (1.5, 0, 0). - - vector positions(5); - positions[0] = Vec3(2.5, 0, 0); - positions[1] = Vec3(1, 0, 0); - - // The center of mass of group 1 is (-1, 0, 0). - - positions[2] = Vec3(-6, 0, 0); - positions[3] = Vec3(-1, 0, 0); - positions[4] = Vec3(2, 0, 0); - - // Check the forces and energy. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(2.5*2.5, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(-2*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-2*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); - - // Update the per-bond parameter and see if the results change. - - parameters[0] = 2.0; - force->setBondParameters(0, groups, parameters); - force->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(2*2.5*2.5, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(-4*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-4*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); - - // All the particles should be treated as a single molecule. - - vector > molecules = context.getMolecules(); - ASSERT_EQUAL(1, molecules.size()); - ASSERT_EQUAL(5, molecules[0].size()); -} - -void testComplexFunction() { - int numParticles = 5; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(2.0); - vector table(20); - for (int i = 0; i < 20; i++) - table[i] = sin(0.11*i); - - // When every group contains only one particle, a CustomCentroidBondForce is identical to a - // CustomCompoundBondForce. Use that to test a complicated energy function with lots of terms. - - CustomCompoundBondForce* compound = new CustomCompoundBondForce(4, "x1+y2+z4+fn(distance(p1,p2))*angle(p3,p2,p4)+scale*dihedral(p2,p1,p4,p3)"); - CustomCentroidBondForce* centroid = new CustomCentroidBondForce(4, "x1+y2+z4+fn(distance(g1,g2))*angle(g3,g2,g4)+scale*dihedral(g2,g1,g4,g3)"); - compound->addGlobalParameter("scale", 0.5); - centroid->addGlobalParameter("scale", 0.5); - compound->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); - centroid->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); - - // Add two bonds to the CustomCompoundBondForce. - - vector particles(4); - vector parameters; - particles[0] = 0; - particles[1] = 1; - particles[2] = 2; - particles[3] = 3; - compound->addBond(particles, parameters); - particles[0] = 2; - particles[1] = 4; - particles[2] = 3; - particles[3] = 1; - compound->addBond(particles, parameters); - - // Add identical bonds to the CustomCentroidBondForce. As a stronger test, make sure that - // group number is different from particle number. - - vector groupMembers(1); - groupMembers[0] = 3; - centroid->addGroup(groupMembers); - groupMembers[0] = 0; - centroid->addGroup(groupMembers); - groupMembers[0] = 1; - centroid->addGroup(groupMembers); - groupMembers[0] = 2; - centroid->addGroup(groupMembers); - groupMembers[0] = 4; - centroid->addGroup(groupMembers); - vector groups(4); - groups[0] = 1; - groups[1] = 2; - groups[2] = 3; - groups[3] = 0; - centroid->addBond(groups, parameters); - groups[0] = 3; - groups[1] = 4; - groups[2] = 0; - groups[3] = 2; - centroid->addBond(groups, parameters); - - // Add both forces as different force groups, and create a context. - - centroid->setForceGroup(1); - system.addForce(compound); - system.addForce(centroid); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - - // Evaluate the force and energy for various positions and see if they match. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < numParticles; j++) - positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy, false, 1<<0); - State state2 = context.getState(State::Forces | State::Energy, false, 1<<1); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), TOL); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], TOL); - } -} - -void testCustomWeights() { - System system; - system.addParticle(1.0); - system.addParticle(2.0); - system.addParticle(3.0); - system.addParticle(4.0); - CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "distance(g1,g2)^2"); - vector particles(2); - vector weights(2); - particles[0] = 0; - particles[1] = 1; - weights[0] = 0.5; - weights[1] = 1.5; - force->addGroup(particles, weights); - particles[0] = 2; - particles[1] = 3; - weights[0] = 2.0; - weights[1] = 1.0; - force->addGroup(particles, weights); - vector groups; - groups.push_back(0); - groups.push_back(1); - vector parameters; - force->addBond(groups, parameters); - system.addForce(force); - - // The center of mass of group 0 is (0, 1, 0). - - vector positions(4); - positions[0] = Vec3(0, 4, 0); - positions[1] = Vec3(0, 0, 0); - - // The center of mass of group 1 is (0, 10, 0). - - positions[2] = Vec3(0, 9, 0); - positions[3] = Vec3(0, 12, 0); - - // Check the forces and energy. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(9.0*9.0, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(0, 2*9*(0.5/2.0), 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 2*9*(1.5/2.0), 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -2*9*(2.0/3.0), 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -2*9*(1.0/3.0), 0), state.getForces()[3], TOL); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testHarmonicBond(); - testComplexFunction(); - testCustomWeights(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCustomCompoundBondForce.cpp b/platforms/cuda/tests/TestCudaCustomCompoundBondForce.cpp index fdd61f61b..2dad6e68c 100644 --- a/platforms/cuda/tests/TestCudaCustomCompoundBondForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomCompoundBondForce.cpp @@ -29,145 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of CustomCompoundBondForce. - */ - -#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/CustomCompoundBondForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testBond() { - // Create a system using a CustomCompoundBondForce. - - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(4, "0.5*kb*((distance(p1,p2)-b0)^2+(distance(p2,p3)-b0)^2)+0.5*ka*(angle(p2,p3,p4)-a0)^2+kt*(1+cos(dihedral(p1,p2,p3,p4)-t0))"); - custom->addPerBondParameter("kb"); - custom->addPerBondParameter("ka"); - custom->addPerBondParameter("kt"); - custom->addPerBondParameter("b0"); - custom->addPerBondParameter("a0"); - custom->addPerBondParameter("t0"); - vector particles(4); - particles[0] = 0; - particles[1] = 1; - particles[2] = 3; - particles[3] = 2; - vector parameters(6); - parameters[0] = 1.5; - parameters[1] = 0.8; - parameters[2] = 0.6; - parameters[3] = 1.1; - parameters[4] = 2.9; - parameters[5] = 1.3; - custom->addBond(particles, parameters); - customSystem.addForce(custom); - - // Create an identical system using standard forces. - - System standardSystem; - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - HarmonicBondForce* bonds = new HarmonicBondForce(); - bonds->addBond(0, 1, 1.1, 1.5); - bonds->addBond(1, 3, 1.1, 1.5); - standardSystem.addForce(bonds); - HarmonicAngleForce* angles = new HarmonicAngleForce(); - angles->addAngle(1, 3, 2, 2.9, 0.8); - standardSystem.addForce(angles); - PeriodicTorsionForce* torsions = new PeriodicTorsionForce(); - torsions->addTorsion(0, 1, 3, 2, 1, 1.3, 0.6); - standardSystem.addForce(torsions); - - // 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); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(standardSystem, integrator2, platform); - vector 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the bond parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[3] = 1.3; - custom->setBondParameters(0, particles, parameters); - custom->updateParametersInContext(c1); - bonds->setBondParameters(0, 0, 1, 1.3, 1.6); - bonds->setBondParameters(1, 1, 3, 1.3, 1.6); - bonds->updateParametersInContext(c2); - { - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} - -void testPositionDependence() { - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(2, "scale1*distance(p1,p2)+scale2*x1+2*y2"); - custom->addGlobalParameter("scale1", 0.3); - custom->addGlobalParameter("scale2", 0.2); - vector particles(2); - particles[0] = 1; - particles[1] = 0; - vector parameters; - custom->addBond(particles, parameters); - customSystem.addForce(custom); - vector positions(2); - positions[0] = Vec3(1.5, 1, 0); - positions[1] = Vec3(0.5, 1, 0); - VerletIntegrator integrator(0.01); - Context context(customSystem, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(0.3*1.0+0.2*0.5+2*1, state.getPotentialEnergy(), 1e-5); - ASSERT_EQUAL_VEC(Vec3(-0.3, -2, 0), state.getForces()[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3-0.2, 0, 0), state.getForces()[1], 1e-5); -} +#include "CudaTests.h" +#include "TestCustomCompoundBondForce.h" void testParallelComputation() { System system; @@ -202,165 +65,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testContinuous2DFunction() { - const int xsize = 10; - const int ysize = 11; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1)+1"); - vector particles(1, 0); - forceField->addBond(particles, vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[0] = Vec3(x, y, 1.5); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - Vec3 force(0, 0, 0); - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1; - force[0] = -0.25*cos(0.25*x)*cos(0.33*y); - force[1] = 0.3*sin(0.25*x)*sin(0.33*y); - } - ASSERT_EQUAL_VEC(force, forces[0], 0.1); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - const double zmin = 0.2; - const double zmax = 1.3; - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1,z1)+1"); - vector particles(1, 0); - forceField->addBond(particles, vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[0] = Vec3(x, y, z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - Vec3 force(0, 0, 0); - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1; - force[0] = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - force[1] = 0.3*sin(0.25*x)*sin(0.33*y)*(1.0+z); - force[2] = -sin(0.25*x)*cos(0.33*y); - } - ASSERT_EQUAL_VEC(force, forces[0], 0.1); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); - } - } - } -} - -void testMultipleBonds() { - // Two compound bonds using Urey-Bradley example from API doc - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(3, - "0.5*(kangle*(angle(p1,p2,p3)-theta0)^2+kbond*(distance(p1,p3)-r0)^2)"); - custom->addPerBondParameter("kangle"); - custom->addPerBondParameter("kbond"); - custom->addPerBondParameter("theta0"); - custom->addPerBondParameter("r0"); - vector parameters(4); - parameters[0] = 1.0; - parameters[1] = 1.0; - parameters[2] = 2 * M_PI / 3; - parameters[3] = sqrt(3.0) / 2; - vector particles0(3); - particles0[0] = 0; - particles0[1] = 1; - particles0[2] = 2; - vector particles1(3); - particles1[0] = 1; - particles1[1] = 2; - particles1[2] = 3; - custom->addBond(particles0, parameters); - custom->addBond(particles1, parameters); - customSystem.addForce(custom); - - vector positions(4); - positions[0] = Vec3(0, 0.5, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(0.5, 0, 0); - positions[3] = Vec3(0.6, 0, 0.4); - VerletIntegrator integrator(0.01); - Context context(customSystem, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(0.199, state.getPotentialEnergy(), 1e-3); - vector forces(state.getForces()); - ASSERT_EQUAL_VEC(Vec3(-1.160, 0.112, 0.0), forces[0], 1e-3); - ASSERT_EQUAL_VEC(Vec3(0.927, 1.047, -0.638), forces[1], 1e-3); - ASSERT_EQUAL_VEC(Vec3(-0.543, -1.160, 0.721), forces[2], 1e-3); - ASSERT_EQUAL_VEC(Vec3(0.776, 0.0, -0.084), forces[3], 1e-3); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testBond(); - testPositionDependence(); - testParallelComputation(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testMultipleBonds(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaCustomExternalForce.cpp b/platforms/cuda/tests/TestCudaCustomExternalForce.cpp index b024ab48d..b770bfcce 100644 --- a/platforms/cuda/tests/TestCudaCustomExternalForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomExternalForce.cpp @@ -29,106 +29,9 @@ * 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 "SimTKOpenMMRealType.h" +#include "CudaTests.h" +#include "TestCustomExternalForce.h" #include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testForce() { - 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 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 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& 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); - } - - // Try changing the parameters and make sure it's still correct. - - parameters[0] = 1.4; - parameters[1] = 3.5; - forceField->setParticleParameters(1, 2, parameters); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& 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.5*2.0*1.4, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(0.5*(1.0 + 2.0*1.5*1.5 + 3.5*1.4*1.4), state.getPotentialEnergy(), TOL); - } -} - -void testManyParameters() { - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomExternalForce* forceField = new CustomExternalForce("xscale*(x-x0)^2+yscale*(y-y0)^2+zscale*(z-z0)^2"); - forceField->addPerParticleParameter("x0"); - forceField->addPerParticleParameter("y0"); - forceField->addPerParticleParameter("z0"); - forceField->addPerParticleParameter("xscale"); - forceField->addPerParticleParameter("yscale"); - forceField->addPerParticleParameter("zscale"); - vector parameters(6); - parameters[0] = 1.0; - parameters[1] = 2.0; - parameters[2] = 3.0; - parameters[3] = 0.1; - parameters[4] = 0.2; - parameters[5] = 0.3; - forceField->addParticle(0, parameters); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - positions[0] = Vec3(0, -1, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2*0.1*1.0, 2*0.2*3.0, 2*0.3*3.0), forces[0], TOL); - ASSERT_EQUAL_TOL(0.1*1*1 + 0.2*3*3 + 0.3*3*3, state.getPotentialEnergy(), TOL); -} void testParallelComputation() { System system; @@ -161,60 +64,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testPeriodic() { - Vec3 vx(5, 0, 0); - Vec3 vy(0, 6, 0); - Vec3 vz(1, 2, 7); - double x0 = 51, y0 = -17, z0 = 11.2; - System system; - system.setDefaultPeriodicBoxVectors(vx, vy, vz); - system.addParticle(1.0); - CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - vector params(3); - params[0] = x0; - params[1] = y0; - params[2] = z0; - force->addParticle(0, params); - system.addForce(force); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - vector positions(1); - positions[0] = Vec3(0, 2, 0); - context.setPositions(positions); - for (int i = 0; i < 100; i++) { - State state = context.getState(State::Positions | State::Forces | State::Energy); - - // Apply periodic boundary conditions to the difference between the two positions. - - Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; - delta -= vz*floor(delta[2]/vz[2]+0.5); - delta -= vy*floor(delta[1]/vy[1]+0.5); - delta -= vx*floor(delta[0]/vx[0]+0.5); - - // Verify that the force and energy are correct. - - ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-5); - ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-5); - integrator.step(1); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testForce(); - testManyParameters(); - testParallelComputation(); - testPeriodic(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaCustomGBForce.cpp b/platforms/cuda/tests/TestCudaCustomGBForce.cpp index cac8c38ae..5b5dcc364 100644 --- a/platforms/cuda/tests/TestCudaCustomGBForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomGBForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,453 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of CustomGBForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "sfmt/SFMT.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/CustomGBForce.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMethod customMethod) { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - const double cutoff = 2.0; - - // Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction. - - System standardSystem; - System customSystem; - for (int i = 0; i < numParticles; i++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - } - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - GBSAOBCForce* obc = new GBSAOBCForce(); - CustomGBForce* custom = new CustomGBForce(); - obc->setCutoffDistance(cutoff); - custom->setCutoffDistance(cutoff); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("solventDielectric", obc->getSolventDielectric()); - custom->addGlobalParameter("soluteDielectric", obc->getSoluteDielectric()); - custom->addComputedValue("I", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=I*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - string invCutoffString = ""; - if (obcMethod != GBSAOBCForce::NoCutoff) { - stringstream s; - s<<(1.0/cutoff); - invCutoffString = s.str(); - } - custom->addEnergyTerm("138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("+invCutoffString+"-1/f);" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - obc->addParticle(1.0, 0.2, 0.5); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.5); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - obc->addParticle(1.0, 0.2, 0.8); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.8); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - obc->setNonbondedMethod(obcMethod); - custom->setNonbondedMethod(customMethod); - standardSystem.addForce(obc); - customSystem.addForce(custom); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - context1.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - context2.setVelocities(velocities); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } - - // Try changing the particle parameters and make sure it's still correct. - - for (int i = 0; i < numMolecules/2; i++) { - obc->setParticleParameters(2*i, 1.1, 0.3, 0.6); - params[0] = 1.1; - params[1] = 0.3; - params[2] = 0.6; - custom->setParticleParameters(2*i, params); - obc->setParticleParameters(2*i+1, -1.1, 0.2, 0.4); - params[0] = -1.1; - params[1] = 0.2; - params[2] = 0.4; - custom->setParticleParameters(2*i+1, params); - } - obc->updateParametersInContext(context1); - custom->updateParametersInContext(context2); - state1 = context1.getState(State::Forces | State::Energy); - state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -void testMembrane() { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - - // Create a system with an implicit membrane. - - System system; - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - CustomGBForce* custom = new CustomGBForce(); - custom->setCutoffDistance(2.0); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("thickness", 3); - custom->addGlobalParameter("solventDielectric", 78.3); - custom->addGlobalParameter("soluteDielectric", 1); - custom->addComputedValue("Imol", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("Imem", "(1/radius+2*log(2)/thickness)/(1+exp(7.2*(abs(z)+radius-0.5*thickness)))", CustomGBForce::SingleParticle); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=max(Imol,Imem)*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - custom->addEnergyTerm("-138.935456*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - system.addForce(custom); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocities(velocities); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-2; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); -} - -void testTabulatedFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "0", CustomGBForce::ParticlePair); - force->addEnergyTerm("fn(r)+1", CustomGBForce::ParticlePair); - force->addParticle(vector()); - force->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(std::sin(0.25*i)); - force->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& 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 testMultipleChainRules() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "2*r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+1", CustomGBForce::SingleParticle); - force->addComputedValue("c", "2*b+a", CustomGBForce::SingleParticle); - force->addEnergyTerm("0.1*a+1*b+10*c", CustomGBForce::SingleParticle); // 0.1*(2*r) + 2*r+1 + 10*(3*a+2) = 0.2*r + 2*r+1 + 40*r+20+20*r = 62.2*r+21 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 1; i < 5; i++) { - positions[1] = Vec3(i, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(124.4, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-124.4, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(2*(62.2*i+21), state.getPotentialEnergy(), 0.02); - } -} - -void testPositionDependence() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+x*y", CustomGBForce::SingleParticle); - force->addEnergyTerm("b*z", CustomGBForce::SingleParticle); - force->addEnergyTerm("b1+b2", CustomGBForce::ParticlePair); // = 2*r+x1*y1+x2*y2 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - vector forces(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < 5; i++) { - positions[0] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - positions[1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - Vec3 delta = positions[0]-positions[1]; - double r = sqrt(delta.dot(delta)); - double energy = 2*r+positions[0][0]*positions[0][1]+positions[1][0]*positions[1][1]; - for (int j = 0; j < 2; j++) - energy += positions[j][2]*(r+positions[j][0]*positions[j][1]); - Vec3 force1(-(1+positions[0][2])*delta[0]/r-(1+positions[0][2])*positions[0][1]-(1+positions[1][2])*delta[0]/r, - -(1+positions[0][2])*delta[1]/r-(1+positions[0][2])*positions[0][0]-(1+positions[1][2])*delta[1]/r, - -(1+positions[0][2])*delta[2]/r-(r+positions[0][0]*positions[0][1])-(1+positions[1][2])*delta[2]/r); - Vec3 force2((1+positions[0][2])*delta[0]/r+(1+positions[1][2])*delta[0]/r-(1+positions[1][2])*positions[1][1], - (1+positions[0][2])*delta[1]/r+(1+positions[1][2])*delta[1]/r-(1+positions[1][2])*positions[1][0], - (1+positions[0][2])*delta[2]/r+(1+positions[1][2])*delta[2]/r-(r+positions[1][0]*positions[1][1])); - ASSERT_EQUAL_VEC(force1, forces[0], 1e-4); - ASSERT_EQUAL_VEC(force2, forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(2), positions3(2); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); - } -} - -void testExclusions() { - for (int i = 0; i < 4; i++) { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", i < 2 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addEnergyTerm("a", CustomGBForce::SingleParticle); - force->addEnergyTerm("(1+a1+a2)*r", i%2 == 0 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addParticle(vector()); - force->addParticle(vector()); - force->addExclusion(0, 1); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double f, energy; - switch (i) - { - case 0: // e = 0 - f = 0; - energy = 0; - break; - case 1: // e = r - f = 1; - energy = 1; - break; - case 2: // e = 2r - f = 2; - energy = 2; - break; - case 3: // e = 3r + 2r^2 - f = 7; - energy = 5; - break; - default: - ASSERT(false); - } - ASSERT_EQUAL_VEC(Vec3(f, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-f, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = stepSize/norm; - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[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); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); - } -} +#include "CudaTests.h" +#include "TestCustomGBForce.h" -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff); - testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic); - testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic); - testMembrane(); - testTabulatedFunction(); - testMultipleChainRules(); - testPositionDependence(); - testExclusions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaPeriodicTorsionForce.cpp b/platforms/cuda/tests/TestCudaPeriodicTorsionForce.cpp index 82349da6e..ef1acf85e 100644 --- a/platforms/cuda/tests/TestCudaPeriodicTorsionForce.cpp +++ b/platforms/cuda/tests/TestCudaPeriodicTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,69 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of PeriodicTorsionForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testPeriodicTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - PeriodicTorsionForce* forceField = new PeriodicTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 2, PI_M/3, 1.1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 2); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double torque = -2*1.1*std::sin(2*PI_M/3); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 3, PI_M/3.2, 1.3); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta = (3*PI_M/2)-(PI_M/3.2); - double torque = -3*1.3*std::sin(dtheta); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.3*(1+std::cos(dtheta)), state.getPotentialEnergy(), TOL); - } -} +#include "CudaTests.h" +#include "TestPeriodicTorsionForce.h" void testParallelComputation() { System system; @@ -121,18 +60,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testPeriodicTorsions(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/cuda/tests/TestCudaRBTorsionForce.cpp b/platforms/cuda/tests/TestCudaRBTorsionForce.cpp index 0db592c08..4e9de86c6 100644 --- a/platforms/cuda/tests/TestCudaRBTorsionForce.cpp +++ b/platforms/cuda/tests/TestCudaRBTorsionForce.cpp @@ -29,88 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of RBTorsionForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/RBTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testRBTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - RBTorsionForce* forceField = new RBTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 1, 1); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.1*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.1*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.11*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.11*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} +#include "CudaTests.h" +#include "TestRBTorsionForce.h" void testParallelComputation() { System system; @@ -140,18 +60,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testRBTorsions(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/opencl/tests/OpenCLTests.h b/platforms/opencl/tests/OpenCLTests.h index 3652c1c1a..a76ea5aa8 100644 --- a/platforms/opencl/tests/OpenCLTests.h +++ b/platforms/opencl/tests/OpenCLTests.h @@ -37,4 +37,4 @@ OpenMM::OpenCLPlatform platform; void initializeTests(int argc, char* argv[]) { if (argc > 1) platform.setPropertyDefaultValue("OpenCLPrecision", std::string(argv[1])); -} \ No newline at end of file +} diff --git a/platforms/opencl/tests/TestOpenCLCustomAngleForce.cpp b/platforms/opencl/tests/TestOpenCLCustomAngleForce.cpp index 19a4befc9..30757bc2a 100644 --- a/platforms/opencl/tests/TestOpenCLCustomAngleForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomAngleForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,109 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomAngleForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomAngleForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -static OpenCLPlatform platform; - -void testAngles() { - // 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 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 positions(4); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(harmonicSystem, integrator2, platform); - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the angle parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 0.9; - custom->setAngleParameters(0, 0, 1, 2, parameters); - parameters[0] = 2.1; - parameters[1] = 0.6; - custom->setAngleParameters(1, 1, 2, 3, parameters); - custom->updateParametersInContext(c1); - harmonic->setAngleParameters(0, 0, 1, 2, 1.6, 0.9); - harmonic->setAngleParameters(1, 1, 2, 3, 2.1, 0.6); - harmonic->updateParametersInContext(c2); - { - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} +#include "OpenCLTests.h" +#include "TestCustomAngleForce.h" void testParallelComputation() { System system; @@ -162,20 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testAngles(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - - - diff --git a/platforms/opencl/tests/TestOpenCLCustomBondForce.cpp b/platforms/opencl/tests/TestOpenCLCustomBondForce.cpp index 357b674b8..8153c0ea6 100644 --- a/platforms/opencl/tests/TestOpenCLCustomBondForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomBondForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,111 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomBondForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomBondForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testBonds() { - 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 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 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& 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); - } - - // Try changing the bond parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 0.9; - forceField->setBondParameters(0, 0, 1, parameters); - parameters[0] = 1.3; - parameters[1] = 0.8; - forceField->setBondParameters(1, 1, 2, parameters); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); - } -} - -void testManyParameters() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomBondForce* forceField = new CustomBondForce("(a+b+c+d+e+f+g+h+i)*r"); - forceField->addPerBondParameter("a"); - forceField->addPerBondParameter("b"); - forceField->addPerBondParameter("c"); - forceField->addPerBondParameter("d"); - forceField->addPerBondParameter("e"); - forceField->addPerBondParameter("f"); - forceField->addPerBondParameter("g"); - forceField->addPerBondParameter("h"); - forceField->addPerBondParameter("i"); - vector parameters(forceField->getNumPerBondParameters()); - for (int i = 0; i < (int) parameters.size(); i++) - parameters[i] = i; - forceField->addBond(0, 1, parameters); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2.5, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double f = 1+2+3+4+5+6+7+8; - ASSERT_EQUAL_VEC(Vec3(0, f, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(f*2.5, state.getPotentialEnergy(), TOL); -} +#include "OpenCLTests.h" +#include "TestCustomBondForce.h" void testParallelComputation() { System system; @@ -164,19 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testBonds(); - testManyParameters(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/opencl/tests/TestOpenCLCustomCentroidBondForce.cpp b/platforms/opencl/tests/TestOpenCLCustomCentroidBondForce.cpp index 1bbd34443..4b6615a22 100644 --- a/platforms/opencl/tests/TestOpenCLCustomCentroidBondForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomCentroidBondForce.cpp @@ -29,247 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomCompoundBondForce. - */ +#include "OpenCLTests.h" +#include "TestCustomCentroidBondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomCentroidBondForce.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testHarmonicBond() { - System system; - system.addParticle(1.0); - system.addParticle(2.0); - system.addParticle(3.0); - system.addParticle(4.0); - system.addParticle(5.0); - CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "k*distance(g1,g2)^2"); - force->addPerBondParameter("k"); - vector particles1; - particles1.push_back(0); - particles1.push_back(1); - vector particles2; - particles2.push_back(2); - particles2.push_back(3); - particles2.push_back(4); - force->addGroup(particles1); - force->addGroup(particles2); - vector groups; - groups.push_back(0); - groups.push_back(1); - vector parameters; - parameters.push_back(1.0); - force->addBond(groups, parameters); - system.addForce(force); - ASSERT(!system.usesPeriodicBoundaryConditions()); - - // The center of mass of group 0 is (1.5, 0, 0). - - vector positions(5); - positions[0] = Vec3(2.5, 0, 0); - positions[1] = Vec3(1, 0, 0); - - // The center of mass of group 1 is (-1, 0, 0). - - positions[2] = Vec3(-6, 0, 0); - positions[3] = Vec3(-1, 0, 0); - positions[4] = Vec3(2, 0, 0); - - // Check the forces and energy. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(2.5*2.5, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(-2*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-2*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); - - // Update the per-bond parameter and see if the results change. - - parameters[0] = 2.0; - force->setBondParameters(0, groups, parameters); - force->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(2*2.5*2.5, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(-4*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-4*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); - - // All the particles should be treated as a single molecule. - - vector > molecules = context.getMolecules(); - ASSERT_EQUAL(1, molecules.size()); - ASSERT_EQUAL(5, molecules[0].size()); -} - -void testComplexFunction() { - int numParticles = 5; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(2.0); - vector table(20); - for (int i = 0; i < 20; i++) - table[i] = sin(0.11*i); - - // When every group contains only one particle, a CustomCentroidBondForce is identical to a - // CustomCompoundBondForce. Use that to test a complicated energy function with lots of terms. - - CustomCompoundBondForce* compound = new CustomCompoundBondForce(4, "x1+y2+z4+fn(distance(p1,p2))*angle(p3,p2,p4)+scale*dihedral(p2,p1,p4,p3)"); - CustomCentroidBondForce* centroid = new CustomCentroidBondForce(4, "x1+y2+z4+fn(distance(g1,g2))*angle(g3,g2,g4)+scale*dihedral(g2,g1,g4,g3)"); - compound->addGlobalParameter("scale", 0.5); - centroid->addGlobalParameter("scale", 0.5); - compound->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); - centroid->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); - - // Add two bonds to the CustomCompoundBondForce. - - vector particles(4); - vector parameters; - particles[0] = 0; - particles[1] = 1; - particles[2] = 2; - particles[3] = 3; - compound->addBond(particles, parameters); - particles[0] = 2; - particles[1] = 4; - particles[2] = 3; - particles[3] = 1; - compound->addBond(particles, parameters); - - // Add identical bonds to the CustomCentroidBondForce. As a stronger test, make sure that - // group number is different from particle number. - - vector groupMembers(1); - groupMembers[0] = 3; - centroid->addGroup(groupMembers); - groupMembers[0] = 0; - centroid->addGroup(groupMembers); - groupMembers[0] = 1; - centroid->addGroup(groupMembers); - groupMembers[0] = 2; - centroid->addGroup(groupMembers); - groupMembers[0] = 4; - centroid->addGroup(groupMembers); - vector groups(4); - groups[0] = 1; - groups[1] = 2; - groups[2] = 3; - groups[3] = 0; - centroid->addBond(groups, parameters); - groups[0] = 3; - groups[1] = 4; - groups[2] = 0; - groups[3] = 2; - centroid->addBond(groups, parameters); - - // Add both forces as different force groups, and create a context. - - centroid->setForceGroup(1); - system.addForce(compound); - system.addForce(centroid); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - - // Evaluate the force and energy for various positions and see if they match. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < numParticles; j++) - positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy, false, 1<<0); - State state2 = context.getState(State::Forces | State::Energy, false, 1<<1); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), TOL); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], TOL); - } -} - -void testCustomWeights() { - System system; - system.addParticle(1.0); - system.addParticle(2.0); - system.addParticle(3.0); - system.addParticle(4.0); - CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "distance(g1,g2)^2"); - vector particles(2); - vector weights(2); - particles[0] = 0; - particles[1] = 1; - weights[0] = 0.5; - weights[1] = 1.5; - force->addGroup(particles, weights); - particles[0] = 2; - particles[1] = 3; - weights[0] = 2.0; - weights[1] = 1.0; - force->addGroup(particles, weights); - vector groups; - groups.push_back(0); - groups.push_back(1); - vector parameters; - force->addBond(groups, parameters); - system.addForce(force); - - // The center of mass of group 0 is (0, 1, 0). - - vector positions(4); - positions[0] = Vec3(0, 4, 0); - positions[1] = Vec3(0, 0, 0); - - // The center of mass of group 1 is (0, 10, 0). - - positions[2] = Vec3(0, 9, 0); - positions[3] = Vec3(0, 12, 0); - - // Check the forces and energy. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(9.0*9.0, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(0, 2*9*(0.5/2.0), 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 2*9*(1.5/2.0), 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -2*9*(2.0/3.0), 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -2*9*(1.0/3.0), 0), state.getForces()[3], TOL); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testHarmonicBond(); - testComplexFunction(); - testCustomWeights(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLCustomCompoundBondForce.cpp b/platforms/opencl/tests/TestOpenCLCustomCompoundBondForce.cpp index 8e7d6fd82..5cc47af23 100644 --- a/platforms/opencl/tests/TestOpenCLCustomCompoundBondForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomCompoundBondForce.cpp @@ -29,145 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomCompoundBondForce. - */ - -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testBond() { - // Create a system using a CustomCompoundBondForce. - - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(4, "0.5*kb*((distance(p1,p2)-b0)^2+(distance(p2,p3)-b0)^2)+0.5*ka*(angle(p2,p3,p4)-a0)^2+kt*(1+cos(dihedral(p1,p2,p3,p4)-t0))"); - custom->addPerBondParameter("kb"); - custom->addPerBondParameter("ka"); - custom->addPerBondParameter("kt"); - custom->addPerBondParameter("b0"); - custom->addPerBondParameter("a0"); - custom->addPerBondParameter("t0"); - vector particles(4); - particles[0] = 0; - particles[1] = 1; - particles[2] = 3; - particles[3] = 2; - vector parameters(6); - parameters[0] = 1.5; - parameters[1] = 0.8; - parameters[2] = 0.6; - parameters[3] = 1.1; - parameters[4] = 2.9; - parameters[5] = 1.3; - custom->addBond(particles, parameters); - customSystem.addForce(custom); - - // Create an identical system using standard forces. - - System standardSystem; - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - HarmonicBondForce* bonds = new HarmonicBondForce(); - bonds->addBond(0, 1, 1.1, 1.5); - bonds->addBond(1, 3, 1.1, 1.5); - standardSystem.addForce(bonds); - HarmonicAngleForce* angles = new HarmonicAngleForce(); - angles->addAngle(1, 3, 2, 2.9, 0.8); - standardSystem.addForce(angles); - PeriodicTorsionForce* torsions = new PeriodicTorsionForce(); - torsions->addTorsion(0, 1, 3, 2, 1, 1.3, 0.6); - standardSystem.addForce(torsions); - - // 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); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(standardSystem, integrator2, platform); - vector 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the bond parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[3] = 1.3; - custom->setBondParameters(0, particles, parameters); - custom->updateParametersInContext(c1); - bonds->setBondParameters(0, 0, 1, 1.3, 1.6); - bonds->setBondParameters(1, 1, 3, 1.3, 1.6); - bonds->updateParametersInContext(c2); - { - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} - -void testPositionDependence() { - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(2, "scale1*distance(p1,p2)+scale2*x1+2*y2"); - custom->addGlobalParameter("scale1", 0.3); - custom->addGlobalParameter("scale2", 0.2); - vector particles(2); - particles[0] = 1; - particles[1] = 0; - vector parameters; - custom->addBond(particles, parameters); - customSystem.addForce(custom); - vector positions(2); - positions[0] = Vec3(1.5, 1, 0); - positions[1] = Vec3(0.5, 1, 0); - VerletIntegrator integrator(0.01); - Context context(customSystem, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(0.3*1.0+0.2*0.5+2*1, state.getPotentialEnergy(), 1e-5); - ASSERT_EQUAL_VEC(Vec3(-0.3, -2, 0), state.getForces()[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3-0.2, 0, 0), state.getForces()[1], 1e-5); -} +#include "OpenCLTests.h" +#include "TestCustomCompoundBondForce.h" void testParallelComputation() { System system; @@ -202,165 +65,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testContinuous2DFunction() { - const int xsize = 10; - const int ysize = 11; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1)+1"); - vector particles(1, 0); - forceField->addBond(particles, vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[0] = Vec3(x, y, 1.5); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - Vec3 force(0, 0, 0); - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1; - force[0] = -0.25*cos(0.25*x)*cos(0.33*y); - force[1] = 0.3*sin(0.25*x)*sin(0.33*y); - } - ASSERT_EQUAL_VEC(force, forces[0], 0.1); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - const double zmin = 0.2; - const double zmax = 1.3; - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1,z1)+1"); - vector particles(1, 0); - forceField->addBond(particles, vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[0] = Vec3(x, y, z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - Vec3 force(0, 0, 0); - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1; - force[0] = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - force[1] = 0.3*sin(0.25*x)*sin(0.33*y)*(1.0+z); - force[2] = -sin(0.25*x)*cos(0.33*y); - } - ASSERT_EQUAL_VEC(force, forces[0], 0.1); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); - } - } - } -} - -void testMultipleBonds() { - // Two compound bonds using Urey-Bradley example from API doc - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(3, - "0.5*(kangle*(angle(p1,p2,p3)-theta0)^2+kbond*(distance(p1,p3)-r0)^2)"); - custom->addPerBondParameter("kangle"); - custom->addPerBondParameter("kbond"); - custom->addPerBondParameter("theta0"); - custom->addPerBondParameter("r0"); - vector parameters(4); - parameters[0] = 1.0; - parameters[1] = 1.0; - parameters[2] = 2 * M_PI / 3; - parameters[3] = sqrt(3.0) / 2; - vector particles0(3); - particles0[0] = 0; - particles0[1] = 1; - particles0[2] = 2; - vector particles1(3); - particles1[0] = 1; - particles1[1] = 2; - particles1[2] = 3; - custom->addBond(particles0, parameters); - custom->addBond(particles1, parameters); - customSystem.addForce(custom); - - vector positions(4); - positions[0] = Vec3(0, 0.5, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(0.5, 0, 0); - positions[3] = Vec3(0.6, 0, 0.4); - VerletIntegrator integrator(0.01); - Context context(customSystem, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(0.199, state.getPotentialEnergy(), 1e-3); - vector forces(state.getForces()); - ASSERT_EQUAL_VEC(Vec3(-1.160, 0.112, 0.0), forces[0], 1e-3); - ASSERT_EQUAL_VEC(Vec3(0.927, 1.047, -0.638), forces[1], 1e-3); - ASSERT_EQUAL_VEC(Vec3(-0.543, -1.160, 0.721), forces[2], 1e-3); - ASSERT_EQUAL_VEC(Vec3(0.776, 0.0, -0.084), forces[3], 1e-3); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testBond(); - testPositionDependence(); - testParallelComputation(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testMultipleBonds(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp b/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp index 58dc7ffb4..d544018d0 100644 --- a/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomExternalForce.cpp @@ -29,106 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomExternalForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" +#include "OpenCLTests.h" +#include "TestCustomExternalForce.h" #include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testForce() { - 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 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 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& 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); - } - - // Try changing the parameters and make sure it's still correct. - - parameters[0] = 1.4; - parameters[1] = 3.5; - forceField->setParticleParameters(1, 2, parameters); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& 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.5*2.0*1.4, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(0.5*(1.0 + 2.0*1.5*1.5 + 3.5*1.4*1.4), state.getPotentialEnergy(), TOL); - } -} - -void testManyParameters() { - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomExternalForce* forceField = new CustomExternalForce("xscale*(x-x0)^2+yscale*(y-y0)^2+zscale*(z-z0)^2"); - forceField->addPerParticleParameter("x0"); - forceField->addPerParticleParameter("y0"); - forceField->addPerParticleParameter("z0"); - forceField->addPerParticleParameter("xscale"); - forceField->addPerParticleParameter("yscale"); - forceField->addPerParticleParameter("zscale"); - vector parameters(6); - parameters[0] = 1.0; - parameters[1] = 2.0; - parameters[2] = 3.0; - parameters[3] = 0.1; - parameters[4] = 0.2; - parameters[5] = 0.3; - forceField->addParticle(0, parameters); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - positions[0] = Vec3(0, -1, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2*0.1*1.0, 2*0.2*3.0, 2*0.3*3.0), forces[0], TOL); - ASSERT_EQUAL_TOL(0.1*1*1 + 0.2*3*3 + 0.3*3*3, state.getPotentialEnergy(), TOL); -} void testParallelComputation() { System system; @@ -161,63 +64,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testPeriodic() { - Vec3 vx(5, 0, 0); - Vec3 vy(0, 6, 0); - Vec3 vz(1, 2, 7); - double x0 = 51, y0 = -17, z0 = 11.2; - System system; - system.setDefaultPeriodicBoxVectors(vx, vy, vz); - system.addParticle(1.0); - CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - vector params(3); - params[0] = x0; - params[1] = y0; - params[2] = z0; - force->addParticle(0, params); - system.addForce(force); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - vector positions(1); - positions[0] = Vec3(0, 2, 0); - context.setPositions(positions); - for (int i = 0; i < 100; i++) { - State state = context.getState(State::Positions | State::Forces | State::Energy); - - // Apply periodic boundary conditions to the difference between the two positions. - - Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; - delta -= vz*floor(delta[2]/vz[2]+0.5); - delta -= vy*floor(delta[1]/vy[1]+0.5); - delta -= vx*floor(delta[0]/vx[0]+0.5); - - // Verify that the force and energy are correct. - - ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-5); - ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-5); - integrator.step(1); - } +void runPlatformTests() { + testParallelComputation(); } - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testForce(); - testManyParameters(); - testParallelComputation(); - testPeriodic(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - - - diff --git a/platforms/opencl/tests/TestOpenCLCustomGBForce.cpp b/platforms/opencl/tests/TestOpenCLCustomGBForce.cpp index d94e09351..f5351d9fc 100644 --- a/platforms/opencl/tests/TestOpenCLCustomGBForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomGBForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,453 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomGBForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "sfmt/SFMT.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomGBForce.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMethod customMethod) { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - const double cutoff = 2.0; - - // Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction. - - System standardSystem; - System customSystem; - for (int i = 0; i < numParticles; i++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - } - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - GBSAOBCForce* obc = new GBSAOBCForce(); - CustomGBForce* custom = new CustomGBForce(); - obc->setCutoffDistance(cutoff); - custom->setCutoffDistance(cutoff); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("solventDielectric", obc->getSolventDielectric()); - custom->addGlobalParameter("soluteDielectric", obc->getSoluteDielectric()); - custom->addComputedValue("I", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=I*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - string invCutoffString = ""; - if (obcMethod != GBSAOBCForce::NoCutoff) { - stringstream s; - s<<(1.0/cutoff); - invCutoffString = s.str(); - } - custom->addEnergyTerm("138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("+invCutoffString+"-1/f);" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - obc->addParticle(1.0, 0.2, 0.5); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.5); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - obc->addParticle(1.0, 0.2, 0.8); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.8); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - obc->setNonbondedMethod(obcMethod); - custom->setNonbondedMethod(customMethod); - standardSystem.addForce(obc); - customSystem.addForce(custom); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - context1.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - context2.setVelocities(velocities); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } - - // Try changing the particle parameters and make sure it's still correct. - - for (int i = 0; i < numMolecules/2; i++) { - obc->setParticleParameters(2*i, 1.1, 0.3, 0.6); - params[0] = 1.1; - params[1] = 0.3; - params[2] = 0.6; - custom->setParticleParameters(2*i, params); - obc->setParticleParameters(2*i+1, -1.1, 0.2, 0.4); - params[0] = -1.1; - params[1] = 0.2; - params[2] = 0.4; - custom->setParticleParameters(2*i+1, params); - } - obc->updateParametersInContext(context1); - custom->updateParametersInContext(context2); - state1 = context1.getState(State::Forces | State::Energy); - state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -void testMembrane() { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - - // Create a system with an implicit membrane. - - System system; - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - CustomGBForce* custom = new CustomGBForce(); - custom->setCutoffDistance(2.0); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("thickness", 3); - custom->addGlobalParameter("solventDielectric", 78.3); - custom->addGlobalParameter("soluteDielectric", 1); - custom->addComputedValue("Imol", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("Imem", "(1/radius+2*log(2)/thickness)/(1+exp(7.2*(abs(z)+radius-0.5*thickness)))", CustomGBForce::SingleParticle); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=max(Imol,Imem)*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - custom->addEnergyTerm("-138.935456*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - system.addForce(custom); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocities(velocities); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-2; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); -} - -void testTabulatedFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "0", CustomGBForce::ParticlePair); - force->addEnergyTerm("fn(r)+1", CustomGBForce::ParticlePair); - force->addParticle(vector()); - force->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(std::sin(0.25*i)); - force->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& 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 testMultipleChainRules() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "2*r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+1", CustomGBForce::SingleParticle); - force->addComputedValue("c", "2*b+a", CustomGBForce::SingleParticle); - force->addEnergyTerm("0.1*a+1*b+10*c", CustomGBForce::SingleParticle); // 0.1*(2*r) + 2*r+1 + 10*(3*a+2) = 0.2*r + 2*r+1 + 40*r+20+20*r = 62.2*r+21 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 1; i < 5; i++) { - positions[1] = Vec3(i, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(124.4, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-124.4, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(2*(62.2*i+21), state.getPotentialEnergy(), 0.02); - } -} - -void testPositionDependence() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+x*y", CustomGBForce::SingleParticle); - force->addEnergyTerm("b*z", CustomGBForce::SingleParticle); - force->addEnergyTerm("b1+b2", CustomGBForce::ParticlePair); // = 2*r+x1*y1+x2*y2 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - vector forces(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < 5; i++) { - positions[0] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - positions[1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - Vec3 delta = positions[0]-positions[1]; - double r = sqrt(delta.dot(delta)); - double energy = 2*r+positions[0][0]*positions[0][1]+positions[1][0]*positions[1][1]; - for (int j = 0; j < 2; j++) - energy += positions[j][2]*(r+positions[j][0]*positions[j][1]); - Vec3 force1(-(1+positions[0][2])*delta[0]/r-(1+positions[0][2])*positions[0][1]-(1+positions[1][2])*delta[0]/r, - -(1+positions[0][2])*delta[1]/r-(1+positions[0][2])*positions[0][0]-(1+positions[1][2])*delta[1]/r, - -(1+positions[0][2])*delta[2]/r-(r+positions[0][0]*positions[0][1])-(1+positions[1][2])*delta[2]/r); - Vec3 force2((1+positions[0][2])*delta[0]/r+(1+positions[1][2])*delta[0]/r-(1+positions[1][2])*positions[1][1], - (1+positions[0][2])*delta[1]/r+(1+positions[1][2])*delta[1]/r-(1+positions[1][2])*positions[1][0], - (1+positions[0][2])*delta[2]/r+(1+positions[1][2])*delta[2]/r-(r+positions[1][0]*positions[1][1])); - ASSERT_EQUAL_VEC(force1, forces[0], 1e-4); - ASSERT_EQUAL_VEC(force2, forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(2), positions3(2); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); - } -} - -void testExclusions() { - for (int i = 0; i < 4; i++) { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", i < 2 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addEnergyTerm("a", CustomGBForce::SingleParticle); - force->addEnergyTerm("(1+a1+a2)*r", i%2 == 0 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addParticle(vector()); - force->addParticle(vector()); - force->addExclusion(0, 1); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double f, energy; - switch (i) - { - case 0: // e = 0 - f = 0; - energy = 0; - break; - case 1: // e = r - f = 1; - energy = 1; - break; - case 2: // e = 2r - f = 2; - energy = 2; - break; - case 3: // e = 3r + 2r^2 - f = 7; - energy = 5; - break; - default: - ASSERT(false); - } - ASSERT_EQUAL_VEC(Vec3(f, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-f, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = stepSize/norm; - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[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); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); - } -} +#include "OpenCLTests.h" +#include "TestCustomGBForce.h" -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff); - testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic); - testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic); - testMembrane(); - testTabulatedFunction(); - testMultipleChainRules(); - testPositionDependence(); - testExclusions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLPeriodicTorsionForce.cpp b/platforms/opencl/tests/TestOpenCLPeriodicTorsionForce.cpp index 5b60ce940..8710f8d21 100644 --- a/platforms/opencl/tests/TestOpenCLPeriodicTorsionForce.cpp +++ b/platforms/opencl/tests/TestOpenCLPeriodicTorsionForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,69 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of PeriodicTorsionForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testPeriodicTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - PeriodicTorsionForce* forceField = new PeriodicTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 2, PI_M/3, 1.1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 2); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double torque = -2*1.1*std::sin(2*PI_M/3); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 3, PI_M/3.2, 1.3); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta = (3*PI_M/2)-(PI_M/3.2); - double torque = -3*1.3*std::sin(dtheta); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.3*(1+std::cos(dtheta)), state.getPotentialEnergy(), TOL); - } -} +#include "OpenCLTests.h" +#include "TestPeriodicTorsionForce.h" void testParallelComputation() { System system; @@ -121,18 +60,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testPeriodicTorsions(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/opencl/tests/TestOpenCLRBTorsionForce.cpp b/platforms/opencl/tests/TestOpenCLRBTorsionForce.cpp index e5da88f6a..3525af580 100644 --- a/platforms/opencl/tests/TestOpenCLRBTorsionForce.cpp +++ b/platforms/opencl/tests/TestOpenCLRBTorsionForce.cpp @@ -29,88 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of RBTorsionForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/RBTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testRBTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - RBTorsionForce* forceField = new RBTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 1, 1); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.1*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.1*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.11*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.11*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} +#include "OpenCLTests.h" +#include "TestRBTorsionForce.h" void testParallelComputation() { System system; @@ -140,18 +60,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testRBTorsions(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/reference/tests/ReferenceTests.h b/platforms/reference/tests/ReferenceTests.h index 5ba196b6a..a76269e0f 100644 --- a/platforms/reference/tests/ReferenceTests.h +++ b/platforms/reference/tests/ReferenceTests.h @@ -34,4 +34,4 @@ OpenMM::ReferencePlatform platform; void initializeTests(int argc, char* argv[]) { -} \ No newline at end of file +} diff --git a/platforms/reference/tests/TestReferenceCustomAngleForce.cpp b/platforms/reference/tests/TestReferenceCustomAngleForce.cpp index b892397e6..98eb5e2bb 100644 --- a/platforms/reference/tests/TestReferenceCustomAngleForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomAngleForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,122 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomAngleForce. - */ -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomAngleForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include +#include "ReferenceTests.h" +#include "TestCustomAngleForce.h" -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testAngles() { - // 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 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); - ASSERT(!custom->usesPeriodicBoundaryConditions()); - ASSERT(!customSystem.usesPeriodicBoundaryConditions()); - - // 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 positions(4); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(harmonicSystem, integrator2, platform); - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the angle parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 0.9; - custom->setAngleParameters(0, 0, 1, 2, parameters); - parameters[0] = 2.1; - parameters[1] = 0.6; - custom->setAngleParameters(1, 1, 2, 3, parameters); - custom->updateParametersInContext(c1); - harmonic->setAngleParameters(0, 0, 1, 2, 1.6, 0.9); - harmonic->setAngleParameters(1, 1, 2, 3, 2.1, 0.6); - harmonic->updateParametersInContext(c2); - { - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} - -int main() { - try { - testAngles(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } - - diff --git a/platforms/reference/tests/TestReferenceCustomBondForce.cpp b/platforms/reference/tests/TestReferenceCustomBondForce.cpp index a50bc3e01..b149d6235 100644 --- a/platforms/reference/tests/TestReferenceCustomBondForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomBondForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,90 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomBondForce. - */ -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomBondForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include +#include "ReferenceTests.h" +#include "TestCustomBondForce.h" -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testBonds() { - 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 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); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& 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); - } - - // Try changing the bond parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 0.9; - forceField->setBondParameters(0, 0, 1, parameters); - parameters[0] = 1.3; - parameters[1] = 0.8; - forceField->setBondParameters(1, 1, 2, parameters); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); - } +void runPlatformTests() { } - -int main() { - try { - testBonds(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferenceCustomCentroidBondForce.cpp b/platforms/reference/tests/TestReferenceCustomCentroidBondForce.cpp index 90e590292..ea7fb8d73 100644 --- a/platforms/reference/tests/TestReferenceCustomCentroidBondForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomCentroidBondForce.cpp @@ -29,246 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomCompoundBondForce. - */ +#include "ReferenceTests.h" +#include "TestCustomCentroidBondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomCentroidBondForce.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/System.h" -#include "openmm/TabulatedFunction.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testHarmonicBond() { - System system; - system.addParticle(1.0); - system.addParticle(2.0); - system.addParticle(3.0); - system.addParticle(4.0); - system.addParticle(5.0); - CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "k*distance(g1,g2)^2"); - force->addPerBondParameter("k"); - vector particles1; - particles1.push_back(0); - particles1.push_back(1); - vector particles2; - particles2.push_back(2); - particles2.push_back(3); - particles2.push_back(4); - force->addGroup(particles1); - force->addGroup(particles2); - vector groups; - groups.push_back(0); - groups.push_back(1); - vector parameters; - parameters.push_back(1.0); - force->addBond(groups, parameters); - system.addForce(force); - ASSERT(!system.usesPeriodicBoundaryConditions()); - - // The center of mass of group 0 is (1.5, 0, 0). - - vector positions(5); - positions[0] = Vec3(2.5, 0, 0); - positions[1] = Vec3(1, 0, 0); - - // The center of mass of group 1 is (-1, 0, 0). - - positions[2] = Vec3(-6, 0, 0); - positions[3] = Vec3(-1, 0, 0); - positions[4] = Vec3(2, 0, 0); - - // Check the forces and energy. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(2.5*2.5, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(-2*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-2*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); - ASSERT_EQUAL_VEC(Vec3(2*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); - - // Update the per-bond parameter and see if the results change. - - parameters[0] = 2.0; - force->setBondParameters(0, groups, parameters); - force->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(2*2.5*2.5, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(-4*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-4*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); - ASSERT_EQUAL_VEC(Vec3(4*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); - - // All the particles should be treated as a single molecule. - - vector > molecules = context.getMolecules(); - ASSERT_EQUAL(1, molecules.size()); - ASSERT_EQUAL(5, molecules[0].size()); -} - -void testComplexFunction() { - int numParticles = 5; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(2.0); - vector table(20); - for (int i = 0; i < 20; i++) - table[i] = sin(0.11*i); - - // When every group contains only one particle, a CustomCentroidBondForce is identical to a - // CustomCompoundBondForce. Use that to test a complicated energy function with lots of terms. - - CustomCompoundBondForce* compound = new CustomCompoundBondForce(4, "x1+y2+z4+fn(distance(p1,p2))*angle(p3,p2,p4)+scale*dihedral(p2,p1,p4,p3)"); - CustomCentroidBondForce* centroid = new CustomCentroidBondForce(4, "x1+y2+z4+fn(distance(g1,g2))*angle(g3,g2,g4)+scale*dihedral(g2,g1,g4,g3)"); - compound->addGlobalParameter("scale", 0.5); - centroid->addGlobalParameter("scale", 0.5); - compound->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); - centroid->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); - - // Add two bonds to the CustomCompoundBondForce. - - vector particles(4); - vector parameters; - particles[0] = 0; - particles[1] = 1; - particles[2] = 2; - particles[3] = 3; - compound->addBond(particles, parameters); - particles[0] = 2; - particles[1] = 4; - particles[2] = 3; - particles[3] = 1; - compound->addBond(particles, parameters); - - // Add identical bonds to the CustomCentroidBondForce. As a stronger test, make sure that - // group number is different from particle number. - - vector groupMembers(1); - groupMembers[0] = 3; - centroid->addGroup(groupMembers); - groupMembers[0] = 0; - centroid->addGroup(groupMembers); - groupMembers[0] = 1; - centroid->addGroup(groupMembers); - groupMembers[0] = 2; - centroid->addGroup(groupMembers); - groupMembers[0] = 4; - centroid->addGroup(groupMembers); - vector groups(4); - groups[0] = 1; - groups[1] = 2; - groups[2] = 3; - groups[3] = 0; - centroid->addBond(groups, parameters); - groups[0] = 3; - groups[1] = 4; - groups[2] = 0; - groups[3] = 2; - centroid->addBond(groups, parameters); - - // Add both forces as different force groups, and create a context. - - centroid->setForceGroup(1); - system.addForce(compound); - system.addForce(centroid); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - - // Evaluate the force and energy for various positions and see if they match. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < numParticles; j++) - positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy, false, 1<<0); - State state2 = context.getState(State::Forces | State::Energy, false, 1<<1); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), TOL); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], TOL); - } -} - -void testCustomWeights() { - System system; - system.addParticle(1.0); - system.addParticle(2.0); - system.addParticle(3.0); - system.addParticle(4.0); - CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "distance(g1,g2)^2"); - vector particles(2); - vector weights(2); - particles[0] = 0; - particles[1] = 1; - weights[0] = 0.5; - weights[1] = 1.5; - force->addGroup(particles, weights); - particles[0] = 2; - particles[1] = 3; - weights[0] = 2.0; - weights[1] = 1.0; - force->addGroup(particles, weights); - vector groups; - groups.push_back(0); - groups.push_back(1); - vector parameters; - force->addBond(groups, parameters); - system.addForce(force); - - // The center of mass of group 0 is (0, 1, 0). - - vector positions(4); - positions[0] = Vec3(0, 4, 0); - positions[1] = Vec3(0, 0, 0); - - // The center of mass of group 1 is (0, 10, 0). - - positions[2] = Vec3(0, 9, 0); - positions[3] = Vec3(0, 12, 0); - - // Check the forces and energy. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(9.0*9.0, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(Vec3(0, 2*9*(0.5/2.0), 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 2*9*(1.5/2.0), 0), state.getForces()[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -2*9*(2.0/3.0), 0), state.getForces()[2], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -2*9*(1.0/3.0), 0), state.getForces()[3], TOL); -} - -int main() { - try { - testHarmonicBond(); - testComplexFunction(); - testCustomWeights(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceCustomCompoundBondForce.cpp b/platforms/reference/tests/TestReferenceCustomCompoundBondForce.cpp index 00c109c75..d93d9b619 100644 --- a/platforms/reference/tests/TestReferenceCustomCompoundBondForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomCompoundBondForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,306 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomCompoundBondForce. - */ +#include "ReferenceTests.h" +#include "TestCustomCompoundBondForce.h" -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testBond() { - // Create a system using a CustomCompoundBondForce. - - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(4, "0.5*kb*((distance(p1,p2)-b0)^2+(distance(p2,p3)-b0)^2)+0.5*ka*(angle(p2,p3,p4)-a0)^2+kt*(1+cos(dihedral(p1,p2,p3,p4)-t0))"); - custom->addPerBondParameter("kb"); - custom->addPerBondParameter("ka"); - custom->addPerBondParameter("kt"); - custom->addPerBondParameter("b0"); - custom->addPerBondParameter("a0"); - custom->addPerBondParameter("t0"); - vector particles(4); - particles[0] = 0; - particles[1] = 1; - particles[2] = 3; - particles[3] = 2; - vector parameters(6); - parameters[0] = 1.5; - parameters[1] = 0.8; - parameters[2] = 0.6; - parameters[3] = 1.1; - parameters[4] = 2.9; - parameters[5] = 1.3; - custom->addBond(particles, parameters); - customSystem.addForce(custom); - ASSERT(!custom->usesPeriodicBoundaryConditions()); - ASSERT(!customSystem.usesPeriodicBoundaryConditions()); - - // Create an identical system using standard forces. - - System standardSystem; - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - HarmonicBondForce* bonds = new HarmonicBondForce(); - bonds->addBond(0, 1, 1.1, 1.5); - bonds->addBond(1, 3, 1.1, 1.5); - standardSystem.addForce(bonds); - HarmonicAngleForce* angles = new HarmonicAngleForce(); - angles->addAngle(1, 3, 2, 2.9, 0.8); - standardSystem.addForce(angles); - PeriodicTorsionForce* torsions = new PeriodicTorsionForce(); - torsions->addTorsion(0, 1, 3, 2, 1, 1.3, 0.6); - standardSystem.addForce(torsions); - - // 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); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(standardSystem, integrator2, platform); - vector 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the bond parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[3] = 1.3; - custom->setBondParameters(0, particles, parameters); - custom->updateParametersInContext(c1); - bonds->setBondParameters(0, 0, 1, 1.3, 1.6); - bonds->setBondParameters(1, 1, 3, 1.3, 1.6); - bonds->updateParametersInContext(c2); - { - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} - -void testPositionDependence() { - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(2, "scale1*distance(p1,p2)+scale2*x1+2*y2"); - custom->addGlobalParameter("scale1", 0.3); - custom->addGlobalParameter("scale2", 0.2); - vector particles(2); - particles[0] = 1; - particles[1] = 0; - vector parameters; - custom->addBond(particles, parameters); - customSystem.addForce(custom); - vector positions(2); - positions[0] = Vec3(1.5, 1, 0); - positions[1] = Vec3(0.5, 1, 0); - VerletIntegrator integrator(0.01); - Context context(customSystem, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(0.3*1.0+0.2*0.5+2*1, state.getPotentialEnergy(), 1e-5); - ASSERT_EQUAL_VEC(Vec3(-0.3, -2, 0), state.getForces()[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3-0.2, 0, 0), state.getForces()[1], 1e-5); +void runPlatformTests() { } - -void testContinuous2DFunction() { - const int xsize = 10; - const int ysize = 11; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1)+1"); - vector particles(1, 0); - forceField->addBond(particles, vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[0] = Vec3(x, y, 1.5); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - Vec3 force(0, 0, 0); - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1; - force[0] = -0.25*cos(0.25*x)*cos(0.33*y); - force[1] = 0.3*sin(0.25*x)*sin(0.33*y); - } - ASSERT_EQUAL_VEC(force, forces[0], 0.1); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - const double zmin = 0.2; - const double zmax = 1.3; - System system; - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1,z1)+1"); - vector particles(1, 0); - forceField->addBond(particles, vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(1); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[0] = Vec3(x, y, z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - Vec3 force(0, 0, 0); - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1; - force[0] = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - force[1] = 0.3*sin(0.25*x)*sin(0.33*y)*(1.0+z); - force[2] = -sin(0.25*x)*cos(0.33*y); - } - ASSERT_EQUAL_VEC(force, forces[0], 0.1); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); - } - } - } -} - -void testMultipleBonds() { - // Two compound bonds using Urey-Bradley example from API doc - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomCompoundBondForce* custom = new CustomCompoundBondForce(3, - "0.5*(kangle*(angle(p1,p2,p3)-theta0)^2+kbond*(distance(p1,p3)-r0)^2)"); - custom->addPerBondParameter("kangle"); - custom->addPerBondParameter("kbond"); - custom->addPerBondParameter("theta0"); - custom->addPerBondParameter("r0"); - vector parameters(4); - parameters[0] = 1.0; - parameters[1] = 1.0; - parameters[2] = 2 * M_PI / 3; - parameters[3] = sqrt(3.0) / 2; - vector particles0(3); - particles0[0] = 0; - particles0[1] = 1; - particles0[2] = 2; - vector particles1(3); - particles1[0] = 1; - particles1[1] = 2; - particles1[2] = 3; - custom->addBond(particles0, parameters); - custom->addBond(particles1, parameters); - customSystem.addForce(custom); - - vector positions(4); - positions[0] = Vec3(0, 0.5, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(0.5, 0, 0); - positions[3] = Vec3(0.6, 0, 0.4); - VerletIntegrator integrator(0.01); - Context context(customSystem, integrator, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(0.199, state.getPotentialEnergy(), 1e-3); - vector forces(state.getForces()); - ASSERT_EQUAL_VEC(Vec3(-1.160, 0.112, 0.0), forces[0], 1e-3); - ASSERT_EQUAL_VEC(Vec3(0.927, 1.047, -0.638), forces[1], 1e-3); - ASSERT_EQUAL_VEC(Vec3(-0.543, -1.160, 0.721), forces[2], 1e-3); - ASSERT_EQUAL_VEC(Vec3(0.776, 0.0, -0.084), forces[3], 1e-3); -} - -int main() { - try { - testBond(); - testPositionDependence(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testMultipleBonds(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - - diff --git a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp index 38baea675..ab5f70314 100644 --- a/platforms/reference/tests/TestReferenceCustomExternalForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomExternalForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,132 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomExternalForce. - */ +#include "ReferenceTests.h" +#include "TestCustomExternalForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testForce() { - 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 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); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& 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); - } - - // Try changing the parameters and make sure it's still correct. - - parameters[0] = 1.4; - parameters[1] = 3.5; - forceField->setParticleParameters(1, 2, parameters); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& 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.5*2.0*1.4, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(0.5*(1.0 + 2.0*1.5*1.5 + 3.5*1.4*1.4), state.getPotentialEnergy(), TOL); - } -} - -void testPeriodic() { - Vec3 vx(5, 0, 0); - Vec3 vy(0, 6, 0); - Vec3 vz(1, 2, 7); - double x0 = 51, y0 = -17, z0 = 11.2; - System system; - system.setDefaultPeriodicBoxVectors(vx, vy, vz); - system.addParticle(1.0); - CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - vector params(3); - params[0] = x0; - params[1] = y0; - params[2] = z0; - force->addParticle(0, params); - system.addForce(force); - ASSERT(force->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - vector positions(1); - positions[0] = Vec3(0, 2, 0); - context.setPositions(positions); - for (int i = 0; i < 100; i++) { - State state = context.getState(State::Positions | State::Forces | State::Energy); - - // Apply periodic boundary conditions to the difference between the two positions. - - Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; - delta -= vz*floor(delta[2]/vz[2]+0.5); - delta -= vy*floor(delta[1]/vy[1]+0.5); - delta -= vx*floor(delta[0]/vx[0]+0.5); - - // Verify that the force and energy are correct. - - ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], 1e-6); - ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), 1e-6); - integrator.step(1); - } +void runPlatformTests() { } - -int main() { - try { - testForce(); - testPeriodic(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - - diff --git a/platforms/reference/tests/TestReferenceCustomGBForce.cpp b/platforms/reference/tests/TestReferenceCustomGBForce.cpp index 1997566b3..2f4612c20 100644 --- a/platforms/reference/tests/TestReferenceCustomGBForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomGBForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,882 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of CustomGBForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "sfmt/SFMT.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomGBForce.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/GBVIForce.h" -#include "openmm/OpenMMException.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMethod customMethod) { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - const double cutoff = 2.0; - - // Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction. - - System standardSystem; - System customSystem; - for (int i = 0; i < numParticles; i++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - } - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - GBSAOBCForce* obc = new GBSAOBCForce(); - CustomGBForce* custom = new CustomGBForce(); - obc->setCutoffDistance(cutoff); - custom->setCutoffDistance(cutoff); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("solventDielectric", obc->getSolventDielectric()); - custom->addGlobalParameter("soluteDielectric", obc->getSoluteDielectric()); - custom->addComputedValue("I", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=I*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935485*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - string invCutoffString = ""; - if (obcMethod != GBSAOBCForce::NoCutoff) { - stringstream s; - s<<(1.0/cutoff); - invCutoffString = s.str(); - } - custom->addEnergyTerm("138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("+invCutoffString+"-1/f);" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - obc->addParticle(1.0, 0.2, 0.5); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.5); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - obc->addParticle(1.0, 0.2, 0.8); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.8); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - obc->setNonbondedMethod(obcMethod); - custom->setNonbondedMethod(customMethod); - standardSystem.addForce(obc); - customSystem.addForce(custom); - if (customMethod == CustomGBForce::CutoffPeriodic) { - ASSERT(custom->usesPeriodicBoundaryConditions()); - ASSERT(obc->usesPeriodicBoundaryConditions()); - ASSERT(standardSystem.usesPeriodicBoundaryConditions()); - ASSERT(customSystem.usesPeriodicBoundaryConditions()); - } - else { - ASSERT(!custom->usesPeriodicBoundaryConditions()); - ASSERT(!obc->usesPeriodicBoundaryConditions()); - ASSERT(!standardSystem.usesPeriodicBoundaryConditions()); - ASSERT(!customSystem.usesPeriodicBoundaryConditions()); - } - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - context1.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - context2.setVelocities(velocities); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } - - // Try changing the particle parameters and make sure it's still correct. - - for (int i = 0; i < numMolecules/2; i++) { - obc->setParticleParameters(2*i, 1.1, 0.3, 0.6); - params[0] = 1.1; - params[1] = 0.3; - params[2] = 0.6; - custom->setParticleParameters(2*i, params); - obc->setParticleParameters(2*i+1, -1.1, 0.2, 0.4); - params[0] = -1.1; - params[1] = 0.2; - params[2] = 0.4; - custom->setParticleParameters(2*i+1, params); - } - obc->updateParametersInContext(context1); - custom->updateParametersInContext(context2); - state1 = context1.getState(State::Forces | State::Energy); - state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -void testMembrane() { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - - // Create a system with an implicit membrane. - - System system; - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - CustomGBForce* custom = new CustomGBForce(); - custom->setCutoffDistance(2.0); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("thickness", 3); - custom->addGlobalParameter("solventDielectric", 78.3); - custom->addGlobalParameter("soluteDielectric", 1); - custom->addComputedValue("Imol", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("Imem", "(1/radius+2*log(2)/thickness)/(1+exp(7.2*(abs(z)+radius-0.5*thickness)))", CustomGBForce::SingleParticle); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=max(Imol,Imem)*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - custom->addEnergyTerm("-138.935456*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - system.addForce(custom); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocities(velocities); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-2; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); -} - -void testTabulatedFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "0", CustomGBForce::ParticlePair); - force->addEnergyTerm("fn(r)+1", CustomGBForce::ParticlePair); - force->addParticle(vector()); - force->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(std::sin(0.25*i)); - force->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& 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); - } -} - -void testMultipleChainRules() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "2*r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+1", CustomGBForce::SingleParticle); - force->addComputedValue("c", "2*b+a", CustomGBForce::SingleParticle); - force->addEnergyTerm("0.1*a+1*b+10*c", CustomGBForce::SingleParticle); // 0.1*(2*r) + 2*r+1 + 10*(3*a+2) = 0.2*r + 2*r+1 + 40*r+20+20*r = 62.2*r+21 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 1; i < 5; i++) { - positions[1] = Vec3(i, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(124.4, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-124.4, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(2*(62.2*i+21), state.getPotentialEnergy(), 0.02); - } -} - -void testPositionDependence() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+x*y", CustomGBForce::SingleParticle); - force->addEnergyTerm("b*z", CustomGBForce::SingleParticle); - force->addEnergyTerm("b1+b2", CustomGBForce::ParticlePair); // = 2*r+x1*y1+x2*y2 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - vector forces(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < 5; i++) { - positions[0] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - positions[1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - Vec3 delta = positions[0]-positions[1]; - double r = sqrt(delta.dot(delta)); - double energy = 2*r+positions[0][0]*positions[0][1]+positions[1][0]*positions[1][1]; - for (int j = 0; j < 2; j++) - energy += positions[j][2]*(r+positions[j][0]*positions[j][1]); - Vec3 force1(-(1+positions[0][2])*delta[0]/r-(1+positions[0][2])*positions[0][1]-(1+positions[1][2])*delta[0]/r, - -(1+positions[0][2])*delta[1]/r-(1+positions[0][2])*positions[0][0]-(1+positions[1][2])*delta[1]/r, - -(1+positions[0][2])*delta[2]/r-(r+positions[0][0]*positions[0][1])-(1+positions[1][2])*delta[2]/r); - Vec3 force2((1+positions[0][2])*delta[0]/r+(1+positions[1][2])*delta[0]/r-(1+positions[1][2])*positions[1][1], - (1+positions[0][2])*delta[1]/r+(1+positions[1][2])*delta[1]/r-(1+positions[1][2])*positions[1][0], - (1+positions[0][2])*delta[2]/r+(1+positions[1][2])*delta[2]/r-(r+positions[1][0]*positions[1][1])); - ASSERT_EQUAL_VEC(force1, forces[0], 1e-4); - ASSERT_EQUAL_VEC(force2, forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(2), positions3(2); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); - } -} - -void testExclusions() { - for (int i = 3; i < 4; i++) { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", i < 2 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addEnergyTerm("a", CustomGBForce::SingleParticle); - force->addEnergyTerm("(1+a1+a2)*r", i%2 == 0 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addParticle(vector()); - force->addParticle(vector()); - force->addExclusion(0, 1); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double f, energy; - switch (i) - { - case 0: // e = 0 - f = 0; - energy = 0; - break; - case 1: // e = r - f = 1; - energy = 1; - break; - case 2: // e = 2r - f = 2; - energy = 2; - break; - case 3: // e = 3r + 2r^2 - f = 7; - energy = 5; - break; - default: - ASSERT(false); - } - ASSERT_EQUAL_VEC(Vec3(f, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-f, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = stepSize/norm; - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[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); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); - } -} - -// create custom GB/VI force - -static CustomGBForce* createCustomGBVI(double solventDielectric, double soluteDielectric) { - - CustomGBForce* customGbviForce = new CustomGBForce(); - - customGbviForce->setCutoffDistance(2.0); - - customGbviForce->addPerParticleParameter("q"); - customGbviForce->addPerParticleParameter("radius"); - customGbviForce->addPerParticleParameter("scaleFactor"); // derived in GBVIForce implmentation, but parameter here - customGbviForce->addPerParticleParameter("gamma"); - - customGbviForce->addGlobalParameter("solventDielectric", solventDielectric); - customGbviForce->addGlobalParameter("soluteDielectric", soluteDielectric); - - customGbviForce->addComputedValue("V", " uL - lL + factor3/(radius1*radius1*radius1);" - "uL = 1.5*x2uI*(0.25*rI-0.33333*xuI+0.125*(r2-S2)*rI*x2uI);" - "lL = 1.5*x2lI*(0.25*rI-0.33333*xlI+0.125*(r2-S2)*rI*x2lI);" - "x2lI = 1.0/(xl*xl);" - "xlI = 1.0/(xl);" - "xuI = 1.0/(xu);" - "x2uI = 1.0/(xu*xu);" - "xu = (r+scaleFactor2);" - "rI = 1.0/(r);" - "r2 = (r*r);" - "xl = factor1*lMax + factor2*xuu + factor3*(r-scaleFactor2);" - "xuu = (r+scaleFactor2);" - "S2 = (scaleFactor2*scaleFactor2);" - "factor1 = step(r-absRadiusScaleDiff);" - "absRadiusScaleDiff = abs(radiusScaleDiff);" - "radiusScaleDiff = (radius1-scaleFactor2);" - "factor2 = step(radius1-scaleFactor2-r);" - "factor3 = step(scaleFactor2-radius1-r);" - "lMax = max(radius1,r-scaleFactor2);" - , CustomGBForce::ParticlePairNoExclusions); - - customGbviForce->addComputedValue("B", "(1.0/(radius*radius*radius)-V)^(-0.33333333)", CustomGBForce::SingleParticle); - - // nonpolar term + polar self energy - - customGbviForce->addEnergyTerm("(-138.935485*0.5*((1.0/soluteDielectric)-(1.0/solventDielectric))*q^2/B)-((1.0/soluteDielectric)-(1.0/solventDielectric))*((gamma*(radius/B)^3))", CustomGBForce::SingleParticle); - - // polar pair energy - - customGbviForce->addEnergyTerm("-138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - - return customGbviForce; -} - -// ethance GB/VI test case - -static void buildEthane(GBVIForce* gbviForce, std::vector& positions) { - - const int numParticles = 8; - - double C_HBondDistance = 0.1097; - double C_CBondDistance = 0.1504; - 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; - } - - for (int i = 0; i < numParticles; i++) { - gbviForce->addParticle(H_charge, H_radius, H_gamma); - } - gbviForce->setParticleParameters(1, C_charge, C_radius, C_gamma); - gbviForce->setParticleParameters(4, C_charge, C_radius, C_gamma); - - gbviForce->addBond(0, 1, C_HBondDistance); - gbviForce->addBond(2, 1, C_HBondDistance); - gbviForce->addBond(3, 1, C_HBondDistance); - gbviForce->addBond(1, 4, C_CBondDistance); - gbviForce->addBond(5, 4, C_HBondDistance); - gbviForce->addBond(6, 4, C_HBondDistance); - gbviForce->addBond(7, 4, C_HBondDistance); - - std::vector > bondExceptions; - std::vector bondDistances; - - bondExceptions.push_back(pair(0, 1)); - bondDistances.push_back(C_HBondDistance); - - bondExceptions.push_back(pair(2, 1)); - bondDistances.push_back(C_HBondDistance); - - bondExceptions.push_back(pair(3, 1)); - bondDistances.push_back(C_HBondDistance); - - bondExceptions.push_back(pair(1, 4)); - bondDistances.push_back(C_CBondDistance); - - bondExceptions.push_back(pair(5, 4)); - bondDistances.push_back(C_HBondDistance); - - bondExceptions.push_back(pair(6, 4)); - bondDistances.push_back(C_HBondDistance); - - bondExceptions.push_back(pair(7, 4)); - bondDistances.push_back(C_HBondDistance); - - positions.resize(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); - -} - -// dimer GB/VI test case - -static void buildDimer(GBVIForce* gbviForce, std::vector& positions) { - - const int numParticles = 2; - - double C_HBondDistance = 0.1097; - double C_CBondDistance = 0.1504; - 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; - - H_charge = 0.0; - C_charge = 0.0; - 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; - } - - for (int i = 0; i < numParticles; i++) { - gbviForce->addParticle(H_charge, H_radius, H_gamma); - } - gbviForce->setParticleParameters(1, C_charge, C_radius, C_gamma); - - gbviForce->addBond(0, 1, C_HBondDistance); - std::vector > bondExceptions; - std::vector bondDistances; - - bondExceptions.push_back(pair(0, 1)); - bondDistances.push_back(C_HBondDistance); - - positions.resize(numParticles); - positions[0] = Vec3(0.0, 0.0, 0.0); - positions[1] = Vec3(0.15, 0.0, 0.0); -} - -// monomer GB/VI test case - -static void buildMonomer(GBVIForce* gbviForce, std::vector& positions) { - - const int numParticles = 1; - - double H_radius, H_gamma, H_charge; - - H_charge = 1.0; - H_radius = 0.125; - H_gamma = 0.2437; - - for (int i = 0; i < numParticles; i++) { - gbviForce->addParticle(H_charge, H_radius, H_gamma); - } - positions.resize(numParticles); - positions[0] = Vec3(0.0, 0.0, 0.0); -} - -// taken from gbviForceImpl class -// computes the scaled radii based on covalent info and atomic radii - -static void findScaledRadii(GBVIForce& gbviForce, std::vector & scaledRadii) { - - int numberOfParticles = gbviForce.getNumParticles(); - int numberOfBonds = gbviForce.getNumBonds(); - - // load 1-2 atom pairs along w/ bond distance using HarmonicBondForce & constraints - // numberOfBonds < 1, indicating they were not set by the user - - std::vector< std::vector > bondIndices; - bondIndices.resize(numberOfBonds); - - std::vector bondLengths; - bondLengths.resize(numberOfBonds); - - scaledRadii.resize(numberOfParticles); - for (int i = 0; i < numberOfParticles; i++) { - double charge, radius, gamma; - gbviForce.getParticleParameters(i, charge, radius, gamma); - scaledRadii[i] = radius; - } - - for (int i = 0; i < numberOfBonds; i++) { - int particle1, particle2; - double bondLength; - gbviForce.getBondParameters(i, particle1, particle2, bondLength); - if (particle1 < 0 || particle1 >= gbviForce.getNumParticles()) { - std::stringstream msg; - msg << "GBVISoftcoreForce: Illegal particle index: "; - msg << particle1; - throw OpenMMException(msg.str()); - } - if (particle2 < 0 || particle2 >= gbviForce.getNumParticles()) { - std::stringstream msg; - msg << "GBVISoftcoreForce: Illegal particle index: "; - msg << particle2; - throw OpenMMException(msg.str()); - } - if (bondLength < 0) { - std::stringstream msg; - msg << "GBVISoftcoreForce: negative bondlength: "; - msg << bondLength; - throw OpenMMException(msg.str()); - } - bondIndices[i].push_back(particle1); - bondIndices[i].push_back(particle2); - bondLengths[i] = bondLength; - } - - - // load 1-2 indicies for each atom - - std::vector > bonded12(numberOfParticles); +#include "ReferenceTests.h" +#include "TestCustomGBForce.h" - for (int i = 0; i < (int) bondIndices.size(); ++i) { - bonded12[bondIndices[i][0]].push_back(i); - bonded12[bondIndices[i][1]].push_back(i); - } - - int errors = 0; - - // compute scaled radii (Eq. 5 of Labute paper [JCC 29 p. 1693-1698 2008]) - - for (int j = 0; j < (int) bonded12.size(); ++j) { - - double charge; - double gamma; - double radiusJ; - double scaledRadiusJ; - - gbviForce.getParticleParameters(j, charge, radiusJ, gamma); - - if ( bonded12[j].size() == 0) { - scaledRadiusJ = radiusJ; -// errors++; - } - else { - - double rJ2 = radiusJ*radiusJ; - - // loop over bonded neighbors of atom j, applying Eq. 5 in Labute - - scaledRadiusJ = 0.0; - for (int i = 0; i < (int) bonded12[j].size(); ++i) { - - int index = bonded12[j][i]; - int bondedAtomIndex = (j == bondIndices[index][0]) ? bondIndices[index][1] : bondIndices[index][0]; - - double radiusI; - gbviForce.getParticleParameters(bondedAtomIndex, charge, radiusI, gamma); - double rI2 = radiusI*radiusI; - - double a_ij = (radiusI - bondLengths[index]); - a_ij *= a_ij; - a_ij = (rJ2 - a_ij)/(2.0*bondLengths[index]); - - double a_ji = radiusJ - bondLengths[index]; - a_ji *= a_ji; - a_ji = (rI2 - a_ji)/(2.0*bondLengths[index]); - - scaledRadiusJ += a_ij*a_ij*(3.0*radiusI - a_ij) + a_ji*a_ji*(3.0*radiusJ - a_ji); - } - - scaledRadiusJ = (radiusJ*radiusJ*radiusJ) - 0.125*scaledRadiusJ; - if (scaledRadiusJ > 0.0) { - scaledRadiusJ = 0.95*pow(scaledRadiusJ, (1.0/3.0)); - } - else { - scaledRadiusJ = 0.0; - } - } - scaledRadii[j] = scaledRadiusJ; - - } - - // abort if errors - - if (errors) { - throw OpenMMException("GBVIForceImpl::findScaledRadii errors -- aborting"); - } +void runPlatformTests() { } - -// load parameters from gbviForce to customGbviForce -// findScaledRadii() is called to calculate the scaled radii (S) -// S is derived quantity in GBVIForce, not a parameter is the case here - -static void loadGbviParameters(GBVIForce* gbviForce, CustomGBForce* customGbviForce) { - - int numParticles = gbviForce->getNumParticles(); - - // charge, radius, scale factor, gamma - - vector params(4); - std::vector scaledRadii; - findScaledRadii(*gbviForce, scaledRadii); - - for (int ii = 0; ii < numParticles; ii++) { - double charge, radius, gamma; - gbviForce->getParticleParameters(ii, charge, radius, gamma); - params[0] = charge; - params[1] = radius; - params[2] = scaledRadii[ii]; - params[3] = gamma; - customGbviForce->addParticle(params); - } - -} - -void testGBVI(GBVIForce::NonbondedMethod gbviMethod, CustomGBForce::NonbondedMethod customGbviMethod, std::string molecule) { - - const int numMolecules = 1; - const double boxSize = 10.0; - - GBVIForce* gbvi = new GBVIForce(); - std::vector positions; - - // select molecule - - if (molecule == "Monomer") { - buildMonomer(gbvi, positions); - } - else if (molecule == "Dimer") { - buildDimer(gbvi, positions); - } - else { - buildEthane(gbvi, positions); - } - - int numParticles = gbvi->getNumParticles(); - System standardSystem; - System customGbviSystem; - for (int i = 0; i < numParticles; i++) { - standardSystem.addParticle(1.0); - customGbviSystem.addParticle(1.0); - } - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - customGbviSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - gbvi->setCutoffDistance(2.0); - - // create customGbviForce GBVI force - - CustomGBForce* customGbviForce = createCustomGBVI(gbvi->getSolventDielectric(), gbvi->getSoluteDielectric()); - customGbviForce->setCutoffDistance(2.0); - - // load parameters from gbvi to customGbviForce - - loadGbviParameters(gbvi, customGbviForce); - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector velocities(numParticles); - for (int ii = 0; ii < numParticles; ii++) { - velocities[ii] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - } - gbvi->setNonbondedMethod(gbviMethod); - customGbviForce->setNonbondedMethod(customGbviMethod); - - standardSystem.addForce(gbvi); - customGbviSystem.addForce(customGbviForce); - - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - context1.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - - Context context2(customGbviSystem, integrator2, platform); - context2.setPositions(positions); - context2.setVelocities(velocities); - State state2 = context2.getState(State::Forces | State::Energy); - - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -int main() { - - try { - testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff); - testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic); - testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic); - testMembrane(); - testTabulatedFunction(); - testMultipleChainRules(); - testPositionDependence(); - testExclusions(); - - // GBVI tests - - testGBVI(GBVIForce::NoCutoff, CustomGBForce::NoCutoff, "Monomer"); - testGBVI(GBVIForce::NoCutoff, CustomGBForce::NoCutoff, "Dimer"); - testGBVI(GBVIForce::NoCutoff, CustomGBForce::NoCutoff, "Ethane"); - - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferencePeriodicTorsionForce.cpp b/platforms/reference/tests/TestReferencePeriodicTorsionForce.cpp index ba7580b6c..c872e849c 100644 --- a/platforms/reference/tests/TestReferencePeriodicTorsionForce.cpp +++ b/platforms/reference/tests/TestReferencePeriodicTorsionForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,80 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of PeriodicTorsionForce. - */ +#include "ReferenceTests.h" +#include "TestPeriodicTorsionForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testPeriodicTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - PeriodicTorsionForce* forceField = new PeriodicTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 2, PI_M/3, 1.1); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 2); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double torque = -2*1.1*std::sin(2*PI_M/3); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 3, PI_M/3.2, 1.3); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta = (3*PI_M/2)-(PI_M/3.2); - double torque = -3*1.3*std::sin(dtheta); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.3*(1+std::cos(dtheta)), state.getPotentialEnergy(), TOL); - } -} - -int main() { - try { - testPeriodicTorsions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceRBTorsionForce.cpp b/platforms/reference/tests/TestReferenceRBTorsionForce.cpp index c7f80b6c9..266f5a5c9 100644 --- a/platforms/reference/tests/TestReferenceRBTorsionForce.cpp +++ b/platforms/reference/tests/TestReferenceRBTorsionForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,99 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of RBTorsionForce. - */ +#include "ReferenceTests.h" +#include "TestRBTorsionForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/RBTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testRBTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - RBTorsionForce* forceField = new RBTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 1, 1); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.1*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.1*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.11*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.11*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -int main() { - try { - testRBTorsions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/tests/TestCustomAngleForce.h b/tests/TestCustomAngleForce.h new file mode 100644 index 000000000..5d79ad433 --- /dev/null +++ b/tests/TestCustomAngleForce.h @@ -0,0 +1,145 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomAngleForce.h" +#include "openmm/HarmonicAngleForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testAngles() { + // 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 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); + ASSERT(!custom->usesPeriodicBoundaryConditions()); + ASSERT(!customSystem.usesPeriodicBoundaryConditions()); + + // 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 positions(4); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context c1(customSystem, integrator1, platform); + Context c2(harmonicSystem, integrator2, platform); + 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)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); + } + + // Try changing the angle parameters and make sure it's still correct. + + parameters[0] = 1.6; + parameters[1] = 0.9; + custom->setAngleParameters(0, 0, 1, 2, parameters); + parameters[0] = 2.1; + parameters[1] = 0.6; + custom->setAngleParameters(1, 1, 2, 3, parameters); + custom->updateParametersInContext(c1); + harmonic->setAngleParameters(0, 0, 1, 2, 1.6, 0.9); + harmonic->setAngleParameters(1, 1, 2, 3, 2.1, 0.6); + harmonic->updateParametersInContext(c2); + { + 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)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testAngles(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + + diff --git a/tests/TestCustomBondForce.h b/tests/TestCustomBondForce.h new file mode 100644 index 000000000..5b630c532 --- /dev/null +++ b/tests/TestCustomBondForce.h @@ -0,0 +1,149 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomBondForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testBonds() { + 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 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); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& 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); + } + + // Try changing the bond parameters and make sure it's still correct. + + parameters[0] = 1.6; + parameters[1] = 0.9; + forceField->setBondParameters(0, 0, 1, parameters); + parameters[0] = 1.3; + parameters[1] = 0.8; + forceField->setBondParameters(1, 1, 2, parameters); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 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.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); + } +} + +void testManyParameters() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomBondForce* forceField = new CustomBondForce("(a+b+c+d+e+f+g+h+i)*r"); + forceField->addPerBondParameter("a"); + forceField->addPerBondParameter("b"); + forceField->addPerBondParameter("c"); + forceField->addPerBondParameter("d"); + forceField->addPerBondParameter("e"); + forceField->addPerBondParameter("f"); + forceField->addPerBondParameter("g"); + forceField->addPerBondParameter("h"); + forceField->addPerBondParameter("i"); + vector parameters(forceField->getNumPerBondParameters()); + for (int i = 0; i < parameters.size(); i++) + parameters[i] = i; + forceField->addBond(0, 1, parameters); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(0, 2.5, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double f = 1+2+3+4+5+6+7+8; + ASSERT_EQUAL_VEC(Vec3(0, f, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -f, 0), forces[1], TOL); + ASSERT_EQUAL_TOL(f*2.5, state.getPotentialEnergy(), TOL); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testBonds(); + testManyParameters(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + diff --git a/tests/TestCustomCentroidBondForce.h b/tests/TestCustomCentroidBondForce.h new file mode 100644 index 000000000..a648d0e8b --- /dev/null +++ b/tests/TestCustomCentroidBondForce.h @@ -0,0 +1,271 @@ +/* -------------------------------------------------------------------------- * + * 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) 2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomCentroidBondForce.h" +#include "openmm/CustomCompoundBondForce.h" +#include "openmm/System.h" +#include "openmm/TabulatedFunction.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testHarmonicBond() { + System system; + system.addParticle(1.0); + system.addParticle(2.0); + system.addParticle(3.0); + system.addParticle(4.0); + system.addParticle(5.0); + CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "k*distance(g1,g2)^2"); + force->addPerBondParameter("k"); + vector particles1; + particles1.push_back(0); + particles1.push_back(1); + vector particles2; + particles2.push_back(2); + particles2.push_back(3); + particles2.push_back(4); + force->addGroup(particles1); + force->addGroup(particles2); + vector groups; + groups.push_back(0); + groups.push_back(1); + vector parameters; + parameters.push_back(1.0); + force->addBond(groups, parameters); + system.addForce(force); + ASSERT(!system.usesPeriodicBoundaryConditions()); + + // The center of mass of group 0 is (1.5, 0, 0). + + vector positions(5); + positions[0] = Vec3(2.5, 0, 0); + positions[1] = Vec3(1, 0, 0); + + // The center of mass of group 1 is (-1, 0, 0). + + positions[2] = Vec3(-6, 0, 0); + positions[3] = Vec3(-1, 0, 0); + positions[4] = Vec3(2, 0, 0); + + // Check the forces and energy. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(2.5*2.5, state.getPotentialEnergy(), TOL); + ASSERT_EQUAL_VEC(Vec3(-2*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(Vec3(-2*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); + ASSERT_EQUAL_VEC(Vec3(2*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); + ASSERT_EQUAL_VEC(Vec3(2*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); + ASSERT_EQUAL_VEC(Vec3(2*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); + + // Update the per-bond parameter and see if the results change. + + parameters[0] = 2.0; + force->setBondParameters(0, groups, parameters); + force->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(2*2.5*2.5, state.getPotentialEnergy(), TOL); + ASSERT_EQUAL_VEC(Vec3(-4*2.5*(1.0/3.0), 0, 0), state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(Vec3(-4*2.5*(2.0/3.0), 0, 0), state.getForces()[1], TOL); + ASSERT_EQUAL_VEC(Vec3(4*2.5*(3.0/12.0), 0, 0), state.getForces()[2], TOL); + ASSERT_EQUAL_VEC(Vec3(4*2.5*(4.0/12.0), 0, 0), state.getForces()[3], TOL); + ASSERT_EQUAL_VEC(Vec3(4*2.5*(5.0/12.0), 0, 0), state.getForces()[4], TOL); + + // All the particles should be treated as a single molecule. + + vector > molecules = context.getMolecules(); + ASSERT_EQUAL(1, molecules.size()); + ASSERT_EQUAL(5, molecules[0].size()); +} + +void testComplexFunction() { + int numParticles = 5; + System system; + for (int i = 0; i < numParticles; i++) + system.addParticle(2.0); + vector table(20); + for (int i = 0; i < 20; i++) + table[i] = sin(0.11*i); + + // When every group contains only one particle, a CustomCentroidBondForce is identical to a + // CustomCompoundBondForce. Use that to test a complicated energy function with lots of terms. + + CustomCompoundBondForce* compound = new CustomCompoundBondForce(4, "x1+y2+z4+fn(distance(p1,p2))*angle(p3,p2,p4)+scale*dihedral(p2,p1,p4,p3)"); + CustomCentroidBondForce* centroid = new CustomCentroidBondForce(4, "x1+y2+z4+fn(distance(g1,g2))*angle(g3,g2,g4)+scale*dihedral(g2,g1,g4,g3)"); + compound->addGlobalParameter("scale", 0.5); + centroid->addGlobalParameter("scale", 0.5); + compound->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); + centroid->addTabulatedFunction("fn", new Continuous1DFunction(table, -1, 10)); + + // Add two bonds to the CustomCompoundBondForce. + + vector particles(4); + vector parameters; + particles[0] = 0; + particles[1] = 1; + particles[2] = 2; + particles[3] = 3; + compound->addBond(particles, parameters); + particles[0] = 2; + particles[1] = 4; + particles[2] = 3; + particles[3] = 1; + compound->addBond(particles, parameters); + + // Add identical bonds to the CustomCentroidBondForce. As a stronger test, make sure that + // group number is different from particle number. + + vector groupMembers(1); + groupMembers[0] = 3; + centroid->addGroup(groupMembers); + groupMembers[0] = 0; + centroid->addGroup(groupMembers); + groupMembers[0] = 1; + centroid->addGroup(groupMembers); + groupMembers[0] = 2; + centroid->addGroup(groupMembers); + groupMembers[0] = 4; + centroid->addGroup(groupMembers); + vector groups(4); + groups[0] = 1; + groups[1] = 2; + groups[2] = 3; + groups[3] = 0; + centroid->addBond(groups, parameters); + groups[0] = 3; + groups[1] = 4; + groups[2] = 0; + groups[3] = 2; + centroid->addBond(groups, parameters); + + // Add both forces as different force groups, and create a context. + + centroid->setForceGroup(1); + system.addForce(compound); + system.addForce(centroid); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + + // Evaluate the force and energy for various positions and see if they match. + + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + vector positions(numParticles); + for (int i = 0; i < 10; i++) { + for (int j = 0; j < numParticles; j++) + positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); + context.setPositions(positions); + State state1 = context.getState(State::Forces | State::Energy, false, 1<<0); + State state2 = context.getState(State::Forces | State::Energy, false, 1<<1); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), TOL); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], TOL); + } +} + +void testCustomWeights() { + System system; + system.addParticle(1.0); + system.addParticle(2.0); + system.addParticle(3.0); + system.addParticle(4.0); + CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "distance(g1,g2)^2"); + vector particles(2); + vector weights(2); + particles[0] = 0; + particles[1] = 1; + weights[0] = 0.5; + weights[1] = 1.5; + force->addGroup(particles, weights); + particles[0] = 2; + particles[1] = 3; + weights[0] = 2.0; + weights[1] = 1.0; + force->addGroup(particles, weights); + vector groups; + groups.push_back(0); + groups.push_back(1); + vector parameters; + force->addBond(groups, parameters); + system.addForce(force); + + // The center of mass of group 0 is (0, 1, 0). + + vector positions(4); + positions[0] = Vec3(0, 4, 0); + positions[1] = Vec3(0, 0, 0); + + // The center of mass of group 1 is (0, 10, 0). + + positions[2] = Vec3(0, 9, 0); + positions[3] = Vec3(0, 12, 0); + + // Check the forces and energy. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(9.0*9.0, state.getPotentialEnergy(), TOL); + ASSERT_EQUAL_VEC(Vec3(0, 2*9*(0.5/2.0), 0), state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 2*9*(1.5/2.0), 0), state.getForces()[1], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -2*9*(2.0/3.0), 0), state.getForces()[2], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -2*9*(1.0/3.0), 0), state.getForces()[3], TOL); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testHarmonicBond(); + testComplexFunction(); + testCustomWeights(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCustomCompoundBondForce.h b/tests/TestCustomCompoundBondForce.h new file mode 100644 index 000000000..24d48ae5a --- /dev/null +++ b/tests/TestCustomCompoundBondForce.h @@ -0,0 +1,332 @@ +/* -------------------------------------------------------------------------- * + * 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) 2012-2015 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "ReferencePlatform.h" +#include "openmm/CustomCompoundBondForce.h" +#include "openmm/HarmonicAngleForce.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/PeriodicTorsionForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testBond() { + // Create a system using a CustomCompoundBondForce. + + System customSystem; + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + CustomCompoundBondForce* custom = new CustomCompoundBondForce(4, "0.5*kb*((distance(p1,p2)-b0)^2+(distance(p2,p3)-b0)^2)+0.5*ka*(angle(p2,p3,p4)-a0)^2+kt*(1+cos(dihedral(p1,p2,p3,p4)-t0))"); + custom->addPerBondParameter("kb"); + custom->addPerBondParameter("ka"); + custom->addPerBondParameter("kt"); + custom->addPerBondParameter("b0"); + custom->addPerBondParameter("a0"); + custom->addPerBondParameter("t0"); + vector particles(4); + particles[0] = 0; + particles[1] = 1; + particles[2] = 3; + particles[3] = 2; + vector parameters(6); + parameters[0] = 1.5; + parameters[1] = 0.8; + parameters[2] = 0.6; + parameters[3] = 1.1; + parameters[4] = 2.9; + parameters[5] = 1.3; + custom->addBond(particles, parameters); + customSystem.addForce(custom); + ASSERT(!custom->usesPeriodicBoundaryConditions()); + ASSERT(!customSystem.usesPeriodicBoundaryConditions()); + + // Create an identical system using standard forces. + + System standardSystem; + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + HarmonicBondForce* bonds = new HarmonicBondForce(); + bonds->addBond(0, 1, 1.1, 1.5); + bonds->addBond(1, 3, 1.1, 1.5); + standardSystem.addForce(bonds); + HarmonicAngleForce* angles = new HarmonicAngleForce(); + angles->addAngle(1, 3, 2, 2.9, 0.8); + standardSystem.addForce(angles); + PeriodicTorsionForce* torsions = new PeriodicTorsionForce(); + torsions->addTorsion(0, 1, 3, 2, 1, 1.3, 0.6); + standardSystem.addForce(torsions); + + // 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); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context c1(customSystem, integrator1, platform); + Context c2(standardSystem, integrator2, platform); + vector 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)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); + } + + // Try changing the bond parameters and make sure it's still correct. + + parameters[0] = 1.6; + parameters[3] = 1.3; + custom->setBondParameters(0, particles, parameters); + custom->updateParametersInContext(c1); + bonds->setBondParameters(0, 0, 1, 1.3, 1.6); + bonds->setBondParameters(1, 1, 3, 1.3, 1.6); + bonds->updateParametersInContext(c2); + { + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + const vector& forces = s1.getForces(); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); + } +} + +void testPositionDependence() { + System customSystem; + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + CustomCompoundBondForce* custom = new CustomCompoundBondForce(2, "scale1*distance(p1,p2)+scale2*x1+2*y2"); + custom->addGlobalParameter("scale1", 0.3); + custom->addGlobalParameter("scale2", 0.2); + vector particles(2); + particles[0] = 1; + particles[1] = 0; + vector parameters; + custom->addBond(particles, parameters); + customSystem.addForce(custom); + vector positions(2); + positions[0] = Vec3(1.5, 1, 0); + positions[1] = Vec3(0.5, 1, 0); + VerletIntegrator integrator(0.01); + Context context(customSystem, integrator, platform); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(0.3*1.0+0.2*0.5+2*1, state.getPotentialEnergy(), 1e-5); + ASSERT_EQUAL_VEC(Vec3(-0.3, -2, 0), state.getForces()[0], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.3-0.2, 0, 0), state.getForces()[1], 1e-5); +} + +void testContinuous2DFunction() { + const int xsize = 10; + const int ysize = 11; + const double xmin = 0.4; + const double xmax = 1.1; + const double ymin = 0.0; + const double ymax = 0.9; + System system; + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1)+1"); + vector particles(1, 0); + forceField->addBond(particles, vector()); + vector table(xsize*ysize); + for (int i = 0; i < xsize; i++) { + for (int j = 0; j < ysize; j++) { + double x = xmin + i*(xmax-xmin)/xsize; + double y = ymin + j*(ymax-ymin)/ysize; + table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); + } + } + forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(1); + for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { + for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { + positions[0] = Vec3(x, y, 1.5); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double energy = 1; + Vec3 force(0, 0, 0); + if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { + energy = sin(0.25*x)*cos(0.33*y)+1; + force[0] = -0.25*cos(0.25*x)*cos(0.33*y); + force[1] = 0.3*sin(0.25*x)*sin(0.33*y); + } + ASSERT_EQUAL_VEC(force, forces[0], 0.1); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); + } + } +} + +void testContinuous3DFunction() { + const int xsize = 10; + const int ysize = 11; + const int zsize = 12; + const double xmin = 0.4; + const double xmax = 1.1; + const double ymin = 0.0; + const double ymax = 0.9; + const double zmin = 0.2; + const double zmax = 1.3; + System system; + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomCompoundBondForce* forceField = new CustomCompoundBondForce(1, "fn(x1,y1,z1)+1"); + vector particles(1, 0); + forceField->addBond(particles, vector()); + vector table(xsize*ysize*zsize); + for (int i = 0; i < xsize; i++) { + for (int j = 0; j < ysize; j++) { + for (int k = 0; k < zsize; k++) { + double x = xmin + i*(xmax-xmin)/xsize; + double y = ymin + j*(ymax-ymin)/ysize; + double z = zmin + k*(zmax-zmin)/zsize; + table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); + } + } + } + forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(1); + for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { + for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { + for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { + positions[0] = Vec3(x, y, z); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double energy = 1; + Vec3 force(0, 0, 0); + if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { + energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1; + force[0] = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); + force[1] = 0.3*sin(0.25*x)*sin(0.33*y)*(1.0+z); + force[2] = -sin(0.25*x)*cos(0.33*y); + } + ASSERT_EQUAL_VEC(force, forces[0], 0.1); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.05); + } + } + } +} + +void testMultipleBonds() { + // Two compound bonds using Urey-Bradley example from API doc + System customSystem; + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + CustomCompoundBondForce* custom = new CustomCompoundBondForce(3, + "0.5*(kangle*(angle(p1,p2,p3)-theta0)^2+kbond*(distance(p1,p3)-r0)^2)"); + custom->addPerBondParameter("kangle"); + custom->addPerBondParameter("kbond"); + custom->addPerBondParameter("theta0"); + custom->addPerBondParameter("r0"); + vector parameters(4); + parameters[0] = 1.0; + parameters[1] = 1.0; + parameters[2] = 2 * M_PI / 3; + parameters[3] = sqrt(3.0) / 2; + vector particles0(3); + particles0[0] = 0; + particles0[1] = 1; + particles0[2] = 2; + vector particles1(3); + particles1[0] = 1; + particles1[1] = 2; + particles1[2] = 3; + custom->addBond(particles0, parameters); + custom->addBond(particles1, parameters); + customSystem.addForce(custom); + + vector positions(4); + positions[0] = Vec3(0, 0.5, 0); + positions[1] = Vec3(0, 0, 0); + positions[2] = Vec3(0.5, 0, 0); + positions[3] = Vec3(0.6, 0, 0.4); + VerletIntegrator integrator(0.01); + Context context(customSystem, integrator, platform); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(0.199, state.getPotentialEnergy(), 1e-3); + vector forces(state.getForces()); + ASSERT_EQUAL_VEC(Vec3(-1.160, 0.112, 0.0), forces[0], 1e-3); + ASSERT_EQUAL_VEC(Vec3(0.927, 1.047, -0.638), forces[1], 1e-3); + ASSERT_EQUAL_VEC(Vec3(-0.543, -1.160, 0.721), forces[2], 1e-3); + ASSERT_EQUAL_VEC(Vec3(0.776, 0.0, -0.084), forces[3], 1e-3); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testBond(); + testPositionDependence(); + testContinuous2DFunction(); + testContinuous3DFunction(); + testMultipleBonds(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + + diff --git a/tests/TestCustomExternalForce.h b/tests/TestCustomExternalForce.h new file mode 100644 index 000000000..59ba5be4c --- /dev/null +++ b/tests/TestCustomExternalForce.h @@ -0,0 +1,188 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomExternalForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testForce() { + 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 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); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& 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); + } + + // Try changing the parameters and make sure it's still correct. + + parameters[0] = 1.4; + parameters[1] = 3.5; + forceField->setParticleParameters(1, 2, parameters); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + { + const vector& 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.5*2.0*1.4, 0), forces[2], TOL); + ASSERT_EQUAL_TOL(0.5*(1.0 + 2.0*1.5*1.5 + 3.5*1.4*1.4), state.getPotentialEnergy(), TOL); + } +} + +void testManyParameters() { + System system; + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomExternalForce* forceField = new CustomExternalForce("xscale*(x-x0)^2+yscale*(y-y0)^2+zscale*(z-z0)^2"); + forceField->addPerParticleParameter("x0"); + forceField->addPerParticleParameter("y0"); + forceField->addPerParticleParameter("z0"); + forceField->addPerParticleParameter("xscale"); + forceField->addPerParticleParameter("yscale"); + forceField->addPerParticleParameter("zscale"); + vector parameters(6); + parameters[0] = 1.0; + parameters[1] = 2.0; + parameters[2] = 3.0; + parameters[3] = 0.1; + parameters[4] = 0.2; + parameters[5] = 0.3; + forceField->addParticle(0, parameters); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(1); + positions[0] = Vec3(0, -1, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(2*0.1*1.0, 2*0.2*3.0, 2*0.3*3.0), forces[0], TOL); + ASSERT_EQUAL_TOL(0.1*1*1 + 0.2*3*3 + 0.3*3*3, state.getPotentialEnergy(), TOL); +} + +void testPeriodic() { + Vec3 vx(5, 0, 0); + Vec3 vy(0, 6, 0); + Vec3 vz(1, 2, 7); + double x0 = 51, y0 = -17, z0 = 11.2; + System system; + system.setDefaultPeriodicBoxVectors(vx, vy, vz); + system.addParticle(1.0); + CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2"); + force->addPerParticleParameter("x0"); + force->addPerParticleParameter("y0"); + force->addPerParticleParameter("z0"); + vector params(3); + params[0] = x0; + params[1] = y0; + params[2] = z0; + force->addParticle(0, params); + system.addForce(force); + ASSERT(force->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + vector positions(1); + positions[0] = Vec3(0, 2, 0); + context.setPositions(positions); + for (int i = 0; i < 100; i++) { + State state = context.getState(State::Positions | State::Forces | State::Energy); + + // Apply periodic boundary conditions to the difference between the two positions. + + Vec3 delta = Vec3(x0, y0, z0)-state.getPositions()[0]; + delta -= vz*floor(delta[2]/vz[2]+0.5); + delta -= vy*floor(delta[1]/vy[1]+0.5); + delta -= vx*floor(delta[0]/vx[0]+0.5); + + // Verify that the force and energy are correct. + + ASSERT_EQUAL_VEC(delta*2, state.getForces()[0], TOL); + ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), TOL); + integrator.step(1); + } + +} +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testForce(); + testManyParameters(); + testPeriodic(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + + diff --git a/tests/TestCustomGBForce.h b/tests/TestCustomGBForce.h new file mode 100644 index 000000000..175611f9e --- /dev/null +++ b/tests/TestCustomGBForce.h @@ -0,0 +1,493 @@ + +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "sfmt/SFMT.h" +#include "openmm/Context.h" +#include "openmm/CustomGBForce.h" +#include "openmm/GBSAOBCForce.h" +#include "openmm/OpenMMException.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMethod customMethod) { + const int numMolecules = 70; + const int numParticles = numMolecules*2; + const double boxSize = 10.0; + const double cutoff = 2.0; + + // Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction. + + System standardSystem; + System customSystem; + for (int i = 0; i < numParticles; i++) { + standardSystem.addParticle(1.0); + customSystem.addParticle(1.0); + } + standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); + customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); + GBSAOBCForce* obc = new GBSAOBCForce(); + CustomGBForce* custom = new CustomGBForce(); + obc->setCutoffDistance(cutoff); + custom->setCutoffDistance(cutoff); + custom->addPerParticleParameter("q"); + custom->addPerParticleParameter("radius"); + custom->addPerParticleParameter("scale"); + custom->addGlobalParameter("solventDielectric", obc->getSolventDielectric()); + custom->addGlobalParameter("soluteDielectric", obc->getSoluteDielectric()); + custom->addComputedValue("I", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" + "U=r+sr2;" + "C=2*(1/or1-1/L)*step(sr2-r-or1);" + "L=max(or1, D);" + "D=abs(r-sr2);" + "sr2 = scale2*or2;" + "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); + custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" + "psi=I*or; or=radius-0.009", CustomGBForce::SingleParticle); + custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935485*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); + string invCutoffString = ""; + if (obcMethod != GBSAOBCForce::NoCutoff) { + stringstream s; + s<<(1.0/cutoff); + invCutoffString = s.str(); + } + custom->addEnergyTerm("138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("+invCutoffString+"-1/f);" + "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); + vector positions(numParticles); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + vector params(3); + for (int i = 0; i < numMolecules; i++) { + if (i < numMolecules/2) { + obc->addParticle(1.0, 0.2, 0.5); + params[0] = 1.0; + params[1] = 0.2; + params[2] = 0.5; + custom->addParticle(params); + obc->addParticle(-1.0, 0.1, 0.5); + params[0] = -1.0; + params[1] = 0.1; + custom->addParticle(params); + } + else { + obc->addParticle(1.0, 0.2, 0.8); + params[0] = 1.0; + params[1] = 0.2; + params[2] = 0.8; + custom->addParticle(params); + obc->addParticle(-1.0, 0.1, 0.8); + params[0] = -1.0; + params[1] = 0.1; + custom->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)); + } + obc->setNonbondedMethod(obcMethod); + custom->setNonbondedMethod(customMethod); + standardSystem.addForce(obc); + customSystem.addForce(custom); + if (customMethod == CustomGBForce::CutoffPeriodic) { + ASSERT(custom->usesPeriodicBoundaryConditions()); + ASSERT(obc->usesPeriodicBoundaryConditions()); + ASSERT(standardSystem.usesPeriodicBoundaryConditions()); + ASSERT(customSystem.usesPeriodicBoundaryConditions()); + } + else { + ASSERT(!custom->usesPeriodicBoundaryConditions()); + ASSERT(!obc->usesPeriodicBoundaryConditions()); + ASSERT(!standardSystem.usesPeriodicBoundaryConditions()); + ASSERT(!customSystem.usesPeriodicBoundaryConditions()); + } + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context context1(standardSystem, integrator1, platform); + context1.setPositions(positions); + context1.setVelocities(velocities); + State state1 = context1.getState(State::Forces | State::Energy); + Context context2(customSystem, integrator2, platform); + context2.setPositions(positions); + context2.setVelocities(velocities); + State state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); + for (int i = 0; i < numParticles; i++) { + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); + } + + // Try changing the particle parameters and make sure it's still correct. + + for (int i = 0; i < numMolecules/2; i++) { + obc->setParticleParameters(2*i, 1.1, 0.3, 0.6); + params[0] = 1.1; + params[1] = 0.3; + params[2] = 0.6; + custom->setParticleParameters(2*i, params); + obc->setParticleParameters(2*i+1, -1.1, 0.2, 0.4); + params[0] = -1.1; + params[1] = 0.2; + params[2] = 0.4; + custom->setParticleParameters(2*i+1, params); + } + obc->updateParametersInContext(context1); + custom->updateParametersInContext(context2); + state1 = context1.getState(State::Forces | State::Energy); + state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); + for (int i = 0; i < numParticles; i++) { + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); + } +} + +void testMembrane() { + const int numMolecules = 70; + const int numParticles = numMolecules*2; + const double boxSize = 10.0; + + // Create a system with an implicit membrane. + + System system; + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.0); + } + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); + CustomGBForce* custom = new CustomGBForce(); + custom->setCutoffDistance(2.0); + custom->addPerParticleParameter("q"); + custom->addPerParticleParameter("radius"); + custom->addPerParticleParameter("scale"); + custom->addGlobalParameter("thickness", 3); + custom->addGlobalParameter("solventDielectric", 78.3); + custom->addGlobalParameter("soluteDielectric", 1); + custom->addComputedValue("Imol", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" + "U=r+sr2;" + "C=2*(1/or1-1/L)*step(sr2-r-or1);" + "L=max(or1, D);" + "D=abs(r-sr2);" + "sr2 = scale2*or2;" + "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); + custom->addComputedValue("Imem", "(1/radius+2*log(2)/thickness)/(1+exp(7.2*(abs(z)+radius-0.5*thickness)))", CustomGBForce::SingleParticle); + custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" + "psi=max(Imol,Imem)*or; or=radius-0.009", CustomGBForce::SingleParticle); + custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); + custom->addEnergyTerm("-138.935456*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;" + "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); + vector positions(numParticles); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + vector params(3); + for (int i = 0; i < numMolecules; i++) { + if (i < numMolecules/2) { + params[0] = 1.0; + params[1] = 0.2; + params[2] = 0.5; + custom->addParticle(params); + params[0] = -1.0; + params[1] = 0.1; + custom->addParticle(params); + } + else { + params[0] = 1.0; + params[1] = 0.2; + params[2] = 0.8; + custom->addParticle(params); + params[0] = -1.0; + params[1] = 0.1; + custom->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)); + } + system.addForce(custom); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocities(velocities); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + + // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. + + double norm = 0.0; + for (int i = 0; i < (int) forces.size(); ++i) + norm += forces[i].dot(forces[i]); + norm = std::sqrt(norm); + const double stepSize = 1e-2; + double step = 0.5*stepSize/norm; + vector positions2(numParticles), positions3(numParticles); + for (int i = 0; i < (int) positions.size(); ++i) { + Vec3 p = positions[i]; + Vec3 f = forces[i]; + positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); + } + context.setPositions(positions2); + State state2 = context.getState(State::Energy); + context.setPositions(positions3); + State state3 = context.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); +} + +void testTabulatedFunction() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomGBForce* force = new CustomGBForce(); + force->addComputedValue("a", "0", CustomGBForce::ParticlePair); + force->addEnergyTerm("fn(r)+1", CustomGBForce::ParticlePair); + force->addParticle(vector()); + force->addParticle(vector()); + vector table; + for (int i = 0; i < 21; i++) + table.push_back(std::sin(0.25*i)); + force->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); + system.addForce(force); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (int i = 1; i < 30; i++) { + // Check interpolated values. + 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& 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++) { + // These values are exactly on table points, so they should match more precisely. + 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 testMultipleChainRules() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomGBForce* force = new CustomGBForce(); + force->addComputedValue("a", "2*r", CustomGBForce::ParticlePair); + force->addComputedValue("b", "a+1", CustomGBForce::SingleParticle); + force->addComputedValue("c", "2*b+a", CustomGBForce::SingleParticle); + force->addEnergyTerm("0.1*a+1*b+10*c", CustomGBForce::SingleParticle); // 0.1*(2*r) + 2*r+1 + 10*(3*a+2) = 0.2*r + 2*r+1 + 40*r+20+20*r = 62.2*r+21 + force->addParticle(vector()); + force->addParticle(vector()); + system.addForce(force); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (int i = 1; i < 5; i++) { + positions[1] = Vec3(i, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(124.4, 0, 0), forces[0], 1e-4); + ASSERT_EQUAL_VEC(Vec3(-124.4, 0, 0), forces[1], 1e-4); + ASSERT_EQUAL_TOL(2*(62.2*i+21), state.getPotentialEnergy(), 0.02); + } +} + +void testPositionDependence() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomGBForce* force = new CustomGBForce(); + force->addComputedValue("a", "r", CustomGBForce::ParticlePair); + force->addComputedValue("b", "a+x*y", CustomGBForce::SingleParticle); + force->addEnergyTerm("b*z", CustomGBForce::SingleParticle); + force->addEnergyTerm("b1+b2", CustomGBForce::ParticlePair); // = 2*r+x1*y1+x2*y2 + force->addParticle(vector()); + force->addParticle(vector()); + system.addForce(force); + Context context(system, integrator, platform); + vector positions(2); + vector forces(2); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + for (int i = 0; i < 5; i++) { + positions[0] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); + positions[1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + Vec3 delta = positions[0]-positions[1]; + double r = sqrt(delta.dot(delta)); + double energy = 2*r+positions[0][0]*positions[0][1]+positions[1][0]*positions[1][1]; + for (int j = 0; j < 2; j++) + energy += positions[j][2]*(r+positions[j][0]*positions[j][1]); + Vec3 force1(-(1+positions[0][2])*delta[0]/r-(1+positions[0][2])*positions[0][1]-(1+positions[1][2])*delta[0]/r, + -(1+positions[0][2])*delta[1]/r-(1+positions[0][2])*positions[0][0]-(1+positions[1][2])*delta[1]/r, + -(1+positions[0][2])*delta[2]/r-(r+positions[0][0]*positions[0][1])-(1+positions[1][2])*delta[2]/r); + Vec3 force2((1+positions[0][2])*delta[0]/r+(1+positions[1][2])*delta[0]/r-(1+positions[1][2])*positions[1][1], + (1+positions[0][2])*delta[1]/r+(1+positions[1][2])*delta[1]/r-(1+positions[1][2])*positions[1][0], + (1+positions[0][2])*delta[2]/r+(1+positions[1][2])*delta[2]/r-(r+positions[1][0]*positions[1][1])); + ASSERT_EQUAL_VEC(force1, forces[0], 1e-4); + ASSERT_EQUAL_VEC(force2, forces[1], 1e-4); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02); + + // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. + + double norm = 0.0; + for (int i = 0; i < (int) forces.size(); ++i) + norm += forces[i].dot(forces[i]); + norm = std::sqrt(norm); + const double stepSize = 1e-3; + double step = 0.5*stepSize/norm; + vector positions2(2), positions3(2); + for (int i = 0; i < (int) positions.size(); ++i) { + Vec3 p = positions[i]; + Vec3 f = forces[i]; + positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); + } + context.setPositions(positions2); + State state2 = context.getState(State::Energy); + context.setPositions(positions3); + State state3 = context.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); + } +} + +void testExclusions() { + for (int i = 0; i < 4; i++) { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomGBForce* force = new CustomGBForce(); + force->addComputedValue("a", "r", i < 2 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); + force->addEnergyTerm("a", CustomGBForce::SingleParticle); + force->addEnergyTerm("(1+a1+a2)*r", i%2 == 0 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); + force->addParticle(vector()); + force->addParticle(vector()); + force->addExclusion(0, 1); + system.addForce(force); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double f, energy; + switch (i) + { + case 0: // e = 0 + f = 0; + energy = 0; + break; + case 1: // e = r + f = 1; + energy = 1; + break; + case 2: // e = 2r + f = 2; + energy = 2; + break; + case 3: // e = 3r + 2r^2 + f = 7; + energy = 5; + break; + default: + ASSERT(false); + } + ASSERT_EQUAL_VEC(Vec3(f, 0, 0), forces[0], 1e-4); + ASSERT_EQUAL_VEC(Vec3(-f, 0, 0), forces[1], 1e-4); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); + + // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. + + double norm = 0.0; + for (int i = 0; i < (int) forces.size(); ++i) + norm += forces[i].dot(forces[i]); + norm = std::sqrt(norm); + const double stepSize = 1e-3; + double step = stepSize/norm; + for (int i = 0; i < (int) positions.size(); ++i) { + Vec3 p = positions[i]; + Vec3 f = forces[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); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff); + testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic); + testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic); + testMembrane(); + testTabulatedFunction(); + testMultipleChainRules(); + testPositionDependence(); + testExclusions(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + diff --git a/tests/TestHarmonicAngleForce.h b/tests/TestHarmonicAngleForce.h index aebeb76e3..e371d9b6c 100644 --- a/tests/TestHarmonicAngleForce.h +++ b/tests/TestHarmonicAngleForce.h @@ -29,10 +29,6 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of HarmonicAngleForce. - */ - #include "openmm/internal/AssertionUtilities.h" #include "openmm/Context.h" #include "openmm/HarmonicAngleForce.h" diff --git a/tests/TestPeriodicTorsionForce.h b/tests/TestPeriodicTorsionForce.h new file mode 100644 index 000000000..1e73cf41f --- /dev/null +++ b/tests/TestPeriodicTorsionForce.h @@ -0,0 +1,105 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/PeriodicTorsionForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testPeriodicTorsions() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + PeriodicTorsionForce* forceField = new PeriodicTorsionForce(); + forceField->addTorsion(0, 1, 2, 3, 2, PI_M/3, 1.1); + system.addForce(forceField); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector positions(4); + positions[0] = Vec3(0, 1, 0); + positions[1] = Vec3(0, 0, 0); + positions[2] = Vec3(1, 0, 0); + positions[3] = Vec3(1, 0, 2); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + double torque = -2*1.1*std::sin(2*PI_M/3); + ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); + 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(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL); + } + + // Try changing the torsion parameters and make sure it's still correct. + + forceField->setTorsionParameters(0, 0, 1, 2, 3, 3, PI_M/3.2, 1.3); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + double dtheta = (3*PI_M/2)-(PI_M/3.2); + double torque = -3*1.3*std::sin(dtheta); + ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); + 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(1.3*(1+std::cos(dtheta)), state.getPotentialEnergy(), TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testPeriodicTorsions(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestRBTorsionForce.h b/tests/TestRBTorsionForce.h new file mode 100644 index 000000000..eea5067ce --- /dev/null +++ b/tests/TestRBTorsionForce.h @@ -0,0 +1,124 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/RBTorsionForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testRBTorsions() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + RBTorsionForce* forceField = new RBTorsionForce(); + forceField->addTorsion(0, 1, 2, 3, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6); + system.addForce(forceField); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector positions(4); + positions[0] = Vec3(0, 1, 0); + positions[1] = Vec3(0, 0, 0); + positions[2] = Vec3(1, 0, 0); + positions[3] = Vec3(1, 1, 1); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + double psi = 0.25*PI_M - PI_M; + double torque = 0.0; + for (int i = 1; i < 6; ++i) { + double c = 0.1*(i+1); + torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); + } + ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); + 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); + double energy = 0.0; + for (int i = 0; i < 6; ++i) { + double c = 0.1*(i+1); + energy += c*std::pow(std::cos(psi), i); + } + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); + } + + // Try changing the torsion parameters and make sure it's still correct. + + forceField->setTorsionParameters(0, 0, 1, 2, 3, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + { + const vector& forces = state.getForces(); + double psi = 0.25*PI_M - PI_M; + double torque = 0.0; + for (int i = 1; i < 6; ++i) { + double c = 0.11*(i+1); + torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); + } + ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); + 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); + double energy = 0.0; + for (int i = 0; i < 6; ++i) { + double c = 0.11*(i+1); + energy += c*std::pow(std::cos(psi), i); + } + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testRBTorsions(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} -- GitLab From 4ed151e126208d49216ca5623ab94b86b15ac663 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Tue, 22 Sep 2015 15:16:45 -0700 Subject: [PATCH 11/49] Continuing to refactor tests --- platforms/cpu/tests/TestCpuCustomGBForce.cpp | 455 +------- .../tests/TestCpuCustomManyParticleForce.cpp | 713 +----------- .../cpu/tests/TestCpuCustomNonbondedForce.cpp | 963 +-------------- .../cpu/tests/TestCpuPeriodicTorsionForce.cpp | 80 +- platforms/cpu/tests/TestCpuRBTorsionForce.cpp | 99 +- .../cuda/tests/TestCudaAndersenThermostat.cpp | 191 +-- .../cuda/tests/TestCudaBrownianIntegrator.cpp | 252 +--- .../cuda/tests/TestCudaCMAPTorsionForce.cpp | 149 +-- .../cuda/tests/TestCudaCMMotionRemover.cpp | 94 +- .../cuda/tests/TestCudaCustomHbondForce.cpp | 220 +--- .../cuda/tests/TestCudaCustomIntegrator.cpp | 777 +------------ .../tests/TestCudaCustomManyParticleForce.cpp | 705 +---------- .../tests/TestCudaCustomNonbondedForce.cpp | 999 +--------------- .../cuda/tests/TestCudaCustomTorsionForce.cpp | 160 +-- .../cuda/tests/TestCudaRBTorsionForce.cpp | 2 +- .../tests/TestOpenCLAndersenThermostat.cpp | 192 +-- .../tests/TestOpenCLBrownianIntegrator.cpp | 253 +--- .../tests/TestOpenCLCMAPTorsionForce.cpp | 150 +-- .../tests/TestOpenCLCMMotionRemover.cpp | 95 +- .../tests/TestOpenCLCustomHbondForce.cpp | 221 +--- .../tests/TestOpenCLCustomIntegrator.cpp | 777 +------------ .../TestOpenCLCustomManyParticleForce.cpp | 705 +---------- .../tests/TestOpenCLCustomNonbondedForce.cpp | 998 +--------------- .../tests/TestOpenCLCustomTorsionForce.cpp | 162 +-- .../tests/TestReferenceAndersenThermostat.cpp | 190 +-- .../tests/TestReferenceBrownianIntegrator.cpp | 241 +--- .../tests/TestReferenceCMAPTorsionForce.cpp | 152 +-- .../tests/TestReferenceCMMotionRemover.cpp | 89 +- .../tests/TestReferenceCustomHbondForce.cpp | 221 +--- .../tests/TestReferenceCustomIntegrator.cpp | 747 +----------- .../TestReferenceCustomManyParticleForce.cpp | 627 +--------- .../TestReferenceCustomNonbondedForce.cpp | 965 +--------------- .../tests/TestReferenceCustomTorsionForce.cpp | 162 +-- tests/TestAndersenThermostat.h | 215 ++++ tests/TestBrownianIntegrator.h | 272 +++++ tests/TestCMAPTorsionForce.h | 177 +++ tests/TestCMMotionRemover.h | 117 ++ tests/TestCustomExternalForce.h | 1 + tests/TestCustomGBForce.h | 20 +- tests/TestCustomHbondForce.h | 246 ++++ tests/TestCustomIntegrator.h | 798 +++++++++++++ tests/TestCustomManyParticleForce.h | 736 ++++++++++++ tests/TestCustomNonbondedForce.h | 1028 +++++++++++++++++ tests/TestCustomTorsionForce.h | 187 +++ 44 files changed, 3921 insertions(+), 12682 deletions(-) create mode 100644 tests/TestAndersenThermostat.h create mode 100644 tests/TestBrownianIntegrator.h create mode 100644 tests/TestCMAPTorsionForce.h create mode 100644 tests/TestCMMotionRemover.h create mode 100644 tests/TestCustomHbondForce.h create mode 100644 tests/TestCustomIntegrator.h create mode 100644 tests/TestCustomManyParticleForce.h create mode 100644 tests/TestCustomNonbondedForce.h create mode 100644 tests/TestCustomTorsionForce.h diff --git a/platforms/cpu/tests/TestCpuCustomGBForce.cpp b/platforms/cpu/tests/TestCpuCustomGBForce.cpp index 6bdaf72d7..8d3b307e3 100644 --- a/platforms/cpu/tests/TestCpuCustomGBForce.cpp +++ b/platforms/cpu/tests/TestCpuCustomGBForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,454 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of CustomGBForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "sfmt/SFMT.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/CustomGBForce.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/GBVIForce.h" -#include "openmm/OpenMMException.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMethod customMethod) { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - const double cutoff = 2.0; - CpuPlatform platform; - - // Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction. - - System standardSystem; - System customSystem; - for (int i = 0; i < numParticles; i++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - } - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - GBSAOBCForce* obc = new GBSAOBCForce(); - CustomGBForce* custom = new CustomGBForce(); - obc->setCutoffDistance(cutoff); - custom->setCutoffDistance(cutoff); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("solventDielectric", obc->getSolventDielectric()); - custom->addGlobalParameter("soluteDielectric", obc->getSoluteDielectric()); - custom->addComputedValue("I", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=I*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935485*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - string invCutoffString = ""; - if (obcMethod != GBSAOBCForce::NoCutoff) { - stringstream s; - s<<(1.0/cutoff); - invCutoffString = s.str(); - } - custom->addEnergyTerm("138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("+invCutoffString+"-1/f);" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - obc->addParticle(1.0, 0.2, 0.5); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.5); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - obc->addParticle(1.0, 0.2, 0.8); - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - obc->addParticle(-1.0, 0.1, 0.8); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - obc->setNonbondedMethod(obcMethod); - custom->setNonbondedMethod(customMethod); - standardSystem.addForce(obc); - customSystem.addForce(custom); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - context1.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - context2.setVelocities(velocities); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } - - // Try changing the particle parameters and make sure it's still correct. - - for (int i = 0; i < numMolecules/2; i++) { - obc->setParticleParameters(2*i, 1.1, 0.3, 0.6); - params[0] = 1.1; - params[1] = 0.3; - params[2] = 0.6; - custom->setParticleParameters(2*i, params); - obc->setParticleParameters(2*i+1, -1.1, 0.2, 0.4); - params[0] = -1.1; - params[1] = 0.2; - params[2] = 0.4; - custom->setParticleParameters(2*i+1, params); - } - obc->updateParametersInContext(context1); - custom->updateParametersInContext(context2); - state1 = context1.getState(State::Forces | State::Energy); - state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -void testMembrane() { - const int numMolecules = 70; - const int numParticles = numMolecules*2; - const double boxSize = 10.0; - CpuPlatform platform; - - // Create a system with an implicit membrane. - - System system; - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize)); - CustomGBForce* custom = new CustomGBForce(); - custom->setCutoffDistance(2.0); - custom->addPerParticleParameter("q"); - custom->addPerParticleParameter("radius"); - custom->addPerParticleParameter("scale"); - custom->addGlobalParameter("thickness", 3); - custom->addGlobalParameter("solventDielectric", 78.3); - custom->addGlobalParameter("soluteDielectric", 1); - custom->addComputedValue("Imol", "step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);" - "U=r+sr2;" - "C=2*(1/or1-1/L)*step(sr2-r-or1);" - "L=max(or1, D);" - "D=abs(r-sr2);" - "sr2 = scale2*or2;" - "or1 = radius1-0.009; or2 = radius2-0.009", CustomGBForce::ParticlePairNoExclusions); - custom->addComputedValue("Imem", "(1/radius+2*log(2)/thickness)/(1+exp(7.2*(abs(z)+radius-0.5*thickness)))", CustomGBForce::SingleParticle); - custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);" - "psi=max(Imol,Imem)*or; or=radius-0.009", CustomGBForce::SingleParticle); - custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle); - custom->addEnergyTerm("-138.935456*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;" - "f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.5; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.8; - custom->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - custom->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)); - } - system.addForce(custom); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocities(velocities); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-2; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); -} - -void testTabulatedFunction() { - CpuPlatform platform; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "0", CustomGBForce::ParticlePair); - force->addEnergyTerm("fn(r)+1", CustomGBForce::ParticlePair); - force->addParticle(vector()); - force->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(std::sin(0.25*i)); - force->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& 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); - } -} - -void testMultipleChainRules() { - CpuPlatform platform; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "2*r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+1", CustomGBForce::SingleParticle); - force->addComputedValue("c", "2*b+a", CustomGBForce::SingleParticle); - force->addEnergyTerm("0.1*a+1*b+10*c", CustomGBForce::SingleParticle); // 0.1*(2*r) + 2*r+1 + 10*(3*a+2) = 0.2*r + 2*r+1 + 40*r+20+20*r = 62.2*r+21 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 1; i < 5; i++) { - positions[1] = Vec3(i, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(124.4, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-124.4, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(2*(62.2*i+21), state.getPotentialEnergy(), 0.02); - } -} - -void testPositionDependence() { - CpuPlatform platform; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", CustomGBForce::ParticlePair); - force->addComputedValue("b", "a+x*y", CustomGBForce::SingleParticle); - force->addEnergyTerm("b*z", CustomGBForce::SingleParticle); - force->addEnergyTerm("b1+b2", CustomGBForce::ParticlePair); // = 2*r+x1*y1+x2*y2 - force->addParticle(vector()); - force->addParticle(vector()); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - vector forces(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < 5; i++) { - positions[0] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - positions[1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - Vec3 delta = positions[0]-positions[1]; - double r = sqrt(delta.dot(delta)); - double energy = 2*r+positions[0][0]*positions[0][1]+positions[1][0]*positions[1][1]; - for (int j = 0; j < 2; j++) - energy += positions[j][2]*(r+positions[j][0]*positions[j][1]); - Vec3 force1(-(1+positions[0][2])*delta[0]/r-(1+positions[0][2])*positions[0][1]-(1+positions[1][2])*delta[0]/r, - -(1+positions[0][2])*delta[1]/r-(1+positions[0][2])*positions[0][0]-(1+positions[1][2])*delta[1]/r, - -(1+positions[0][2])*delta[2]/r-(r+positions[0][0]*positions[0][1])-(1+positions[1][2])*delta[2]/r); - Vec3 force2((1+positions[0][2])*delta[0]/r+(1+positions[1][2])*delta[0]/r-(1+positions[1][2])*positions[1][1], - (1+positions[0][2])*delta[1]/r+(1+positions[1][2])*delta[1]/r-(1+positions[1][2])*positions[1][0], - (1+positions[0][2])*delta[2]/r+(1+positions[1][2])*delta[2]/r-(r+positions[1][0]*positions[1][1])); - ASSERT_EQUAL_VEC(force1, forces[0], 1e-4); - ASSERT_EQUAL_VEC(force2, forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(2), positions3(2); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-3); - } -} - -void testExclusions() { - CpuPlatform platform; - for (int i = 3; i < 4; i++) { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomGBForce* force = new CustomGBForce(); - force->addComputedValue("a", "r", i < 2 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addEnergyTerm("a", CustomGBForce::SingleParticle); - force->addEnergyTerm("(1+a1+a2)*r", i%2 == 0 ? CustomGBForce::ParticlePair : CustomGBForce::ParticlePairNoExclusions); - force->addParticle(vector()); - force->addParticle(vector()); - force->addExclusion(0, 1); - system.addForce(force); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double f, energy; - switch (i) - { - case 0: // e = 0 - f = 0; - energy = 0; - break; - case 1: // e = r - f = 1; - energy = 1; - break; - case 2: // e = 2r - f = 2; - energy = 2; - break; - case 3: // e = 3r + 2r^2 - f = 7; - energy = 5; - break; - default: - ASSERT(false); - } - ASSERT_EQUAL_VEC(Vec3(f, 0, 0), forces[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(-f, 0, 0), forces[1], 1e-4); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = stepSize/norm; - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[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); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); - } -} +#include "CpuTests.h" +#include "TestCustomGBForce.h" -int main() { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff); - testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic); - testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic); - testMembrane(); - testTabulatedFunction(); - testMultipleChainRules(); - testPositionDependence(); - testExclusions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuCustomManyParticleForce.cpp b/platforms/cpu/tests/TestCpuCustomManyParticleForce.cpp index 03a6f803c..ae8f595bc 100644 --- a/platforms/cpu/tests/TestCpuCustomManyParticleForce.cpp +++ b/platforms/cpu/tests/TestCpuCustomManyParticleForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,713 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CPU implementation of CustomManyParticleForce. - */ +#include "CpuTests.h" +#include "TestCustomManyParticleForce.h" -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/CustomManyParticleForce.h" -#include "openmm/System.h" -#include "openmm/TabulatedFunction.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -Vec3 computeDelta(const Vec3& pos1, const Vec3& pos2, bool periodic, const Vec3* periodicBoxVectors) { - Vec3 diff = pos1-pos2; - if (periodic) { - diff -= periodicBoxVectors[2]*floor(diff[2]/periodicBoxVectors[2][2]+0.5); - diff -= periodicBoxVectors[1]*floor(diff[1]/periodicBoxVectors[1][1]+0.5); - diff -= periodicBoxVectors[0]*floor(diff[0]/periodicBoxVectors[0][0]+0.5); - } - return diff; -} - -void validateAxilrodTeller(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize, bool triclinic) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - Vec3 boxVectors[3]; - if (triclinic) { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0.2*boxSize, boxSize, 0); - boxVectors[2] = Vec3(-0.3*boxSize, -0.1*boxSize, boxSize); - } - else { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0, boxSize, 0); - boxVectors[2] = Vec3(0, 0, boxSize); - } - system.setDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]); - system.addForce(force); - VerletIntegrator integrator(0.001); - CpuPlatform platform; - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double c = context.getParameter("C"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - bool periodic = (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic); - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = computeDelta(positions[p2], positions[p1], periodic, boxVectors); - Vec3 d13 = computeDelta(positions[p3], positions[p1], periodic, boxVectors); - Vec3 d23 = computeDelta(positions[p3], positions[p2], periodic, boxVectors); - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - double rprod = r12*r13*r23; - expectedEnergy += c*(1+3*ctheta1*ctheta2*ctheta3)/(rprod*rprod*rprod); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void validateStillingerWeber(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator(0.001); - CpuPlatform platform; - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double L = context.getParameter("L"); - double eps = context.getParameter("eps"); - double a = context.getParameter("a"); - double gamma = context.getParameter("gamma"); - double sigma = context.getParameter("sigma"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - Vec3 d23 = positions[p3]-positions[p2]; - if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) { - for (int j = 0; j < 3; j++) { - d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize; - d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize; - d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize; - } - } - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - expectedEnergy += L*eps*(ctheta1+1.0/3.0)*(ctheta1+1.0/3.0)*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma)); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void testNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - int sets[4][3] = {{0,1,2}, {1,2,3}, {2,3,0}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(1.55); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - int sets[7][3] = {{0,1,2}, {0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,2,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[7]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testPeriodic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[5][3] = {{0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, false); -} - -void testTriclinic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[4][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, true); -} - -void testExclusions() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - force->addExclusion(0, 2); - force->addExclusion(0, 3); - int sets[5][3] = {{0,1,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testAllTerms() { - int numParticles = 4; - CpuPlatform platform; - - // Create a system with a CustomManyParticleForce. - - System system1; - CustomManyParticleForce* force1 = new CustomManyParticleForce(4, - "distance(p1,p2)+angle(p1,p4,p3)+dihedral(p1,p3,p2,p4)+x1+y4+z3"); - system1.addForce(force1); - vector params; - for (int i = 0; i < numParticles; i++) { - system1.addParticle(1.0); - force1->addParticle(params, i); - } - set filter; - filter.insert(0); - force1->setTypeFilter(0, filter); - filter.clear(); - filter.insert(1); - force1->setTypeFilter(1, filter); - filter.clear(); - filter.insert(3); - force1->setTypeFilter(2, filter); - filter.clear(); - filter.insert(2); - force1->setTypeFilter(3, filter); - - // Create a system that use a CustomCompoundBondForce to compute exactly the same interactions. - - System system2; - CustomCompoundBondForce* force2 = new CustomCompoundBondForce(4, - "distance(p1,p2)+angle(p1,p3,p4)+dihedral(p1,p4,p2,p3)+x1+y3+z4"); - system2.addForce(force2); - vector particles; - particles.push_back(0); - particles.push_back(1); - particles.push_back(2); - particles.push_back(3); - force2->addBond(particles, params); - for (int i = 0; i < numParticles; i++) - system2.addParticle(1.0); - - // Create contexts for both of them. - - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system1, integrator1, platform); - Context context2(system2, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - - // See if they produce identical forces and energies. - - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state2.getForces()[i], state1.getForces()[i], 1e-4); -} - -void testParameters() { - // Create a system. - - int numParticles = 5; - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "C*scale1*scale2*scale3*(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))"); - force->addGlobalParameter("C", 2.0); - force->addPerParticleParameter("scale"); - vector params(1); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - params[0] = i+1; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - CpuPlatform platform; - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 2.0*(i+1)*(j+1)*(k+1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); - - // Modify the parameters. - - context.setParameter("C", 3.5); - for (int i = 0; i < numParticles; i++) { - params[0] = 0.5*i-0.1; - force->setParticleParameters(i, params, 0); - } - force->updateParametersInContext(context); - - // See if the energy is still correct. - - state = context.getState(State::Energy); - expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 3.5*(0.5*i-0.1)*(0.5*j-0.1)*(0.5*k-0.1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTabulatedFunctions() { - int numParticles = 5; - - // Create two tabulated functions. - - vector values; - values.push_back(0.0); - values.push_back(50.0); - Continuous1DFunction* f1 = new Continuous1DFunction(values, 0, 100); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector c(numParticles); - for (int i = 0; i < numParticles; i++) - c[i] = genrand_real2(sfmt); - values.resize(numParticles*numParticles*numParticles); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < numParticles; j++) - for (int k = 0; k < numParticles; k++) - values[i+numParticles*j+numParticles*numParticles*k] = c[i]+c[j]+c[k]; - Discrete3DFunction* f2 = new Discrete3DFunction(numParticles, numParticles, numParticles, values); - - // Create a system. - - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "f1(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))*f2(atom1, atom2, atom3)"); - force->addPerParticleParameter("atom"); - force->addTabulatedFunction("f1", f1); - force->addTabulatedFunction("f2", f2); - vector params(1); - vector positions; - for (int i = 0; i < numParticles; i++) { - params[0] = i; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - CpuPlatform platform; - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 0.5*(r12+r13+r23)*(c[i]+c[j]+c[k]); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTypeFilters() { - // Create a system. - - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CustomManyParticleForce* force = new CustomManyParticleForce(3, "c1*(distance(p1,p2)+distance(p1,p3))"); - force->addPerParticleParameter("c"); - double c[] = {1.0, 2.0, 1.3, 1.5, -2.1}; - int type[] = {0, 1, 0, 1, 5}; - vector params(1); - for (int i = 0; i < 5; i++) { - params[0] = c[i]; - force->addParticle(params, type[i]); - } - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - set f1, f2; - f1.insert(0); - f2.insert(1); - f2.insert(5); - force->setTypeFilter(0, f1); - force->setTypeFilter(1, f2); - force->setTypeFilter(2, f2); - system.addForce(force); - VerletIntegrator integrator(0.001); - CpuPlatform platform; - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - int sets[6][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {2,1,3}, {2,1,4}, {2,3,4}}; - for (int i = 0; i < 6; i++) { - int p1 = sets[i][0]; - int p2 = sets[i][1]; - int p3 = sets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - expectedEnergy += c[p1]*(r12+r13); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testLargeSystem() { - int gridSize = 8; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = 3.0; - double spacing = boxSize/gridSize; - CpuPlatform platform; - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(0.6); - vector params; - vector positions; - System system; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - force->addParticle(params); - positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system, integrator1, Platform::getPlatformByName("Reference")); - Context context2(system, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); -} - -void testCentralParticleModeNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[12][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {2,0,3}, {2, 1, 3}, {3,0,1}, {3,0,2}, {3,1,2}}; - vector expectedSets(&sets[0], &sets[12]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(0.155); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[8][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[8]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeLargeSystem() { - int gridSize = 8; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = 2.0; - double spacing = boxSize/gridSize; - CpuPlatform platform; - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.8*0.23925); - vector params; - vector positions; - System system; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - force->addParticle(params); - positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system, integrator1, Platform::getPlatformByName("Reference")); - Context context2(system, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); -} - -int main() { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testNoCutoff(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testExclusions(); - testAllTerms(); - testParameters(); - testTabulatedFunctions(); - testTypeFilters(); - testLargeSystem(); - testCentralParticleModeNoCutoff(); - testCentralParticleModeCutoff(); - testCentralParticleModeLargeSystem(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuCustomNonbondedForce.cpp b/platforms/cpu/tests/TestCpuCustomNonbondedForce.cpp index fed1bc2b0..0c82130e1 100644 --- a/platforms/cpu/tests/TestCpuCustomNonbondedForce.cpp +++ b/platforms/cpu/tests/TestCpuCustomNonbondedForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,962 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of CustomNonbondedForce. - */ - -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "CpuPlatform.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "openmm/CustomNonbondedForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -CpuPlatform platform; - -const double TOL = 1e-5; - -void testSimpleExpression() { - 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()); - forceField->addParticle(vector()); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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 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 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 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); - - // Try changing the global parameters and make sure it's still correct. - - 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); - - // Try changing the per-particle parameters and make sure it's still correct. - - params[0] = 1.6; - params[1] = 2.1; - forceField->setParticleParameters(0, params); - params[0] = 1.9; - params[1] = 2.8; - forceField->setParticleParameters(1, params); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - forces = state.getForces(); - force = -1.5*1.6*1.9*3*5.9*(11.8*11.8); - 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*1.6*1.9*(11.8*11.8*11.8), state.getPotentialEnergy(), TOL); -} - -void testExclusions() { - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("a*r; a=a1+a2"); - nonbonded->addPerParticleParameter("a"); - vector params(1); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - forceField->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - forceField->setCutoffDistance(2.5); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - 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 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& 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 testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("r"); - nonbonded->addParticle(vector()); - nonbonded->addParticle(vector()); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta/sqrt(delta.dot(delta)); - ASSERT_EQUAL_TOL(distance, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); - } - } -} - -void testContinuous1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& forces = state.getForces(); - double force = (x < 1.0 || x > 6.0 ? 0.0 : -cos(x-1.0)); - double energy = (x < 1.0 || x > 6.0 ? 0.0 : 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 : sin(x-1.0))+1.0; - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - } -} - -void testContinuous2DFunction() { - const int xsize = 20; - const int ysize = 21; - const double xmin = 0.4; - const double xmax = 1.5; - const double ymin = 0.0; - const double ymax = 2.1; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y); - } - 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); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - const double zmin = 0.2; - const double zmax = 1.3; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setParameter("b", z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - } - 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.05); - } - } - } -} - -void testDiscrete1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Discrete1DFunction(table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete2DFunction() { - const int xsize = 10; - const int ysize = 5; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - table.push_back(sin(0.25*i)+cos(0.33*j)); - forceField->addTabulatedFunction("fn", new Discrete2DFunction(xsize, ysize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i%xsize, 0, 0); - context.setPositions(positions); - context.setParameter("a", i/xsize); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete3DFunction() { - const int xsize = 8; - const int ysize = 5; - const int zsize = 6; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - for (int k = 0; k < zsize; k++) - table.push_back(sin(0.25*i)+cos(0.33*j)+0.12345*k); - forceField->addTabulatedFunction("fn", new Discrete3DFunction(xsize, ysize, zsize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i%xsize, 0, 0); - context.setPositions(positions); - context.setParameter("a", (i/xsize)%ysize); - context.setParameter("b", i/(xsize*ysize)); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testCoulombLennardJones() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // 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 positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector 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); - Context context1(standardSystem, integrator1, platform); - Context context2(customSystem, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - context1.setVelocities(velocities); - context2.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -void testSwitchingFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("10/r^2"); - vector params; - nonbonded->addParticle(params); - nonbonded->addParticle(params); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double expectedEnergy = 10/(r*r); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - -void testLongRangeCorrection() { - // Create a box of particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System standardSystem; - System customSystem; - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - NonbondedForce* standardNonbonded = new NonbondedForce(); - CustomNonbondedForce* customNonbonded = new CustomNonbondedForce("4*eps*((sigma/r)^12-(sigma/r)^6); sigma=0.5*(sigma1+sigma2); eps=sqrt(eps1*eps2)"); - customNonbonded->addPerParticleParameter("sigma"); - customNonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - int index = 0; - vector params1(2); - params1[0] = 1.1; - params1[1] = 0.5; - vector params2(2); - params2[0] = 1; - params2[1] = 1; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - if (index%2 == 0) { - standardNonbonded->addParticle(0, params1[0], params1[1]); - customNonbonded->addParticle(params1); - } - else { - standardNonbonded->addParticle(0, params2[0], params2[1]); - customNonbonded->addParticle(params2); - } - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - standardNonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - customNonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - standardNonbonded->setCutoffDistance(cutoff); - customNonbonded->setCutoffDistance(cutoff); - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - standardNonbonded->setUseDispersionCorrection(true); - customNonbonded->setUseLongRangeCorrection(true); - standardNonbonded->setUseSwitchingFunction(true); - customNonbonded->setUseSwitchingFunction(true); - standardNonbonded->setSwitchingDistance(0.8*cutoff); - customNonbonded->setSwitchingDistance(0.8*cutoff); - standardSystem.addForce(standardNonbonded); - customSystem.addForce(customNonbonded); - - // Compute the correction for the standard force. - - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - double standardEnergy1 = context1.getState(State::Energy).getPotentialEnergy(); - standardNonbonded->setUseDispersionCorrection(false); - context1.reinitialize(); - context1.setPositions(positions); - double standardEnergy2 = context1.getState(State::Energy).getPotentialEnergy(); - - // Compute the correction for the custom force. - - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - double customEnergy1 = context2.getState(State::Energy).getPotentialEnergy(); - customNonbonded->setUseLongRangeCorrection(false); - context2.reinitialize(); - context2.setPositions(positions); - double customEnergy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // See if they agree. - - ASSERT_EQUAL_TOL(standardEnergy1-standardEnergy2, customEnergy1-customEnergy2, 1e-4); -} - -void testInteractionGroups() { - const int numParticles = 6; - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("v1+v2"); - nonbonded->addPerParticleParameter("v"); - vector params(1, 0.001); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(params); - params[0] *= 10; - } - set set1, set2, set3, set4; - set1.insert(2); - set2.insert(0); - set2.insert(1); - set2.insert(2); - set2.insert(3); - set2.insert(4); - set2.insert(5); - nonbonded->addInteractionGroup(set1, set2); // Particle 2 interacts with every other particle. - set3.insert(0); - set3.insert(1); - set4.insert(4); - set4.insert(5); - nonbonded->addInteractionGroup(set3, set4); // Particles 0 and 1 interact with 4 and 5. - nonbonded->addExclusion(1, 2); // Add an exclusion to make sure it gets skipped. - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - context.setPositions(positions); - State state = context.getState(State::Energy); - double expectedEnergy = 331.423; // Each digit is the number of interactions a particle particle is involved in. - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), TOL); -} - -void testLargeInteractionGroup() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // Create a large system. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomNonbondedForce* nonbonded = 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)"); - nonbonded->addPerParticleParameter("q"); - nonbonded->addPerParticleParameter("sigma"); - nonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.1; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.2; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->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]); - nonbonded->addExclusion(2*i, 2*i+1); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Compute the forces. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces); - - // Modify the force so only one particle interacts with everything else. - - set set1, set2; - set1.insert(151); - for (int i = 0; i < numParticles; i++) - set2.insert(i); - nonbonded->addInteractionGroup(set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state2 = context.getState(State::Forces); - - // The force on that one particle should be the same. - - ASSERT_EQUAL_VEC(state1.getForces()[151], state2.getForces()[151], 1e-4); - - // Modify the interaction group so it includes all interactions. This should now reproduce the original forces - // on all atoms. - - for (int i = 0; i < numParticles; i++) - set1.insert(i); - nonbonded->setInteractionGroupParameters(0, set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state3 = context.getState(State::Forces); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state3.getForces()[i], 1e-4); -} - -void testInteractionGroupLongRangeCorrection() { - const int numParticles = 10; - const double boxSize = 10.0; - const double cutoff = 0.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("c1*c2*r^-4"); - nonbonded->addPerParticleParameter("c"); - vector positions(numParticles); - vector params(1); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - params[0] = (i%2 == 0 ? 1.1 : 2.0); - nonbonded->addParticle(params); - positions[i] = Vec3(0.5*i, 0, 0); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - - // Setup nonbonded groups. They involve 1 interaction of type AA, - // 2 of type BB, and 5 of type AB. - - set set1, set2, set3, set4, set5; - set1.insert(0); - set1.insert(1); - set1.insert(2); - nonbonded->addInteractionGroup(set1, set1); - set2.insert(3); - set3.insert(4); - set3.insert(6); - set3.insert(8); - nonbonded->addInteractionGroup(set2, set3); - set4.insert(5); - set5.insert(7); - set5.insert(9); - nonbonded->addInteractionGroup(set4, set5); - - // Compute energy with and without the correction. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseLongRangeCorrection(true); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - - // Check the result. - - double sum = (1.1*1.1 + 2*2.0*2.0 + 5*1.1*2.0)*2.0; - int numPairs = (numParticles*(numParticles+1))/2; - double expected = 2*M_PI*numParticles*numParticles*sum/(numPairs*boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy2-energy1, 1e-4); -} - -void testMultipleCutoffs() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - - // Add multiple nonbonded forces that have different cutoffs. - - CustomNonbondedForce* nonbonded1 = new CustomNonbondedForce("2*r"); - nonbonded1->addParticle(vector()); - nonbonded1->addParticle(vector()); - nonbonded1->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded1->setCutoffDistance(2.5); - system.addForce(nonbonded1); - CustomNonbondedForce* nonbonded2 = new CustomNonbondedForce("3*r"); - nonbonded2->addParticle(vector()); - nonbonded2->addParticle(vector()); - nonbonded2->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded2->setCutoffDistance(2.9); - nonbonded2->setForceGroup(1); - system.addForce(nonbonded2); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 0, 0); - for (double r = 2.4; r < 3.2; r += 0.2) { - positions[1][1] = r; - context.setPositions(positions); - double e1 = (r < 2.5 ? 2.0*r : 0.0); - double e2 = (r < 2.9 ? 3.0*r : 0.0); - double f1 = (r < 2.5 ? 2.0 : 0.0); - double f2 = (r < 2.9 ? 3.0 : 0.0); - - // Check the first force. - - State state = context.getState(State::Forces | State::Energy, false, 1); - ASSERT_EQUAL_VEC(Vec3(0, f1, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1, state.getPotentialEnergy(), TOL); - - // Check the second force. - - state = context.getState(State::Forces | State::Energy, false, 2); - ASSERT_EQUAL_VEC(Vec3(0, f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e2, state.getPotentialEnergy(), TOL); - - // Check the sum of both forces. - - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_VEC(Vec3(0, f1+f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1-f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1+e2, state.getPotentialEnergy(), TOL); - } -} +#include "CpuTests.h" +#include "TestCustomNonbondedForce.h" -int main() { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testSimpleExpression(); - testParameters(); - testExclusions(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testContinuous1DFunction(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testDiscrete1DFunction(); - testDiscrete2DFunction(); - testDiscrete3DFunction(); - testCoulombLennardJones(); - testSwitchingFunction(); - testLongRangeCorrection(); - testInteractionGroups(); - testLargeInteractionGroup(); - testInteractionGroupLongRangeCorrection(); - testMultipleCutoffs(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuPeriodicTorsionForce.cpp b/platforms/cpu/tests/TestCpuPeriodicTorsionForce.cpp index aa660f207..9e03ea01e 100644 --- a/platforms/cpu/tests/TestCpuPeriodicTorsionForce.cpp +++ b/platforms/cpu/tests/TestCpuPeriodicTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,69 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CPU implementation of PeriodicTorsionForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CpuPlatform platform; - -const double TOL = 1e-5; - -void testPeriodicTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - PeriodicTorsionForce* forceField = new PeriodicTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 2, PI_M/3, 1.1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 2); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double torque = -2*1.1*std::sin(2*PI_M/3); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 3, PI_M/3.2, 1.3); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double dtheta = (3*PI_M/2)-(PI_M/3.2); - double torque = -3*1.3*std::sin(dtheta); - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); - 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(1.3*(1+std::cos(dtheta)), state.getPotentialEnergy(), TOL); - } -} +#include "CpuTests.h" +#include "TestPeriodicTorsionForce.h" void testParallelComputation() { System system; @@ -119,15 +58,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - testPeriodicTorsions(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cpu/tests/TestCpuRBTorsionForce.cpp b/platforms/cpu/tests/TestCpuRBTorsionForce.cpp index c35ae7d02..db3b5a37e 100644 --- a/platforms/cpu/tests/TestCpuRBTorsionForce.cpp +++ b/platforms/cpu/tests/TestCpuRBTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,88 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of RBTorsionForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/RBTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CpuPlatform platform; - -const double TOL = 1e-5; - -void testRBTorsions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - RBTorsionForce* forceField = new RBTorsionForce(); - forceField->addTorsion(0, 1, 2, 3, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 1, 0); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 1, 1); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.1*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.1*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - forceField->setTorsionParameters(0, 0, 1, 2, 3, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - { - const vector& forces = state.getForces(); - double psi = 0.25*PI_M - PI_M; - double torque = 0.0; - for (int i = 1; i < 6; ++i) { - double c = 0.11*(i+1); - torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi); - } - ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL); - 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); - double energy = 0.0; - for (int i = 0; i < 6; ++i) { - double c = 0.11*(i+1); - energy += c*std::pow(std::cos(psi), i); - } - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} +#include "CpuTests.h" +#include "TestRBTorsionForce.h" void testParallelComputation() { System system; @@ -138,15 +58,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - testRBTorsions(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaAndersenThermostat.cpp b/platforms/cuda/tests/TestCudaAndersenThermostat.cpp index 7656136b4..30e41d480 100644 --- a/platforms/cuda/tests/TestCudaAndersenThermostat.cpp +++ b/platforms/cuda/tests/TestCudaAndersenThermostat.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,191 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of AndersenThermostat. - */ +#include "CudaTests.h" +#include "TestAndersenThermostat.h" -#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 "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -void testTemperature() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 5000; - System system; - VerletIntegrator integrator(0.003); - 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 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); - context.setVelocitiesToTemperature(temp); - - // 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(10); - } - ke /= numSteps; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 15000; - System system; - VerletIntegrator integrator(0.004); - 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 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); - context.setVelocitiesToTemperature(temp); - - // Let it equilibrate. - - integrator.step(5000); - - // 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_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testTemperature(); - testConstraints(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaBrownianIntegrator.cpp b/platforms/cuda/tests/TestCudaBrownianIntegrator.cpp index cfb05f0e6..ed96d7d6c 100644 --- a/platforms/cuda/tests/TestCudaBrownianIntegrator.cpp +++ b/platforms/cuda/tests/TestCudaBrownianIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,252 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -#include "openmm/System.h" +#include "CudaTests.h" +#include "TestBrownianIntegrator.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 "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testSingleBond() { - 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 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; - 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 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; - 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 positions(numParticles); - vector 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 testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - BrownianIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCMAPTorsionForce.cpp b/platforms/cuda/tests/TestCudaCMAPTorsionForce.cpp index 6a95ade0f..fb9598262 100644 --- a/platforms/cuda/tests/TestCudaCMAPTorsionForce.cpp +++ b/platforms/cuda/tests/TestCudaCMAPTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2010-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,149 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of CMAPTorsionForce. - */ +#include "CudaTests.h" +#include "TestCMAPTorsionForce.h" -#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 "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -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. - - 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 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(system1, integrator1, platform); - Context c2(system2, integrator2, platform); - for (int i = 0; i < 50; 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < system1.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 0.05); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), 1e-3); - } -} - -void testChangingParameters() { - // Create a system with two maps and one torsion. - - const int mapSize = 8; - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CMAPTorsionForce* cmap = new CMAPTorsionForce(); - vector mapEnergy1(mapSize*mapSize); - vector mapEnergy2(mapSize*mapSize); - for (int i = 0; i < mapSize; i++) { - double angle1 = i*2*M_PI/mapSize; - double energy1 = cos(angle1); - for (int j = 0; j < mapSize; j++) { - double angle2 = j*2*M_PI/mapSize; - double energy2 = 10*sin(angle2); - mapEnergy1[i+j*mapSize] = energy1+energy2; - mapEnergy2[i+j*mapSize] = energy1-energy2; - } - } - cmap->addMap(mapSize, mapEnergy1); - cmap->addMap(mapSize, mapEnergy2); - cmap->addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4); - system.addForce(cmap); - - // Set particle positions so angle1=0 and angle2=PI/4. - - vector positions(5); - positions[0] = Vec3(0, 0, 1); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 1); - positions[4] = Vec3(0.5, -0.5, 1); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Check that the energy is correct. - - double energy = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(1+10*sin(M_PI/4), energy, 1e-5); - - // Modify the parameters. - - cmap->setTorsionParameters(0, 1, 0, 1, 2, 3, 1, 2, 3, 4); - for (int i = 0; i < mapSize*mapSize; i++) - mapEnergy2[i] *= 2.0; - cmap->setMapParameters(1, mapSize, mapEnergy2); - cmap->updateParametersInContext(context); - - // See if the results are correct. - - energy = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(2-20*sin(M_PI/4), energy, 1e-5); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testCMAPTorsions(); - testChangingParameters(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCMMotionRemover.cpp b/platforms/cuda/tests/TestCudaCMMotionRemover.cpp index d7140ef24..72a111c35 100644 --- a/platforms/cuda/tests/TestCudaCMMotionRemover.cpp +++ b/platforms/cuda/tests/TestCudaCMMotionRemover.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,94 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of AndersenThermostat. - */ +#include "CudaTests.h" +#include "TestCMMotionRemover.h" -#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 "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -Vec3 calcCM(const vector& 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; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - 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; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCustomHbondForce.cpp b/platforms/cuda/tests/TestCudaCustomHbondForce.cpp index a4e9b769a..ae5000050 100644 --- a/platforms/cuda/tests/TestCudaCustomHbondForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomHbondForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,220 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of CustomHbondForce. - */ +#include "CudaTests.h" +#include "TestCustomHbondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/CustomHbondForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void testHbond() { - // Create a system using a CustomHbondForce. - - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomHbondForce* custom = new CustomHbondForce("0.5*kr*(distance(d1,a1)-r0)^2 + 0.5*ktheta*(angle(a1,d1,d2)-theta0)^2 + 0.5*kpsi*(angle(d1,a1,a2)-psi0)^2 + kchi*(1+cos(n*dihedral(a3,a2,a1,d1)-chi0))"); - custom->addPerDonorParameter("r0"); - custom->addPerDonorParameter("theta0"); - custom->addPerDonorParameter("psi0"); - custom->addPerAcceptorParameter("chi0"); - custom->addPerAcceptorParameter("n"); - custom->addGlobalParameter("kr", 0.4); - custom->addGlobalParameter("ktheta", 0.5); - custom->addGlobalParameter("kpsi", 0.6); - custom->addGlobalParameter("kchi", 0.7); - vector parameters(3); - parameters[0] = 1.5; - parameters[1] = 1.7; - parameters[2] = 1.9; - custom->addDonor(1, 0, -1, parameters); - parameters.resize(2); - parameters[0] = 2.1; - parameters[1] = 2; - custom->addAcceptor(2, 3, 4, parameters); - custom->setCutoffDistance(10.0); - customSystem.addForce(custom); - - // Create an identical system using HarmonicBondForce, HarmonicAngleForce, and PeriodicTorsionForce. - - System standardSystem; - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - HarmonicBondForce* bond = new HarmonicBondForce(); - bond->addBond(1, 2, 1.5, 0.4); - standardSystem.addForce(bond); - HarmonicAngleForce* angle = new HarmonicAngleForce(); - angle->addAngle(0, 1, 2, 1.7, 0.5); - angle->addAngle(1, 2, 3, 1.9, 0.6); - standardSystem.addForce(angle); - PeriodicTorsionForce* torsion = new PeriodicTorsionForce(); - torsion->addTorsion(1, 2, 3, 4, 2, 2.1, 0.7); - standardSystem.addForce(torsion); - - // 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(standardSystem, integrator2, platform); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < (int) positions.size(); j++) - positions[j] = Vec3(2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); - } - - // Try changing the parameters and make sure it's still correct. - - parameters.resize(3); - parameters[0] = 1.4; - parameters[1] = 1.7; - parameters[2] = 1.9; - custom->setDonorParameters(0, 1, 0, -1, parameters); - parameters.resize(2); - parameters[0] = 2.2; - parameters[1] = 2; - custom->setAcceptorParameters(0, 2, 3, 4, parameters); - bond->setBondParameters(0, 1, 2, 1.4, 0.4); - torsion->setTorsionParameters(0, 1, 2, 3, 4, 2, 2.2, 0.7); - custom->updateParametersInContext(c1); - bond->updateParametersInContext(c2); - torsion->updateParametersInContext(c2); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); -} - -void testExclusions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); - custom->addDonor(0, 1, -1, vector()); - custom->addDonor(1, 0, -1, vector()); - custom->addAcceptor(2, 0, -1, vector()); - custom->addExclusion(1, 0); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); - custom->addDonor(0, 1, -1, vector()); - custom->addDonor(1, 0, -1, vector()); - custom->addAcceptor(2, 0, -1, vector()); - custom->setNonbondedMethod(CustomHbondForce::CutoffNonPeriodic); - custom->setCutoffDistance(2.5); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 3, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); -} - -void testCustomFunctions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("foo(distance(d1,a1))"); - custom->addDonor(1, 0, -1, vector()); - custom->addDonor(2, 0, -1, vector()); - custom->addAcceptor(0, 1, -1, vector()); - vector function(2); - function[0] = 0; - function[1] = 1; - custom->addTabulatedFunction("foo", new Continuous1DFunction(function, 0, 10)); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0.1, 0.1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -0.1, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-0.1, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(0.1*2+0.1*2, state.getPotentialEnergy(), TOL); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testHbond(); - testExclusions(); - testCutoff(); - testCustomFunctions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCustomIntegrator.cpp b/platforms/cuda/tests/TestCudaCustomIntegrator.cpp index ca7acd423..369b9375b 100644 --- a/platforms/cuda/tests/TestCudaCustomIntegrator.cpp +++ b/platforms/cuda/tests/TestCudaCustomIntegrator.cpp @@ -29,666 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of CustomIntegrator. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/CustomIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -/** - * Test a simple leapfrog integrator on a single bond. - */ -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.setKineticEnergyExpression("m*v1*v1/2; v1=v+0.5*dt*f/m"); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - vector velocities(2); - velocities[0] = Vec3(-0.5*dt*0.5*0.5, 0, 0); - velocities[1] = Vec3(0.5*dt*0.5*0.5, 0, 0); - context.setVelocities(velocities); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*std::cos(freq*time); - ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 1e-4); - double expectedSpeed = -0.5*freq*std::sin(freq*(time-dt/2)); - ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 1e-4); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(0.5*0.5*0.5, energy, 1e-4); - integrator.step(1); - } -} - -/** - * Test an integrator that enforces constraints. - */ -void testConstraints() { - const int numParticles = 8; - System system; - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "(x-oldx)/dt"); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -/** - * Test an integrator that applies constraints directly to velocities. - */ -void testVelocityConstraints() { - const int numParticles = 10; - System system; - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("x1", 0); - integrator.addComputePerDof("v", "v+0.5*dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputePerDof("x1", "x"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "v+0.5*dt*f/m+(x-x1)/dt"); - integrator.addConstrainVelocities(); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - - // Constrain the first three particles with SHAKE. - - system.addConstraint(0, 1, 1.0); - system.addConstraint(1, 2, 1.0); - - // Constrain the next three with SETTLE. - - system.addConstraint(3, 4, 1.0); - system.addConstraint(5, 4, 1.0); - system.addConstraint(3, 5, sqrt(2.0)); - - // Constraint the rest with CCMA. - - for (int i = 6; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - integrator.step(2); - State state = context.getState(State::Positions | State::Velocities | State::Energy); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - if (i > 0) { - Vec3 v1 = state.getVelocities()[particle1]; - Vec3 v2 = state.getVelocities()[particle2]; - double vel = (v1-v2).dot(p1-p2); - ASSERT_EQUAL_TOL(0.0, vel, 2e-5); - } - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 0) - initialEnergy = energy; - else if (i > 0) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "(x-oldx)/dt"); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -/** - * Test an integrator with an AndersenThermostat to see if updateContextState() - * is being handled correctly. - */ -void testWithThermostat() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 20.0; - const int numSteps = 5000; - System system; - CustomIntegrator integrator(0.003); - integrator.addUpdateContextState(); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - 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); - integrator.setRandomNumberSeed(thermostat->getRandomNumberSeed()); - Context context(system, integrator, platform); - vector 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); - context.setVelocitiesToTemperature(temp); - - // 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(10); - } - ke /= numSteps; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -/** - * Test a Monte Carlo integrator that uses global variables and depends on energy. - */ -void testMonteCarlo() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - const double kT = BOLTZ*300.0; - integrator.addGlobalVariable("kT", kT); - integrator.addGlobalVariable("oldE", 0); - integrator.addGlobalVariable("accept", 0); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputeGlobal("oldE", "energy"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*gaussian"); - integrator.addComputeGlobal("accept", "step(exp((oldE-energy)/kT)-uniform)"); - integrator.addComputePerDof("x", "select(accept, x, oldx)"); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 2.0, 10.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // Compute the histogram of distances and see if it satisfies a Boltzmann distribution. - - const int numBins = 100; - const double maxDist = 4.0; - const int numIterations = 5000; - vector counts(numBins, 0); - for (int i = 0; i < numIterations; ++i) { - integrator.step(10); - State state = context.getState(State::Positions); - Vec3 delta = state.getPositions()[0]-state.getPositions()[1]; - double dist = sqrt(delta.dot(delta)); - if (dist < maxDist) - counts[(int) (numBins*dist/maxDist)]++; - } - vector expected(numBins, 0); - double sum = 0; - for (int i = 0; i < numBins; i++) { - double dist = (i+0.5)*maxDist/numBins; - expected[i] = dist*dist*exp(-5.0*(dist-2)*(dist-2)/kT); - sum += expected[i]; - } - for (int i = 0; i < numBins; i++) - ASSERT_USUALLY_EQUAL_TOL((double) counts[i]/numIterations, expected[i]/sum, 0.01); -} - -/** - * Test the ComputeSum operation. - */ -void testSum() { - const int numParticles = 200; - const double boxSize = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nb = new NonbondedForce(); - system.addForce(nb); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(i%10 == 0 ? 0.0 : 1.5); - nb->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.1, 1); - bool close = true; - while (close) { - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - close = false; - for (int j = 0; j < i; ++j) { - Vec3 delta = positions[i]-positions[j]; - if (delta.dot(delta) < 1) - close = true; - } - } - } - CustomIntegrator integrator(0.005); - integrator.addGlobalVariable("ke", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputeSum("ke", "m*v*v/2"); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the sum is being computed correctly. - - for (int i = 0; i < 100; ++i) { - State state = context.getState(State::Energy); - ASSERT_EQUAL_TOL(state.getKineticEnergy(), integrator.getGlobalVariable(0), 1e-5); - integrator.step(1); - } -} - -/** - * Test an integrator that both uses and modifies a context parameter. - */ -void testParameter() { - System system; - system.addParticle(1.0); - AndersenThermostat* thermostat = new AndersenThermostat(0.1, 0.1); - system.addForce(thermostat); - CustomIntegrator integrator(0.1); - integrator.addGlobalVariable("temp", 0); - integrator.addComputeGlobal("temp", "AndersenTemperature"); - integrator.addComputeGlobal("AndersenTemperature", "temp*2"); - integrator.setRandomNumberSeed(thermostat->getRandomNumberSeed()); - Context context(system, integrator, platform); - - // See if the parameter is being used correctly. - - for (int i = 0; i < 10; i++) { - integrator.step(1); - ASSERT_EQUAL_TOL(context.getParameter("AndersenTemperature"), 0.1*(1<<(i+1)), 1e-5); - } -} - -/** - * Test random number distributions. - */ -void testRandomDistributions() { - const int numParticles = 100; - const int numBins = 20; - const int numSteps = 100; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - integrator.addPerDofVariable("a", 0); - integrator.addPerDofVariable("b", 0); - integrator.addComputePerDof("a", "uniform"); - integrator.addComputePerDof("b", "gaussian"); - Context context(system, integrator, platform); - - // See if the random numbers are distributed correctly. - - vector bins(numBins); - double mean = 0.0; - double var = 0.0; - double skew = 0.0; - double kurtosis = 0.0; - vector values; - for (int i = 0; i < numSteps; i++) { - integrator.step(1); - integrator.getPerDofVariable(0, values); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < 3; j++) { - double v = values[i][j]; - ASSERT(v >= 0 && v < 1); - bins[(int) (v*numBins)]++; - } - integrator.getPerDofVariable(1, values); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < 3; j++) { - double v = values[i][j]; - mean += v; - var += v*v; - skew += v*v*v; - kurtosis += v*v*v*v; - } - } - - // Check the distribution of uniform randoms. - - int numValues = numParticles*numSteps*3; - double expected = numValues/(double) numBins; - double tol = 4*sqrt(expected); - for (int i = 0; i < numBins; i++) - ASSERT(bins[i] >= expected-tol && bins[i] <= expected+tol); - - // Check the distribution of gaussian randoms. - - mean /= numValues; - var /= numValues; - skew /= numValues; - kurtosis /= numValues; - double c2 = var-mean*mean; - double c3 = skew-3*var*mean+2*mean*mean*mean; - double c4 = kurtosis-4*skew*mean-3*var*var+12*var*mean*mean-6*mean*mean*mean*mean; - ASSERT_EQUAL_TOL(0.0, mean, 3.0/sqrt((double) numValues)); - ASSERT_EQUAL_TOL(1.0, c2, 3.0/pow(numValues, 1.0/3.0)); - ASSERT_EQUAL_TOL(0.0, c3, 3.0/pow(numValues, 1.0/4.0)); - ASSERT_EQUAL_TOL(0.0, c4, 3.0/pow(numValues, 1.0/4.0)); -} - -/** - * Test getting and setting per-DOF variables. - */ -void testPerDofVariables() { - const int numParticles = 200; - const double boxSize = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nb = new NonbondedForce(); - system.addForce(nb); - nb->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.5); - nb->addParticle(i%2 == 0 ? 1 : -1, 0.1, 1); - bool close = true; - while (close) { - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - close = false; - for (int j = 0; j < i; ++j) { - Vec3 delta = positions[i]-positions[j]; - if (delta.dot(delta) < 0.1) - close = true; - } - } - } - CustomIntegrator integrator(0.01); - integrator.addPerDofVariable("temp", 0); - integrator.addPerDofVariable("pos", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputePerDof("pos", "x"); - Context context(system, integrator, platform); - context.setPositions(positions); - vector initialValues(numParticles); - for (int i = 0; i < numParticles; i++) - initialValues[i] = Vec3(i+0.1, i+0.2, i+0.3); - integrator.setPerDofVariable(0, initialValues); - - // Run a simulation, then query per-DOF values and see if they are correct. - - vector values; - context.getState(State::Forces); // Cause atom reordering to happen before the first step - for (int i = 0; i < 200; ++i) { - integrator.step(1); - State state = context.getState(State::Positions); - integrator.getPerDofVariable(0, values); - for (int j = 0; j < numParticles; j++) - ASSERT_EQUAL_VEC(initialValues[j], values[j], 1e-5); - integrator.getPerDofVariable(1, values); - for (int j = 0; j < numParticles; j++) - ASSERT_EQUAL_VEC(state.getPositions()[j], values[j], 1e-5); - } -} - -/** - * Test evaluating force groups separately. - */ -void testForceGroups() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - CustomIntegrator integrator(0.01); - integrator.addPerDofVariable("outf", 0); - integrator.addPerDofVariable("outf1", 0); - integrator.addPerDofVariable("outf2", 0); - integrator.addGlobalVariable("oute", 0); - integrator.addGlobalVariable("oute1", 0); - integrator.addGlobalVariable("oute2", 0); - integrator.addComputePerDof("outf", "f"); - integrator.addComputePerDof("outf1", "f1"); - integrator.addComputePerDof("outf2", "f2"); - integrator.addComputeGlobal("oute", "energy"); - integrator.addComputeGlobal("oute1", "energy1"); - integrator.addComputeGlobal("oute2", "energy2"); - HarmonicBondForce* bonds = new HarmonicBondForce(); - bonds->addBond(0, 1, 1.5, 1.1); - bonds->setForceGroup(1); - system.addForce(bonds); - NonbondedForce* nb = new NonbondedForce(); - nb->addParticle(0.2, 1, 0); - nb->addParticle(0.2, 1, 0); - nb->setForceGroup(2); - system.addForce(nb); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // See if the various forces are computed correctly. - - integrator.step(1); - vector f, f1, f2; - double e1 = 0.5*1.1*0.5*0.5; - double e2 = 138.935456*0.2*0.2/2.0; - integrator.getPerDofVariable(0, f); - integrator.getPerDofVariable(1, f1); - integrator.getPerDofVariable(2, f2); - ASSERT_EQUAL_VEC(Vec3(1.1*0.5, 0, 0), f1[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(-1.1*0.5, 0, 0), f1[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(-138.935456*0.2*0.2/4.0, 0, 0), f2[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(138.935456*0.2*0.2/4.0, 0, 0), f2[1], 1e-5); - ASSERT_EQUAL_VEC(f1[0]+f2[0], f[0], 1e-5); - ASSERT_EQUAL_VEC(f1[1]+f2[1], f[1], 1e-5); - ASSERT_EQUAL_TOL(e1, integrator.getGlobalVariable(1), 1e-5); - ASSERT_EQUAL_TOL(e2, integrator.getGlobalVariable(2), 1e-5); - ASSERT_EQUAL_TOL(e1+e2, integrator.getGlobalVariable(0), 1e-5); - - // Make sure they also match the values returned by the Context. - - State s = context.getState(State::Forces | State::Energy, false); - State s1 = context.getState(State::Forces | State::Energy, false, 2); - State s2 = context.getState(State::Forces | State::Energy, false, 4); - vector c, c1, c2; - c = context.getState(State::Forces, false).getForces(); - c1 = context.getState(State::Forces, false, 2).getForces(); - c2 = context.getState(State::Forces, false, 4).getForces(); - ASSERT_EQUAL_VEC(f[0], c[0], 1e-5); - ASSERT_EQUAL_VEC(f[1], c[1], 1e-5); - ASSERT_EQUAL_VEC(f1[0], c1[0], 1e-5); - ASSERT_EQUAL_VEC(f1[1], c1[1], 1e-5); - ASSERT_EQUAL_VEC(f2[0], c2[0], 1e-5); - ASSERT_EQUAL_VEC(f2[1], c2[1], 1e-5); - ASSERT_EQUAL_TOL(s.getPotentialEnergy(), integrator.getGlobalVariable(0), 1e-5); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), integrator.getGlobalVariable(1), 1e-5); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), integrator.getGlobalVariable(2), 1e-5); -} - -/** - * Test a multiple time step r-RESPA integrator. - */ -void testRespa() { - const int numParticles = 8; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - CustomIntegrator integrator(0.002); - integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); - for (int i = 0; i < 2; i++) { - integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); - integrator.addComputePerDof("x", "x+(dt/2)*v"); - integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); - } - integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); - HarmonicBondForce* bonds = new HarmonicBondForce(); - for (int i = 0; i < numParticles-2; i++) - bonds->addBond(i, i+1, 1.0, 0.5); - system.addForce(bonds); - NonbondedForce* nb = new NonbondedForce(); - nb->setCutoffDistance(2.0); - nb->setNonbondedMethod(NonbondedForce::Ewald); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - nb->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - nb->setForceGroup(1); - nb->setReciprocalSpaceForceGroup(0); - system.addForce(nb); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 monitor energy conservations. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Energy); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); - integrator.step(2); - } -} +#include "CudaTests.h" +#include "TestCustomIntegrator.h" /** * Make sure random numbers are computed correctly when steps get merged. @@ -756,117 +98,6 @@ void testMergedRandoms() { } } -void testIfBlock() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addGlobalVariable("a", 0); - integrator.addGlobalVariable("b", 0); - integrator.addComputeGlobal("b", "1"); - integrator.beginIfBlock("a < 3.5"); - integrator.addComputeGlobal("b", "a+1"); - integrator.endBlock(); - Context context(system, integrator, platform); - - // Set "a" to 1.7 and verify that "b" gets set to a+1. - - integrator.setGlobalVariable(0, 1.7); - integrator.step(1); - ASSERT_EQUAL_TOL(2.7, integrator.getGlobalVariable(1), 1e-6); - - // Now set it to a value that should cause the block to be skipped. - - integrator.setGlobalVariable(0, 4.1); - integrator.step(1); - ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); -} - -void testWhileBlock() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addGlobalVariable("a", 0); - integrator.addGlobalVariable("b", 0); - integrator.addComputeGlobal("b", "1"); - integrator.beginWhileBlock("b <= a"); - integrator.addComputeGlobal("b", "b+1"); - integrator.endBlock(); - Context context(system, integrator, platform); - - // Try a case where the loop should be skipped. - - integrator.setGlobalVariable(0, -3.3); - integrator.step(1); - ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); - - // In this case it should be executed exactly once. - - integrator.setGlobalVariable(0, 1.2); - integrator.step(1); - ASSERT_EQUAL_TOL(2.0, integrator.getGlobalVariable(1), 1e-6); - - // In this case, it should be executed several times. - - integrator.setGlobalVariable(0, 5.3); - integrator.step(1); - ASSERT_EQUAL_TOL(6.0, integrator.getGlobalVariable(1), 1e-6); -} - -/** - * Test modifying a global variable, then using it in a per-DOF computation. - */ -void testChangingGlobal() { - System system; - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - integrator.addGlobalVariable("g", 0); - integrator.addPerDofVariable("a", 0); - integrator.addPerDofVariable("b", 0); - integrator.addComputeGlobal("g", "g+1"); - integrator.addComputePerDof("a", "0.5"); - integrator.addComputePerDof("b", "a+g"); - Context context(system, integrator, platform); - - // See if everything is being calculated correctly.. - - for (int i = 0; i < 10; i++) { - integrator.step(1); - ASSERT_EQUAL_TOL(i+1.0, integrator.getGlobalVariable(0), 1e-5); - vector values; - integrator.getPerDofVariable(1, values); - ASSERT_EQUAL_VEC(Vec3(i+1.5, i+1.5, i+1.5), values[0], 1e-5); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleBond(); - testConstraints(); - testVelocityConstraints(); - testConstrainedMasslessParticles(); - testWithThermostat(); - testMonteCarlo(); - testSum(); - testParameter(); - testRandomDistributions(); - testPerDofVariables(); - testForceGroups(); - testRespa(); - testMergedRandoms(); - testIfBlock(); - testWhileBlock(); - testChangingGlobal(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testMergedRandoms(); } diff --git a/platforms/cuda/tests/TestCudaCustomManyParticleForce.cpp b/platforms/cuda/tests/TestCudaCustomManyParticleForce.cpp index 95c7a17ee..76a657b00 100644 --- a/platforms/cuda/tests/TestCudaCustomManyParticleForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomManyParticleForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,705 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of CustomManyParticleForce. - */ +#include "CudaTests.h" +#include "TestCustomManyParticleForce.h" -#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/CustomCompoundBondForce.h" -#include "openmm/CustomManyParticleForce.h" -#include "openmm/System.h" -#include "openmm/TabulatedFunction.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -Vec3 computeDelta(const Vec3& pos1, const Vec3& pos2, bool periodic, const Vec3* periodicBoxVectors) { - Vec3 diff = pos1-pos2; - if (periodic) { - diff -= periodicBoxVectors[2]*floor(diff[2]/periodicBoxVectors[2][2]+0.5); - diff -= periodicBoxVectors[1]*floor(diff[1]/periodicBoxVectors[1][1]+0.5); - diff -= periodicBoxVectors[0]*floor(diff[0]/periodicBoxVectors[0][0]+0.5); - } - return diff; -} - -void validateAxilrodTeller(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize, bool triclinic) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - Vec3 boxVectors[3]; - if (triclinic) { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0.2*boxSize, boxSize, 0); - boxVectors[2] = Vec3(-0.3*boxSize, -0.1*boxSize, boxSize); - } - else { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0, boxSize, 0); - boxVectors[2] = Vec3(0, 0, boxSize); - } - system.setDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double c = context.getParameter("C"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - bool periodic = (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic); - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = computeDelta(positions[p2], positions[p1], periodic, boxVectors); - Vec3 d13 = computeDelta(positions[p3], positions[p1], periodic, boxVectors); - Vec3 d23 = computeDelta(positions[p3], positions[p2], periodic, boxVectors); - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - double rprod = r12*r13*r23; - expectedEnergy += c*(1+3*ctheta1*ctheta2*ctheta3)/(rprod*rprod*rprod); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void validateStillingerWeber(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double L = context.getParameter("L"); - double eps = context.getParameter("eps"); - double a = context.getParameter("a"); - double gamma = context.getParameter("gamma"); - double sigma = context.getParameter("sigma"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - Vec3 d23 = positions[p3]-positions[p2]; - if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) { - for (int j = 0; j < 3; j++) { - d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize; - d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize; - d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize; - } - } - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - expectedEnergy += L*eps*(ctheta1+1.0/3.0)*(ctheta1+1.0/3.0)*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma)); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void testNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - int sets[4][3] = {{0,1,2}, {1,2,3}, {2,3,0}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(1.55); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - int sets[7][3] = {{0,1,2}, {0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,2,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[7]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testPeriodic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[5][3] = {{0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, false); -} - -void testTriclinic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[4][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, true); -} - -void testExclusions() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - force->addExclusion(0, 2); - force->addExclusion(0, 3); - int sets[5][3] = {{0,1,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testAllTerms() { - int numParticles = 4; - - // Create a system with a CustomManyParticleForce. - - System system1; - CustomManyParticleForce* force1 = new CustomManyParticleForce(4, - "distance(p1,p2)+angle(p1,p4,p3)+dihedral(p1,p3,p2,p4)+x1+y4+z3"); - system1.addForce(force1); - vector params; - for (int i = 0; i < numParticles; i++) { - system1.addParticle(1.0); - force1->addParticle(params, i); - } - set filter; - filter.insert(0); - force1->setTypeFilter(0, filter); - filter.clear(); - filter.insert(1); - force1->setTypeFilter(1, filter); - filter.clear(); - filter.insert(3); - force1->setTypeFilter(2, filter); - filter.clear(); - filter.insert(2); - force1->setTypeFilter(3, filter); - - // Create a system that use a CustomCompoundBondForce to compute exactly the same interactions. - - System system2; - CustomCompoundBondForce* force2 = new CustomCompoundBondForce(4, - "distance(p1,p2)+angle(p1,p3,p4)+dihedral(p1,p4,p2,p3)+x1+y3+z4"); - system2.addForce(force2); - vector particles; - particles.push_back(0); - particles.push_back(1); - particles.push_back(2); - particles.push_back(3); - force2->addBond(particles, params); - for (int i = 0; i < numParticles; i++) - system2.addParticle(1.0); - - // Create contexts for both of them. - - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system1, integrator1, platform); - Context context2(system2, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - - // See if they produce identical forces and energies. - - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state2.getForces()[i], state1.getForces()[i], 1e-4); -} - -void testParameters() { - // Create a system. - - int numParticles = 5; - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "C*scale1*scale2*scale3*(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))"); - force->addGlobalParameter("C", 2.0); - force->addPerParticleParameter("scale"); - vector params(1); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - params[0] = i+1; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 2.0*(i+1)*(j+1)*(k+1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); - - // Modify the parameters. - - context.setParameter("C", 3.5); - for (int i = 0; i < numParticles; i++) { - params[0] = 0.5*i-0.1; - force->setParticleParameters(i, params, 0); - } - force->updateParametersInContext(context); - - // See if the energy is still correct. - - state = context.getState(State::Energy); - expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 3.5*(0.5*i-0.1)*(0.5*j-0.1)*(0.5*k-0.1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTabulatedFunctions() { - int numParticles = 5; - - // Create two tabulated functions. - - vector values; - values.push_back(0.0); - values.push_back(50.0); - Continuous1DFunction* f1 = new Continuous1DFunction(values, 0, 100); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector c(numParticles); - for (int i = 0; i < numParticles; i++) - c[i] = genrand_real2(sfmt); - values.resize(numParticles*numParticles*numParticles); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < numParticles; j++) - for (int k = 0; k < numParticles; k++) - values[i+numParticles*j+numParticles*numParticles*k] = c[i]+c[j]+c[k]; - Discrete3DFunction* f2 = new Discrete3DFunction(numParticles, numParticles, numParticles, values); - - // Create a system. - - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "f1(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))*f2(atom1, atom2, atom3)"); - force->addPerParticleParameter("atom"); - force->addTabulatedFunction("f1", f1); - force->addTabulatedFunction("f2", f2); - vector params(1); - vector positions; - for (int i = 0; i < numParticles; i++) { - params[0] = i; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 0.5*(r12+r13+r23)*(c[i]+c[j]+c[k]); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTypeFilters() { - // Create a system. - - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CustomManyParticleForce* force = new CustomManyParticleForce(3, "c1*(distance(p1,p2)+distance(p1,p3))"); - force->addPerParticleParameter("c"); - double c[] = {1.0, 2.0, 1.3, 1.5, -2.1}; - int type[] = {0, 1, 0, 1, 5}; - vector params(1); - for (int i = 0; i < 5; i++) { - params[0] = c[i]; - force->addParticle(params, type[i]); - } - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - set f1, f2; - f1.insert(0); - f2.insert(1); - f2.insert(5); - force->setTypeFilter(0, f1); - force->setTypeFilter(1, f2); - force->setTypeFilter(2, f2); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - int sets[6][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {2,1,3}, {2,1,4}, {2,3,4}}; - for (int i = 0; i < 6; i++) { - int p1 = sets[i][0]; - int p2 = sets[i][1]; - int p3 = sets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - expectedEnergy += c[p1]*(r12+r13); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testLargeSystem() { - int gridSize = 8; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = 3.0; - double spacing = boxSize/gridSize; - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(0.6); - vector params; - vector positions; - System system; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - force->addParticle(params); - positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system, integrator1, Platform::getPlatformByName("Reference")); - Context context2(system, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); -} - -void testCentralParticleModeNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[12][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {2,0,3}, {2, 1, 3}, {3,0,1}, {3,0,2}, {3,1,2}}; - vector expectedSets(&sets[0], &sets[12]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(0.155); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[8][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[8]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeLargeSystem() { - int gridSize = 8; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = 2.0; - double spacing = boxSize/gridSize; - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.8*0.23925); - vector params; - vector positions; - System system; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - force->addParticle(params); - positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system, integrator1, Platform::getPlatformByName("Reference")); - Context context2(system, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testNoCutoff(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testExclusions(); - testAllTerms(); - testParameters(); - testTabulatedFunctions(); - testTypeFilters(); - testLargeSystem(); - testCentralParticleModeNoCutoff(); - testCentralParticleModeCutoff(); - testCentralParticleModeLargeSystem(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCustomNonbondedForce.cpp b/platforms/cuda/tests/TestCudaCustomNonbondedForce.cpp index 2f11c1410..57165f63b 100644 --- a/platforms/cuda/tests/TestCudaCustomNonbondedForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomNonbondedForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -30,608 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the CUDA implementation of CustomNonbondedForce. - */ - -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#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 -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testSimpleExpression() { - 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()); - forceField->addParticle(vector()); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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 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 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 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); - - // Try changing the global parameters and make sure it's still correct. - - 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); - - // Try changing the per-particle parameters and make sure it's still correct. - - params[0] = 1.6; - params[1] = 2.1; - forceField->setParticleParameters(0, params); - params[0] = 1.9; - params[1] = 2.8; - forceField->setParticleParameters(1, params); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - forces = state.getForces(); - force = -1.5*1.6*1.9*3*5.9*(11.8*11.8); - 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*1.6*1.9*(11.8*11.8*11.8), state.getPotentialEnergy(), TOL); -} - -void testManyParameters() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("(a1*a2+b1*b2+c1*c2+d1*d2+e1*e2)*r"); - forceField->addPerParticleParameter("a"); - forceField->addPerParticleParameter("b"); - forceField->addPerParticleParameter("c"); - forceField->addPerParticleParameter("d"); - forceField->addPerParticleParameter("e"); - vector params(5); - params[0] = 1.0; - params[1] = 2.0; - params[2] = 3.0; - params[3] = 4.0; - params[4] = 5.0; - forceField->addParticle(params); - params[0] = 1.1; - params[1] = 1.2; - params[2] = 1.3; - params[3] = 1.4; - params[4] = 1.5; - forceField->addParticle(params); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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); - vector forces = state.getForces(); - double force = 1*1.1 + 2*1.2 + 3*1.3 + 4*1.4 + 5*1.5; - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(2*force, state.getPotentialEnergy(), TOL); -} - -void testExclusions() { - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("a*r; a=a1+a2"); - nonbonded->addPerParticleParameter("a"); - vector params(1); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - forceField->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - forceField->setCutoffDistance(2.5); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - 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 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& 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 testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("r"); - nonbonded->addParticle(vector()); - nonbonded->addParticle(vector()); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta/sqrt(delta.dot(delta)); - ASSERT_EQUAL_TOL(distance, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); - } - } -} - -void testContinuous1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& forces = state.getForces(); - double force = (x < 1.0 || x > 6.0 ? 0.0 : -cos(x-1.0)); - double energy = (x < 1.0 || x > 6.0 ? 0.0 : 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 : sin(x-1.0))+1.0; - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - } -} - -void testContinuous2DFunction() { - const int xsize = 20; - const int ysize = 21; - const double xmin = 0.4; - const double xmax = 1.5; - const double ymin = 0.0; - const double ymax = 2.1; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y); - } - 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); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - const double zmin = 0.2; - const double zmax = 1.3; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setParameter("b", z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - } - 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.05); - } - } - } -} - -void testDiscrete1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Discrete1DFunction(table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i+1, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete2DFunction() { - const int xsize = 10; - const int ysize = 5; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - table.push_back(sin(0.25*i)+cos(0.33*j)); - forceField->addTabulatedFunction("fn", new Discrete2DFunction(xsize, ysize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3((i%xsize)+1, 0, 0); - context.setPositions(positions); - context.setParameter("a", i/xsize); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete3DFunction() { - const int xsize = 8; - const int ysize = 5; - const int zsize = 6; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - for (int k = 0; k < zsize; k++) - table.push_back(sin(0.25*i)+cos(0.33*j)+0.12345*k); - forceField->addTabulatedFunction("fn", new Discrete3DFunction(xsize, ysize, zsize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3((i%xsize)+1, 0, 0); - context.setPositions(positions); - context.setParameter("a", (i/xsize)%ysize); - context.setParameter("b", i/(xsize*ysize)); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testCoulombLennardJones() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // 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 positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector 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); - Context context1(standardSystem, integrator1, platform); - Context context2(customSystem, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - context1.setVelocities(velocities); - context2.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} +#include "CudaTests.h" +#include "TestCustomNonbondedForce.h" void testParallelComputation() { System system; @@ -670,396 +69,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testSwitchingFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("10/r^2"); - vector params; - nonbonded->addParticle(params); - nonbonded->addParticle(params); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double expectedEnergy = 10/(r*r); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - -void testLongRangeCorrection() { - // Create a box of particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System standardSystem; - System customSystem; - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - NonbondedForce* standardNonbonded = new NonbondedForce(); - CustomNonbondedForce* customNonbonded = new CustomNonbondedForce("4*eps*((sigma/r)^12-(sigma/r)^6); sigma=0.5*(sigma1+sigma2); eps=sqrt(eps1*eps2)"); - customNonbonded->addPerParticleParameter("sigma"); - customNonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - int index = 0; - vector params1(2); - params1[0] = 1.1; - params1[1] = 0.5; - vector params2(2); - params2[0] = 1; - params2[1] = 1; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - if (index%2 == 0) { - standardNonbonded->addParticle(0, params1[0], params1[1]); - customNonbonded->addParticle(params1); - } - else { - standardNonbonded->addParticle(0, params2[0], params2[1]); - customNonbonded->addParticle(params2); - } - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - standardNonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - customNonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - standardNonbonded->setCutoffDistance(cutoff); - customNonbonded->setCutoffDistance(cutoff); - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - standardNonbonded->setUseDispersionCorrection(true); - customNonbonded->setUseLongRangeCorrection(true); - standardNonbonded->setUseSwitchingFunction(true); - customNonbonded->setUseSwitchingFunction(true); - standardNonbonded->setSwitchingDistance(0.8*cutoff); - customNonbonded->setSwitchingDistance(0.8*cutoff); - standardSystem.addForce(standardNonbonded); - customSystem.addForce(customNonbonded); - - // Compute the correction for the standard force. - - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - double standardEnergy1 = context1.getState(State::Energy).getPotentialEnergy(); - standardNonbonded->setUseDispersionCorrection(false); - context1.reinitialize(); - context1.setPositions(positions); - double standardEnergy2 = context1.getState(State::Energy).getPotentialEnergy(); - - // Compute the correction for the custom force. - - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - double customEnergy1 = context2.getState(State::Energy).getPotentialEnergy(); - customNonbonded->setUseLongRangeCorrection(false); - context2.reinitialize(); - context2.setPositions(positions); - double customEnergy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // See if they agree. - - ASSERT_EQUAL_TOL(standardEnergy1-standardEnergy2, customEnergy1-customEnergy2, 1e-4); -} - -void testInteractionGroups() { - const int numParticles = 6; - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("v1+v2"); - nonbonded->addPerParticleParameter("v"); - vector params(1, 0.001); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(params); - params[0] *= 10; - } - set set1, set2, set3, set4; - set1.insert(2); - set2.insert(0); - set2.insert(1); - set2.insert(2); - set2.insert(3); - set2.insert(4); - set2.insert(5); - nonbonded->addInteractionGroup(set1, set2); // Particle 2 interacts with every other particle. - set3.insert(0); - set3.insert(1); - set4.insert(4); - set4.insert(5); - nonbonded->addInteractionGroup(set3, set4); // Particles 0 and 1 interact with 4 and 5. - nonbonded->addExclusion(1, 2); // Add an exclusion to make sure it gets skipped. - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - context.setPositions(positions); - State state = context.getState(State::Energy); - double expectedEnergy = 331.423; // Each digit is the number of interactions a particle particle is involved in. - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), TOL); -} - -void testLargeInteractionGroup() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // Create a large system. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomNonbondedForce* nonbonded = 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)"); - nonbonded->addPerParticleParameter("q"); - nonbonded->addPerParticleParameter("sigma"); - nonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.1; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.2; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->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]); - nonbonded->addExclusion(2*i, 2*i+1); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Compute the forces. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces); - - // Modify the force so only one particle interacts with everything else. - - set set1, set2; - set1.insert(151); - for (int i = 0; i < numParticles; i++) - set2.insert(i); - nonbonded->addInteractionGroup(set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state2 = context.getState(State::Forces); - - // The force on that one particle should be the same. - - ASSERT_EQUAL_VEC(state1.getForces()[151], state2.getForces()[151], 1e-4); - - // Modify the interaction group so it includes all interactions. This should now reproduce the original forces - // on all atoms. - - for (int i = 0; i < numParticles; i++) - set1.insert(i); - nonbonded->setInteractionGroupParameters(0, set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state3 = context.getState(State::Forces); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state3.getForces()[i], 1e-4); -} - -void testInteractionGroupLongRangeCorrection() { - const int numParticles = 10; - const double boxSize = 10.0; - const double cutoff = 0.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("c1*c2*r^-4"); - nonbonded->addPerParticleParameter("c"); - vector positions(numParticles); - vector params(1); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - params[0] = (i%2 == 0 ? 1.1 : 2.0); - nonbonded->addParticle(params); - positions[i] = Vec3(0.5*i, 0, 0); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - - // Setup nonbonded groups. They involve 1 interaction of type AA, - // 2 of type BB, and 5 of type AB. - - set set1, set2, set3, set4, set5; - set1.insert(0); - set1.insert(1); - set1.insert(2); - nonbonded->addInteractionGroup(set1, set1); - set2.insert(3); - set3.insert(4); - set3.insert(6); - set3.insert(8); - nonbonded->addInteractionGroup(set2, set3); - set4.insert(5); - set5.insert(7); - set5.insert(9); - nonbonded->addInteractionGroup(set4, set5); - - // Compute energy with and without the correction. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseLongRangeCorrection(true); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - - // Check the result. - - double sum = (1.1*1.1 + 2*2.0*2.0 + 5*1.1*2.0)*2.0; - int numPairs = (numParticles*(numParticles+1))/2; - double expected = 2*M_PI*numParticles*numParticles*sum/(numPairs*boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy2-energy1, 1e-4); -} - -void testMultipleCutoffs() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - - // Add multiple nonbonded forces that have different cutoffs. - - CustomNonbondedForce* nonbonded1 = new CustomNonbondedForce("2*r"); - nonbonded1->addParticle(vector()); - nonbonded1->addParticle(vector()); - nonbonded1->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded1->setCutoffDistance(2.5); - system.addForce(nonbonded1); - CustomNonbondedForce* nonbonded2 = new CustomNonbondedForce("3*r"); - nonbonded2->addParticle(vector()); - nonbonded2->addParticle(vector()); - nonbonded2->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded2->setCutoffDistance(2.9); - nonbonded2->setForceGroup(1); - system.addForce(nonbonded2); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 0, 0); - for (double r = 2.4; r < 3.2; r += 0.2) { - positions[1][1] = r; - context.setPositions(positions); - double e1 = (r < 2.5 ? 2.0*r : 0.0); - double e2 = (r < 2.9 ? 3.0*r : 0.0); - double f1 = (r < 2.5 ? 2.0 : 0.0); - double f2 = (r < 2.9 ? 3.0 : 0.0); - - // Check the first force. - - State state = context.getState(State::Forces | State::Energy, false, 1); - ASSERT_EQUAL_VEC(Vec3(0, f1, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1, state.getPotentialEnergy(), TOL); - - // Check the second force. - - state = context.getState(State::Forces | State::Energy, false, 2); - ASSERT_EQUAL_VEC(Vec3(0, f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e2, state.getPotentialEnergy(), TOL); - - // Check the sum of both forces. - - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_VEC(Vec3(0, f1+f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1-f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1+e2, state.getPotentialEnergy(), TOL); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSimpleExpression(); - testParameters(); - testManyParameters(); - testExclusions(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testContinuous1DFunction(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testDiscrete1DFunction(); - testDiscrete2DFunction(); - testDiscrete3DFunction(); - testCoulombLennardJones(); - testParallelComputation(); - testSwitchingFunction(); - testLongRangeCorrection(); - testInteractionGroups(); - testLargeInteractionGroup(); - testInteractionGroupLongRangeCorrection(); - testMultipleCutoffs(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaCustomTorsionForce.cpp b/platforms/cuda/tests/TestCudaCustomTorsionForce.cpp index b6f17d69b..3693a80df 100644 --- a/platforms/cuda/tests/TestCudaCustomTorsionForce.cpp +++ b/platforms/cuda/tests/TestCudaCustomTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,146 +29,8 @@ * 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 -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testTorsions() { - // 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 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(harmonicSystem, integrator2, platform); - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 2; - custom->setTorsionParameters(0, 0, 1, 2, 3, parameters); - parameters[0] = 2.1; - parameters[1] = 3; - custom->setTorsionParameters(1, 1, 2, 3, 4, parameters); - custom->updateParametersInContext(c1); - periodic->setTorsionParameters(0, 0, 1, 2, 3, 2, 1.6, 0.5); - periodic->setTorsionParameters(1, 1, 2, 3, 4, 3, 2.1, 0.5); - periodic->updateParametersInContext(c2); - { - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} - -void testRange() { - 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()); - 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 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); -} +#include "CudaTests.h" +#include "TestCustomTorsionForce.h" void testParallelComputation() { System system; @@ -199,18 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testTorsions(); - testRange(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/cuda/tests/TestCudaRBTorsionForce.cpp b/platforms/cuda/tests/TestCudaRBTorsionForce.cpp index 4e9de86c6..aa0cfd5a3 100644 --- a/platforms/cuda/tests/TestCudaRBTorsionForce.cpp +++ b/platforms/cuda/tests/TestCudaRBTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * diff --git a/platforms/opencl/tests/TestOpenCLAndersenThermostat.cpp b/platforms/opencl/tests/TestOpenCLAndersenThermostat.cpp index aefa83098..33ba5dafe 100644 --- a/platforms/opencl/tests/TestOpenCLAndersenThermostat.cpp +++ b/platforms/opencl/tests/TestOpenCLAndersenThermostat.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,192 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of AndersenThermostat. - */ +#include "OpenCLTests.h" +#include "TestAndersenThermostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -void testTemperature() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 5000; - System system; - VerletIntegrator integrator(0.003); - 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 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); - context.setVelocitiesToTemperature(temp); - - // 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(10); - } - ke /= numSteps; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 15000; - System system; - VerletIntegrator integrator(0.004); - 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 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); - context.setVelocitiesToTemperature(temp); - - // Let it equilibrate. - - integrator.step(5000); - - // 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_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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]); - } - } +void runPlatformTests() { } - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testTemperature(); - testConstraints(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/opencl/tests/TestOpenCLBrownianIntegrator.cpp b/platforms/opencl/tests/TestOpenCLBrownianIntegrator.cpp index 75d6043ce..adf6ca352 100644 --- a/platforms/opencl/tests/TestOpenCLBrownianIntegrator.cpp +++ b/platforms/opencl/tests/TestOpenCLBrownianIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,253 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -#include "openmm/System.h" +#include "OpenCLTests.h" +#include "TestBrownianIntegrator.h" - -/** - * This tests the OpenCL implementation of BrownianIntegrator. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/BrownianIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - 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 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; - 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 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; - 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 positions(numParticles); - vector 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 testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - BrownianIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } - diff --git a/platforms/opencl/tests/TestOpenCLCMAPTorsionForce.cpp b/platforms/opencl/tests/TestOpenCLCMAPTorsionForce.cpp index 10deec857..d519c6c1a 100644 --- a/platforms/opencl/tests/TestOpenCLCMAPTorsionForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCMAPTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2010-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,150 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CMAPTorsionForce. - */ +#include "OpenCLTests.h" +#include "TestCMAPTorsionForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CMAPTorsionForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -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. - - 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 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(system1, integrator1, platform); - Context c2(system2, integrator2, platform); - for (int i = 0; i < 50; 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < system1.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 0.05); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), 1e-3); - } -} - -void testChangingParameters() { - // Create a system with two maps and one torsion. - - const int mapSize = 8; - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CMAPTorsionForce* cmap = new CMAPTorsionForce(); - vector mapEnergy1(mapSize*mapSize); - vector mapEnergy2(mapSize*mapSize); - for (int i = 0; i < mapSize; i++) { - double angle1 = i*2*M_PI/mapSize; - double energy1 = cos(angle1); - for (int j = 0; j < mapSize; j++) { - double angle2 = j*2*M_PI/mapSize; - double energy2 = 10*sin(angle2); - mapEnergy1[i+j*mapSize] = energy1+energy2; - mapEnergy2[i+j*mapSize] = energy1-energy2; - } - } - cmap->addMap(mapSize, mapEnergy1); - cmap->addMap(mapSize, mapEnergy2); - cmap->addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4); - system.addForce(cmap); - - // Set particle positions so angle1=0 and angle2=PI/4. - - vector positions(5); - positions[0] = Vec3(0, 0, 1); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 1); - positions[4] = Vec3(0.5, -0.5, 1); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Check that the energy is correct. - - double energy = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(1+10*sin(M_PI/4), energy, 1e-5); - - // Modify the parameters. - - cmap->setTorsionParameters(0, 1, 0, 1, 2, 3, 1, 2, 3, 4); - for (int i = 0; i < mapSize*mapSize; i++) - mapEnergy2[i] *= 2.0; - cmap->setMapParameters(1, mapSize, mapEnergy2); - cmap->updateParametersInContext(context); - - // See if the results are correct. - - energy = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(2-20*sin(M_PI/4), energy, 1e-5); +void runPlatformTests() { } - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testCMAPTorsions(); - testChangingParameters(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/opencl/tests/TestOpenCLCMMotionRemover.cpp b/platforms/opencl/tests/TestOpenCLCMMotionRemover.cpp index c0aa145c5..d8d2a1757 100644 --- a/platforms/opencl/tests/TestOpenCLCMMotionRemover.cpp +++ b/platforms/opencl/tests/TestOpenCLCMMotionRemover.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,95 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of AndersenThermostat. - */ +#include "OpenCLTests.h" +#include "TestCMMotionRemover.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/CMMotionRemover.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -Vec3 calcCM(const vector& 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 runPlatformTests() { } - -void testMotionRemoval(Integrator& integrator) { - const int numParticles = 8; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - 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; -} - diff --git a/platforms/opencl/tests/TestOpenCLCustomHbondForce.cpp b/platforms/opencl/tests/TestOpenCLCustomHbondForce.cpp index a990d2394..380fdf2e9 100644 --- a/platforms/opencl/tests/TestOpenCLCustomHbondForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomHbondForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,221 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomHbondForce. - */ +#include "OpenCLTests.h" +#include "TestCustomHbondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomHbondForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testHbond() { - // Create a system using a CustomHbondForce. - - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomHbondForce* custom = new CustomHbondForce("0.5*kr*(distance(d1,a1)-r0)^2 + 0.5*ktheta*(angle(a1,d1,d2)-theta0)^2 + 0.5*kpsi*(angle(d1,a1,a2)-psi0)^2 + kchi*(1+cos(n*dihedral(a3,a2,a1,d1)-chi0))"); - custom->addPerDonorParameter("r0"); - custom->addPerDonorParameter("theta0"); - custom->addPerDonorParameter("psi0"); - custom->addPerAcceptorParameter("chi0"); - custom->addPerAcceptorParameter("n"); - custom->addGlobalParameter("kr", 0.4); - custom->addGlobalParameter("ktheta", 0.5); - custom->addGlobalParameter("kpsi", 0.6); - custom->addGlobalParameter("kchi", 0.7); - vector parameters(3); - parameters[0] = 1.5; - parameters[1] = 1.7; - parameters[2] = 1.9; - custom->addDonor(1, 0, -1, parameters); - parameters.resize(2); - parameters[0] = 2.1; - parameters[1] = 2; - custom->addAcceptor(2, 3, 4, parameters); - custom->setCutoffDistance(10.0); - customSystem.addForce(custom); - - // Create an identical system using HarmonicBondForce, HarmonicAngleForce, and PeriodicTorsionForce. - - System standardSystem; - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - HarmonicBondForce* bond = new HarmonicBondForce(); - bond->addBond(1, 2, 1.5, 0.4); - standardSystem.addForce(bond); - HarmonicAngleForce* angle = new HarmonicAngleForce(); - angle->addAngle(0, 1, 2, 1.7, 0.5); - angle->addAngle(1, 2, 3, 1.9, 0.6); - standardSystem.addForce(angle); - PeriodicTorsionForce* torsion = new PeriodicTorsionForce(); - torsion->addTorsion(1, 2, 3, 4, 2, 2.1, 0.7); - standardSystem.addForce(torsion); - - // 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(standardSystem, integrator2, platform); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < (int) positions.size(); j++) - positions[j] = Vec3(2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); - } - - // Try changing the parameters and make sure it's still correct. - - parameters.resize(3); - parameters[0] = 1.4; - parameters[1] = 1.7; - parameters[2] = 1.9; - custom->setDonorParameters(0, 1, 0, -1, parameters); - parameters.resize(2); - parameters[0] = 2.2; - parameters[1] = 2; - custom->setAcceptorParameters(0, 2, 3, 4, parameters); - bond->setBondParameters(0, 1, 2, 1.4, 0.4); - torsion->setTorsionParameters(0, 1, 2, 3, 4, 2, 2.2, 0.7); - custom->updateParametersInContext(c1); - bond->updateParametersInContext(c2); - torsion->updateParametersInContext(c2); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); +void runPlatformTests() { } - -void testExclusions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); - custom->addDonor(0, 1, -1, vector()); - custom->addDonor(1, 0, -1, vector()); - custom->addAcceptor(2, 0, -1, vector()); - custom->addExclusion(1, 0); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); - custom->addDonor(0, 1, -1, vector()); - custom->addDonor(1, 0, -1, vector()); - custom->addAcceptor(2, 0, -1, vector()); - custom->setNonbondedMethod(CustomHbondForce::CutoffNonPeriodic); - custom->setCutoffDistance(2.5); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 3, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); -} - -void testCustomFunctions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("foo(distance(d1,a1))"); - custom->addDonor(1, 0, -1, vector()); - custom->addDonor(2, 0, -1, vector()); - custom->addAcceptor(0, 1, -1, vector()); - vector function(2); - function[0] = 0; - function[1] = 1; - custom->addTabulatedFunction("foo", new Continuous1DFunction(function, 0, 10)); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0.1, 0.1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -0.1, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-0.1, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(0.1*2+0.1*2, state.getPotentialEnergy(), TOL); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testHbond(); - testExclusions(); - testCutoff(); - testCustomFunctions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/opencl/tests/TestOpenCLCustomIntegrator.cpp b/platforms/opencl/tests/TestOpenCLCustomIntegrator.cpp index 6db85d4e5..4d3381b85 100644 --- a/platforms/opencl/tests/TestOpenCLCustomIntegrator.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomIntegrator.cpp @@ -29,666 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomIntegrator. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/CustomIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -/** - * Test a simple leapfrog integrator on a single bond. - */ -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.setKineticEnergyExpression("m*v1*v1/2; v1=v+0.5*dt*f/m"); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - vector velocities(2); - velocities[0] = Vec3(-0.5*dt*0.5*0.5, 0, 0); - velocities[1] = Vec3(0.5*dt*0.5*0.5, 0, 0); - context.setVelocities(velocities); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*std::cos(freq*time); - ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 1e-4); - double expectedSpeed = -0.5*freq*std::sin(freq*(time-dt/2)); - ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 1e-4); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(0.5*0.5*0.5, energy, 1e-4); - integrator.step(1); - } -} - -/** - * Test an integrator that enforces constraints. - */ -void testConstraints() { - const int numParticles = 8; - System system; - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "(x-oldx)/dt"); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -/** - * Test an integrator that applies constraints directly to velocities. - */ -void testVelocityConstraints() { - const int numParticles = 10; - System system; - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("x1", 0); - integrator.addComputePerDof("v", "v+0.5*dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputePerDof("x1", "x"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "v+0.5*dt*f/m+(x-x1)/dt"); - integrator.addConstrainVelocities(); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - - // Constrain the first three particles with SHAKE. - - system.addConstraint(0, 1, 1.0); - system.addConstraint(1, 2, 1.0); - - // Constrain the next three with SETTLE. - - system.addConstraint(3, 4, 1.0); - system.addConstraint(5, 4, 1.0); - system.addConstraint(3, 5, sqrt(2.0)); - - // Constraint the rest with CCMA. - - for (int i = 6; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - integrator.step(2); - State state = context.getState(State::Positions | State::Velocities | State::Energy); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - if (i > 0) { - Vec3 v1 = state.getVelocities()[particle1]; - Vec3 v2 = state.getVelocities()[particle2]; - double vel = (v1-v2).dot(p1-p2); - ASSERT_EQUAL_TOL(0.0, vel, 2e-5); - } - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 0) - initialEnergy = energy; - else if (i > 0) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "(x-oldx)/dt"); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -/** - * Test an integrator with an AndersenThermostat to see if updateContextState() - * is being handled correctly. - */ -void testWithThermostat() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 5000; - System system; - CustomIntegrator integrator(0.003); - integrator.addUpdateContextState(); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - 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); - integrator.setRandomNumberSeed(thermostat->getRandomNumberSeed()); - Context context(system, integrator, platform); - vector 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); - context.setVelocitiesToTemperature(temp); - - // 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(10); - } - ke /= numSteps; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -/** - * Test a Monte Carlo integrator that uses global variables and depends on energy. - */ -void testMonteCarlo() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - const double kT = BOLTZ*300.0; - integrator.addGlobalVariable("kT", kT); - integrator.addGlobalVariable("oldE", 0); - integrator.addGlobalVariable("accept", 0); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputeGlobal("oldE", "energy"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*gaussian"); - integrator.addComputeGlobal("accept", "step(exp((oldE-energy)/kT)-uniform)"); - integrator.addComputePerDof("x", "select(accept, x, oldx)"); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 2.0, 10.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // Compute the histogram of distances and see if it satisfies a Boltzmann distribution. - - const int numBins = 100; - const double maxDist = 4.0; - const int numIterations = 5000; - vector counts(numBins, 0); - for (int i = 0; i < numIterations; ++i) { - integrator.step(10); - State state = context.getState(State::Positions); - Vec3 delta = state.getPositions()[0]-state.getPositions()[1]; - double dist = sqrt(delta.dot(delta)); - if (dist < maxDist) - counts[(int) (numBins*dist/maxDist)]++; - } - vector expected(numBins, 0); - double sum = 0; - for (int i = 0; i < numBins; i++) { - double dist = (i+0.5)*maxDist/numBins; - expected[i] = dist*dist*exp(-5.0*(dist-2)*(dist-2)/kT); - sum += expected[i]; - } - for (int i = 0; i < numBins; i++) - ASSERT_USUALLY_EQUAL_TOL((double) counts[i]/numIterations, expected[i]/sum, 0.01); -} - -/** - * Test the ComputeSum operation. - */ -void testSum() { - const int numParticles = 200; - const double boxSize = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nb = new NonbondedForce(); - system.addForce(nb); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(i%10 == 0 ? 0.0 : 1.5); - nb->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.1, 1); - bool close = true; - while (close) { - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - close = false; - for (int j = 0; j < i; ++j) { - Vec3 delta = positions[i]-positions[j]; - if (delta.dot(delta) < 1) - close = true; - } - } - } - CustomIntegrator integrator(0.005); - integrator.addGlobalVariable("ke", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputeSum("ke", "m*v*v/2"); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the sum is being computed correctly. - - for (int i = 0; i < 100; ++i) { - State state = context.getState(State::Energy); - ASSERT_EQUAL_TOL(state.getKineticEnergy(), integrator.getGlobalVariable(0), 1e-5); - integrator.step(1); - } -} - -/** - * Test an integrator that both uses and modifies a context parameter. - */ -void testParameter() { - System system; - system.addParticle(1.0); - AndersenThermostat* thermostat = new AndersenThermostat(0.1, 0.1); - system.addForce(thermostat); - CustomIntegrator integrator(0.1); - integrator.addGlobalVariable("temp", 0); - integrator.addComputeGlobal("temp", "AndersenTemperature"); - integrator.addComputeGlobal("AndersenTemperature", "temp*2"); - integrator.setRandomNumberSeed(thermostat->getRandomNumberSeed()); - Context context(system, integrator, platform); - - // See if the parameter is being used correctly. - - for (int i = 0; i < 10; i++) { - integrator.step(1); - ASSERT_EQUAL_TOL(context.getParameter("AndersenTemperature"), 0.1*(1<<(i+1)), 1e-5); - } -} - -/** - * Test random number distributions. - */ -void testRandomDistributions() { - const int numParticles = 100; - const int numBins = 20; - const int numSteps = 100; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - integrator.addPerDofVariable("a", 0); - integrator.addPerDofVariable("b", 0); - integrator.addComputePerDof("a", "uniform"); - integrator.addComputePerDof("b", "gaussian"); - Context context(system, integrator, platform); - - // See if the random numbers are distributed correctly. - - vector bins(numBins); - double mean = 0.0; - double var = 0.0; - double skew = 0.0; - double kurtosis = 0.0; - vector values; - for (int i = 0; i < numSteps; i++) { - integrator.step(1); - integrator.getPerDofVariable(0, values); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < 3; j++) { - double v = values[i][j]; - ASSERT(v >= 0 && v < 1); - bins[(int) (v*numBins)]++; - } - integrator.getPerDofVariable(1, values); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < 3; j++) { - double v = values[i][j]; - mean += v; - var += v*v; - skew += v*v*v; - kurtosis += v*v*v*v; - } - } - - // Check the distribution of uniform randoms. - - int numValues = numParticles*numSteps*3; - double expected = numValues/(double) numBins; - double tol = 4*sqrt(expected); - for (int i = 0; i < numBins; i++) - ASSERT(bins[i] >= expected-tol && bins[i] <= expected+tol); - - // Check the distribution of gaussian randoms. - - mean /= numValues; - var /= numValues; - skew /= numValues; - kurtosis /= numValues; - double c2 = var-mean*mean; - double c3 = skew-3*var*mean+2*mean*mean*mean; - double c4 = kurtosis-4*skew*mean-3*var*var+12*var*mean*mean-6*mean*mean*mean*mean; - ASSERT_EQUAL_TOL(0.0, mean, 3.0/sqrt((double) numValues)); - ASSERT_EQUAL_TOL(1.0, c2, 3.0/pow(numValues, 1.0/3.0)); - ASSERT_EQUAL_TOL(0.0, c3, 3.0/pow(numValues, 1.0/4.0)); - ASSERT_EQUAL_TOL(0.0, c4, 3.0/pow(numValues, 1.0/4.0)); -} - -/** - * Test getting and setting per-DOF variables. - */ -void testPerDofVariables() { - const int numParticles = 200; - const double boxSize = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nb = new NonbondedForce(); - system.addForce(nb); - nb->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.5); - nb->addParticle(i%2 == 0 ? 1 : -1, 0.1, 1); - bool close = true; - while (close) { - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - close = false; - for (int j = 0; j < i; ++j) { - Vec3 delta = positions[i]-positions[j]; - if (delta.dot(delta) < 0.1) - close = true; - } - } - } - CustomIntegrator integrator(0.01); - integrator.addPerDofVariable("temp", 0); - integrator.addPerDofVariable("pos", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputePerDof("pos", "x"); - Context context(system, integrator, platform); - context.setPositions(positions); - vector initialValues(numParticles); - for (int i = 0; i < numParticles; i++) - initialValues[i] = Vec3(i+0.1, i+0.2, i+0.3); - integrator.setPerDofVariable(0, initialValues); - - // Run a simulation, then query per-DOF values and see if they are correct. - - vector values; - context.getState(State::Forces); // Cause atom reordering to happen before the first step - for (int i = 0; i < 200; ++i) { - integrator.step(1); - State state = context.getState(State::Positions); - integrator.getPerDofVariable(0, values); - for (int j = 0; j < numParticles; j++) - ASSERT_EQUAL_VEC(initialValues[j], values[j], 1e-5); - integrator.getPerDofVariable(1, values); - for (int j = 0; j < numParticles; j++) - ASSERT_EQUAL_VEC(state.getPositions()[j], values[j], 1e-5); - } -} - -/** - * Test evaluating force groups separately. - */ -void testForceGroups() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - CustomIntegrator integrator(0.01); - integrator.addPerDofVariable("outf", 0); - integrator.addPerDofVariable("outf1", 0); - integrator.addPerDofVariable("outf2", 0); - integrator.addGlobalVariable("oute", 0); - integrator.addGlobalVariable("oute1", 0); - integrator.addGlobalVariable("oute2", 0); - integrator.addComputePerDof("outf", "f"); - integrator.addComputePerDof("outf1", "f1"); - integrator.addComputePerDof("outf2", "f2"); - integrator.addComputeGlobal("oute", "energy"); - integrator.addComputeGlobal("oute1", "energy1"); - integrator.addComputeGlobal("oute2", "energy2"); - HarmonicBondForce* bonds = new HarmonicBondForce(); - bonds->addBond(0, 1, 1.5, 1.1); - bonds->setForceGroup(1); - system.addForce(bonds); - NonbondedForce* nb = new NonbondedForce(); - nb->addParticle(0.2, 1, 0); - nb->addParticle(0.2, 1, 0); - nb->setForceGroup(2); - system.addForce(nb); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // See if the various forces are computed correctly. - - integrator.step(1); - vector f, f1, f2; - double e1 = 0.5*1.1*0.5*0.5; - double e2 = 138.935456*0.2*0.2/2.0; - integrator.getPerDofVariable(0, f); - integrator.getPerDofVariable(1, f1); - integrator.getPerDofVariable(2, f2); - ASSERT_EQUAL_VEC(Vec3(1.1*0.5, 0, 0), f1[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(-1.1*0.5, 0, 0), f1[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(-138.935456*0.2*0.2/4.0, 0, 0), f2[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(138.935456*0.2*0.2/4.0, 0, 0), f2[1], 1e-5); - ASSERT_EQUAL_VEC(f1[0]+f2[0], f[0], 1e-5); - ASSERT_EQUAL_VEC(f1[1]+f2[1], f[1], 1e-5); - ASSERT_EQUAL_TOL(e1, integrator.getGlobalVariable(1), 1e-5); - ASSERT_EQUAL_TOL(e2, integrator.getGlobalVariable(2), 1e-5); - ASSERT_EQUAL_TOL(e1+e2, integrator.getGlobalVariable(0), 1e-5); - - // Make sure they also match the values returned by the Context. - - State s = context.getState(State::Forces | State::Energy, false); - State s1 = context.getState(State::Forces | State::Energy, false, 2); - State s2 = context.getState(State::Forces | State::Energy, false, 4); - vector c, c1, c2; - c = context.getState(State::Forces, false).getForces(); - c1 = context.getState(State::Forces, false, 2).getForces(); - c2 = context.getState(State::Forces, false, 4).getForces(); - ASSERT_EQUAL_VEC(f[0], c[0], 1e-5); - ASSERT_EQUAL_VEC(f[1], c[1], 1e-5); - ASSERT_EQUAL_VEC(f1[0], c1[0], 1e-5); - ASSERT_EQUAL_VEC(f1[1], c1[1], 1e-5); - ASSERT_EQUAL_VEC(f2[0], c2[0], 1e-5); - ASSERT_EQUAL_VEC(f2[1], c2[1], 1e-5); - ASSERT_EQUAL_TOL(s.getPotentialEnergy(), integrator.getGlobalVariable(0), 1e-5); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), integrator.getGlobalVariable(1), 1e-5); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), integrator.getGlobalVariable(2), 1e-5); -} - -/** - * Test a multiple time step r-RESPA integrator. - */ -void testRespa() { - const int numParticles = 8; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - CustomIntegrator integrator(0.002); - integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); - for (int i = 0; i < 2; i++) { - integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); - integrator.addComputePerDof("x", "x+(dt/2)*v"); - integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); - } - integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); - HarmonicBondForce* bonds = new HarmonicBondForce(); - for (int i = 0; i < numParticles-2; i++) - bonds->addBond(i, i+1, 1.0, 0.5); - system.addForce(bonds); - NonbondedForce* nb = new NonbondedForce(); - nb->setCutoffDistance(2.0); - nb->setNonbondedMethod(NonbondedForce::Ewald); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - nb->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - nb->setForceGroup(1); - nb->setReciprocalSpaceForceGroup(0); - system.addForce(nb); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 monitor energy conservations. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Energy); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); - integrator.step(2); - } -} +#include "OpenCLTests.h" +#include "TestCustomIntegrator.h" /** * Make sure random numbers are computed correctly when steps get merged. @@ -756,117 +98,6 @@ void testMergedRandoms() { } } -void testIfBlock() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addGlobalVariable("a", 0); - integrator.addGlobalVariable("b", 0); - integrator.addComputeGlobal("b", "1"); - integrator.beginIfBlock("a < 3.5"); - integrator.addComputeGlobal("b", "a+1"); - integrator.endBlock(); - Context context(system, integrator, platform); - - // Set "a" to 1.7 and verify that "b" gets set to a+1. - - integrator.setGlobalVariable(0, 1.7); - integrator.step(1); - ASSERT_EQUAL_TOL(2.7, integrator.getGlobalVariable(1), 1e-6); - - // Now set it to a value that should cause the block to be skipped. - - integrator.setGlobalVariable(0, 4.1); - integrator.step(1); - ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); -} - -void testWhileBlock() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addGlobalVariable("a", 0); - integrator.addGlobalVariable("b", 0); - integrator.addComputeGlobal("b", "1"); - integrator.beginWhileBlock("b <= a"); - integrator.addComputeGlobal("b", "b+1"); - integrator.endBlock(); - Context context(system, integrator, platform); - - // Try a case where the loop should be skipped. - - integrator.setGlobalVariable(0, -3.3); - integrator.step(1); - ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); - - // In this case it should be executed exactly once. - - integrator.setGlobalVariable(0, 1.2); - integrator.step(1); - ASSERT_EQUAL_TOL(2.0, integrator.getGlobalVariable(1), 1e-6); - - // In this case, it should be executed several times. - - integrator.setGlobalVariable(0, 5.3); - integrator.step(1); - ASSERT_EQUAL_TOL(6.0, integrator.getGlobalVariable(1), 1e-6); -} - -/** - * Test modifying a global variable, then using it in a per-DOF computation. - */ -void testChangingGlobal() { - System system; - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - integrator.addGlobalVariable("g", 0); - integrator.addPerDofVariable("a", 0); - integrator.addPerDofVariable("b", 0); - integrator.addComputeGlobal("g", "g+1"); - integrator.addComputePerDof("a", "0.5"); - integrator.addComputePerDof("b", "a+g"); - Context context(system, integrator, platform); - - // See if everything is being calculated correctly.. - - for (int i = 0; i < 10; i++) { - integrator.step(1); - ASSERT_EQUAL_TOL(i+1.0, integrator.getGlobalVariable(0), 1e-5); - vector values; - integrator.getPerDofVariable(1, values); - ASSERT_EQUAL_VEC(Vec3(i+1.5, i+1.5, i+1.5), values[0], 1e-5); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSingleBond(); - testConstraints(); - testVelocityConstraints(); - testConstrainedMasslessParticles(); - testWithThermostat(); - testMonteCarlo(); - testSum(); - testParameter(); - testRandomDistributions(); - testPerDofVariables(); - testForceGroups(); - testRespa(); - testMergedRandoms(); - testIfBlock(); - testWhileBlock(); - testChangingGlobal(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testMergedRandoms(); } diff --git a/platforms/opencl/tests/TestOpenCLCustomManyParticleForce.cpp b/platforms/opencl/tests/TestOpenCLCustomManyParticleForce.cpp index 29b35f387..a94e8ed35 100644 --- a/platforms/opencl/tests/TestOpenCLCustomManyParticleForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomManyParticleForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2014-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,705 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of CustomManyParticleForce. - */ +#include "OpenCLTests.h" +#include "TestCustomManyParticleForce.h" -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/CustomManyParticleForce.h" -#include "openmm/System.h" -#include "openmm/TabulatedFunction.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -OpenCLPlatform platform; - -Vec3 computeDelta(const Vec3& pos1, const Vec3& pos2, bool periodic, const Vec3* periodicBoxVectors) { - Vec3 diff = pos1-pos2; - if (periodic) { - diff -= periodicBoxVectors[2]*floor(diff[2]/periodicBoxVectors[2][2]+0.5); - diff -= periodicBoxVectors[1]*floor(diff[1]/periodicBoxVectors[1][1]+0.5); - diff -= periodicBoxVectors[0]*floor(diff[0]/periodicBoxVectors[0][0]+0.5); - } - return diff; -} - -void validateAxilrodTeller(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize, bool triclinic) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - Vec3 boxVectors[3]; - if (triclinic) { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0.2*boxSize, boxSize, 0); - boxVectors[2] = Vec3(-0.3*boxSize, -0.1*boxSize, boxSize); - } - else { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0, boxSize, 0); - boxVectors[2] = Vec3(0, 0, boxSize); - } - system.setDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double c = context.getParameter("C"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - bool periodic = (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic); - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = computeDelta(positions[p2], positions[p1], periodic, boxVectors); - Vec3 d13 = computeDelta(positions[p3], positions[p1], periodic, boxVectors); - Vec3 d23 = computeDelta(positions[p3], positions[p2], periodic, boxVectors); - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - double rprod = r12*r13*r23; - expectedEnergy += c*(1+3*ctheta1*ctheta2*ctheta3)/(rprod*rprod*rprod); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void validateStillingerWeber(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double L = context.getParameter("L"); - double eps = context.getParameter("eps"); - double a = context.getParameter("a"); - double gamma = context.getParameter("gamma"); - double sigma = context.getParameter("sigma"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - Vec3 d23 = positions[p3]-positions[p2]; - if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) { - for (int j = 0; j < 3; j++) { - d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize; - d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize; - d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize; - } - } - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - expectedEnergy += L*eps*(ctheta1+1.0/3.0)*(ctheta1+1.0/3.0)*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma)); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void testNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - int sets[4][3] = {{0,1,2}, {1,2,3}, {2,3,0}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(1.55); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - int sets[7][3] = {{0,1,2}, {0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,2,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[7]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testPeriodic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[5][3] = {{0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, false); -} - -void testTriclinic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[4][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, true); -} - -void testExclusions() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - force->addExclusion(0, 2); - force->addExclusion(0, 3); - int sets[5][3] = {{0,1,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testAllTerms() { - int numParticles = 4; - - // Create a system with a CustomManyParticleForce. - - System system1; - CustomManyParticleForce* force1 = new CustomManyParticleForce(4, - "distance(p1,p2)+angle(p1,p4,p3)+dihedral(p1,p3,p2,p4)+x1+y4+z3"); - system1.addForce(force1); - vector params; - for (int i = 0; i < numParticles; i++) { - system1.addParticle(1.0); - force1->addParticle(params, i); - } - set filter; - filter.insert(0); - force1->setTypeFilter(0, filter); - filter.clear(); - filter.insert(1); - force1->setTypeFilter(1, filter); - filter.clear(); - filter.insert(3); - force1->setTypeFilter(2, filter); - filter.clear(); - filter.insert(2); - force1->setTypeFilter(3, filter); - - // Create a system that use a CustomCompoundBondForce to compute exactly the same interactions. - - System system2; - CustomCompoundBondForce* force2 = new CustomCompoundBondForce(4, - "distance(p1,p2)+angle(p1,p3,p4)+dihedral(p1,p4,p2,p3)+x1+y3+z4"); - system2.addForce(force2); - vector particles; - particles.push_back(0); - particles.push_back(1); - particles.push_back(2); - particles.push_back(3); - force2->addBond(particles, params); - for (int i = 0; i < numParticles; i++) - system2.addParticle(1.0); - - // Create contexts for both of them. - - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system1, integrator1, platform); - Context context2(system2, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - - // See if they produce identical forces and energies. - - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state2.getForces()[i], state1.getForces()[i], 1e-4); -} - -void testParameters() { - // Create a system. - - int numParticles = 5; - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "C*scale1*scale2*scale3*(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))"); - force->addGlobalParameter("C", 2.0); - force->addPerParticleParameter("scale"); - vector params(1); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - params[0] = i+1; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 2.0*(i+1)*(j+1)*(k+1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); - - // Modify the parameters. - - context.setParameter("C", 3.5); - for (int i = 0; i < numParticles; i++) { - params[0] = 0.5*i-0.1; - force->setParticleParameters(i, params, 0); - } - force->updateParametersInContext(context); - - // See if the energy is still correct. - - state = context.getState(State::Energy); - expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 3.5*(0.5*i-0.1)*(0.5*j-0.1)*(0.5*k-0.1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTabulatedFunctions() { - int numParticles = 5; - - // Create two tabulated functions. - - vector values; - values.push_back(0.0); - values.push_back(50.0); - Continuous1DFunction* f1 = new Continuous1DFunction(values, 0, 100); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector c(numParticles); - for (int i = 0; i < numParticles; i++) - c[i] = genrand_real2(sfmt); - values.resize(numParticles*numParticles*numParticles); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < numParticles; j++) - for (int k = 0; k < numParticles; k++) - values[i+numParticles*j+numParticles*numParticles*k] = c[i]+c[j]+c[k]; - Discrete3DFunction* f2 = new Discrete3DFunction(numParticles, numParticles, numParticles, values); - - // Create a system. - - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "f1(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))*f2(atom1, atom2, atom3)"); - force->addPerParticleParameter("atom"); - force->addTabulatedFunction("f1", f1); - force->addTabulatedFunction("f2", f2); - vector params(1); - vector positions; - for (int i = 0; i < numParticles; i++) { - params[0] = i; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 0.5*(r12+r13+r23)*(c[i]+c[j]+c[k]); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTypeFilters() { - // Create a system. - - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CustomManyParticleForce* force = new CustomManyParticleForce(3, "c1*(distance(p1,p2)+distance(p1,p3))"); - force->addPerParticleParameter("c"); - double c[] = {1.0, 2.0, 1.3, 1.5, -2.1}; - int type[] = {0, 1, 0, 1, 5}; - vector params(1); - for (int i = 0; i < 5; i++) { - params[0] = c[i]; - force->addParticle(params, type[i]); - } - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - set f1, f2; - f1.insert(0); - f2.insert(1); - f2.insert(5); - force->setTypeFilter(0, f1); - force->setTypeFilter(1, f2); - force->setTypeFilter(2, f2); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - int sets[6][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {2,1,3}, {2,1,4}, {2,3,4}}; - for (int i = 0; i < 6; i++) { - int p1 = sets[i][0]; - int p2 = sets[i][1]; - int p3 = sets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - expectedEnergy += c[p1]*(r12+r13); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testLargeSystem() { - int gridSize = 8; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = 3.0; - double spacing = boxSize/gridSize; - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(0.6); - vector params; - vector positions; - System system; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - force->addParticle(params); - positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system, integrator1, Platform::getPlatformByName("Reference")); - Context context2(system, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); -} - -void testCentralParticleModeNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[12][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {2,0,3}, {2, 1, 3}, {3,0,1}, {3,0,2}, {3,1,2}}; - vector expectedSets(&sets[0], &sets[12]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(0.155); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[8][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[8]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeLargeSystem() { - int gridSize = 8; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = 2.0; - double spacing = boxSize/gridSize; - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.8*0.23925); - vector params; - vector positions; - System system; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - force->addParticle(params); - positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); - system.addParticle(1.0); - } - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system, integrator1, Platform::getPlatformByName("Reference")); - Context context2(system, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testNoCutoff(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testExclusions(); - testAllTerms(); - testParameters(); - testTabulatedFunctions(); - testTypeFilters(); - testLargeSystem(); - testCentralParticleModeNoCutoff(); - testCentralParticleModeCutoff(); - testCentralParticleModeLargeSystem(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLCustomNonbondedForce.cpp b/platforms/opencl/tests/TestOpenCLCustomNonbondedForce.cpp index 652ddd7a9..6782c2958 100644 --- a/platforms/opencl/tests/TestOpenCLCustomNonbondedForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomNonbondedForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -30,607 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the OpenCL implementation of CustomNonbondedForce. - */ - -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "sfmt/SFMT.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomNonbondedForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSimpleExpression() { - 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()); - forceField->addParticle(vector()); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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 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 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 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); - - // Try changing the global parameters and make sure it's still correct. - - 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); - - // Try changing the per-particle parameters and make sure it's still correct. - - params[0] = 1.6; - params[1] = 2.1; - forceField->setParticleParameters(0, params); - params[0] = 1.9; - params[1] = 2.8; - forceField->setParticleParameters(1, params); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - forces = state.getForces(); - force = -1.5*1.6*1.9*3*5.9*(11.8*11.8); - 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*1.6*1.9*(11.8*11.8*11.8), state.getPotentialEnergy(), TOL); -} - -void testManyParameters() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("(a1*a2+b1*b2+c1*c2+d1*d2+e1*e2)*r"); - forceField->addPerParticleParameter("a"); - forceField->addPerParticleParameter("b"); - forceField->addPerParticleParameter("c"); - forceField->addPerParticleParameter("d"); - forceField->addPerParticleParameter("e"); - vector params(5); - params[0] = 1.0; - params[1] = 2.0; - params[2] = 3.0; - params[3] = 4.0; - params[4] = 5.0; - forceField->addParticle(params); - params[0] = 1.1; - params[1] = 1.2; - params[2] = 1.3; - params[3] = 1.4; - params[4] = 1.5; - forceField->addParticle(params); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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); - vector forces = state.getForces(); - double force = 1*1.1 + 2*1.2 + 3*1.3 + 4*1.4 + 5*1.5; - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(2*force, state.getPotentialEnergy(), TOL); -} - -void testExclusions() { - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("a*r; a=a1+a2"); - nonbonded->addPerParticleParameter("a"); - vector params(1); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - forceField->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - forceField->setCutoffDistance(2.5); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - 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 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& 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 testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("r"); - nonbonded->addParticle(vector()); - nonbonded->addParticle(vector()); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta/sqrt(delta.dot(delta)); - ASSERT_EQUAL_TOL(distance, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); - } - } -} - -void testContinuous1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& forces = state.getForces(); - double force = (x < 1.0 || x > 6.0 ? 0.0 : -cos(x-1.0)); - double energy = (x < 1.0 || x > 6.0 ? 0.0 : 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 : sin(x-1.0))+1.0; - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - } -} - -void testContinuous2DFunction() { - const int xsize = 20; - const int ysize = 21; - const double xmin = 0.4; - const double xmax = 1.5; - const double ymin = 0.0; - const double ymax = 2.1; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y); - } - 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); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.4; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.9; - const double zmin = 0.2; - const double zmax = 1.3; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setParameter("b", z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - } - 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.05); - } - } - } -} - -void testDiscrete1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Discrete1DFunction(table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i+1, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} -void testDiscrete2DFunction() { - const int xsize = 10; - const int ysize = 5; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - table.push_back(sin(0.25*i)+cos(0.33*j)); - forceField->addTabulatedFunction("fn", new Discrete2DFunction(xsize, ysize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3((i%xsize)+1, 0, 0); - context.setPositions(positions); - context.setParameter("a", i/xsize); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete3DFunction() { - const int xsize = 8; - const int ysize = 5; - const int zsize = 6; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - for (int k = 0; k < zsize; k++) - table.push_back(sin(0.25*i)+cos(0.33*j)+0.12345*k); - forceField->addTabulatedFunction("fn", new Discrete3DFunction(xsize, ysize, zsize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3((i%xsize)+1, 0, 0); - context.setPositions(positions); - context.setParameter("a", (i/xsize)%ysize); - context.setParameter("b", i/(xsize*ysize)); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testCoulombLennardJones() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // 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 positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector 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); - Context context1(standardSystem, integrator1, platform); - Context context2(customSystem, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - context1.setVelocities(velocities); - context2.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} +#include "OpenCLTests.h" +#include "TestCustomNonbondedForce.h" void testParallelComputation() { System system; @@ -669,396 +69,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testSwitchingFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("10/r^2"); - vector params; - nonbonded->addParticle(params); - nonbonded->addParticle(params); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double expectedEnergy = 10/(r*r); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 2e-3); - } -} - -void testLongRangeCorrection() { - // Create a box of particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System standardSystem; - System customSystem; - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - NonbondedForce* standardNonbonded = new NonbondedForce(); - CustomNonbondedForce* customNonbonded = new CustomNonbondedForce("4*eps*((sigma/r)^12-(sigma/r)^6); sigma=0.5*(sigma1+sigma2); eps=sqrt(eps1*eps2)"); - customNonbonded->addPerParticleParameter("sigma"); - customNonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - int index = 0; - vector params1(2); - params1[0] = 1.1; - params1[1] = 0.5; - vector params2(2); - params2[0] = 1; - params2[1] = 1; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - if (index%2 == 0) { - standardNonbonded->addParticle(0, params1[0], params1[1]); - customNonbonded->addParticle(params1); - } - else { - standardNonbonded->addParticle(0, params2[0], params2[1]); - customNonbonded->addParticle(params2); - } - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - standardNonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - customNonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - standardNonbonded->setCutoffDistance(cutoff); - customNonbonded->setCutoffDistance(cutoff); - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - standardNonbonded->setUseDispersionCorrection(true); - customNonbonded->setUseLongRangeCorrection(true); - standardNonbonded->setUseSwitchingFunction(true); - customNonbonded->setUseSwitchingFunction(true); - standardNonbonded->setSwitchingDistance(0.8*cutoff); - customNonbonded->setSwitchingDistance(0.8*cutoff); - standardSystem.addForce(standardNonbonded); - customSystem.addForce(customNonbonded); - - // Compute the correction for the standard force. - - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - double standardEnergy1 = context1.getState(State::Energy).getPotentialEnergy(); - standardNonbonded->setUseDispersionCorrection(false); - context1.reinitialize(); - context1.setPositions(positions); - double standardEnergy2 = context1.getState(State::Energy).getPotentialEnergy(); - - // Compute the correction for the custom force. - - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - double customEnergy1 = context2.getState(State::Energy).getPotentialEnergy(); - customNonbonded->setUseLongRangeCorrection(false); - context2.reinitialize(); - context2.setPositions(positions); - double customEnergy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // See if they agree. - - ASSERT_EQUAL_TOL(standardEnergy1-standardEnergy2, customEnergy1-customEnergy2, 1e-4); -} - -void testInteractionGroups() { - const int numParticles = 6; - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("v1+v2"); - nonbonded->addPerParticleParameter("v"); - vector params(1, 0.001); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(params); - params[0] *= 10; - } - set set1, set2, set3, set4; - set1.insert(2); - set2.insert(0); - set2.insert(1); - set2.insert(2); - set2.insert(3); - set2.insert(4); - set2.insert(5); - nonbonded->addInteractionGroup(set1, set2); // Particle 2 interacts with every other particle. - set3.insert(0); - set3.insert(1); - set4.insert(4); - set4.insert(5); - nonbonded->addInteractionGroup(set3, set4); // Particles 0 and 1 interact with 4 and 5. - nonbonded->addExclusion(1, 2); // Add an exclusion to make sure it gets skipped. - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - context.setPositions(positions); - State state = context.getState(State::Energy); - double expectedEnergy = 331.423; // Each digit is the number of interactions a particle particle is involved in. - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), TOL); -} - -void testLargeInteractionGroup() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // Create a large system. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomNonbondedForce* nonbonded = 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)"); - nonbonded->addPerParticleParameter("q"); - nonbonded->addPerParticleParameter("sigma"); - nonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.1; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.2; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->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]); - nonbonded->addExclusion(2*i, 2*i+1); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Compute the forces. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces); - - // Modify the force so only one particle interacts with everything else. - - set set1, set2; - set1.insert(151); - for (int i = 0; i < numParticles; i++) - set2.insert(i); - nonbonded->addInteractionGroup(set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state2 = context.getState(State::Forces); - - // The force on that one particle should be the same. - - ASSERT_EQUAL_VEC(state1.getForces()[151], state2.getForces()[151], 1e-4); - - // Modify the interaction group so it includes all interactions. This should now reproduce the original forces - // on all atoms. - - for (int i = 0; i < numParticles; i++) - set1.insert(i); - nonbonded->setInteractionGroupParameters(0, set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state3 = context.getState(State::Forces); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state3.getForces()[i], 1e-4); -} - -void testInteractionGroupLongRangeCorrection() { - const int numParticles = 10; - const double boxSize = 10.0; - const double cutoff = 0.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("c1*c2*r^-4"); - nonbonded->addPerParticleParameter("c"); - vector positions(numParticles); - vector params(1); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - params[0] = (i%2 == 0 ? 1.1 : 2.0); - nonbonded->addParticle(params); - positions[i] = Vec3(0.5*i, 0, 0); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - - // Setup nonbonded groups. They involve 1 interaction of type AA, - // 2 of type BB, and 5 of type AB. - - set set1, set2, set3, set4, set5; - set1.insert(0); - set1.insert(1); - set1.insert(2); - nonbonded->addInteractionGroup(set1, set1); - set2.insert(3); - set3.insert(4); - set3.insert(6); - set3.insert(8); - nonbonded->addInteractionGroup(set2, set3); - set4.insert(5); - set5.insert(7); - set5.insert(9); - nonbonded->addInteractionGroup(set4, set5); - - // Compute energy with and without the correction. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseLongRangeCorrection(true); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - - // Check the result. - - double sum = (1.1*1.1 + 2*2.0*2.0 + 5*1.1*2.0)*2.0; - int numPairs = (numParticles*(numParticles+1))/2; - double expected = 2*M_PI*numParticles*numParticles*sum/(numPairs*boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy2-energy1, 1e-4); -} - -void testMultipleCutoffs() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - - // Add multiple nonbonded forces that have different cutoffs. - - CustomNonbondedForce* nonbonded1 = new CustomNonbondedForce("2*r"); - nonbonded1->addParticle(vector()); - nonbonded1->addParticle(vector()); - nonbonded1->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded1->setCutoffDistance(2.5); - system.addForce(nonbonded1); - CustomNonbondedForce* nonbonded2 = new CustomNonbondedForce("3*r"); - nonbonded2->addParticle(vector()); - nonbonded2->addParticle(vector()); - nonbonded2->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded2->setCutoffDistance(2.9); - nonbonded2->setForceGroup(1); - system.addForce(nonbonded2); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 0, 0); - for (double r = 2.4; r < 3.2; r += 0.2) { - positions[1][1] = r; - context.setPositions(positions); - double e1 = (r < 2.5 ? 2.0*r : 0.0); - double e2 = (r < 2.9 ? 3.0*r : 0.0); - double f1 = (r < 2.5 ? 2.0 : 0.0); - double f2 = (r < 2.9 ? 3.0 : 0.0); - - // Check the first force. - - State state = context.getState(State::Forces | State::Energy, false, 1); - ASSERT_EQUAL_VEC(Vec3(0, f1, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1, state.getPotentialEnergy(), TOL); - - // Check the second force. - - state = context.getState(State::Forces | State::Energy, false, 2); - ASSERT_EQUAL_VEC(Vec3(0, f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e2, state.getPotentialEnergy(), TOL); - - // Check the sum of both forces. - - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_VEC(Vec3(0, f1+f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1-f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1+e2, state.getPotentialEnergy(), TOL); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSimpleExpression(); - testParameters(); - testManyParameters(); - testExclusions(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testContinuous1DFunction(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testDiscrete1DFunction(); - testDiscrete2DFunction(); - testDiscrete3DFunction(); - testCoulombLennardJones(); - testParallelComputation(); - testSwitchingFunction(); - testLongRangeCorrection(); - testInteractionGroups(); - testLargeInteractionGroup(); - testInteractionGroupLongRangeCorrection(); - testMultipleCutoffs(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } diff --git a/platforms/opencl/tests/TestOpenCLCustomTorsionForce.cpp b/platforms/opencl/tests/TestOpenCLCustomTorsionForce.cpp index 63a64e15e..7be950621 100644 --- a/platforms/opencl/tests/TestOpenCLCustomTorsionForce.cpp +++ b/platforms/opencl/tests/TestOpenCLCustomTorsionForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,147 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL 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 "OpenCLPlatform.h" -#include "openmm/CustomTorsionForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testTorsions() { - // 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 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(harmonicSystem, integrator2, platform); - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 2; - custom->setTorsionParameters(0, 0, 1, 2, 3, parameters); - parameters[0] = 2.1; - parameters[1] = 3; - custom->setTorsionParameters(1, 1, 2, 3, 4, parameters); - custom->updateParametersInContext(c1); - periodic->setTorsionParameters(0, 0, 1, 2, 3, 2, 1.6, 0.5); - periodic->setTorsionParameters(1, 1, 2, 3, 4, 3, 2.1, 0.5); - periodic->updateParametersInContext(c2); - { - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } -} - -void testRange() { - 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()); - 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 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); -} +#include "OpenCLTests.h" +#include "TestCustomTorsionForce.h" void testParallelComputation() { System system; @@ -200,19 +61,6 @@ void testParallelComputation() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testTorsions(); - testRange(); - testParallelComputation(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(); } - diff --git a/platforms/reference/tests/TestReferenceAndersenThermostat.cpp b/platforms/reference/tests/TestReferenceAndersenThermostat.cpp index 5e61024ce..39a79bb6e 100644 --- a/platforms/reference/tests/TestReferenceAndersenThermostat.cpp +++ b/platforms/reference/tests/TestReferenceAndersenThermostat.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,190 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of AndersenThermostat. - */ +#include "ReferenceTests.h" +#include "TestAndersenThermostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -void testTemperature() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 5000; - System system; - VerletIntegrator integrator(0.003); - 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); - ASSERT(!thermostat->usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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); - context.setVelocitiesToTemperature(temp); - - // 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(10); - } - ke /= numSteps; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 15000; - System system; - VerletIntegrator integrator(0.004); - 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* thermostat = new AndersenThermostat(temp, collisionFreq); - system.addForce(thermostat); - Context context(system, integrator, platform); - vector 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); - context.setVelocitiesToTemperature(temp); - - // Let it equilibrate. - - integrator.step(5000); - - // 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_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceBrownianIntegrator.cpp b/platforms/reference/tests/TestReferenceBrownianIntegrator.cpp index c50e9ffc2..71d19d0f4 100644 --- a/platforms/reference/tests/TestReferenceBrownianIntegrator.cpp +++ b/platforms/reference/tests/TestReferenceBrownianIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,241 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of BrownianIntegrator. - */ +#include "ReferenceTests.h" +#include "TestBrownianIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/BrownianIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - 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 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; - 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 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 double temp = 100.0; - 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); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 < numParticles-1; ++j) { - Vec3 p1 = state.getPositions()[j]; - Vec3 p2 = state.getPositions()[j+1]; - 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(1.0, dist, 2e-5); - } - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - BrownianIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceCMAPTorsionForce.cpp b/platforms/reference/tests/TestReferenceCMAPTorsionForce.cpp index f0e722365..b84f408b4 100644 --- a/platforms/reference/tests/TestReferenceCMAPTorsionForce.cpp +++ b/platforms/reference/tests/TestReferenceCMAPTorsionForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2010-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,152 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CMAPTorsionForce. - */ +#include "ReferenceTests.h" +#include "TestCMAPTorsionForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CMAPTorsionForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -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. - - 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); - ASSERT(!periodic->usesPeriodicBoundaryConditions()); - ASSERT(!system1.usesPeriodicBoundaryConditions()); - System system2; - for (int i = 0; i < 5; i++) - system2.addParticle(1.0); - CMAPTorsionForce* cmap = new CMAPTorsionForce(); - vector 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); - ASSERT(!cmap->usesPeriodicBoundaryConditions()); - ASSERT(!system2.usesPeriodicBoundaryConditions()); - - // 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(system1, integrator1, platform); - Context c2(system2, integrator2, platform); - for (int i = 0; i < 50; 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < system1.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 0.05); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), 1e-3); - } -} - -void testChangingParameters() { - // Create a system with two maps and one torsion. - - const int mapSize = 8; - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CMAPTorsionForce* cmap = new CMAPTorsionForce(); - vector mapEnergy1(mapSize*mapSize); - vector mapEnergy2(mapSize*mapSize); - for (int i = 0; i < mapSize; i++) { - double angle1 = i*2*M_PI/mapSize; - double energy1 = cos(angle1); - for (int j = 0; j < mapSize; j++) { - double angle2 = j*2*M_PI/mapSize; - double energy2 = 10*sin(angle2); - mapEnergy1[i+j*mapSize] = energy1+energy2; - mapEnergy2[i+j*mapSize] = energy1-energy2; - } - } - cmap->addMap(mapSize, mapEnergy1); - cmap->addMap(mapSize, mapEnergy2); - cmap->addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4); - system.addForce(cmap); - - // Set particle positions so angle1=0 and angle2=PI/4. - - vector positions(5); - positions[0] = Vec3(0, 0, 1); - positions[1] = Vec3(0, 0, 0); - positions[2] = Vec3(1, 0, 0); - positions[3] = Vec3(1, 0, 1); - positions[4] = Vec3(0.5, -0.5, 1); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Check that the energy is correct. - - double energy = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(1+10*sin(M_PI/4), energy, 1e-5); - - // Modify the parameters. - - cmap->setTorsionParameters(0, 1, 0, 1, 2, 3, 1, 2, 3, 4); - for (int i = 0; i < mapSize*mapSize; i++) - mapEnergy2[i] *= 2.0; - cmap->setMapParameters(1, mapSize, mapEnergy2); - cmap->updateParametersInContext(context); - - // See if the results are correct. - - energy = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(2-20*sin(M_PI/4), energy, 1e-5); +void runPlatformTests() { } - -int main() { - try { - testCMAPTorsions(); - testChangingParameters(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferenceCMMotionRemover.cpp b/platforms/reference/tests/TestReferenceCMMotionRemover.cpp index 7e8403277..200223e87 100644 --- a/platforms/reference/tests/TestReferenceCMMotionRemover.cpp +++ b/platforms/reference/tests/TestReferenceCMMotionRemover.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,89 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of AndersenThermostat. - */ +#include "ReferenceTests.h" +#include "TestCMMotionRemover.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/CMMotionRemover.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -Vec3 calcCM(const vector& 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() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - System system; - VerletIntegrator integrator(0.01); - 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 positions(numParticles); - vector 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); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), vel, 1e-2); - } -} - -int main() { - try { - testMotionRemoval(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceCustomHbondForce.cpp b/platforms/reference/tests/TestReferenceCustomHbondForce.cpp index e0dd8c1dd..a477075e8 100644 --- a/platforms/reference/tests/TestReferenceCustomHbondForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomHbondForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,221 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomHbondForce. - */ +#include "ReferenceTests.h" +#include "TestCustomHbondForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomHbondForce.h" -#include "openmm/HarmonicAngleForce.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testHbond() { - // Create a system using a CustomHbondForce. - - System customSystem; - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - customSystem.addParticle(1.0); - CustomHbondForce* custom = new CustomHbondForce("0.5*kr*(distance(d1,a1)-r0)^2 + 0.5*ktheta*(angle(a1,d1,d2)-theta0)^2 + 0.5*kpsi*(angle(d1,a1,a2)-psi0)^2 + kchi*(1+cos(n*dihedral(a3,a2,a1,d1)-chi0))"); - custom->addPerDonorParameter("r0"); - custom->addPerDonorParameter("theta0"); - custom->addPerDonorParameter("psi0"); - custom->addPerAcceptorParameter("chi0"); - custom->addPerAcceptorParameter("n"); - custom->addGlobalParameter("kr", 0.4); - custom->addGlobalParameter("ktheta", 0.5); - custom->addGlobalParameter("kpsi", 0.6); - custom->addGlobalParameter("kchi", 0.7); - vector parameters(3); - parameters[0] = 1.5; - parameters[1] = 1.7; - parameters[2] = 1.9; - custom->addDonor(1, 0, -1, parameters); - parameters.resize(2); - parameters[0] = 2.1; - parameters[1] = 2; - custom->addAcceptor(2, 3, 4, parameters); - custom->setCutoffDistance(10.0); - customSystem.addForce(custom); - ASSERT(!custom->usesPeriodicBoundaryConditions()); - ASSERT(!customSystem.usesPeriodicBoundaryConditions()); - - // Create an identical system using HarmonicBondForce, HarmonicAngleForce, and PeriodicTorsionForce. - - System standardSystem; - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - standardSystem.addParticle(1.0); - HarmonicBondForce* bond = new HarmonicBondForce(); - bond->addBond(1, 2, 1.5, 0.4); - standardSystem.addForce(bond); - HarmonicAngleForce* angle = new HarmonicAngleForce(); - angle->addAngle(0, 1, 2, 1.7, 0.5); - angle->addAngle(1, 2, 3, 1.9, 0.6); - standardSystem.addForce(angle); - PeriodicTorsionForce* torsion = new PeriodicTorsionForce(); - torsion->addTorsion(1, 2, 3, 4, 2, 2.1, 0.7); - standardSystem.addForce(torsion); - - // 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(standardSystem, integrator2, platform); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < (int) positions.size(); j++) - positions[j] = Vec3(2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); - } - - // Try changing the parameters and make sure it's still correct. - - parameters.resize(3); - parameters[0] = 1.4; - parameters[1] = 1.7; - parameters[2] = 1.9; - custom->setDonorParameters(0, 1, 0, -1, parameters); - parameters.resize(2); - parameters[0] = 2.2; - parameters[1] = 2; - custom->setAcceptorParameters(0, 2, 3, 4, parameters); - bond->setBondParameters(0, 1, 2, 1.4, 0.4); - torsion->setTorsionParameters(0, 1, 2, 3, 4, 2, 2.2, 0.7); - custom->updateParametersInContext(c1); - bond->updateParametersInContext(c2); - torsion->updateParametersInContext(c2); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); +void runPlatformTests() { } - -void testExclusions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); - custom->addDonor(0, 1, -1, vector()); - custom->addDonor(1, 0, -1, vector()); - custom->addAcceptor(2, 0, -1, vector()); - custom->addExclusion(1, 0); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); - custom->addDonor(0, 1, -1, vector()); - custom->addDonor(1, 0, -1, vector()); - custom->addAcceptor(2, 0, -1, vector()); - custom->setNonbondedMethod(CustomHbondForce::CutoffNonPeriodic); - custom->setCutoffDistance(2.5); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 3, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); -} - -void testCustomFunctions() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomHbondForce* custom = new CustomHbondForce("foo(distance(d1,a1))"); - custom->addDonor(1, 0, -1, vector()); - custom->addDonor(2, 0, -1, vector()); - custom->addAcceptor(0, 1, -1, vector()); - vector function(2); - function[0] = 0; - function[1] = 1; - custom->addTabulatedFunction("foo", new Continuous1DFunction(function, 0, 10)); - system.addForce(custom); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 2, 0); - positions[2] = Vec3(2, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0.1, 0.1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -0.1, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(-0.1, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(0.1*2+0.1*2, state.getPotentialEnergy(), TOL); -} - -int main() { - try { - testHbond(); - testExclusions(); - testCutoff(); - testCustomFunctions(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferenceCustomIntegrator.cpp b/platforms/reference/tests/TestReferenceCustomIntegrator.cpp index 01090cc35..d2e9c7432 100644 --- a/platforms/reference/tests/TestReferenceCustomIntegrator.cpp +++ b/platforms/reference/tests/TestReferenceCustomIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,747 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomIntegrator. - */ +#include "ReferenceTests.h" +#include "TestCustomIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/CustomIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -/** - * Test a simple leapfrog integrator on a single bond. - */ -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.setKineticEnergyExpression("m*v1*v1/2; v1=v+0.5*dt*f/m"); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - vector velocities(2); - velocities[0] = Vec3(-0.5*dt*0.5*0.5, 0, 0); - velocities[1] = Vec3(0.5*dt*0.5*0.5, 0, 0); - context.setVelocities(velocities); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*std::cos(freq*time); - ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 1e-4); - double expectedSpeed = -0.5*freq*std::sin(freq*(time-dt/2)); - ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 1e-4); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(0.5*0.5*0.5, energy, 1e-4); - integrator.step(1); - } -} - -/** - * Test an integrator that enforces constraints. - */ -void testConstraints() { - const int numParticles = 8; - const double temp = 500.0; - System system; - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "(x-oldx)/dt"); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -/** - * Test an integrator that applies constraints directly to velocities. - */ -void testVelocityConstraints() { - const int numParticles = 10; - System system; - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("x1", 0); - integrator.addComputePerDof("v", "v+0.5*dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputePerDof("x1", "x"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "v+0.5*dt*f/m+(x-x1)/dt"); - integrator.addConstrainVelocities(); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - - // Constrain the first three particles with SHAKE. - - system.addConstraint(0, 1, 1.0); - system.addConstraint(1, 2, 1.0); - - // Constrain the next three with SETTLE. - - system.addConstraint(3, 4, 1.0); - system.addConstraint(5, 4, 1.0); - system.addConstraint(3, 5, sqrt(2.0)); - - // Constraint the rest with CCMA. - - for (int i = 6; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - integrator.step(2); - State state = context.getState(State::Positions | State::Velocities | State::Energy); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - if (i > 0) { - Vec3 v1 = state.getVelocities()[particle1]; - Vec3 v2 = state.getVelocities()[particle2]; - double vel = (v1-v2).dot(p1-p2); - ASSERT_EQUAL_TOL(0.0, vel, 2e-5); - } - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 0) - initialEnergy = energy; - else if (i > 0) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - CustomIntegrator integrator(0.002); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addConstrainPositions(); - integrator.addComputePerDof("v", "(x-oldx)/dt"); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -/** - * Test an integrator with an AndersenThermostat to see if updateContextState() - * is being handled correctly. - */ -void testWithThermostat() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - const int numSteps = 5000; - System system; - CustomIntegrator integrator(0.003); - integrator.addUpdateContextState(); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - 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); - Context context(system, integrator, platform); - vector 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); - context.setVelocitiesToTemperature(temp); - - // 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(10); - } - ke /= numSteps; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -/** - * Test a Monte Carlo integrator that uses global variables and depends on energy. - */ -void testMonteCarlo() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - const double kT = BOLTZ*300.0; - integrator.addGlobalVariable("kT", kT); - integrator.addGlobalVariable("oldE", 0); - integrator.addGlobalVariable("accept", 0); - integrator.addPerDofVariable("oldx", 0); - integrator.addComputeGlobal("oldE", "energy"); - integrator.addComputePerDof("oldx", "x"); - integrator.addComputePerDof("x", "x+dt*gaussian"); - integrator.addComputeGlobal("accept", "step(exp((oldE-energy)/kT)-uniform)"); - integrator.addComputePerDof("x", "select(accept, x, oldx)"); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 2.0, 10.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // Compute the histogram of distances and see if it satisfies a Boltzmann distribution. - - const int numBins = 100; - const double maxDist = 4.0; - const int numIterations = 5000; - vector counts(numBins, 0); - for (int i = 0; i < numIterations; ++i) { - integrator.step(10); - State state = context.getState(State::Positions); - Vec3 delta = state.getPositions()[0]-state.getPositions()[1]; - double dist = sqrt(delta.dot(delta)); - if (dist < maxDist) - counts[(int) (numBins*dist/maxDist)]++; - } - vector expected(numBins, 0); - double sum = 0; - for (int i = 0; i < numBins; i++) { - double dist = (i+0.5)*maxDist/numBins; - expected[i] = dist*dist*exp(-5.0*(dist-2)*(dist-2)/kT); - sum += expected[i]; - } - for (int i = 0; i < numBins; i++) - ASSERT_USUALLY_EQUAL_TOL((double) counts[i]/numIterations, expected[i]/sum, 0.01); -} - -/** - * Test the ComputeSum operation. - */ -void testSum() { - const int numParticles = 200; - const double boxSize = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nb = new NonbondedForce(); - system.addForce(nb); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(i%10 == 0 ? 0.0 : 1.5); - nb->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.1, 1); - bool close = true; - while (close) { - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - close = false; - for (int j = 0; j < i; ++j) { - Vec3 delta = positions[i]-positions[j]; - if (delta.dot(delta) < 1) - close = true; - } - } - } - CustomIntegrator integrator(0.005); - integrator.addGlobalVariable("ke", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputeSum("ke", "m*v*v/2"); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the sum is being computed correctly. - - for (int i = 0; i < 100; ++i) { - State state = context.getState(State::Energy); - ASSERT_EQUAL_TOL(state.getKineticEnergy(), integrator.getGlobalVariable(0), 1e-5); - integrator.step(1); - } -} - -/** - * Test an integrator that both uses and modifies a context parameter. - */ -void testParameter() { - System system; - system.addParticle(1.0); - AndersenThermostat* thermostat = new AndersenThermostat(0.1, 0.1); - system.addForce(thermostat); - CustomIntegrator integrator(0.1); - integrator.addGlobalVariable("temp", 0); - integrator.addComputeGlobal("temp", "AndersenTemperature"); - integrator.addComputeGlobal("AndersenTemperature", "temp*2"); - Context context(system, integrator, platform); - - // See if the parameter is being used correctly. - - for (int i = 0; i < 10; i++) { - integrator.step(1); - ASSERT_EQUAL_TOL(context.getParameter("AndersenTemperature"), 0.1*(1<<(i+1)), 1e-10); - } -} - -/** - * Test random number distributions. - */ -void testRandomDistributions() { - const int numParticles = 100; - const int numBins = 20; - const int numSteps = 100; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomIntegrator integrator(0.1); - integrator.addPerDofVariable("a", 0); - integrator.addPerDofVariable("b", 0); - integrator.addComputePerDof("a", "uniform"); - integrator.addComputePerDof("b", "gaussian"); - Context context(system, integrator, platform); - - // See if the random numbers are distributed correctly. - - vector bins(numBins); - double mean = 0.0; - double var = 0.0; - double skew = 0.0; - double kurtosis = 0.0; - vector values; - for (int i = 0; i < numSteps; i++) { - integrator.step(1); - integrator.getPerDofVariable(0, values); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < 3; j++) { - double v = values[i][j]; - ASSERT(v >= 0 && v < 1); - bins[(int) (v*numBins)]++; - } - integrator.getPerDofVariable(1, values); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < 3; j++) { - double v = values[i][j]; - mean += v; - var += v*v; - skew += v*v*v; - kurtosis += v*v*v*v; - } - } - - // Check the distribution of uniform randoms. - - int numValues = numParticles*numSteps*3; - double expected = numValues/(double) numBins; - double tol = 4*sqrt(expected); - for (int i = 0; i < numBins; i++) - ASSERT(bins[i] >= expected-tol && bins[i] <= expected+tol); - - // Check the distribution of gaussian randoms. - - mean /= numValues; - var /= numValues; - skew /= numValues; - kurtosis /= numValues; - double c2 = var-mean*mean; - double c3 = skew-3*var*mean+2*mean*mean*mean; - double c4 = kurtosis-4*skew*mean-3*var*var+12*var*mean*mean-6*mean*mean*mean*mean; - ASSERT_EQUAL_TOL(0.0, mean, 3.0/sqrt((double) numValues)); - ASSERT_EQUAL_TOL(1.0, c2, 3.0/pow(numValues, 1.0/3.0)); - ASSERT_EQUAL_TOL(0.0, c3, 3.0/pow(numValues, 1.0/4.0)); - ASSERT_EQUAL_TOL(0.0, c4, 3.0/pow(numValues, 1.0/4.0)); -} - -/** - * Test getting and setting per-DOF variables. - */ -void testPerDofVariables() { - const int numParticles = 200; - const double boxSize = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nb = new NonbondedForce(); - system.addForce(nb); - nb->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.5); - nb->addParticle(i%2 == 0 ? 1 : -1, 0.1, 1); - bool close = true; - while (close) { - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - close = false; - for (int j = 0; j < i; ++j) { - Vec3 delta = positions[i]-positions[j]; - if (delta.dot(delta) < 0.1) - close = true; - } - } - } - CustomIntegrator integrator(0.01); - integrator.addPerDofVariable("temp", 0); - integrator.addPerDofVariable("pos", 0); - integrator.addComputePerDof("v", "v+dt*f/m"); - integrator.addComputePerDof("x", "x+dt*v"); - integrator.addComputePerDof("pos", "x"); - Context context(system, integrator, platform); - context.setPositions(positions); - vector initialValues(numParticles); - for (int i = 0; i < numParticles; i++) - initialValues[i] = Vec3(i+0.1, i+0.2, i+0.3); - integrator.setPerDofVariable(0, initialValues); - - // Run a simulation, then query per-DOF values and see if they are correct. - - vector values; - for (int i = 0; i < 100; ++i) { - integrator.step(1); - State state = context.getState(State::Positions); - integrator.getPerDofVariable(0, values); - for (int j = 0; j < numParticles; j++) - ASSERT_EQUAL_VEC(initialValues[j], values[j], 1e-5); - integrator.getPerDofVariable(1, values); - for (int j = 0; j < numParticles; j++) - ASSERT_EQUAL_VEC(state.getPositions()[j], values[j], 1e-5); - } -} - -/** - * Test evaluating force groups separately. - */ -void testForceGroups() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - CustomIntegrator integrator(0.01); - integrator.addPerDofVariable("outf", 0); - integrator.addPerDofVariable("outf1", 0); - integrator.addPerDofVariable("outf2", 0); - integrator.addGlobalVariable("oute", 0); - integrator.addGlobalVariable("oute1", 0); - integrator.addGlobalVariable("oute2", 0); - integrator.addComputePerDof("outf", "f"); - integrator.addComputePerDof("outf1", "f1"); - integrator.addComputePerDof("outf2", "f2"); - integrator.addComputeGlobal("oute", "energy"); - integrator.addComputeGlobal("oute1", "energy1"); - integrator.addComputeGlobal("oute2", "energy2"); - HarmonicBondForce* bonds = new HarmonicBondForce(); - bonds->addBond(0, 1, 1.5, 1.1); - bonds->setForceGroup(1); - system.addForce(bonds); - NonbondedForce* nb = new NonbondedForce(); - nb->addParticle(0.2, 1, 0); - nb->addParticle(0.2, 1, 0); - nb->setForceGroup(2); - system.addForce(nb); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // See if the various forces are computed correctly. - - integrator.step(1); - vector f, f1, f2; - double e1 = 0.5*1.1*0.5*0.5; - double e2 = 138.935456*0.2*0.2/2.0; - integrator.getPerDofVariable(0, f); - integrator.getPerDofVariable(1, f1); - integrator.getPerDofVariable(2, f2); - ASSERT_EQUAL_VEC(Vec3(1.1*0.5, 0, 0), f1[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(-1.1*0.5, 0, 0), f1[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(-138.935456*0.2*0.2/4.0, 0, 0), f2[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(138.935456*0.2*0.2/4.0, 0, 0), f2[1], 1e-5); - ASSERT_EQUAL_VEC(f1[0]+f2[0], f[0], 1e-5); - ASSERT_EQUAL_VEC(f1[1]+f2[1], f[1], 1e-5); - ASSERT_EQUAL_TOL(e1, integrator.getGlobalVariable(1), 1e-5); - ASSERT_EQUAL_TOL(e2, integrator.getGlobalVariable(2), 1e-5); - ASSERT_EQUAL_TOL(e1+e2, integrator.getGlobalVariable(0), 1e-5); - - // Make sure they also match the values returned by the Context. - - State s = context.getState(State::Forces | State::Energy, false); - State s1 = context.getState(State::Forces | State::Energy, false, 2); - State s2 = context.getState(State::Forces | State::Energy, false, 4); - vector c, c1, c2; - c = context.getState(State::Forces, false).getForces(); - c1 = context.getState(State::Forces, false, 2).getForces(); - c2 = context.getState(State::Forces, false, 4).getForces(); - ASSERT_EQUAL_VEC(f[0], c[0], 1e-5); - ASSERT_EQUAL_VEC(f[1], c[1], 1e-5); - ASSERT_EQUAL_VEC(f1[0], c1[0], 1e-5); - ASSERT_EQUAL_VEC(f1[1], c1[1], 1e-5); - ASSERT_EQUAL_VEC(f2[0], c2[0], 1e-5); - ASSERT_EQUAL_VEC(f2[1], c2[1], 1e-5); - ASSERT_EQUAL_TOL(s.getPotentialEnergy(), integrator.getGlobalVariable(0), 1e-5); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), integrator.getGlobalVariable(1), 1e-5); - ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), integrator.getGlobalVariable(2), 1e-5); -} - -/** - * Test a multiple time step r-RESPA integrator. - */ -void testRespa() { - const int numParticles = 8; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - CustomIntegrator integrator(0.002); - integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); - for (int i = 0; i < 2; i++) { - integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); - integrator.addComputePerDof("x", "x+(dt/2)*v"); - integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); - } - integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); - HarmonicBondForce* bonds = new HarmonicBondForce(); - for (int i = 0; i < numParticles-2; i++) - bonds->addBond(i, i+1, 1.0, 0.5); - system.addForce(bonds); - NonbondedForce* nb = new NonbondedForce(); - nb->setCutoffDistance(2.0); - nb->setNonbondedMethod(NonbondedForce::Ewald); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - nb->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - nb->setForceGroup(1); - nb->setReciprocalSpaceForceGroup(0); - system.addForce(nb); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 monitor energy conservations. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Energy); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); - integrator.step(2); - } -} - -void testIfBlock() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addGlobalVariable("a", 0); - integrator.addGlobalVariable("b", 0); - integrator.addComputeGlobal("b", "1"); - integrator.beginIfBlock("a < 3.5"); - integrator.addComputeGlobal("b", "a+1"); - integrator.endBlock(); - Context context(system, integrator, platform); - - // Set "a" to 1.7 and verify that "b" gets set to a+1. - - integrator.setGlobalVariable(0, 1.7); - integrator.step(1); - ASSERT_EQUAL_TOL(2.7, integrator.getGlobalVariable(1), 1e-6); - - // Now set it to a value that should cause the block to be skipped. - - integrator.setGlobalVariable(0, 4.1); - integrator.step(1); - ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); -} - -void testWhileBlock() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - const double dt = 0.01; - CustomIntegrator integrator(dt); - integrator.addGlobalVariable("a", 0); - integrator.addGlobalVariable("b", 0); - integrator.addComputeGlobal("b", "1"); - integrator.beginWhileBlock("b <= a"); - integrator.addComputeGlobal("b", "b+1"); - integrator.endBlock(); - Context context(system, integrator, platform); - - // Try a case where the loop should be skipped. - - integrator.setGlobalVariable(0, -3.3); - integrator.step(1); - ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); - - // In this case it should be executed exactly once. - - integrator.setGlobalVariable(0, 1.2); - integrator.step(1); - ASSERT_EQUAL_TOL(2.0, integrator.getGlobalVariable(1), 1e-6); - - // In this case, it should be executed several times. - - integrator.setGlobalVariable(0, 5.3); - integrator.step(1); - ASSERT_EQUAL_TOL(6.0, integrator.getGlobalVariable(1), 1e-6); -} - - -int main() { - try { - testSingleBond(); - testConstraints(); - testVelocityConstraints(); - testConstrainedMasslessParticles(); - testWithThermostat(); - testMonteCarlo(); - testSum(); - testParameter(); - testRandomDistributions(); - testPerDofVariables(); - testForceGroups(); - testRespa(); - testIfBlock(); - testWhileBlock(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceCustomManyParticleForce.cpp b/platforms/reference/tests/TestReferenceCustomManyParticleForce.cpp index ec3f926a5..92036f049 100644 --- a/platforms/reference/tests/TestReferenceCustomManyParticleForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomManyParticleForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,627 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomManyParticleForce. - */ +#include "ReferenceTests.h" +#include "TestCustomManyParticleForce.h" -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomCompoundBondForce.h" -#include "openmm/CustomManyParticleForce.h" -#include "openmm/System.h" -#include "openmm/TabulatedFunction.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -Vec3 computeDelta(const Vec3& pos1, const Vec3& pos2, bool periodic, const Vec3* periodicBoxVectors) { - Vec3 diff = pos1-pos2; - if (periodic) { - diff -= periodicBoxVectors[2]*floor(diff[2]/periodicBoxVectors[2][2]+0.5); - diff -= periodicBoxVectors[1]*floor(diff[1]/periodicBoxVectors[1][1]+0.5); - diff -= periodicBoxVectors[0]*floor(diff[0]/periodicBoxVectors[0][0]+0.5); - } - return diff; -} - -void validateAxilrodTeller(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize, bool triclinic) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - Vec3 boxVectors[3]; - if (triclinic) { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0.2*boxSize, boxSize, 0); - boxVectors[2] = Vec3(-0.3*boxSize, -0.1*boxSize, boxSize); - } - else { - boxVectors[0] = Vec3(boxSize, 0, 0); - boxVectors[1] = Vec3(0, boxSize, 0); - boxVectors[2] = Vec3(0, 0, boxSize); - } - system.setDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]); - system.addForce(force); - if (force->getNonbondedMethod() == CustomManyParticleForce::CutoffPeriodic) { - ASSERT(force->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - } - else { - ASSERT(!force->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - } - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double c = context.getParameter("C"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - bool periodic = (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic); - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = computeDelta(positions[p2], positions[p1], periodic, boxVectors); - Vec3 d13 = computeDelta(positions[p3], positions[p1], periodic, boxVectors); - Vec3 d23 = computeDelta(positions[p3], positions[p2], periodic, boxVectors); - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - double rprod = r12*r13*r23; - expectedEnergy += c*(1+3*ctheta1*ctheta2*ctheta3)/(rprod*rprod*rprod); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void validateStillingerWeber(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize) { - // Create a System and Context. - - int numParticles = force->getNumParticles(); - CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - double L = context.getParameter("L"); - double eps = context.getParameter("eps"); - double a = context.getParameter("a"); - double gamma = context.getParameter("gamma"); - double sigma = context.getParameter("sigma"); - - // See if the energy matches the expected value. - - double expectedEnergy = 0; - for (int i = 0; i < (int) expectedSets.size(); i++) { - int p1 = expectedSets[i][0]; - int p2 = expectedSets[i][1]; - int p3 = expectedSets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - Vec3 d23 = positions[p3]-positions[p2]; - if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) { - for (int j = 0; j < 3; j++) { - d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize; - d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize; - d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize; - } - } - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - double ctheta1 = d12.dot(d13)/(r12*r13); - double ctheta2 = -d12.dot(d23)/(r12*r23); - double ctheta3 = d13.dot(d23)/(r13*r23); - expectedEnergy += L*eps*(ctheta1+1.0/3.0)*(ctheta1+1.0/3.0)*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma)); - } - ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - const vector& forces = state1.getForces(); - double norm = 0.0; - for (int i = 0; i < (int) forces.size(); ++i) - norm += forces[i].dot(forces[i]); - norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = 0.5*stepSize/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); -} - -void testNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - int sets[4][3] = {{0,1,2}, {1,2,3}, {2,3,0}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(1.55); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - int sets[7][3] = {{0,1,2}, {0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,2,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[7]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testPeriodic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[5][3] = {{0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, false); -} - -void testTriclinic() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); - force->setCutoffDistance(1.05); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - double boxSize = 2.1; - int sets[4][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {1,3,4}}; - vector expectedSets(&sets[0], &sets[4]); - validateAxilrodTeller(force, positions, expectedSets, boxSize, true); -} - -void testExclusions() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" - "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" - "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); - force->addGlobalParameter("C", 1.5); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - force->addExclusion(0, 2); - force->addExclusion(0, 3); - int sets[5][3] = {{0,1,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4}}; - vector expectedSets(&sets[0], &sets[5]); - validateAxilrodTeller(force, positions, expectedSets, 2.0, false); -} - -void testAllTerms() { - int numParticles = 4; - - // Create a system with a CustomManyParticleForce. - - System system1; - CustomManyParticleForce* force1 = new CustomManyParticleForce(4, - "distance(p1,p2)+angle(p1,p4,p3)+dihedral(p1,p3,p2,p4)+x1+y4+z3"); - system1.addForce(force1); - vector params; - for (int i = 0; i < numParticles; i++) { - system1.addParticle(1.0); - force1->addParticle(params, i); - } - set filter; - filter.insert(0); - force1->setTypeFilter(0, filter); - filter.clear(); - filter.insert(1); - force1->setTypeFilter(1, filter); - filter.clear(); - filter.insert(3); - force1->setTypeFilter(2, filter); - filter.clear(); - filter.insert(2); - force1->setTypeFilter(3, filter); - - // Create a system that use a CustomCompoundBondForce to compute exactly the same interactions. - - System system2; - CustomCompoundBondForce* force2 = new CustomCompoundBondForce(4, - "distance(p1,p2)+angle(p1,p3,p4)+dihedral(p1,p4,p2,p3)+x1+y3+z4"); - system2.addForce(force2); - vector particles; - particles.push_back(0); - particles.push_back(1); - particles.push_back(2); - particles.push_back(3); - force2->addBond(particles, params); - for (int i = 0; i < numParticles; i++) - system2.addParticle(1.0); - - // Create contexts for both of them. - - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - VerletIntegrator integrator1(0.001); - VerletIntegrator integrator2(0.001); - Context context1(system1, integrator1, platform); - Context context2(system2, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - - // See if they produce identical forces and energies. - - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state2.getForces()[i], state1.getForces()[i], 1e-4); -} - -void testParameters() { - // Create a system. - - int numParticles = 5; - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "C*scale1*scale2*scale3*(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))"); - force->addGlobalParameter("C", 2.0); - force->addPerParticleParameter("scale"); - vector params(1); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - params[0] = i+1; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 2.0*(i+1)*(j+1)*(k+1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); - - // Modify the parameters. - - context.setParameter("C", 3.5); - for (int i = 0; i < numParticles; i++) { - params[0] = 0.5*i-0.1; - force->setParticleParameters(i, params, 0); - } - force->updateParametersInContext(context); - - // See if the energy is still correct. - - state = context.getState(State::Energy); - expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 3.5*(0.5*i-0.1)*(0.5*j-0.1)*(0.5*k-0.1)*(r12+r13+r23); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTabulatedFunctions() { - int numParticles = 5; - - // Create two tabulated functions. - - vector values; - values.push_back(0.0); - values.push_back(50.0); - Continuous1DFunction* f1 = new Continuous1DFunction(values, 0, 100); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector c(numParticles); - for (int i = 0; i < numParticles; i++) - c[i] = genrand_real2(sfmt); - values.resize(numParticles*numParticles*numParticles); - for (int i = 0; i < numParticles; i++) - for (int j = 0; j < numParticles; j++) - for (int k = 0; k < numParticles; k++) - values[i+numParticles*j+numParticles*numParticles*k] = c[i]+c[j]+c[k]; - Discrete3DFunction* f2 = new Discrete3DFunction(numParticles, numParticles, numParticles, values); - - // Create a system. - - System system; - CustomManyParticleForce* force = new CustomManyParticleForce(3, "f1(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))*f2(atom1, atom2, atom3)"); - force->addPerParticleParameter("atom"); - force->addTabulatedFunction("f1", f1); - force->addTabulatedFunction("f2", f2); - vector params(1); - vector positions; - for (int i = 0; i < numParticles; i++) { - params[0] = i; - force->addParticle(params); - positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); - system.addParticle(1.0); - } - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - for (int i = 0; i < numParticles; i++) - for (int j = i+1; j < numParticles; j++) - for (int k = j+1; k < numParticles; k++) { - Vec3 d12 = positions[j]-positions[i]; - Vec3 d13 = positions[k]-positions[i]; - Vec3 d23 = positions[k]-positions[j]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - double r23 = sqrt(d23.dot(d23)); - expectedEnergy += 0.5*(r12+r13+r23)*(c[i]+c[j]+c[k]); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testTypeFilters() { - // Create a system. - - System system; - for (int i = 0; i < 5; i++) - system.addParticle(1.0); - CustomManyParticleForce* force = new CustomManyParticleForce(3, "c1*(distance(p1,p2)+distance(p1,p3))"); - force->addPerParticleParameter("c"); - double c[] = {1.0, 2.0, 1.3, 1.5, -2.1}; - int type[] = {0, 1, 0, 1, 5}; - vector params(1); - for (int i = 0; i < 5; i++) { - params[0] = c[i]; - force->addParticle(params, type[i]); - } - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(1, 0, 0)); - positions.push_back(Vec3(0, 1.1, 0.3)); - positions.push_back(Vec3(0.4, 0, -0.8)); - positions.push_back(Vec3(0.2, 0.5, -0.1)); - set f1, f2; - f1.insert(0); - f2.insert(1); - f2.insert(5); - force->setTypeFilter(0, f1); - force->setTypeFilter(1, f2); - force->setTypeFilter(2, f2); - system.addForce(force); - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - - // See if the energy is correct. - - State state = context.getState(State::Energy); - double expectedEnergy = 0; - int sets[6][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {2,1,3}, {2,1,4}, {2,3,4}}; - for (int i = 0; i < 6; i++) { - int p1 = sets[i][0]; - int p2 = sets[i][1]; - int p3 = sets[i][2]; - Vec3 d12 = positions[p2]-positions[p1]; - Vec3 d13 = positions[p3]-positions[p1]; - double r12 = sqrt(d12.dot(d12)); - double r13 = sqrt(d13.dot(d13)); - expectedEnergy += c[p1]*(r12+r13); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); -} - -void testCentralParticleModeNoCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[12][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {2,0,3}, {2, 1, 3}, {3,0,1}, {3,0,2}, {3,1,2}}; - vector expectedSets(&sets[0], &sets[12]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -void testCentralParticleModeCutoff() { - CustomManyParticleForce* force = new CustomManyParticleForce(3, - "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" - "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); - force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); - force->addGlobalParameter("L", 23.13); - force->addGlobalParameter("eps", 25.894776); - force->addGlobalParameter("a", 1.8); - force->addGlobalParameter("sigma", 0.23925); - force->addGlobalParameter("gamma", 1.2); - force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); - force->setCutoffDistance(0.155); - vector params; - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - force->addParticle(params); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(0.1, 0, 0)); - positions.push_back(Vec3(0, 0.11, 0.03)); - positions.push_back(Vec3(0.04, 0, -0.08)); - int sets[8][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {3,0,1}}; - vector expectedSets(&sets[0], &sets[8]); - validateStillingerWeber(force, positions, expectedSets, 2.0); -} - -int main() { - try { - testNoCutoff(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testExclusions(); - testAllTerms(); - testParameters(); - testTabulatedFunctions(); - testTypeFilters(); - testCentralParticleModeNoCutoff(); - testCentralParticleModeCutoff(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceCustomNonbondedForce.cpp b/platforms/reference/tests/TestReferenceCustomNonbondedForce.cpp index f922c3ffe..3ed4bfcd1 100644 --- a/platforms/reference/tests/TestReferenceCustomNonbondedForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomNonbondedForce.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,964 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of CustomNonbondedForce. - */ - -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "sfmt/SFMT.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomNonbondedForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSimpleExpression() { - 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()); - forceField->addParticle(vector()); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& 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() { - 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 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 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 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); - - // Try changing the global parameters and make sure it's still correct. - - 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); - - // Try changing the per-particle parameters and make sure it's still correct. - - params[0] = 1.6; - params[1] = 2.1; - forceField->setParticleParameters(0, params); - params[0] = 1.9; - params[1] = 2.8; - forceField->setParticleParameters(1, params); - forceField->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - forces = state.getForces(); - force = -1.5*1.6*1.9*3*5.9*(11.8*11.8); - 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*1.6*1.9*(11.8*11.8*11.8), state.getPotentialEnergy(), TOL); -} - -void testExclusions() { - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("a*r; a=a1+a2"); - nonbonded->addPerParticleParameter("a"); - vector params(1); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - forceField->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - forceField->setCutoffDistance(2.5); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& 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() { - 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()); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - 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); - ASSERT(forceField->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& 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 testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("r"); - nonbonded->addParticle(vector()); - nonbonded->addParticle(vector()); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta/sqrt(delta.dot(delta)); - ASSERT_EQUAL_TOL(distance, state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); - } - } -} - -void testContinuous1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - 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& forces = state.getForces(); - double force = (x < 1.0 || x > 6.0 ? 0.0 : -cos(x-1.0)); - double energy = (x < 1.0 || x > 6.0 ? 0.0 : 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 : sin(x-1.0))+1.0; - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); - } -} - -void testContinuous2DFunction() { - const int xsize = 20; - const int ysize = 21; - const double xmin = 0.4; - const double xmax = 1.5; - const double ymin = 0.0; - const double ymax = 2.1; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); - } - } - forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { - energy = sin(0.25*x)*cos(0.33*y)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y); - } - 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); - } - } -} - -void testContinuous3DFunction() { - const int xsize = 10; - const int ysize = 11; - const int zsize = 12; - const double xmin = 0.6; - const double xmax = 1.1; - const double ymin = 0.0; - const double ymax = 0.7; - const double zmin = 0.2; - const double zmax = 0.9; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table(xsize*ysize*zsize); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - for (int k = 0; k < zsize; k++) { - double x = xmin + i*(xmax-xmin)/xsize; - double y = ymin + j*(ymax-ymin)/ysize; - double z = zmin + k*(zmax-zmin)/zsize; - table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); - } - } - } - forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { - for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { - for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { - positions[1] = Vec3(x, 0, 0); - context.setParameter("a", y); - context.setParameter("b", z); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double energy = 1; - double force = 0; - if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { - energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1.0; - force = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); - } - 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.05); - } - } - } -} - -void testDiscrete1DFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < 21; i++) - table.push_back(sin(0.25*i)); - forceField->addTabulatedFunction("fn", new Discrete1DFunction(table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete2DFunction() { - const int xsize = 10; - const int ysize = 5; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - table.push_back(sin(0.25*i)+cos(0.33*j)); - forceField->addTabulatedFunction("fn", new Discrete2DFunction(xsize, ysize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i%xsize, 0, 0); - context.setPositions(positions); - context.setParameter("a", i/xsize); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testDiscrete3DFunction() { - const int xsize = 8; - const int ysize = 5; - const int zsize = 6; - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); - forceField->addGlobalParameter("a", 0.0); - forceField->addGlobalParameter("b", 0.0); - forceField->addParticle(vector()); - forceField->addParticle(vector()); - vector table; - for (int i = 0; i < xsize; i++) - for (int j = 0; j < ysize; j++) - for (int k = 0; k < zsize; k++) - table.push_back(sin(0.25*i)+cos(0.33*j)+0.12345*k); - forceField->addTabulatedFunction("fn", new Discrete3DFunction(xsize, ysize, zsize, table)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - for (int i = 0; i < (int) table.size(); i++) { - positions[1] = Vec3(i%xsize, 0, 0); - context.setPositions(positions); - context.setParameter("a", (i/xsize)%ysize); - context.setParameter("b", i/(xsize*ysize)); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); - ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); - } -} - -void testCoulombLennardJones() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // 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 positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - vector 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); - ASSERT(!customNonbonded->usesPeriodicBoundaryConditions()); - ASSERT(!customSystem.usesPeriodicBoundaryConditions()); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context context1(standardSystem, integrator1, platform); - Context context2(customSystem, integrator2, platform); - context1.setPositions(positions); - context2.setPositions(positions); - context1.setVelocities(velocities); - context2.setVelocities(velocities); - State state1 = context1.getState(State::Forces | State::Energy); - State state2 = context2.getState(State::Forces | State::Energy); - ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); - } -} - -void testSwitchingFunction() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("10/r^2"); - vector params; - nonbonded->addParticle(params); - nonbonded->addParticle(params); - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double expectedEnergy = 10/(r*r); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - -void testLongRangeCorrection() { - // Create a box of particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System standardSystem; - System customSystem; - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - NonbondedForce* standardNonbonded = new NonbondedForce(); - CustomNonbondedForce* customNonbonded = new CustomNonbondedForce("4*eps*((sigma/r)^12-(sigma/r)^6); sigma=0.5*(sigma1+sigma2); eps=sqrt(eps1*eps2)"); - customNonbonded->addPerParticleParameter("sigma"); - customNonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - int index = 0; - vector params1(2); - params1[0] = 1.1; - params1[1] = 0.5; - vector params2(2); - params2[0] = 1; - params2[1] = 1; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - standardSystem.addParticle(1.0); - customSystem.addParticle(1.0); - if (index%2 == 0) { - standardNonbonded->addParticle(0, params1[0], params1[1]); - customNonbonded->addParticle(params1); - } - else { - standardNonbonded->addParticle(0, params2[0], params2[1]); - customNonbonded->addParticle(params2); - } - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - standardNonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - customNonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - standardNonbonded->setCutoffDistance(cutoff); - customNonbonded->setCutoffDistance(cutoff); - standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - standardNonbonded->setUseDispersionCorrection(true); - customNonbonded->setUseLongRangeCorrection(true); - standardNonbonded->setUseSwitchingFunction(true); - customNonbonded->setUseSwitchingFunction(true); - standardNonbonded->setSwitchingDistance(0.8*cutoff); - customNonbonded->setSwitchingDistance(0.8*cutoff); - standardSystem.addForce(standardNonbonded); - customSystem.addForce(customNonbonded); - - // Compute the correction for the standard force. - - Context context1(standardSystem, integrator1, platform); - context1.setPositions(positions); - double standardEnergy1 = context1.getState(State::Energy).getPotentialEnergy(); - standardNonbonded->setUseDispersionCorrection(false); - context1.reinitialize(); - context1.setPositions(positions); - double standardEnergy2 = context1.getState(State::Energy).getPotentialEnergy(); - - // Compute the correction for the custom force. - - Context context2(customSystem, integrator2, platform); - context2.setPositions(positions); - double customEnergy1 = context2.getState(State::Energy).getPotentialEnergy(); - customNonbonded->setUseLongRangeCorrection(false); - context2.reinitialize(); - context2.setPositions(positions); - double customEnergy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // See if they agree. - - ASSERT_EQUAL_TOL(standardEnergy1-standardEnergy2, customEnergy1-customEnergy2, 1e-4); -} - -void testInteractionGroups() { - const int numParticles = 6; - System system; - VerletIntegrator integrator(0.01); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("v1+v2"); - nonbonded->addPerParticleParameter("v"); - vector params(1, 0.001); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(params); - params[0] *= 10; - } - set set1, set2, set3, set4; - set1.insert(2); - set2.insert(0); - set2.insert(1); - set2.insert(2); - set2.insert(3); - set2.insert(4); - set2.insert(5); - nonbonded->addInteractionGroup(set1, set2); // Particle 2 interacts with every other particle. - set3.insert(0); - set3.insert(1); - set4.insert(4); - set4.insert(5); - nonbonded->addInteractionGroup(set3, set4); // Particles 0 and 1 interact with 4 and 5. - nonbonded->addExclusion(1, 2); // Add an exclusion to make sure it gets skipped. - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - context.setPositions(positions); - State state = context.getState(State::Energy); - double expectedEnergy = 331.423; // Each digit is the number of interactions a particle particle is involved in. - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), TOL); -} - -void testLargeInteractionGroup() { - const int numMolecules = 300; - const int numParticles = numMolecules*2; - const double boxSize = 20.0; - - // Create a large system. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - CustomNonbondedForce* nonbonded = 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)"); - nonbonded->addPerParticleParameter("q"); - nonbonded->addPerParticleParameter("sigma"); - nonbonded->addPerParticleParameter("eps"); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector params(3); - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.1; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->addParticle(params); - } - else { - params[0] = 1.0; - params[1] = 0.2; - params[2] = 0.2; - nonbonded->addParticle(params); - params[0] = -1.0; - params[1] = 0.1; - nonbonded->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]); - nonbonded->addExclusion(2*i, 2*i+1); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Compute the forces. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces); - - // Modify the force so only one particle interacts with everything else. - - set set1, set2; - set1.insert(151); - for (int i = 0; i < numParticles; i++) - set2.insert(i); - nonbonded->addInteractionGroup(set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state2 = context.getState(State::Forces); - - // The force on that one particle should be the same. - - ASSERT_EQUAL_VEC(state1.getForces()[151], state2.getForces()[151], 1e-4); - - // Modify the interaction group so it includes all interactions. This should now reproduce the original forces - // on all atoms. - - for (int i = 0; i < numParticles; i++) - set1.insert(i); - nonbonded->setInteractionGroupParameters(0, set1, set2); - context.reinitialize(); - context.setPositions(positions); - State state3 = context.getState(State::Forces); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(state1.getForces()[i], state3.getForces()[i], 1e-4); -} - -void testInteractionGroupLongRangeCorrection() { - const int numParticles = 10; - const double boxSize = 10.0; - const double cutoff = 0.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - CustomNonbondedForce* nonbonded = new CustomNonbondedForce("c1*c2*r^-4"); - nonbonded->addPerParticleParameter("c"); - vector positions(numParticles); - vector params(1); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - params[0] = (i%2 == 0 ? 1.1 : 2.0); - nonbonded->addParticle(params); - positions[i] = Vec3(0.5*i, 0, 0); - } - nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - - // Setup nonbonded groups. They involve 1 interaction of type AA, - // 2 of type BB, and 5 of type AB. - - set set1, set2, set3, set4, set5; - set1.insert(0); - set1.insert(1); - set1.insert(2); - nonbonded->addInteractionGroup(set1, set1); - set2.insert(3); - set3.insert(4); - set3.insert(6); - set3.insert(8); - nonbonded->addInteractionGroup(set2, set3); - set4.insert(5); - set5.insert(7); - set5.insert(9); - nonbonded->addInteractionGroup(set4, set5); - - // Compute energy with and without the correction. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseLongRangeCorrection(true); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - - // Check the result. - - double sum = (1.1*1.1 + 2*2.0*2.0 + 5*1.1*2.0)*2.0; - int numPairs = (numParticles*(numParticles+1))/2; - double expected = 2*M_PI*numParticles*numParticles*sum/(numPairs*boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy2-energy1, 1e-4); -} - -void testMultipleCutoffs() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - - // Add multiple nonbonded forces that have different cutoffs. - - CustomNonbondedForce* nonbonded1 = new CustomNonbondedForce("2*r"); - nonbonded1->addParticle(vector()); - nonbonded1->addParticle(vector()); - nonbonded1->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded1->setCutoffDistance(2.5); - system.addForce(nonbonded1); - CustomNonbondedForce* nonbonded2 = new CustomNonbondedForce("3*r"); - nonbonded2->addParticle(vector()); - nonbonded2->addParticle(vector()); - nonbonded2->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); - nonbonded2->setCutoffDistance(2.9); - nonbonded2->setForceGroup(1); - system.addForce(nonbonded2); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(0, 0, 0); - for (double r = 2.4; r < 3.2; r += 0.2) { - positions[1][1] = r; - context.setPositions(positions); - double e1 = (r < 2.5 ? 2.0*r : 0.0); - double e2 = (r < 2.9 ? 3.0*r : 0.0); - double f1 = (r < 2.5 ? 2.0 : 0.0); - double f2 = (r < 2.9 ? 3.0 : 0.0); - - // Check the first force. - - State state = context.getState(State::Forces | State::Energy, false, 1); - ASSERT_EQUAL_VEC(Vec3(0, f1, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1, state.getPotentialEnergy(), TOL); - - // Check the second force. - - state = context.getState(State::Forces | State::Energy, false, 2); - ASSERT_EQUAL_VEC(Vec3(0, f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e2, state.getPotentialEnergy(), TOL); - - // Check the sum of both forces. - - state = context.getState(State::Forces | State::Energy); - ASSERT_EQUAL_VEC(Vec3(0, f1+f2, 0), state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, -f1-f2, 0), state.getForces()[1], TOL); - ASSERT_EQUAL_TOL(e1+e2, state.getPotentialEnergy(), TOL); - } -} +#include "ReferenceTests.h" +#include "TestCustomNonbondedForce.h" -int main() { - try { - testSimpleExpression(); - testParameters(); - testExclusions(); - testCutoff(); - testPeriodic(); - testTriclinic(); - testContinuous1DFunction(); - testContinuous2DFunction(); - testContinuous3DFunction(); - testDiscrete1DFunction(); - testDiscrete2DFunction(); - testDiscrete3DFunction(); - testCoulombLennardJones(); - testSwitchingFunction(); - testLongRangeCorrection(); - testInteractionGroups(); - testLargeInteractionGroup(); - testInteractionGroupLongRangeCorrection(); - testMultipleCutoffs(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceCustomTorsionForce.cpp b/platforms/reference/tests/TestReferenceCustomTorsionForce.cpp index b2dcb3e5b..205169867 100644 --- a/platforms/reference/tests/TestReferenceCustomTorsionForce.cpp +++ b/platforms/reference/tests/TestReferenceCustomTorsionForce.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,162 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of CustomTorsionForce. - */ +#include "ReferenceTests.h" +#include "TestCustomTorsionForce.h" -#ifdef WIN32 - #define _USE_MATH_DEFINES // Needed to get M_PI -#endif -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomTorsionForce.h" -#include "openmm/PeriodicTorsionForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testTorsions() { - // 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 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); - ASSERT(!custom->usesPeriodicBoundaryConditions()); - ASSERT(!customSystem.usesPeriodicBoundaryConditions()); - - // 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 positions(5); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context c1(customSystem, integrator1, platform); - Context c2(harmonicSystem, integrator2, platform); - for (int i = 0; i < 50; 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } - - // Try changing the torsion parameters and make sure it's still correct. - - parameters[0] = 1.6; - parameters[1] = 2; - custom->setTorsionParameters(0, 0, 1, 2, 3, parameters); - parameters[0] = 2.1; - parameters[1] = 3; - custom->setTorsionParameters(1, 1, 2, 3, 4, parameters); - custom->updateParametersInContext(c1); - periodic->setTorsionParameters(0, 0, 1, 2, 3, 2, 1.6, 0.5); - periodic->setTorsionParameters(1, 1, 2, 3, 4, 3, 2.1, 0.5); - periodic->updateParametersInContext(c2); - { - 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)); - c1.setPositions(positions); - c2.setPositions(positions); - State s1 = c1.getState(State::Forces | State::Energy); - State s2 = c2.getState(State::Forces | State::Energy); - const vector& forces = s1.getForces(); - for (int i = 0; i < customSystem.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); - ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); - } +void runPlatformTests() { } - -void testRange() { - 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()); - 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 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; -} - - - diff --git a/tests/TestAndersenThermostat.h b/tests/TestAndersenThermostat.h new file mode 100644 index 000000000..716814432 --- /dev/null +++ b/tests/TestAndersenThermostat.h @@ -0,0 +1,215 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/AndersenThermostat.h" +#include "openmm/Context.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +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 = 5000; + System system; + VerletIntegrator integrator(0.003); + 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); + ASSERT(!thermostat->usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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); + context.setVelocitiesToTemperature(temp); + + // 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(10); + } + ke /= numSteps; + double expected = 0.5*numParticles*3*BOLTZ*temp; + ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); +} + +void testConstraints() { + const int numParticles = 8; + const double temp = 100.0; + const double collisionFreq = 10.0; + const int numSteps = 15000; + System system; + VerletIntegrator integrator(0.004); + 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* thermostat = new AndersenThermostat(temp, collisionFreq); + system.addForce(thermostat); + Context context(system, integrator, platform); + vector 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); + context.setVelocitiesToTemperature(temp); + + // Let it equilibrate. + + integrator.step(5000); + + // 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_USUALLY_EQUAL_TOL(expected, ke, 0.1); +} + +void testRandomSeed() { + const int numParticles = 8; + const double temp = 100.0; + const double collisionFreq = 10.0; + 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 positions(numParticles); + vector 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]); + } + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testTemperature(); + testConstraints(); + testRandomSeed(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestBrownianIntegrator.h b/tests/TestBrownianIntegrator.h new file mode 100644 index 000000000..2dd858bda --- /dev/null +++ b/tests/TestBrownianIntegrator.h @@ -0,0 +1,272 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/BrownianIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSingleBond() { + 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 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; + 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 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; + 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 positions(numParticles); + vector 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 testConstrainedMasslessParticles() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + system.addConstraint(0, 1, 1.5); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + BrownianIntegrator integrator(300.0, 2.0, 0.01); + bool failed = false; + try { + // This should throw an exception. + + Context context(system, integrator, platform); + } + catch (exception& ex) { + failed = true; + } + ASSERT(failed); + + // Now make both particles massless, which should work. + + system.setParticleMass(1, 0.0); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(300.0); + integrator.step(1); + State state = context.getState(State::Velocities); + ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +} + +void testRandomSeed() { + const int numParticles = 8; + const double temp = 100.0; + const double collisionFreq = 10.0; + 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 positions(numParticles); + vector 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]); + } + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleBond(); + testTemperature(); + testConstraints(); + testConstrainedMasslessParticles(); + testRandomSeed(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCMAPTorsionForce.h b/tests/TestCMAPTorsionForce.h new file mode 100644 index 000000000..54a2b90f6 --- /dev/null +++ b/tests/TestCMAPTorsionForce.h @@ -0,0 +1,177 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CMAPTorsionForce.h" +#include "openmm/PeriodicTorsionForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +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. + + 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); + ASSERT(!periodic->usesPeriodicBoundaryConditions()); + ASSERT(!system1.usesPeriodicBoundaryConditions()); + System system2; + for (int i = 0; i < 5; i++) + system2.addParticle(1.0); + CMAPTorsionForce* cmap = new CMAPTorsionForce(); + vector 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); + ASSERT(!cmap->usesPeriodicBoundaryConditions()); + ASSERT(!system2.usesPeriodicBoundaryConditions()); + + // 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 positions(5); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context c1(system1, integrator1, platform); + Context c2(system2, integrator2, platform); + for (int i = 0; i < 50; 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)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < system1.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 0.05); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), 1e-3); + } +} + +void testChangingParameters() { + // Create a system with two maps and one torsion. + + const int mapSize = 8; + System system; + for (int i = 0; i < 5; i++) + system.addParticle(1.0); + CMAPTorsionForce* cmap = new CMAPTorsionForce(); + vector mapEnergy1(mapSize*mapSize); + vector mapEnergy2(mapSize*mapSize); + for (int i = 0; i < mapSize; i++) { + double angle1 = i*2*M_PI/mapSize; + double energy1 = cos(angle1); + for (int j = 0; j < mapSize; j++) { + double angle2 = j*2*M_PI/mapSize; + double energy2 = 10*sin(angle2); + mapEnergy1[i+j*mapSize] = energy1+energy2; + mapEnergy2[i+j*mapSize] = energy1-energy2; + } + } + cmap->addMap(mapSize, mapEnergy1); + cmap->addMap(mapSize, mapEnergy2); + cmap->addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4); + system.addForce(cmap); + + // Set particle positions so angle1=0 and angle2=PI/4. + + vector positions(5); + positions[0] = Vec3(0, 0, 1); + positions[1] = Vec3(0, 0, 0); + positions[2] = Vec3(1, 0, 0); + positions[3] = Vec3(1, 0, 1); + positions[4] = Vec3(0.5, -0.5, 1); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + + // Check that the energy is correct. + + double energy = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL(1+10*sin(M_PI/4), energy, 1e-5); + + // Modify the parameters. + + cmap->setTorsionParameters(0, 1, 0, 1, 2, 3, 1, 2, 3, 4); + for (int i = 0; i < mapSize*mapSize; i++) + mapEnergy2[i] *= 2.0; + cmap->setMapParameters(1, mapSize, mapEnergy2); + cmap->updateParametersInContext(context); + + // See if the results are correct. + + energy = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL(2-20*sin(M_PI/4), energy, 1e-5); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testCMAPTorsions(); + testChangingParameters(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + diff --git a/tests/TestCMMotionRemover.h b/tests/TestCMMotionRemover.h new file mode 100644 index 000000000..cc100181e --- /dev/null +++ b/tests/TestCMMotionRemover.h @@ -0,0 +1,117 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/CMMotionRemover.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/LangevinIntegrator.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +Vec3 calcCM(const vector& 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; + 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 positions(numParticles); + vector 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); + } + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + LangevinIntegrator langevin(0.0, 1e-5, 0.01); + testMotionRemoval(langevin); + VerletIntegrator verlet(0.01); + testMotionRemoval(verlet); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCustomExternalForce.h b/tests/TestCustomExternalForce.h index 59ba5be4c..5575639ed 100644 --- a/tests/TestCustomExternalForce.h +++ b/tests/TestCustomExternalForce.h @@ -167,6 +167,7 @@ void testPeriodic() { } } + void runPlatformTests(); int main(int argc, char* argv[]) { diff --git a/tests/TestCustomGBForce.h b/tests/TestCustomGBForce.h index 175611f9e..6840119df 100644 --- a/tests/TestCustomGBForce.h +++ b/tests/TestCustomGBForce.h @@ -455,16 +455,18 @@ void testExclusions() { for (int i = 0; i < (int) forces.size(); ++i) norm += forces[i].dot(forces[i]); norm = std::sqrt(norm); - const double stepSize = 1e-3; - double step = stepSize/norm; - for (int i = 0; i < (int) positions.size(); ++i) { - Vec3 p = positions[i]; - Vec3 f = forces[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + if (norm > 0) { + const double stepSize = 1e-3; + double step = stepSize/norm; + for (int i = 0; i < (int) positions.size(); ++i) { + Vec3 p = positions[i]; + Vec3 f = forces[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); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); } - context.setPositions(positions); - State state2 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/stepSize, 1e-3*abs(state.getPotentialEnergy())); } } diff --git a/tests/TestCustomHbondForce.h b/tests/TestCustomHbondForce.h new file mode 100644 index 000000000..344d0d2b5 --- /dev/null +++ b/tests/TestCustomHbondForce.h @@ -0,0 +1,246 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomHbondForce.h" +#include "openmm/HarmonicAngleForce.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/PeriodicTorsionForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testHbond() { + // Create a system using a CustomHbondForce. + + System customSystem; + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + customSystem.addParticle(1.0); + CustomHbondForce* custom = new CustomHbondForce("0.5*kr*(distance(d1,a1)-r0)^2 + 0.5*ktheta*(angle(a1,d1,d2)-theta0)^2 + 0.5*kpsi*(angle(d1,a1,a2)-psi0)^2 + kchi*(1+cos(n*dihedral(a3,a2,a1,d1)-chi0))"); + custom->addPerDonorParameter("r0"); + custom->addPerDonorParameter("theta0"); + custom->addPerDonorParameter("psi0"); + custom->addPerAcceptorParameter("chi0"); + custom->addPerAcceptorParameter("n"); + custom->addGlobalParameter("kr", 0.4); + custom->addGlobalParameter("ktheta", 0.5); + custom->addGlobalParameter("kpsi", 0.6); + custom->addGlobalParameter("kchi", 0.7); + vector parameters(3); + parameters[0] = 1.5; + parameters[1] = 1.7; + parameters[2] = 1.9; + custom->addDonor(1, 0, -1, parameters); + parameters.resize(2); + parameters[0] = 2.1; + parameters[1] = 2; + custom->addAcceptor(2, 3, 4, parameters); + custom->setCutoffDistance(10.0); + customSystem.addForce(custom); + ASSERT(!custom->usesPeriodicBoundaryConditions()); + ASSERT(!customSystem.usesPeriodicBoundaryConditions()); + + // Create an identical system using HarmonicBondForce, HarmonicAngleForce, and PeriodicTorsionForce. + + System standardSystem; + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + standardSystem.addParticle(1.0); + HarmonicBondForce* bond = new HarmonicBondForce(); + bond->addBond(1, 2, 1.5, 0.4); + standardSystem.addForce(bond); + HarmonicAngleForce* angle = new HarmonicAngleForce(); + angle->addAngle(0, 1, 2, 1.7, 0.5); + angle->addAngle(1, 2, 3, 1.9, 0.6); + standardSystem.addForce(angle); + PeriodicTorsionForce* torsion = new PeriodicTorsionForce(); + torsion->addTorsion(1, 2, 3, 4, 2, 2.1, 0.7); + standardSystem.addForce(torsion); + + // 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 positions(5); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context c1(customSystem, integrator1, platform); + Context c2(standardSystem, integrator2, platform); + for (int i = 0; i < 10; i++) { + for (int j = 0; j < (int) positions.size(); j++) + positions[j] = Vec3(2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); + } + + // Try changing the parameters and make sure it's still correct. + + parameters.resize(3); + parameters[0] = 1.4; + parameters[1] = 1.7; + parameters[2] = 1.9; + custom->setDonorParameters(0, 1, 0, -1, parameters); + parameters.resize(2); + parameters[0] = 2.2; + parameters[1] = 2; + custom->setAcceptorParameters(0, 2, 3, 4, parameters); + bond->setBondParameters(0, 1, 2, 1.4, 0.4); + torsion->setTorsionParameters(0, 1, 2, 3, 4, 2, 2.2, 0.7); + custom->updateParametersInContext(c1); + bond->updateParametersInContext(c2); + torsion->updateParametersInContext(c2); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); +} + +void testExclusions() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); + custom->addDonor(0, 1, -1, vector()); + custom->addDonor(1, 0, -1, vector()); + custom->addAcceptor(2, 0, -1, vector()); + custom->addExclusion(1, 0); + system.addForce(custom); + Context context(system, integrator, platform); + vector positions(3); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(0, 2, 0); + positions[2] = Vec3(2, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); + ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); + ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); +} + +void testCutoff() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomHbondForce* custom = new CustomHbondForce("(distance(d1,a1)-1)^2"); + custom->addDonor(0, 1, -1, vector()); + custom->addDonor(1, 0, -1, vector()); + custom->addAcceptor(2, 0, -1, vector()); + custom->setNonbondedMethod(CustomHbondForce::CutoffNonPeriodic); + custom->setCutoffDistance(2.5); + system.addForce(custom); + Context context(system, integrator, platform); + vector positions(3); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(0, 3, 0); + positions[2] = Vec3(2, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(2, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], TOL); + ASSERT_EQUAL_VEC(Vec3(-2, 0, 0), forces[2], TOL); + ASSERT_EQUAL_TOL(1.0, state.getPotentialEnergy(), TOL); +} + +void testCustomFunctions() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomHbondForce* custom = new CustomHbondForce("foo(distance(d1,a1))"); + custom->addDonor(1, 0, -1, vector()); + custom->addDonor(2, 0, -1, vector()); + custom->addAcceptor(0, 1, -1, vector()); + vector function(2); + function[0] = 0; + function[1] = 1; + custom->addTabulatedFunction("foo", new Continuous1DFunction(function, 0, 10)); + system.addForce(custom); + Context context(system, integrator, platform); + vector positions(3); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(0, 2, 0); + positions[2] = Vec3(2, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0.1, 0.1, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -0.1, 0), forces[1], TOL); + ASSERT_EQUAL_VEC(Vec3(-0.1, 0, 0), forces[2], TOL); + ASSERT_EQUAL_TOL(0.1*2+0.1*2, state.getPotentialEnergy(), TOL); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testHbond(); + testExclusions(); + testCutoff(); + testCustomFunctions(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + diff --git a/tests/TestCustomIntegrator.h b/tests/TestCustomIntegrator.h new file mode 100644 index 000000000..1ca894d2e --- /dev/null +++ b/tests/TestCustomIntegrator.h @@ -0,0 +1,798 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/AndersenThermostat.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/CustomIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +/** + * Test a simple leapfrog integrator on a single bond. + */ +void testSingleBond() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + const double dt = 0.01; + CustomIntegrator integrator(dt); + integrator.addComputePerDof("v", "v+dt*f/m"); + integrator.addComputePerDof("x", "x+dt*v"); + integrator.setKineticEnergyExpression("m*v1*v1/2; v1=v+0.5*dt*f/m"); + HarmonicBondForce* forceField = new HarmonicBondForce(); + forceField->addBond(0, 1, 1.5, 1); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + vector velocities(2); + velocities[0] = Vec3(-0.5*dt*0.5*0.5, 0, 0); + velocities[1] = Vec3(0.5*dt*0.5*0.5, 0, 0); + context.setVelocities(velocities); + + // This is simply a harmonic oscillator, so compare it to the analytical solution. + + const double freq = 1.0;; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Velocities | State::Energy); + double time = state.getTime(); + double expectedDist = 1.5+0.5*std::cos(freq*time); + ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 1e-4); + ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 1e-4); + double expectedSpeed = -0.5*freq*std::sin(freq*(time-dt/2)); + ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 1e-4); + ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 1e-4); + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + ASSERT_EQUAL_TOL(0.5*0.5*0.5, energy, 1e-4); + integrator.step(1); + } +} + +/** + * Test an integrator that enforces constraints. + */ +void testConstraints() { + const int numParticles = 8; + const double temp = 500.0; + System system; + CustomIntegrator integrator(0.002); + integrator.addPerDofVariable("oldx", 0); + integrator.addComputePerDof("v", "v+dt*f/m"); + integrator.addComputePerDof("oldx", "x"); + integrator.addComputePerDof("x", "x+dt*v"); + integrator.addConstrainPositions(); + integrator.addComputePerDof("v", "(x-oldx)/dt"); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i%2 == 0 ? 5.0 : 10.0); + forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); + } + for (int i = 0; i < numParticles-1; ++i) + system.addConstraint(i, i+1, 1.0); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(numParticles); + vector 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. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Energy); + for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); + } + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + if (i == 1) + initialEnergy = energy; + else if (i > 1) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + integrator.step(1); + } +} + +/** + * Test an integrator that applies constraints directly to velocities. + */ +void testVelocityConstraints() { + const int numParticles = 10; + System system; + CustomIntegrator integrator(0.002); + integrator.addPerDofVariable("x1", 0); + integrator.addComputePerDof("v", "v+0.5*dt*f/m"); + integrator.addComputePerDof("x", "x+dt*v"); + integrator.addComputePerDof("x1", "x"); + integrator.addConstrainPositions(); + integrator.addComputePerDof("v", "v+0.5*dt*f/m+(x-x1)/dt"); + integrator.addConstrainVelocities(); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i%2 == 0 ? 5.0 : 10.0); + forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); + } + + // Constrain the first three particles with SHAKE. + + system.addConstraint(0, 1, 1.0); + system.addConstraint(1, 2, 1.0); + + // Constrain the next three with SETTLE. + + system.addConstraint(3, 4, 1.0); + system.addConstraint(5, 4, 1.0); + system.addConstraint(3, 5, sqrt(2.0)); + + // Constraint the rest with CCMA. + + for (int i = 6; i < numParticles-1; ++i) + system.addConstraint(i, i+1, 1.0); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(numParticles); + vector 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. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + integrator.step(2); + State state = context.getState(State::Positions | State::Velocities | State::Energy); + for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); + if (i > 0) { + Vec3 v1 = state.getVelocities()[particle1]; + Vec3 v2 = state.getVelocities()[particle2]; + double vel = (v1-v2).dot(p1-p2); + ASSERT_EQUAL_TOL(0.0, vel, 2e-5); + } + } + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + if (i == 0) + initialEnergy = energy; + else if (i > 0) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + } +} + +void testConstrainedMasslessParticles() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + system.addConstraint(0, 1, 1.5); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + CustomIntegrator integrator(0.002); + integrator.addPerDofVariable("oldx", 0); + integrator.addComputePerDof("v", "v+dt*f/m"); + integrator.addComputePerDof("oldx", "x"); + integrator.addComputePerDof("x", "x+dt*v"); + integrator.addConstrainPositions(); + integrator.addComputePerDof("v", "(x-oldx)/dt"); + bool failed = false; + try { + // This should throw an exception. + + Context context(system, integrator, platform); + } + catch (exception& ex) { + failed = true; + } + ASSERT(failed); + + // Now make both particles massless, which should work. + + system.setParticleMass(1, 0.0); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(300.0); + integrator.step(1); + State state = context.getState(State::Velocities | State::Positions); + ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +} + +/** + * Test an integrator with an AndersenThermostat to see if updateContextState() + * is being handled correctly. + */ +void testWithThermostat() { + const int numParticles = 8; + const double temp = 100.0; + const double collisionFreq = 10.0; + const int numSteps = 5000; + System system; + CustomIntegrator integrator(0.003); + integrator.addUpdateContextState(); + integrator.addComputePerDof("v", "v+dt*f/m"); + integrator.addComputePerDof("x", "x+dt*v"); + 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); + Context context(system, integrator, platform); + vector 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); + context.setVelocitiesToTemperature(temp); + + // 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(10); + } + ke /= numSteps; + double expected = 0.5*numParticles*3*BOLTZ*temp; + ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); +} + +/** + * Test a Monte Carlo integrator that uses global variables and depends on energy. + */ +void testMonteCarlo() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + CustomIntegrator integrator(0.1); + const double kT = BOLTZ*300.0; + integrator.addGlobalVariable("kT", kT); + integrator.addGlobalVariable("oldE", 0); + integrator.addGlobalVariable("accept", 0); + integrator.addPerDofVariable("oldx", 0); + integrator.addComputeGlobal("oldE", "energy"); + integrator.addComputePerDof("oldx", "x"); + integrator.addComputePerDof("x", "x+dt*gaussian"); + integrator.addComputeGlobal("accept", "step(exp((oldE-energy)/kT)-uniform)"); + integrator.addComputePerDof("x", "select(accept, x, oldx)"); + HarmonicBondForce* forceField = new HarmonicBondForce(); + forceField->addBond(0, 1, 2.0, 10.0); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + + // Compute the histogram of distances and see if it satisfies a Boltzmann distribution. + + const int numBins = 100; + const double maxDist = 4.0; + const int numIterations = 5000; + vector counts(numBins, 0); + for (int i = 0; i < numIterations; ++i) { + integrator.step(10); + State state = context.getState(State::Positions); + Vec3 delta = state.getPositions()[0]-state.getPositions()[1]; + double dist = sqrt(delta.dot(delta)); + if (dist < maxDist) + counts[(int) (numBins*dist/maxDist)]++; + } + vector expected(numBins, 0); + double sum = 0; + for (int i = 0; i < numBins; i++) { + double dist = (i+0.5)*maxDist/numBins; + expected[i] = dist*dist*exp(-5.0*(dist-2)*(dist-2)/kT); + sum += expected[i]; + } + for (int i = 0; i < numBins; i++) + ASSERT_USUALLY_EQUAL_TOL((double) counts[i]/numIterations, expected[i]/sum, 0.01); +} + +/** + * Test the ComputeSum operation. + */ +void testSum() { + const int numParticles = 200; + const double boxSize = 10; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + NonbondedForce* nb = new NonbondedForce(); + system.addForce(nb); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; i++) { + system.addParticle(i%10 == 0 ? 0.0 : 1.5); + nb->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.1, 1); + bool close = true; + while (close) { + positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + close = false; + for (int j = 0; j < i; ++j) { + Vec3 delta = positions[i]-positions[j]; + if (delta.dot(delta) < 1) + close = true; + } + } + } + CustomIntegrator integrator(0.005); + integrator.addGlobalVariable("ke", 0); + integrator.addComputePerDof("v", "v+dt*f/m"); + integrator.addComputePerDof("x", "x+dt*v"); + integrator.addComputeSum("ke", "m*v*v/2"); + Context context(system, integrator, platform); + context.setPositions(positions); + + // See if the sum is being computed correctly. + + for (int i = 0; i < 100; ++i) { + State state = context.getState(State::Energy); + ASSERT_EQUAL_TOL(state.getKineticEnergy(), integrator.getGlobalVariable(0), 1e-5); + integrator.step(1); + } +} + +/** + * Test an integrator that both uses and modifies a context parameter. + */ +void testParameter() { + System system; + system.addParticle(1.0); + AndersenThermostat* thermostat = new AndersenThermostat(0.1, 0.1); + system.addForce(thermostat); + CustomIntegrator integrator(0.1); + integrator.addGlobalVariable("temp", 0); + integrator.addComputeGlobal("temp", "AndersenTemperature"); + integrator.addComputeGlobal("AndersenTemperature", "temp*2"); + Context context(system, integrator, platform); + + // See if the parameter is being used correctly. + + for (int i = 0; i < 10; i++) { + integrator.step(1); + ASSERT_EQUAL_TOL(context.getParameter("AndersenTemperature"), 0.1*(1<<(i+1)), 1e-10); + } +} + +/** + * Test random number distributions. + */ +void testRandomDistributions() { + const int numParticles = 100; + const int numBins = 20; + const int numSteps = 100; + System system; + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + CustomIntegrator integrator(0.1); + integrator.addPerDofVariable("a", 0); + integrator.addPerDofVariable("b", 0); + integrator.addComputePerDof("a", "uniform"); + integrator.addComputePerDof("b", "gaussian"); + Context context(system, integrator, platform); + + // See if the random numbers are distributed correctly. + + vector bins(numBins); + double mean = 0.0; + double var = 0.0; + double skew = 0.0; + double kurtosis = 0.0; + vector values; + for (int i = 0; i < numSteps; i++) { + integrator.step(1); + integrator.getPerDofVariable(0, values); + for (int i = 0; i < numParticles; i++) + for (int j = 0; j < 3; j++) { + double v = values[i][j]; + ASSERT(v >= 0 && v < 1); + bins[(int) (v*numBins)]++; + } + integrator.getPerDofVariable(1, values); + for (int i = 0; i < numParticles; i++) + for (int j = 0; j < 3; j++) { + double v = values[i][j]; + mean += v; + var += v*v; + skew += v*v*v; + kurtosis += v*v*v*v; + } + } + + // Check the distribution of uniform randoms. + + int numValues = numParticles*numSteps*3; + double expected = numValues/(double) numBins; + double tol = 4*sqrt(expected); + for (int i = 0; i < numBins; i++) + ASSERT(bins[i] >= expected-tol && bins[i] <= expected+tol); + + // Check the distribution of gaussian randoms. + + mean /= numValues; + var /= numValues; + skew /= numValues; + kurtosis /= numValues; + double c2 = var-mean*mean; + double c3 = skew-3*var*mean+2*mean*mean*mean; + double c4 = kurtosis-4*skew*mean-3*var*var+12*var*mean*mean-6*mean*mean*mean*mean; + ASSERT_EQUAL_TOL(0.0, mean, 3.0/sqrt((double) numValues)); + ASSERT_EQUAL_TOL(1.0, c2, 3.0/pow(numValues, 1.0/3.0)); + ASSERT_EQUAL_TOL(0.0, c3, 3.0/pow(numValues, 1.0/4.0)); + ASSERT_EQUAL_TOL(0.0, c4, 3.0/pow(numValues, 1.0/4.0)); +} + +/** + * Test getting and setting per-DOF variables. + */ +void testPerDofVariables() { + const int numParticles = 200; + const double boxSize = 10; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + NonbondedForce* nb = new NonbondedForce(); + system.addForce(nb); + nb->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.5); + nb->addParticle(i%2 == 0 ? 1 : -1, 0.1, 1); + bool close = true; + while (close) { + positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + close = false; + for (int j = 0; j < i; ++j) { + Vec3 delta = positions[i]-positions[j]; + if (delta.dot(delta) < 0.1) + close = true; + } + } + } + CustomIntegrator integrator(0.01); + integrator.addPerDofVariable("temp", 0); + integrator.addPerDofVariable("pos", 0); + integrator.addComputePerDof("v", "v+dt*f/m"); + integrator.addComputePerDof("x", "x+dt*v"); + integrator.addComputePerDof("pos", "x"); + Context context(system, integrator, platform); + context.setPositions(positions); + vector initialValues(numParticles); + for (int i = 0; i < numParticles; i++) + initialValues[i] = Vec3(i+0.1, i+0.2, i+0.3); + integrator.setPerDofVariable(0, initialValues); + + // Run a simulation, then query per-DOF values and see if they are correct. + + vector values; + for (int i = 0; i < 100; ++i) { + integrator.step(1); + State state = context.getState(State::Positions); + integrator.getPerDofVariable(0, values); + for (int j = 0; j < numParticles; j++) + ASSERT_EQUAL_VEC(initialValues[j], values[j], 1e-5); + integrator.getPerDofVariable(1, values); + for (int j = 0; j < numParticles; j++) + ASSERT_EQUAL_VEC(state.getPositions()[j], values[j], 1e-5); + } +} + +/** + * Test evaluating force groups separately. + */ +void testForceGroups() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + CustomIntegrator integrator(0.01); + integrator.addPerDofVariable("outf", 0); + integrator.addPerDofVariable("outf1", 0); + integrator.addPerDofVariable("outf2", 0); + integrator.addGlobalVariable("oute", 0); + integrator.addGlobalVariable("oute1", 0); + integrator.addGlobalVariable("oute2", 0); + integrator.addComputePerDof("outf", "f"); + integrator.addComputePerDof("outf1", "f1"); + integrator.addComputePerDof("outf2", "f2"); + integrator.addComputeGlobal("oute", "energy"); + integrator.addComputeGlobal("oute1", "energy1"); + integrator.addComputeGlobal("oute2", "energy2"); + HarmonicBondForce* bonds = new HarmonicBondForce(); + bonds->addBond(0, 1, 1.5, 1.1); + bonds->setForceGroup(1); + system.addForce(bonds); + NonbondedForce* nb = new NonbondedForce(); + nb->addParticle(0.2, 1, 0); + nb->addParticle(0.2, 1, 0); + nb->setForceGroup(2); + system.addForce(nb); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + + // See if the various forces are computed correctly. + + integrator.step(1); + vector f, f1, f2; + double e1 = 0.5*1.1*0.5*0.5; + double e2 = 138.935456*0.2*0.2/2.0; + integrator.getPerDofVariable(0, f); + integrator.getPerDofVariable(1, f1); + integrator.getPerDofVariable(2, f2); + ASSERT_EQUAL_VEC(Vec3(1.1*0.5, 0, 0), f1[0], 1e-5); + ASSERT_EQUAL_VEC(Vec3(-1.1*0.5, 0, 0), f1[1], 1e-5); + ASSERT_EQUAL_VEC(Vec3(-138.935456*0.2*0.2/4.0, 0, 0), f2[0], 1e-5); + ASSERT_EQUAL_VEC(Vec3(138.935456*0.2*0.2/4.0, 0, 0), f2[1], 1e-5); + ASSERT_EQUAL_VEC(f1[0]+f2[0], f[0], 1e-5); + ASSERT_EQUAL_VEC(f1[1]+f2[1], f[1], 1e-5); + ASSERT_EQUAL_TOL(e1, integrator.getGlobalVariable(1), 1e-5); + ASSERT_EQUAL_TOL(e2, integrator.getGlobalVariable(2), 1e-5); + ASSERT_EQUAL_TOL(e1+e2, integrator.getGlobalVariable(0), 1e-5); + + // Make sure they also match the values returned by the Context. + + State s = context.getState(State::Forces | State::Energy, false); + State s1 = context.getState(State::Forces | State::Energy, false, 2); + State s2 = context.getState(State::Forces | State::Energy, false, 4); + vector c, c1, c2; + c = context.getState(State::Forces, false).getForces(); + c1 = context.getState(State::Forces, false, 2).getForces(); + c2 = context.getState(State::Forces, false, 4).getForces(); + ASSERT_EQUAL_VEC(f[0], c[0], 1e-5); + ASSERT_EQUAL_VEC(f[1], c[1], 1e-5); + ASSERT_EQUAL_VEC(f1[0], c1[0], 1e-5); + ASSERT_EQUAL_VEC(f1[1], c1[1], 1e-5); + ASSERT_EQUAL_VEC(f2[0], c2[0], 1e-5); + ASSERT_EQUAL_VEC(f2[1], c2[1], 1e-5); + ASSERT_EQUAL_TOL(s.getPotentialEnergy(), integrator.getGlobalVariable(0), 1e-5); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), integrator.getGlobalVariable(1), 1e-5); + ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), integrator.getGlobalVariable(2), 1e-5); +} + +/** + * Test a multiple time step r-RESPA integrator. + */ +void testRespa() { + const int numParticles = 8; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); + CustomIntegrator integrator(0.002); + integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); + for (int i = 0; i < 2; i++) { + integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); + integrator.addComputePerDof("x", "x+(dt/2)*v"); + integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); + } + integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); + HarmonicBondForce* bonds = new HarmonicBondForce(); + for (int i = 0; i < numParticles-2; i++) + bonds->addBond(i, i+1, 1.0, 0.5); + system.addForce(bonds); + NonbondedForce* nb = new NonbondedForce(); + nb->setCutoffDistance(2.0); + nb->setNonbondedMethod(NonbondedForce::Ewald); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i%2 == 0 ? 5.0 : 10.0); + nb->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); + } + nb->setForceGroup(1); + nb->setReciprocalSpaceForceGroup(0); + system.addForce(nb); + Context context(system, integrator, platform); + vector positions(numParticles); + vector 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 monitor energy conservations. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Energy); + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + if (i == 1) + initialEnergy = energy; + else if (i > 1) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); + integrator.step(2); + } +} + +void testIfBlock() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + const double dt = 0.01; + CustomIntegrator integrator(dt); + integrator.addGlobalVariable("a", 0); + integrator.addGlobalVariable("b", 0); + integrator.addComputeGlobal("b", "1"); + integrator.beginIfBlock("a < 3.5"); + integrator.addComputeGlobal("b", "a+1"); + integrator.endBlock(); + Context context(system, integrator, platform); + + // Set "a" to 1.7 and verify that "b" gets set to a+1. + + integrator.setGlobalVariable(0, 1.7); + integrator.step(1); + ASSERT_EQUAL_TOL(2.7, integrator.getGlobalVariable(1), 1e-6); + + // Now set it to a value that should cause the block to be skipped. + + integrator.setGlobalVariable(0, 4.1); + integrator.step(1); + ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); +} + +void testWhileBlock() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + const double dt = 0.01; + CustomIntegrator integrator(dt); + integrator.addGlobalVariable("a", 0); + integrator.addGlobalVariable("b", 0); + integrator.addComputeGlobal("b", "1"); + integrator.beginWhileBlock("b <= a"); + integrator.addComputeGlobal("b", "b+1"); + integrator.endBlock(); + Context context(system, integrator, platform); + + // Try a case where the loop should be skipped. + + integrator.setGlobalVariable(0, -3.3); + integrator.step(1); + ASSERT_EQUAL_TOL(1.0, integrator.getGlobalVariable(1), 1e-6); + + // In this case it should be executed exactly once. + + integrator.setGlobalVariable(0, 1.2); + integrator.step(1); + ASSERT_EQUAL_TOL(2.0, integrator.getGlobalVariable(1), 1e-6); + + // In this case, it should be executed several times. + + integrator.setGlobalVariable(0, 5.3); + integrator.step(1); + ASSERT_EQUAL_TOL(6.0, integrator.getGlobalVariable(1), 1e-6); +} + +/** + * Test modifying a global variable, then using it in a per-DOF computation. + */ +void testChangingGlobal() { + System system; + system.addParticle(1.0); + CustomIntegrator integrator(0.1); + integrator.addGlobalVariable("g", 0); + integrator.addPerDofVariable("a", 0); + integrator.addPerDofVariable("b", 0); + integrator.addComputeGlobal("g", "g+1"); + integrator.addComputePerDof("a", "0.5"); + integrator.addComputePerDof("b", "a+g"); + Context context(system, integrator, platform); + + // See if everything is being calculated correctly.. + + for (int i = 0; i < 10; i++) { + integrator.step(1); + ASSERT_EQUAL_TOL(i+1.0, integrator.getGlobalVariable(0), 1e-5); + vector values; + integrator.getPerDofVariable(1, values); + ASSERT_EQUAL_VEC(Vec3(i+1.5, i+1.5, i+1.5), values[0], 1e-5); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleBond(); + testConstraints(); + testVelocityConstraints(); + testConstrainedMasslessParticles(); + testWithThermostat(); + testMonteCarlo(); + testSum(); + testParameter(); + testRandomDistributions(); + testPerDofVariables(); + testForceGroups(); + testRespa(); + testIfBlock(); + testWhileBlock(); + testChangingGlobal(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCustomManyParticleForce.h b/tests/TestCustomManyParticleForce.h new file mode 100644 index 000000000..5234b2b65 --- /dev/null +++ b/tests/TestCustomManyParticleForce.h @@ -0,0 +1,736 @@ +/* -------------------------------------------------------------------------- * + * 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) 2014-2015 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomCompoundBondForce.h" +#include "openmm/CustomManyParticleForce.h" +#include "openmm/System.h" +#include "openmm/TabulatedFunction.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +Vec3 computeDelta(const Vec3& pos1, const Vec3& pos2, bool periodic, const Vec3* periodicBoxVectors) { + Vec3 diff = pos1-pos2; + if (periodic) { + diff -= periodicBoxVectors[2]*floor(diff[2]/periodicBoxVectors[2][2]+0.5); + diff -= periodicBoxVectors[1]*floor(diff[1]/periodicBoxVectors[1][1]+0.5); + diff -= periodicBoxVectors[0]*floor(diff[0]/periodicBoxVectors[0][0]+0.5); + } + return diff; +} + +void validateAxilrodTeller(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize, bool triclinic) { + // Create a System and Context. + + int numParticles = force->getNumParticles(); + CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); + System system; + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + Vec3 boxVectors[3]; + if (triclinic) { + boxVectors[0] = Vec3(boxSize, 0, 0); + boxVectors[1] = Vec3(0.2*boxSize, boxSize, 0); + boxVectors[2] = Vec3(-0.3*boxSize, -0.1*boxSize, boxSize); + } + else { + boxVectors[0] = Vec3(boxSize, 0, 0); + boxVectors[1] = Vec3(0, boxSize, 0); + boxVectors[2] = Vec3(0, 0, boxSize); + } + system.setDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]); + system.addForce(force); + if (force->getNonbondedMethod() == CustomManyParticleForce::CutoffPeriodic) { + ASSERT(force->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + } + else { + ASSERT(!force->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + } + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + State state1 = context.getState(State::Forces | State::Energy); + double c = context.getParameter("C"); + + // See if the energy matches the expected value. + + double expectedEnergy = 0; + bool periodic = (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic); + for (int i = 0; i < (int) expectedSets.size(); i++) { + int p1 = expectedSets[i][0]; + int p2 = expectedSets[i][1]; + int p3 = expectedSets[i][2]; + Vec3 d12 = computeDelta(positions[p2], positions[p1], periodic, boxVectors); + Vec3 d13 = computeDelta(positions[p3], positions[p1], periodic, boxVectors); + Vec3 d23 = computeDelta(positions[p3], positions[p2], periodic, boxVectors); + double r12 = sqrt(d12.dot(d12)); + double r13 = sqrt(d13.dot(d13)); + double r23 = sqrt(d23.dot(d23)); + double ctheta1 = d12.dot(d13)/(r12*r13); + double ctheta2 = -d12.dot(d23)/(r12*r23); + double ctheta3 = d13.dot(d23)/(r13*r23); + double rprod = r12*r13*r23; + expectedEnergy += c*(1+3*ctheta1*ctheta2*ctheta3)/(rprod*rprod*rprod); + } + ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); + + // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. + + const vector& forces = state1.getForces(); + double norm = 0.0; + for (int i = 0; i < (int) forces.size(); ++i) + norm += forces[i].dot(forces[i]); + norm = std::sqrt(norm); + const double stepSize = 1e-3; + double step = 0.5*stepSize/norm; + vector positions2(numParticles), positions3(numParticles); + for (int i = 0; i < (int) positions.size(); ++i) { + Vec3 p = positions[i]; + Vec3 f = forces[i]; + positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); + } + context.setPositions(positions2); + State state2 = context.getState(State::Energy); + context.setPositions(positions3); + State state3 = context.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); +} + +void validateStillingerWeber(CustomManyParticleForce* force, const vector& positions, const vector& expectedSets, double boxSize) { + // Create a System and Context. + + int numParticles = force->getNumParticles(); + CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod(); + System system; + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + system.addForce(force); + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + State state1 = context.getState(State::Forces | State::Energy); + double L = context.getParameter("L"); + double eps = context.getParameter("eps"); + double a = context.getParameter("a"); + double gamma = context.getParameter("gamma"); + double sigma = context.getParameter("sigma"); + + // See if the energy matches the expected value. + + double expectedEnergy = 0; + for (int i = 0; i < (int) expectedSets.size(); i++) { + int p1 = expectedSets[i][0]; + int p2 = expectedSets[i][1]; + int p3 = expectedSets[i][2]; + Vec3 d12 = positions[p2]-positions[p1]; + Vec3 d13 = positions[p3]-positions[p1]; + Vec3 d23 = positions[p3]-positions[p2]; + if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) { + for (int j = 0; j < 3; j++) { + d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize; + d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize; + d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize; + } + } + double r12 = sqrt(d12.dot(d12)); + double r13 = sqrt(d13.dot(d13)); + double r23 = sqrt(d23.dot(d23)); + double ctheta1 = d12.dot(d13)/(r12*r13); + double ctheta2 = -d12.dot(d23)/(r12*r23); + double ctheta3 = d13.dot(d23)/(r13*r23); + expectedEnergy += L*eps*(ctheta1+1.0/3.0)*(ctheta1+1.0/3.0)*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma)); + } + ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5); + + // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. + + const vector& forces = state1.getForces(); + double norm = 0.0; + for (int i = 0; i < (int) forces.size(); ++i) + norm += forces[i].dot(forces[i]); + norm = std::sqrt(norm); + const double stepSize = 1e-3; + double step = 0.5*stepSize/norm; + vector positions2(numParticles), positions3(numParticles); + for (int i = 0; i < (int) positions.size(); ++i) { + Vec3 p = positions[i]; + Vec3 f = forces[i]; + positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); + } + context.setPositions(positions2); + State state2 = context.getState(State::Energy); + context.setPositions(positions3); + State state3 = context.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4); +} + +void testNoCutoff() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); + force->addGlobalParameter("C", 1.5); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(1, 0, 0)); + positions.push_back(Vec3(0, 1.1, 0.3)); + positions.push_back(Vec3(0.4, 0, -0.8)); + int sets[4][3] = {{0,1,2}, {1,2,3}, {2,3,0}, {3,0,1}}; + vector expectedSets(&sets[0], &sets[4]); + validateAxilrodTeller(force, positions, expectedSets, 2.0, false); +} + +void testCutoff() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); + force->addGlobalParameter("C", 1.5); + force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); + force->setCutoffDistance(1.55); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(1, 0, 0)); + positions.push_back(Vec3(0, 1.1, 0.3)); + positions.push_back(Vec3(0.4, 0, -0.8)); + positions.push_back(Vec3(0.2, 0.5, -0.1)); + int sets[7][3] = {{0,1,2}, {0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,2,4}, {1,3,4}}; + vector expectedSets(&sets[0], &sets[7]); + validateAxilrodTeller(force, positions, expectedSets, 2.0, false); +} + +void testPeriodic() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); + force->addGlobalParameter("C", 1.5); + force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); + force->setCutoffDistance(1.05); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(1, 0, 0)); + positions.push_back(Vec3(0, 1.1, 0.3)); + positions.push_back(Vec3(0.4, 0, -0.8)); + positions.push_back(Vec3(0.2, 0.5, -0.1)); + double boxSize = 2.1; + int sets[5][3] = {{0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,3,4}}; + vector expectedSets(&sets[0], &sets[5]); + validateAxilrodTeller(force, positions, expectedSets, boxSize, false); +} + +void testTriclinic() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); + force->addGlobalParameter("C", 1.5); + force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); + force->setCutoffDistance(1.05); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(1, 0, 0)); + positions.push_back(Vec3(0, 1.1, 0.3)); + positions.push_back(Vec3(0.4, 0, -0.8)); + positions.push_back(Vec3(0.2, 0.5, -0.1)); + double boxSize = 2.1; + int sets[4][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {1,3,4}}; + vector expectedSets(&sets[0], &sets[4]); + validateAxilrodTeller(force, positions, expectedSets, boxSize, true); +} + +void testExclusions() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); + force->addGlobalParameter("C", 1.5); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(1, 0, 0)); + positions.push_back(Vec3(0, 1.1, 0.3)); + positions.push_back(Vec3(0.4, 0, -0.8)); + positions.push_back(Vec3(0.2, 0.5, -0.1)); + force->addExclusion(0, 2); + force->addExclusion(0, 3); + int sets[5][3] = {{0,1,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4}}; + vector expectedSets(&sets[0], &sets[5]); + validateAxilrodTeller(force, positions, expectedSets, 2.0, false); +} + +void testAllTerms() { + int numParticles = 4; + + // Create a system with a CustomManyParticleForce. + + System system1; + CustomManyParticleForce* force1 = new CustomManyParticleForce(4, + "distance(p1,p2)+angle(p1,p4,p3)+dihedral(p1,p3,p2,p4)+x1+y4+z3"); + system1.addForce(force1); + vector params; + for (int i = 0; i < numParticles; i++) { + system1.addParticle(1.0); + force1->addParticle(params, i); + } + set filter; + filter.insert(0); + force1->setTypeFilter(0, filter); + filter.clear(); + filter.insert(1); + force1->setTypeFilter(1, filter); + filter.clear(); + filter.insert(3); + force1->setTypeFilter(2, filter); + filter.clear(); + filter.insert(2); + force1->setTypeFilter(3, filter); + + // Create a system that use a CustomCompoundBondForce to compute exactly the same interactions. + + System system2; + CustomCompoundBondForce* force2 = new CustomCompoundBondForce(4, + "distance(p1,p2)+angle(p1,p3,p4)+dihedral(p1,p4,p2,p3)+x1+y3+z4"); + system2.addForce(force2); + vector particles; + particles.push_back(0); + particles.push_back(1); + particles.push_back(2); + particles.push_back(3); + force2->addBond(particles, params); + for (int i = 0; i < numParticles; i++) + system2.addParticle(1.0); + + // Create contexts for both of them. + + vector positions; + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; i++) + positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); + VerletIntegrator integrator1(0.001); + VerletIntegrator integrator2(0.001); + Context context1(system1, integrator1, platform); + Context context2(system2, integrator2, platform); + context1.setPositions(positions); + context2.setPositions(positions); + + // See if they produce identical forces and energies. + + State state1 = context1.getState(State::Forces | State::Energy); + State state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), 1e-4); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state2.getForces()[i], state1.getForces()[i], 1e-4); +} + +void testParameters() { + // Create a system. + + int numParticles = 5; + System system; + CustomManyParticleForce* force = new CustomManyParticleForce(3, "C*scale1*scale2*scale3*(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))"); + force->addGlobalParameter("C", 2.0); + force->addPerParticleParameter("scale"); + vector params(1); + vector positions; + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; i++) { + params[0] = i+1; + force->addParticle(params); + positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); + system.addParticle(1.0); + } + system.addForce(force); + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + + // See if the energy is correct. + + State state = context.getState(State::Energy); + double expectedEnergy = 0; + for (int i = 0; i < numParticles; i++) + for (int j = i+1; j < numParticles; j++) + for (int k = j+1; k < numParticles; k++) { + Vec3 d12 = positions[j]-positions[i]; + Vec3 d13 = positions[k]-positions[i]; + Vec3 d23 = positions[k]-positions[j]; + double r12 = sqrt(d12.dot(d12)); + double r13 = sqrt(d13.dot(d13)); + double r23 = sqrt(d23.dot(d23)); + expectedEnergy += 2.0*(i+1)*(j+1)*(k+1)*(r12+r13+r23); + } + ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); + + // Modify the parameters. + + context.setParameter("C", 3.5); + for (int i = 0; i < numParticles; i++) { + params[0] = 0.5*i-0.1; + force->setParticleParameters(i, params, 0); + } + force->updateParametersInContext(context); + + // See if the energy is still correct. + + state = context.getState(State::Energy); + expectedEnergy = 0; + for (int i = 0; i < numParticles; i++) + for (int j = i+1; j < numParticles; j++) + for (int k = j+1; k < numParticles; k++) { + Vec3 d12 = positions[j]-positions[i]; + Vec3 d13 = positions[k]-positions[i]; + Vec3 d23 = positions[k]-positions[j]; + double r12 = sqrt(d12.dot(d12)); + double r13 = sqrt(d13.dot(d13)); + double r23 = sqrt(d23.dot(d23)); + expectedEnergy += 3.5*(0.5*i-0.1)*(0.5*j-0.1)*(0.5*k-0.1)*(r12+r13+r23); + } + ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); +} + +void testTabulatedFunctions() { + int numParticles = 5; + + // Create two tabulated functions. + + vector values; + values.push_back(0.0); + values.push_back(50.0); + Continuous1DFunction* f1 = new Continuous1DFunction(values, 0, 100); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + vector c(numParticles); + for (int i = 0; i < numParticles; i++) + c[i] = genrand_real2(sfmt); + values.resize(numParticles*numParticles*numParticles); + for (int i = 0; i < numParticles; i++) + for (int j = 0; j < numParticles; j++) + for (int k = 0; k < numParticles; k++) + values[i+numParticles*j+numParticles*numParticles*k] = c[i]+c[j]+c[k]; + Discrete3DFunction* f2 = new Discrete3DFunction(numParticles, numParticles, numParticles, values); + + // Create a system. + + System system; + CustomManyParticleForce* force = new CustomManyParticleForce(3, "f1(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))*f2(atom1, atom2, atom3)"); + force->addPerParticleParameter("atom"); + force->addTabulatedFunction("f1", f1); + force->addTabulatedFunction("f2", f2); + vector params(1); + vector positions; + for (int i = 0; i < numParticles; i++) { + params[0] = i; + force->addParticle(params); + positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))); + system.addParticle(1.0); + } + system.addForce(force); + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + + // See if the energy is correct. + + State state = context.getState(State::Energy); + double expectedEnergy = 0; + for (int i = 0; i < numParticles; i++) + for (int j = i+1; j < numParticles; j++) + for (int k = j+1; k < numParticles; k++) { + Vec3 d12 = positions[j]-positions[i]; + Vec3 d13 = positions[k]-positions[i]; + Vec3 d23 = positions[k]-positions[j]; + double r12 = sqrt(d12.dot(d12)); + double r13 = sqrt(d13.dot(d13)); + double r23 = sqrt(d23.dot(d23)); + expectedEnergy += 0.5*(r12+r13+r23)*(c[i]+c[j]+c[k]); + } + ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); +} + +void testTypeFilters() { + // Create a system. + + System system; + for (int i = 0; i < 5; i++) + system.addParticle(1.0); + CustomManyParticleForce* force = new CustomManyParticleForce(3, "c1*(distance(p1,p2)+distance(p1,p3))"); + force->addPerParticleParameter("c"); + double c[] = {1.0, 2.0, 1.3, 1.5, -2.1}; + int type[] = {0, 1, 0, 1, 5}; + vector params(1); + for (int i = 0; i < 5; i++) { + params[0] = c[i]; + force->addParticle(params, type[i]); + } + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(1, 0, 0)); + positions.push_back(Vec3(0, 1.1, 0.3)); + positions.push_back(Vec3(0.4, 0, -0.8)); + positions.push_back(Vec3(0.2, 0.5, -0.1)); + set f1, f2; + f1.insert(0); + f2.insert(1); + f2.insert(5); + force->setTypeFilter(0, f1); + force->setTypeFilter(1, f2); + force->setTypeFilter(2, f2); + system.addForce(force); + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + + // See if the energy is correct. + + State state = context.getState(State::Energy); + double expectedEnergy = 0; + int sets[6][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {2,1,3}, {2,1,4}, {2,3,4}}; + for (int i = 0; i < 6; i++) { + int p1 = sets[i][0]; + int p2 = sets[i][1]; + int p3 = sets[i][2]; + Vec3 d12 = positions[p2]-positions[p1]; + Vec3 d13 = positions[p3]-positions[p1]; + double r12 = sqrt(d12.dot(d12)); + double r13 = sqrt(d13.dot(d13)); + expectedEnergy += c[p1]*(r12+r13); + } + ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); +} + +void testLargeSystem() { + int gridSize = 8; + int numParticles = gridSize*gridSize*gridSize; + double boxSize = 3.0; + double spacing = boxSize/gridSize; + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)"); + force->addGlobalParameter("C", 1.5); + force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); + force->setCutoffDistance(0.6); + vector params; + vector positions; + System system; + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < gridSize; i++) + for (int j = 0; j < gridSize; j++) + for (int k = 0; k < gridSize; k++) { + force->addParticle(params); + positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); + system.addParticle(1.0); + } + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + system.addForce(force); + VerletIntegrator integrator1(0.001); + VerletIntegrator integrator2(0.001); + Context context1(system, integrator1, Platform::getPlatformByName("Reference")); + Context context2(system, integrator2, platform); + context1.setPositions(positions); + context2.setPositions(positions); + State state1 = context1.getState(State::Forces | State::Energy); + State state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); +} + +void testCentralParticleModeNoCutoff() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" + "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); + force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); + force->addGlobalParameter("L", 23.13); + force->addGlobalParameter("eps", 25.894776); + force->addGlobalParameter("a", 1.8); + force->addGlobalParameter("sigma", 0.23925); + force->addGlobalParameter("gamma", 1.2); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(0.1, 0, 0)); + positions.push_back(Vec3(0, 0.11, 0.03)); + positions.push_back(Vec3(0.04, 0, -0.08)); + int sets[12][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {2,0,3}, {2, 1, 3}, {3,0,1}, {3,0,2}, {3,1,2}}; + vector expectedSets(&sets[0], &sets[12]); + validateStillingerWeber(force, positions, expectedSets, 2.0); +} + +void testCentralParticleModeCutoff() { + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" + "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); + force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); + force->addGlobalParameter("L", 23.13); + force->addGlobalParameter("eps", 25.894776); + force->addGlobalParameter("a", 1.8); + force->addGlobalParameter("sigma", 0.23925); + force->addGlobalParameter("gamma", 1.2); + force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic); + force->setCutoffDistance(0.155); + vector params; + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + force->addParticle(params); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(0.1, 0, 0)); + positions.push_back(Vec3(0, 0.11, 0.03)); + positions.push_back(Vec3(0.04, 0, -0.08)); + int sets[8][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {3,0,1}}; + vector expectedSets(&sets[0], &sets[8]); + validateStillingerWeber(force, positions, expectedSets, 2.0); +} + +void testCentralParticleModeLargeSystem() { + int gridSize = 8; + int numParticles = gridSize*gridSize*gridSize; + double boxSize = 2.0; + double spacing = boxSize/gridSize; + CustomManyParticleForce* force = new CustomManyParticleForce(3, + "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));" + "r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)"); + force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle); + force->addGlobalParameter("L", 23.13); + force->addGlobalParameter("eps", 25.894776); + force->addGlobalParameter("a", 1.8); + force->addGlobalParameter("sigma", 0.23925); + force->addGlobalParameter("gamma", 1.2); + force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic); + force->setCutoffDistance(1.8*0.23925); + vector params; + vector positions; + System system; + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < gridSize; i++) + for (int j = 0; j < gridSize; j++) + for (int k = 0; k < gridSize; k++) { + force->addParticle(params); + positions.push_back(Vec3((i+0.4*genrand_real2(sfmt))*spacing, (j+0.4*genrand_real2(sfmt))*spacing, (k+0.4*genrand_real2(sfmt))*spacing)); + system.addParticle(1.0); + } + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + system.addForce(force); + VerletIntegrator integrator1(0.001); + VerletIntegrator integrator2(0.001); + Context context1(system, integrator1, Platform::getPlatformByName("Reference")); + Context context2(system, integrator2, platform); + context1.setPositions(positions); + context2.setPositions(positions); + State state1 = context1.getState(State::Forces | State::Energy); + State state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testNoCutoff(); + testCutoff(); + testPeriodic(); + testTriclinic(); + testExclusions(); + testAllTerms(); + testParameters(); + testTabulatedFunctions(); + testTypeFilters(); + testLargeSystem(); + testCentralParticleModeNoCutoff(); + testCentralParticleModeCutoff(); + testCentralParticleModeLargeSystem(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCustomNonbondedForce.h b/tests/TestCustomNonbondedForce.h new file mode 100644 index 000000000..66e43774b --- /dev/null +++ b/tests/TestCustomNonbondedForce.h @@ -0,0 +1,1028 @@ + +/* -------------------------------------------------------------------------- * + * 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-2015 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif +#include "openmm/internal/AssertionUtilities.h" +#include "sfmt/SFMT.h" +#include "openmm/Context.h" +#include "openmm/CustomNonbondedForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include +#include +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSimpleExpression() { + 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()); + forceField->addParticle(vector()); + system.addForce(forceField); + Context context(system, integrator, platform); + vector 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& 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() { + 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 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 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 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); + + // Try changing the global parameters and make sure it's still correct. + + 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); + + // Try changing the per-particle parameters and make sure it's still correct. + + params[0] = 1.6; + params[1] = 2.1; + forceField->setParticleParameters(0, params); + params[0] = 1.9; + params[1] = 2.8; + forceField->setParticleParameters(1, params); + forceField->updateParametersInContext(context); + state = context.getState(State::Forces | State::Energy); + forces = state.getForces(); + force = -1.5*1.6*1.9*3*5.9*(11.8*11.8); + 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*1.6*1.9*(11.8*11.8*11.8), state.getPotentialEnergy(), TOL); +} + +void testManyParameters() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("(a1*a2+b1*b2+c1*c2+d1*d2+e1*e2)*r"); + forceField->addPerParticleParameter("a"); + forceField->addPerParticleParameter("b"); + forceField->addPerParticleParameter("c"); + forceField->addPerParticleParameter("d"); + forceField->addPerParticleParameter("e"); + vector params(5); + params[0] = 1.0; + params[1] = 2.0; + params[2] = 3.0; + params[3] = 4.0; + params[4] = 5.0; + forceField->addParticle(params); + params[0] = 1.1; + params[1] = 1.2; + params[2] = 1.3; + params[3] = 1.4; + params[4] = 1.5; + forceField->addParticle(params); + system.addForce(forceField); + Context context(system, integrator, platform); + vector 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); + vector forces = state.getForces(); + double force = 1*1.1 + 2*1.2 + 3*1.3 + 4*1.4 + 5*1.5; + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); + ASSERT_EQUAL_TOL(2*force, state.getPotentialEnergy(), TOL); +} + +void testExclusions() { + System system; + VerletIntegrator integrator(0.01); + CustomNonbondedForce* nonbonded = new CustomNonbondedForce("a*r; a=a1+a2"); + nonbonded->addPerParticleParameter("a"); + vector params(1); + vector 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& 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() { + 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()); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + forceField->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); + forceField->setCutoffDistance(2.5); + system.addForce(forceField); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& 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() { + 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()); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + 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); + ASSERT(forceField->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& 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 testTriclinic() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + Vec3 a(3.1, 0, 0); + Vec3 b(0.4, 3.5, 0); + Vec3 c(-0.1, -0.5, 4.0); + system.setDefaultPeriodicBoxVectors(a, b, c); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* nonbonded = new CustomNonbondedForce("r"); + nonbonded->addParticle(vector()); + nonbonded->addParticle(vector()); + nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); + const double cutoff = 1.5; + nonbonded->setCutoffDistance(cutoff); + system.addForce(nonbonded); + Context context(system, integrator, platform); + vector positions(2); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int iteration = 0; iteration < 50; iteration++) { + // Generate random positions for the two particles. + + positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); + positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); + context.setPositions(positions); + + // Loop over all possible periodic copies and find the nearest one. + + Vec3 delta; + double distance2 = 100.0; + for (int i = -1; i < 2; i++) + for (int j = -1; j < 2; j++) + for (int k = -1; k < 2; k++) { + Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; + if (d.dot(d) < distance2) { + delta = d; + distance2 = d.dot(d); + } + } + double distance = sqrt(distance2); + + // See if the force and energy are correct. + + State state = context.getState(State::Forces | State::Energy); + if (distance >= cutoff) { + ASSERT_EQUAL(0.0, state.getPotentialEnergy()); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); + } + else { + const Vec3 force = delta/sqrt(delta.dot(delta)); + ASSERT_EQUAL_TOL(distance, state.getPotentialEnergy(), TOL); + ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); + } + } +} + +void testContinuous1DFunction() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r)+1"); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + vector table; + for (int i = 0; i < 21; i++) + table.push_back(sin(0.25*i)); + forceField->addTabulatedFunction("fn", new Continuous1DFunction(table, 1.0, 6.0)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + 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& forces = state.getForces(); + double force = (x < 1.0 || x > 6.0 ? 0.0 : -cos(x-1.0)); + double energy = (x < 1.0 || x > 6.0 ? 0.0 : 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 : sin(x-1.0))+1.0; + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 1e-4); + } +} + +void testContinuous2DFunction() { + const int xsize = 20; + const int ysize = 21; + const double xmin = 0.4; + const double xmax = 1.5; + const double ymin = 0.0; + const double ymax = 2.1; + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a)+1"); + forceField->addGlobalParameter("a", 0.0); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + vector table(xsize*ysize); + for (int i = 0; i < xsize; i++) { + for (int j = 0; j < ysize; j++) { + double x = xmin + i*(xmax-xmin)/xsize; + double y = ymin + j*(ymax-ymin)/ysize; + table[i+xsize*j] = sin(0.25*x)*cos(0.33*y); + } + } + forceField->addTabulatedFunction("fn", new Continuous2DFunction(xsize, ysize, table, xmin, xmax, ymin, ymax)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { + for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { + positions[1] = Vec3(x, 0, 0); + context.setParameter("a", y); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double energy = 1; + double force = 0; + if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { + energy = sin(0.25*x)*cos(0.33*y)+1.0; + force = -0.25*cos(0.25*x)*cos(0.33*y); + } + 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); + } + } +} + +void testContinuous3DFunction() { + const int xsize = 10; + const int ysize = 11; + const int zsize = 12; + const double xmin = 0.6; + const double xmax = 1.1; + const double ymin = 0.0; + const double ymax = 0.7; + const double zmin = 0.2; + const double zmax = 0.9; + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r,a,b)+1"); + forceField->addGlobalParameter("a", 0.0); + forceField->addGlobalParameter("b", 0.0); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + vector table(xsize*ysize*zsize); + for (int i = 0; i < xsize; i++) { + for (int j = 0; j < ysize; j++) { + for (int k = 0; k < zsize; k++) { + double x = xmin + i*(xmax-xmin)/xsize; + double y = ymin + j*(ymax-ymin)/ysize; + double z = zmin + k*(zmax-zmin)/zsize; + table[i+xsize*j+xsize*ysize*k] = sin(0.25*x)*cos(0.33*y)*(1+z); + } + } + } + forceField->addTabulatedFunction("fn", new Continuous3DFunction(xsize, ysize, zsize, table, xmin, xmax, ymin, ymax, zmin, zmax)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (double x = xmin-0.15; x < xmax+0.2; x += 0.1) { + for (double y = ymin-0.15; y < ymax+0.2; y += 0.1) { + for (double z = zmin-0.15; z < zmax+0.2; z += 0.1) { + positions[1] = Vec3(x, 0, 0); + context.setParameter("a", y); + context.setParameter("b", z); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double energy = 1; + double force = 0; + if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin && z <= zmax) { + energy = sin(0.25*x)*cos(0.33*y)*(1.0+z)+1.0; + force = -0.25*cos(0.25*x)*cos(0.33*y)*(1.0+z); + } + 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.05); + } + } + } +} + +void testDiscrete1DFunction() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1)+1"); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + vector table; + for (int i = 0; i < 21; i++) + table.push_back(sin(0.25*i)); + forceField->addTabulatedFunction("fn", new Discrete1DFunction(table)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (int i = 0; i < (int) table.size(); i++) { + positions[1] = Vec3(i+1, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); + ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); + } +} + +void testDiscrete2DFunction() { + const int xsize = 10; + const int ysize = 5; + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1,a)+1"); + forceField->addGlobalParameter("a", 0.0); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + vector table; + for (int i = 0; i < xsize; i++) + for (int j = 0; j < ysize; j++) + table.push_back(sin(0.25*i)+cos(0.33*j)); + forceField->addTabulatedFunction("fn", new Discrete2DFunction(xsize, ysize, table)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (int i = 0; i < (int) table.size(); i++) { + positions[1] = Vec3((i%xsize)+1, 0, 0); + context.setPositions(positions); + context.setParameter("a", i/xsize); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); + ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); + } +} + +void testDiscrete3DFunction() { + const int xsize = 8; + const int ysize = 5; + const int zsize = 6; + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* forceField = new CustomNonbondedForce("fn(r-1,a,b)+1"); + forceField->addGlobalParameter("a", 0.0); + forceField->addGlobalParameter("b", 0.0); + forceField->addParticle(vector()); + forceField->addParticle(vector()); + vector table; + for (int i = 0; i < xsize; i++) + for (int j = 0; j < ysize; j++) + for (int k = 0; k < zsize; k++) + table.push_back(sin(0.25*i)+cos(0.33*j)+0.12345*k); + forceField->addTabulatedFunction("fn", new Discrete3DFunction(xsize, ysize, zsize, table)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + for (int i = 0; i < (int) table.size(); i++) { + positions[1] = Vec3((i%xsize)+1, 0, 0); + context.setPositions(positions); + context.setParameter("a", (i/xsize)%ysize); + context.setParameter("b", i/(xsize*ysize)); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[0], 1e-6); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[1], 1e-6); + ASSERT_EQUAL_TOL(table[i]+1.0, state.getPotentialEnergy(), 1e-6); + } +} + +void testCoulombLennardJones() { + const int numMolecules = 300; + const int numParticles = numMolecules*2; + const double boxSize = 20.0; + + // 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 positions(numParticles); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + vector 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); + ASSERT(!customNonbonded->usesPeriodicBoundaryConditions()); + ASSERT(!customSystem.usesPeriodicBoundaryConditions()); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context context1(standardSystem, integrator1, platform); + Context context2(customSystem, integrator2, platform); + context1.setPositions(positions); + context2.setPositions(positions); + context1.setVelocities(velocities); + context2.setVelocities(velocities); + State state1 = context1.getState(State::Forces | State::Energy); + State state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-4); + for (int i = 0; i < numParticles; i++) { + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); + } +} + +void testSwitchingFunction() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + CustomNonbondedForce* nonbonded = new CustomNonbondedForce("10/r^2"); + vector params; + nonbonded->addParticle(params); + nonbonded->addParticle(params); + nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); + nonbonded->setCutoffDistance(2.0); + nonbonded->setUseSwitchingFunction(true); + nonbonded->setSwitchingDistance(1.5); + system.addForce(nonbonded); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + + // Compute the interaction at various distances. + + for (double r = 1.0; r < 2.5; r += 0.1) { + positions[1] = Vec3(r, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + + // See if the energy is correct. + + double expectedEnergy = 10/(r*r); + double switchValue; + if (r <= 1.5) + switchValue = 1; + else if (r >= 2.0) + switchValue = 0; + else { + double t = (r-1.5)/0.5; + switchValue = 1+t*t*t*(-10+t*(15-t*6)); + } + ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); + + // See if the force is the gradient of the energy. + + double delta = 1e-3; + positions[1] = Vec3(r-delta, 0, 0); + context.setPositions(positions); + double e1 = context.getState(State::Energy).getPotentialEnergy(); + positions[1] = Vec3(r+delta, 0, 0); + context.setPositions(positions); + double e2 = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); + } +} + +void testLongRangeCorrection() { + // Create a box of particles. + + int gridSize = 5; + int numParticles = gridSize*gridSize*gridSize; + double boxSize = gridSize*0.7; + double cutoff = boxSize/3; + System standardSystem; + System customSystem; + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + NonbondedForce* standardNonbonded = new NonbondedForce(); + CustomNonbondedForce* customNonbonded = new CustomNonbondedForce("4*eps*((sigma/r)^12-(sigma/r)^6); sigma=0.5*(sigma1+sigma2); eps=sqrt(eps1*eps2)"); + customNonbonded->addPerParticleParameter("sigma"); + customNonbonded->addPerParticleParameter("eps"); + vector positions(numParticles); + int index = 0; + vector params1(2); + params1[0] = 1.1; + params1[1] = 0.5; + vector params2(2); + params2[0] = 1; + params2[1] = 1; + for (int i = 0; i < gridSize; i++) + for (int j = 0; j < gridSize; j++) + for (int k = 0; k < gridSize; k++) { + standardSystem.addParticle(1.0); + customSystem.addParticle(1.0); + if (index%2 == 0) { + standardNonbonded->addParticle(0, params1[0], params1[1]); + customNonbonded->addParticle(params1); + } + else { + standardNonbonded->addParticle(0, params2[0], params2[1]); + customNonbonded->addParticle(params2); + } + positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); + index++; + } + standardNonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + customNonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); + standardNonbonded->setCutoffDistance(cutoff); + customNonbonded->setCutoffDistance(cutoff); + standardSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + standardNonbonded->setUseDispersionCorrection(true); + customNonbonded->setUseLongRangeCorrection(true); + standardNonbonded->setUseSwitchingFunction(true); + customNonbonded->setUseSwitchingFunction(true); + standardNonbonded->setSwitchingDistance(0.8*cutoff); + customNonbonded->setSwitchingDistance(0.8*cutoff); + standardSystem.addForce(standardNonbonded); + customSystem.addForce(customNonbonded); + + // Compute the correction for the standard force. + + Context context1(standardSystem, integrator1, platform); + context1.setPositions(positions); + double standardEnergy1 = context1.getState(State::Energy).getPotentialEnergy(); + standardNonbonded->setUseDispersionCorrection(false); + context1.reinitialize(); + context1.setPositions(positions); + double standardEnergy2 = context1.getState(State::Energy).getPotentialEnergy(); + + // Compute the correction for the custom force. + + Context context2(customSystem, integrator2, platform); + context2.setPositions(positions); + double customEnergy1 = context2.getState(State::Energy).getPotentialEnergy(); + customNonbonded->setUseLongRangeCorrection(false); + context2.reinitialize(); + context2.setPositions(positions); + double customEnergy2 = context2.getState(State::Energy).getPotentialEnergy(); + + // See if they agree. + + ASSERT_EQUAL_TOL(standardEnergy1-standardEnergy2, customEnergy1-customEnergy2, 1e-4); +} + +void testInteractionGroups() { + const int numParticles = 6; + System system; + VerletIntegrator integrator(0.01); + CustomNonbondedForce* nonbonded = new CustomNonbondedForce("v1+v2"); + nonbonded->addPerParticleParameter("v"); + vector params(1, 0.001); + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.0); + nonbonded->addParticle(params); + params[0] *= 10; + } + set set1, set2, set3, set4; + set1.insert(2); + set2.insert(0); + set2.insert(1); + set2.insert(2); + set2.insert(3); + set2.insert(4); + set2.insert(5); + nonbonded->addInteractionGroup(set1, set2); // Particle 2 interacts with every other particle. + set3.insert(0); + set3.insert(1); + set4.insert(4); + set4.insert(5); + nonbonded->addInteractionGroup(set3, set4); // Particles 0 and 1 interact with 4 and 5. + nonbonded->addExclusion(1, 2); // Add an exclusion to make sure it gets skipped. + system.addForce(nonbonded); + Context context(system, integrator, platform); + vector positions(numParticles); + context.setPositions(positions); + State state = context.getState(State::Energy); + double expectedEnergy = 331.423; // Each digit is the number of interactions a particle particle is involved in. + ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), TOL); +} + +void testLargeInteractionGroup() { + const int numMolecules = 300; + const int numParticles = numMolecules*2; + const double boxSize = 20.0; + + // Create a large system. + + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + CustomNonbondedForce* nonbonded = 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)"); + nonbonded->addPerParticleParameter("q"); + nonbonded->addPerParticleParameter("sigma"); + nonbonded->addPerParticleParameter("eps"); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + vector params(3); + for (int i = 0; i < numMolecules; i++) { + if (i < numMolecules/2) { + params[0] = 1.0; + params[1] = 0.2; + params[2] = 0.1; + nonbonded->addParticle(params); + params[0] = -1.0; + params[1] = 0.1; + nonbonded->addParticle(params); + } + else { + params[0] = 1.0; + params[1] = 0.2; + params[2] = 0.2; + nonbonded->addParticle(params); + params[0] = -1.0; + params[1] = 0.1; + nonbonded->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]); + nonbonded->addExclusion(2*i, 2*i+1); + } + nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); + system.addForce(nonbonded); + + // Compute the forces. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + State state1 = context.getState(State::Forces); + + // Modify the force so only one particle interacts with everything else. + + set set1, set2; + set1.insert(151); + for (int i = 0; i < numParticles; i++) + set2.insert(i); + nonbonded->addInteractionGroup(set1, set2); + context.reinitialize(); + context.setPositions(positions); + State state2 = context.getState(State::Forces); + + // The force on that one particle should be the same. + + ASSERT_EQUAL_VEC(state1.getForces()[151], state2.getForces()[151], 1e-4); + + // Modify the interaction group so it includes all interactions. This should now reproduce the original forces + // on all atoms. + + for (int i = 0; i < numParticles; i++) + set1.insert(i); + nonbonded->setInteractionGroupParameters(0, set1, set2); + context.reinitialize(); + context.setPositions(positions); + State state3 = context.getState(State::Forces); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state1.getForces()[i], state3.getForces()[i], 1e-4); +} + +void testInteractionGroupLongRangeCorrection() { + const int numParticles = 10; + const double boxSize = 10.0; + const double cutoff = 0.5; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + CustomNonbondedForce* nonbonded = new CustomNonbondedForce("c1*c2*r^-4"); + nonbonded->addPerParticleParameter("c"); + vector positions(numParticles); + vector params(1); + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.0); + params[0] = (i%2 == 0 ? 1.1 : 2.0); + nonbonded->addParticle(params); + positions[i] = Vec3(0.5*i, 0, 0); + } + nonbonded->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic); + nonbonded->setCutoffDistance(cutoff); + system.addForce(nonbonded); + + // Setup nonbonded groups. They involve 1 interaction of type AA, + // 2 of type BB, and 5 of type AB. + + set set1, set2, set3, set4, set5; + set1.insert(0); + set1.insert(1); + set1.insert(2); + nonbonded->addInteractionGroup(set1, set1); + set2.insert(3); + set3.insert(4); + set3.insert(6); + set3.insert(8); + nonbonded->addInteractionGroup(set2, set3); + set4.insert(5); + set5.insert(7); + set5.insert(9); + nonbonded->addInteractionGroup(set4, set5); + + // Compute energy with and without the correction. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + double energy1 = context.getState(State::Energy).getPotentialEnergy(); + nonbonded->setUseLongRangeCorrection(true); + context.reinitialize(); + context.setPositions(positions); + double energy2 = context.getState(State::Energy).getPotentialEnergy(); + + // Check the result. + + double sum = (1.1*1.1 + 2*2.0*2.0 + 5*1.1*2.0)*2.0; + int numPairs = (numParticles*(numParticles+1))/2; + double expected = 2*M_PI*numParticles*numParticles*sum/(numPairs*boxSize*boxSize*boxSize); + ASSERT_EQUAL_TOL(expected, energy2-energy1, 1e-4); +} + +void testMultipleCutoffs() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + + // Add multiple nonbonded forces that have different cutoffs. + + CustomNonbondedForce* nonbonded1 = new CustomNonbondedForce("2*r"); + nonbonded1->addParticle(vector()); + nonbonded1->addParticle(vector()); + nonbonded1->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); + nonbonded1->setCutoffDistance(2.5); + system.addForce(nonbonded1); + CustomNonbondedForce* nonbonded2 = new CustomNonbondedForce("3*r"); + nonbonded2->addParticle(vector()); + nonbonded2->addParticle(vector()); + nonbonded2->setNonbondedMethod(CustomNonbondedForce::CutoffNonPeriodic); + nonbonded2->setCutoffDistance(2.9); + nonbonded2->setForceGroup(1); + system.addForce(nonbonded2); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(0, 0, 0); + for (double r = 2.4; r < 3.2; r += 0.2) { + positions[1][1] = r; + context.setPositions(positions); + double e1 = (r < 2.5 ? 2.0*r : 0.0); + double e2 = (r < 2.9 ? 3.0*r : 0.0); + double f1 = (r < 2.5 ? 2.0 : 0.0); + double f2 = (r < 2.9 ? 3.0 : 0.0); + + // Check the first force. + + State state = context.getState(State::Forces | State::Energy, false, 1); + ASSERT_EQUAL_VEC(Vec3(0, f1, 0), state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -f1, 0), state.getForces()[1], TOL); + ASSERT_EQUAL_TOL(e1, state.getPotentialEnergy(), TOL); + + // Check the second force. + + state = context.getState(State::Forces | State::Energy, false, 2); + ASSERT_EQUAL_VEC(Vec3(0, f2, 0), state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -f2, 0), state.getForces()[1], TOL); + ASSERT_EQUAL_TOL(e2, state.getPotentialEnergy(), TOL); + + // Check the sum of both forces. + + state = context.getState(State::Forces | State::Energy); + ASSERT_EQUAL_VEC(Vec3(0, f1+f2, 0), state.getForces()[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, -f1-f2, 0), state.getForces()[1], TOL); + ASSERT_EQUAL_TOL(e1+e2, state.getPotentialEnergy(), TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSimpleExpression(); + testParameters(); + testExclusions(); + testCutoff(); + testPeriodic(); + testTriclinic(); + testContinuous1DFunction(); + testContinuous2DFunction(); + testContinuous3DFunction(); + testDiscrete1DFunction(); + testDiscrete2DFunction(); + testDiscrete3DFunction(); + testCoulombLennardJones(); + testSwitchingFunction(); + testLongRangeCorrection(); + testInteractionGroups(); + testLargeInteractionGroup(); + testInteractionGroupLongRangeCorrection(); + testMultipleCutoffs(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCustomTorsionForce.h b/tests/TestCustomTorsionForce.h new file mode 100644 index 000000000..d98dab3ed --- /dev/null +++ b/tests/TestCustomTorsionForce.h @@ -0,0 +1,187 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomTorsionForce.h" +#include "openmm/PeriodicTorsionForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testTorsions() { + // 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 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); + ASSERT(!custom->usesPeriodicBoundaryConditions()); + ASSERT(!customSystem.usesPeriodicBoundaryConditions()); + + // 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 positions(5); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context c1(customSystem, integrator1, platform); + Context c2(harmonicSystem, integrator2, platform); + for (int i = 0; i < 50; 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)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); + } + + // Try changing the torsion parameters and make sure it's still correct. + + parameters[0] = 1.6; + parameters[1] = 2; + custom->setTorsionParameters(0, 0, 1, 2, 3, parameters); + parameters[0] = 2.1; + parameters[1] = 3; + custom->setTorsionParameters(1, 1, 2, 3, 4, parameters); + custom->updateParametersInContext(c1); + periodic->setTorsionParameters(0, 0, 1, 2, 3, 2, 1.6, 0.5); + periodic->setTorsionParameters(1, 1, 2, 3, 4, 3, 2.1, 0.5); + periodic->updateParametersInContext(c2); + { + 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)); + c1.setPositions(positions); + c2.setPositions(positions); + State s1 = c1.getState(State::Forces | State::Energy); + State s2 = c2.getState(State::Forces | State::Energy); + const vector& forces = s1.getForces(); + for (int i = 0; i < customSystem.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); + ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); + } +} + +void testRange() { + 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()); + 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 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); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testTorsions(); + testRange(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + + + -- GitLab From 2f553a66c61be51c2f5ac6021857f5fa48c0b9ba Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Wed, 23 Sep 2015 11:37:06 -0700 Subject: [PATCH 12/49] Continuing to refactor tests --- platforms/cpu/tests/CpuTests.h | 6 + platforms/cpu/tests/TestCpuCheckpoints.cpp | 99 ++ platforms/cpu/tests/TestCpuEwald.cpp | 311 +---- platforms/cpu/tests/TestCpuGBSAOBCForce.cpp | 244 +--- .../cpu/tests/TestCpuLangevinIntegrator.cpp | 255 +---- platforms/cpu/tests/TestCpuNonbondedForce.cpp | 684 +---------- platforms/cpu/tests/TestCpuSettle.cpp | 92 +- platforms/cuda/tests/TestCudaCheckpoints.cpp | 112 +- platforms/cuda/tests/TestCudaEwald.cpp | 358 +----- platforms/cuda/tests/TestCudaGBSAOBCForce.cpp | 245 +--- .../cuda/tests/TestCudaLangevinIntegrator.cpp | 256 +---- .../tests/TestCudaLocalEnergyMinimizer.cpp | 188 +--- .../TestCudaMonteCarloAnisotropicBarostat.cpp | 451 +------- .../cuda/tests/TestCudaMonteCarloBarostat.cpp | 262 +---- .../cuda/tests/TestCudaNonbondedForce.cpp | 870 +------------- platforms/cuda/tests/TestCudaSettle.cpp | 91 +- platforms/cuda/tests/nacl_amorph.dat | 894 --------------- .../opencl/tests/TestOpenCLCheckpoints.cpp | 112 +- platforms/opencl/tests/TestOpenCLEwald.cpp | 359 +----- .../opencl/tests/TestOpenCLGBSAOBCForce.cpp | 243 +--- .../tests/TestOpenCLLangevinIntegrator.cpp | 256 +---- .../tests/TestOpenCLLocalEnergyMinimizer.cpp | 189 +--- ...estOpenCLMonteCarloAnisotropicBarostat.cpp | 451 +------- .../tests/TestOpenCLMonteCarloBarostat.cpp | 264 +---- .../opencl/tests/TestOpenCLNonbondedForce.cpp | 874 +------------- platforms/opencl/tests/TestOpenCLSettle.cpp | 91 +- platforms/opencl/tests/nacl_amorph.dat | 894 --------------- .../tests/TestReferenceCheckpoints.cpp | 125 +-- .../reference/tests/TestReferenceEwald.cpp | 455 +------- .../tests/TestReferenceGBSAOBCForce.cpp | 216 +--- .../tests/TestReferenceLangevinIntegrator.cpp | 248 +--- .../TestReferenceLocalEnergyMinimizer.cpp | 186 +-- ...ReferenceMonteCarloAnisotropicBarostat.cpp | 456 +------- .../tests/TestReferenceMonteCarloBarostat.cpp | 196 +--- .../tests/TestReferenceNonbondedForce.cpp | 546 +-------- .../reference/tests/TestReferenceSettle.cpp | 89 +- platforms/reference/tests/nacl_amorph.dat | 894 --------------- .../tests/nacl_amorph_GromacsForcesEwald.dat | 894 --------------- .../tests/nacl_amorph_GromacsForcesPME.dat | 894 --------------- .../reference/tests/nacl_crystal.forces_ewald | 1000 ----------------- platforms/reference/tests/water.dat | 648 ----------- .../reference/tests/water_GromacsForces.dat | 648 ----------- tests/TestCheckpoints.h | 133 +++ tests/TestEwald.h | 405 +++++++ tests/TestGBSAOBCForce.h | 283 +++++ tests/TestLangevinIntegrator.h | 279 +++++ tests/TestLocalEnergyMinimizer.h | 215 ++++ tests/TestMonteCarloAnisotropicBarostat.h | 479 ++++++++ tests/TestMonteCarloBarostat.h | 289 +++++ tests/TestNonbondedForce.h | 712 ++++++++++++ tests/TestSettle.h | 114 ++ .../cpu/tests => tests}/nacl_amorph.dat | 0 .../tests => tests}/nacl_crystal.dat | 0 53 files changed, 3168 insertions(+), 16387 deletions(-) create mode 100644 platforms/cpu/tests/TestCpuCheckpoints.cpp delete mode 100644 platforms/cuda/tests/nacl_amorph.dat delete mode 100644 platforms/opencl/tests/nacl_amorph.dat delete mode 100644 platforms/reference/tests/nacl_amorph.dat delete mode 100644 platforms/reference/tests/nacl_amorph_GromacsForcesEwald.dat delete mode 100644 platforms/reference/tests/nacl_amorph_GromacsForcesPME.dat delete mode 100644 platforms/reference/tests/nacl_crystal.forces_ewald delete mode 100644 platforms/reference/tests/water.dat delete mode 100644 platforms/reference/tests/water_GromacsForces.dat create mode 100644 tests/TestCheckpoints.h create mode 100644 tests/TestEwald.h create mode 100644 tests/TestGBSAOBCForce.h create mode 100644 tests/TestLangevinIntegrator.h create mode 100644 tests/TestLocalEnergyMinimizer.h create mode 100644 tests/TestMonteCarloAnisotropicBarostat.h create mode 100644 tests/TestMonteCarloBarostat.h create mode 100644 tests/TestNonbondedForce.h create mode 100644 tests/TestSettle.h rename {platforms/cpu/tests => tests}/nacl_amorph.dat (100%) rename {platforms/reference/tests => tests}/nacl_crystal.dat (100%) diff --git a/platforms/cpu/tests/CpuTests.h b/platforms/cpu/tests/CpuTests.h index a237e4978..6bba1f573 100644 --- a/platforms/cpu/tests/CpuTests.h +++ b/platforms/cpu/tests/CpuTests.h @@ -30,8 +30,14 @@ * -------------------------------------------------------------------------- */ #include "CpuPlatform.h" +#include +#include OpenMM::CpuPlatform platform; void initializeTests(int argc, char* argv[]) { + if (!OpenMM::CpuPlatform::isProcessorSupported()) { + std::cout << "CPU is not supported. Exiting." << std::endl; + exit(0); + } } diff --git a/platforms/cpu/tests/TestCpuCheckpoints.cpp b/platforms/cpu/tests/TestCpuCheckpoints.cpp new file mode 100644 index 000000000..875111158 --- /dev/null +++ b/platforms/cpu/tests/TestCpuCheckpoints.cpp @@ -0,0 +1,99 @@ +/* -------------------------------------------------------------------------- * + * 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) 2012-2015 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 "CpuTests.h" +#include "TestCheckpoints.h" + +void testCheckpoint() { + const int numParticles = 100; + const double boxSize = 5.0; + const double temperature = 200.0; + System system; + system.addForce(new AndersenThermostat(0.0, 100.0)); + NonbondedForce* nonbonded = new NonbondedForce(); + system.addForce(nonbonded); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.0); + nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1); + bool clash; + do { + clash = false; + positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + for (int j = 0; j < i; j++) { + Vec3 delta = positions[i]-positions[j]; + if (sqrt(delta.dot(delta)) < 0.1) + clash = true; + } + } while (clash); + } + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + context.setParameter(AndersenThermostat::Temperature(), temperature); + + // Run for a little while. + + integrator.step(100); + + // Record the current state and make a checkpoint. + + State s1 = context.getState(State::Positions | State::Velocities | State::Parameters); + stringstream stream1(ios_base::out | ios_base::in | ios_base::binary); + context.createCheckpoint(stream1); + + // Continue the simulation for a few more steps and record the state again. + + integrator.step(10); + State s2 = context.getState(State::Positions | State::Velocities | State::Parameters); + + // Restore from the checkpoint and see if everything gets restored correctly. + + context.setPeriodicBoxVectors(Vec3(2*boxSize, 0, 0), Vec3(0, 2*boxSize, 0), Vec3(0, 0, 2*boxSize)); + context.setParameter(AndersenThermostat::Temperature(), temperature+10); + context.loadCheckpoint(stream1); + State s3 = context.getState(State::Positions | State::Velocities | State::Parameters); + compareStates(s1, s3); + + // Now simulate from there and see if the trajectory is identical. + + integrator.step(10); + State s4 = context.getState(State::Positions | State::Velocities | State::Parameters); + compareStates(s2, s4); +} + +void runPlatformTests() { + testCheckpoint(); +} diff --git a/platforms/cpu/tests/TestCpuEwald.cpp b/platforms/cpu/tests/TestCpuEwald.cpp index b18d1ee6c..30a1361c7 100644 --- a/platforms/cpu/tests/TestCpuEwald.cpp +++ b/platforms/cpu/tests/TestCpuEwald.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,311 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the Ewald summation method CPU implementation of NonbondedForce. - */ +#include "CpuTests.h" +#include "TestEwald.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.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 "openmm/internal/NonbondedForceImpl.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CpuPlatform platform; - -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; - - 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 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 CPU platforms agree when using Ewald Method - - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context cpuContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - cpuContext.setPositions(positions); - referenceContext.setPositions(positions); - State cpuState = cpuContext.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], cpuState.getForces()[i], tol); - } - tol = 1e-5; - ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cpuState.getPotentialEnergy(), tol); - -// (2) Check whether Ewald method in CPU is self-consistent - - double norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = cpuState.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 = cpuState.getForces()[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - } - VerletIntegrator integrator3(0.01); - Context cpuContext2(system, integrator3, platform); - cpuContext2.setPositions(positions); - - tol = 1e-2; - State cpuState2 = cpuContext2.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (cpuState2.getPotentialEnergy()-cpuState.getPotentialEnergy())/delta, tol) - -// (3) Check whether the Reference and CPU platforms agree when using PME - - nonbonded->setNonbondedMethod(NonbondedForce::PME); - cpuContext.reinitialize(); - referenceContext.reinitialize(); - cpuContext.setPositions(positions); - referenceContext.setPositions(positions); - cpuState = cpuContext.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], cpuState.getForces()[i], tol); - } - tol = 1e-5; - ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cpuState.getPotentialEnergy(), tol); - -// (4) Check whether PME method in CPU is self-consistent - - norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = cpuState.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 = cpuState.getForces()[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - } - VerletIntegrator integrator4(0.01); - Context cpuContext3(system, integrator4, platform); - cpuContext3.setPositions(positions); - - tol = 1e-2; - State cpuState3 = cpuContext3.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (cpuState3.getPotentialEnergy()-cpuState.getPotentialEnergy())/delta, tol) -} - -void testEwald2Ions() { - 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 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& 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 testTriclinic() { - // Create a triclinic box containing eight particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(2.5, 0, 0), Vec3(0.5, 3.0, 0), Vec3(0.7, 0.9, 3.5)); - for (int i = 0; i < 8; i++) - system.addParticle(1.0); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - force->setNonbondedMethod(NonbondedForce::PME); - force->setCutoffDistance(1.0); - force->setPMEParameters(3.45891, 32, 40, 48); - for (int i = 0; i < 4; i++) - force->addParticle(-1, 0.440104, 0.4184); // Cl parameters - for (int i = 0; i < 4; i++) - force->addParticle(1, 0.332840, 0.0115897); // Na parameters - vector positions(8); - positions[0] = Vec3(1.744, 2.788, 3.162); - positions[1] = Vec3(1.048, 0.762, 2.340); - positions[2] = Vec3(2.489, 1.570, 2.817); - positions[3] = Vec3(1.027, 1.893, 3.271); - positions[4] = Vec3(0.937, 0.825, 0.009); - positions[5] = Vec3(2.290, 1.887, 3.352); - positions[6] = Vec3(1.266, 1.111, 2.894); - positions[7] = Vec3(0.933, 1.862, 3.490); - - // Compute the forces and energy. - - VerletIntegrator integ(0.001); - Context context(system, integ, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // Compare them to values computed by Gromacs. - - double expectedEnergy = -963.370; - vector expectedForce(8); - expectedForce[0] = Vec3(4.25253e+01, -1.23503e+02, 1.22139e+02); - expectedForce[1] = Vec3(9.74752e+01, 1.68213e+02, 1.93169e+02); - expectedForce[2] = Vec3(-1.50348e+02, 1.29165e+02, 3.70435e+02); - expectedForce[3] = Vec3(9.18644e+02, -3.52571e+00, -1.34772e+03); - expectedForce[4] = Vec3(-1.61193e+02, 9.01528e+01, -7.12904e+01); - expectedForce[5] = Vec3(2.82630e+02, 2.78029e+01, -3.72864e+02); - expectedForce[6] = Vec3(-1.47454e+02, -2.14448e+02, -3.55789e+02); - expectedForce[7] = Vec3(-8.82195e+02, -7.39132e+01, 1.46202e+03); - for (int i = 0; i < 8; i++) { - ASSERT_EQUAL_VEC(expectedForce[i], state.getForces()[i], 1e-4); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-4); -} - -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 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); - - // 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 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); - } - if (method == NonbondedForce::PME) { - // See if the PME parameters were calculated correctly. - - double expectedAlpha, actualAlpha; - int expectedSize[3], actualSize[3]; - NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); - force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); - ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); - for (int i = 0; i < 3; i++) { - ASSERT(actualSize[i] >= expectedSize[i]); - ASSERT(actualSize[i] < expectedSize[i]+10); - } - } - } - } -} - -int main(int argc, char* argv[]) { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testEwaldPME(false); - testEwaldPME(true); -// testEwald2Ions(); - testTriclinic(); - testErrorTolerance(NonbondedForce::Ewald); - testErrorTolerance(NonbondedForce::PME); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuGBSAOBCForce.cpp b/platforms/cpu/tests/TestCpuGBSAOBCForce.cpp index 972cfe003..df121cef8 100644 --- a/platforms/cpu/tests/TestCpuGBSAOBCForce.cpp +++ b/platforms/cpu/tests/TestCpuGBSAOBCForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,244 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CPU implementation of GBSAOBCForce. - */ +#include "CpuTests.h" +#include "TestGBSAOBCForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/NonbondedForce.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -void testSingleParticle() { - CpuPlatform platform; - System system; - system.addParticle(2.0); - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - forceField->addParticle(0.5, 0.15, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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/forceField->getSoluteDielectric()-1.0/forceField->getSolventDielectric())/bornRadius; - double extendedRadius = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); - - // Change the parameters and see if it is still correct. - - forceField->setParticleParameters(0, 0.4, 0.25, 1); - forceField->updateParametersInContext(context); - state = context.getState(State::Energy); - bornRadius = 0.25-0.009; // dielectric offset - bornEnergy = (-0.4*0.4/(8*PI_M*eps0))*(1.0/forceField->getSoluteDielectric()-1.0/forceField->getSolventDielectric())/bornRadius; - extendedRadius = 0.25+0.14; - nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.25/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testGlobalSettings() { - CpuPlatform platform; - System system; - system.addParticle(2.0); - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - forceField->addParticle(0.5, 0.15, 1); - const double soluteDielectric = 2.1; - const double solventDielectric = 35.0; - const double surfaceAreaEnergy = 0.75; - forceField->setSoluteDielectric(soluteDielectric); - forceField->setSolventDielectric(solventDielectric); - forceField->setSurfaceAreaEnergy(surfaceAreaEnergy); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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/soluteDielectric-1.0/solventDielectric)/bornRadius; - double extendedRadius = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*surfaceAreaEnergy*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testCutoffAndPeriodic() { - CpuPlatform platform; - 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 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, platform); - 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) { - CpuPlatform platform; - 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, platform); - Context refContext(system, integrator2, reference); - - // Set random (but uniformly distributed) positions for all the particles. - - vector 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 CPU 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 and see whether the potential energy changes by the expected amount. - // (This doesn't work with cutoffs, since the energy changes discontinuously at the cutoff distance.) - - if (method == NonbondedForce::NoCutoff) - { - const double delta = 0.3; - double step = 0.5*delta/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < numParticles; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-2) - } -} - -int main() { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testSingleParticle(); - testGlobalSettings(); - 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; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuLangevinIntegrator.cpp b/platforms/cpu/tests/TestCpuLangevinIntegrator.cpp index 7d740178b..c5b988f8f 100644 --- a/platforms/cpu/tests/TestCpuLangevinIntegrator.cpp +++ b/platforms/cpu/tests/TestCpuLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,255 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of LangevinIntegrator. - */ +#include "CpuTests.h" +#include "TestLangevinIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -void testSingleBond() { - CpuPlatform 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 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; - CpuPlatform 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 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 double temp = 100.0; - CpuPlatform 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); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 < numParticles-1; ++j) { - Vec3 p1 = state.getPositions()[j]; - Vec3 p2 = state.getPositions()[j+1]; - 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(1.0, dist, 2e-5); - } - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - CpuPlatform platform; - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - LangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - CpuPlatform 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 positions(numParticles); - vector 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_EQUAL_TOL(state1.getPositions()[i][j], state2.getPositions()[i][j], 1e-5); - ASSERT_EQUAL_TOL(state3.getPositions()[i][j], state4.getPositions()[i][j], 1e-5); - ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]); - } - } -} - -int main() { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuNonbondedForce.cpp b/platforms/cpu/tests/TestCpuNonbondedForce.cpp index 65dc0dd65..dce296d33 100644 --- a/platforms/cpu/tests/TestCpuNonbondedForce.cpp +++ b/platforms/cpu/tests/TestCpuNonbondedForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,684 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the CUDA implementation of NonbondedForce. - */ +#include "CpuTests.h" +#include "TestNonbondedForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/internal/ContextImpl.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CpuPlatform platform; - -const double TOL = 1e-5; - -void testCoulomb() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0.5, 1, 0); - forceField->addParticle(-1.5, 1, 0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double force = ONE_4PI_EPS0*(-0.75)/4.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(-0.75)/2.0, state.getPotentialEnergy(), TOL); -} - -void testLJ() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0, 1.2, 1); - forceField->addParticle(0, 1.4, 2); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double x = 1.3/2.0; - double eps = SQRT_TWO; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL); -} - -void testExclusionsAnd14() { - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - for (int i = 0; i < 5; ++i) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - vector positions(5); - const double r = 1.0; - for (int j = 0; j < 5; ++j) { - nonbonded->setParticleParameters(j, 0, 1.5, 0); - positions[j] = Vec3(0, j, 0); - } - nonbonded->setParticleParameters(0, 0, 1.5, 1); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - positions[i] = Vec3(r, 0, 0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double x = 1.5/r; - double eps = 1.0; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - nonbonded->setParticleParameters(0, 2, 1.5, 0); - nonbonded->setParticleParameters(i, 2, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - context.reinitialize(); - context.setPositions(positions); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*4/(r*r); - energy = ONE_4PI_EPS0*4/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - const double cutoff = 2.9; - forceField->setCutoffDistance(cutoff); - const double eps = 50.0; - forceField->setReactionFieldDielectric(eps); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force1 = ONE_4PI_EPS0*(1.0)*(0.25-2.0*krf*2.0); - const double force2 = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL); - const double energy1 = ONE_4PI_EPS0*(1.0)*(0.5+krf*4.0-crf); - const double energy2 = ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf); - ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL); -} - -void testCutoff14() { - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - for (int i = 0; i < 5; ++i) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - const double cutoff = 3.5; - nonbonded->setCutoffDistance(cutoff); - const double eps = 30.0; - nonbonded->setReactionFieldDielectric(eps); - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(5); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(2, 0, 0); - positions[3] = Vec3(3, 0, 0); - positions[4] = Vec3(4, 0, 0); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - nonbonded->setParticleParameters(0, 0, 1.5, 1); - for (int j = 1; j < 5; ++j) - nonbonded->setParticleParameters(j, 0, 1.5, 0); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double r = positions[i][0]; - double x = 1.5/r; - double e = 1.0; - double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - const double q = 0.7; - nonbonded->setParticleParameters(0, q, 1.5, 0); - nonbonded->setParticleParameters(i, q, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - context.reinitialize(); - context.setPositions(positions); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*q*q/(r*r); - energy = ONE_4PI_EPS0*q*q/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testPeriodic() { - System system; - system.addParticle(1.0); - 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->addParticle(1.0, 1, 0); - nonbonded->addException(0, 1, 0.0, 1.0, 0.0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 2.0; - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(2, 0, 0); - positions[2] = Vec3(3, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(2*ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL); -} - -void testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta*ONE_4PI_EPS0*(-1.0/(distance*distance*distance)+2.0*krf); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(1.0/distance+krf*distance*distance-crf), state.getPotentialEnergy(), 1e-4); - ASSERT_EQUAL_VEC(force, state.getForces()[0], 2e-5); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], 2e-5); - } - } -} - -void testLargeSystem() { - const int numMolecules = 600; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 20.0; - const double tol = 2e-3; - ReferencePlatform reference; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - HarmonicBondForce* bonds = new HarmonicBondForce(); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - nonbonded->addParticle(-1.0, 0.2, 0.1); - nonbonded->addParticle(1.0, 0.1, 0.1); - } - else { - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.1, 0.2); - } - 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)); - bonds->addBond(2*i, 2*i+1, 1.0, 0.1); - nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); - } - - // Try with cutoffs but not periodic boundary conditions, and make sure the cl and Reference - // platforms agree. - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - system.addForce(bonds); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context cpuContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - cpuContext.setPositions(positions); - cpuContext.setVelocities(velocities); - referenceContext.setPositions(positions); - referenceContext.setVelocities(velocities); - State cpuState = cpuContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - State referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(cpuState.getPositions()[i], referenceState.getPositions()[i], tol); - ASSERT_EQUAL_VEC(cpuState.getVelocities()[i], referenceState.getVelocities()[i], tol); - ASSERT_EQUAL_VEC(cpuState.getForces()[i], referenceState.getForces()[i], tol); - } - ASSERT_EQUAL_TOL(cpuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); - - // Now do the same thing with periodic boundary conditions. - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - cpuContext.reinitialize(); - referenceContext.reinitialize(); - cpuContext.setPositions(positions); - cpuContext.setVelocities(velocities); - referenceContext.setPositions(positions); - referenceContext.setVelocities(velocities); - cpuState = cpuContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) { - double dx = cpuState.getPositions()[i][0]-referenceState.getPositions()[i][0]; - double dy = cpuState.getPositions()[i][1]-referenceState.getPositions()[i][1]; - double dz = cpuState.getPositions()[i][2]-referenceState.getPositions()[i][2]; - ASSERT_EQUAL_TOL(fmod(cpuState.getPositions()[i][0]-referenceState.getPositions()[i][0], boxSize), 0, tol); - ASSERT_EQUAL_TOL(fmod(cpuState.getPositions()[i][1]-referenceState.getPositions()[i][1], boxSize), 0, tol); - ASSERT_EQUAL_TOL(fmod(cpuState.getPositions()[i][2]-referenceState.getPositions()[i][2], boxSize), 0, tol); - ASSERT_EQUAL_VEC(cpuState.getVelocities()[i], referenceState.getVelocities()[i], tol); - ASSERT_EQUAL_VEC(cpuState.getForces()[i], referenceState.getForces()[i], tol); - } - ASSERT_EQUAL_TOL(cpuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); -} - -void testDispersionCorrection() { - // Create a box full of identical particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - int index = 0; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.1, 0.5); - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - // See if the correction has the correct value. - - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(false); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); - - // Now modify half the particles to be different, and see if it is still correct. - - int numType2 = 0; - for (int i = 0; i < numParticles; i += 2) { - nonbonded->setParticleParameters(i, 0, 1, 1); - numType2++; - } - int numType1 = numParticles-numType2; - nonbonded->updateParametersInContext(context); - energy2 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(true); - context.reinitialize(); - context.setPositions(positions); - energy1 = context.getState(State::Energy).getPotentialEnergy(); - term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9; - term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3; - double combinedSigma = 0.5*(1+1.1); - double combinedEpsilon = sqrt(1*0.5); - term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9; - term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3; - term1 /= (numParticles*(numParticles+1))/2; - term2 /= (numParticles*(numParticles+1))/2; - expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); -} - -void testChangingParameters() { - const int numMolecules = 600; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 20.0; - const double tol = 2e-3; - ReferencePlatform reference; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - nonbonded->addParticle(-1.0, 0.2, 0.1); - nonbonded->addParticle(1.0, 0.1, 0.1); - } - else { - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.1, 0.2); - } - 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]); - system.addConstraint(2*i, 2*i+1, 1.0); - nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); - } - nonbonded->setNonbondedMethod(NonbondedForce::PME); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - - // See if Reference and CPU give the same forces and energies. - - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context cpuContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - cpuContext.setPositions(positions); - referenceContext.setPositions(positions); - State cpuState = cpuContext.getState(State::Forces | State::Energy); - State referenceState = referenceContext.getState(State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(cpuState.getForces()[i], referenceState.getForces()[i], tol); - ASSERT_EQUAL_TOL(cpuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); - - // Now modify parameters and see if they still agree. - - for (int i = 0; i < numParticles; i += 5) { - double charge, sigma, epsilon; - nonbonded->getParticleParameters(i, charge, sigma, epsilon); - nonbonded->setParticleParameters(i, 1.5*charge, 1.1*sigma, 1.7*epsilon); - } - nonbonded->updateParametersInContext(cpuContext); - nonbonded->updateParametersInContext(referenceContext); - cpuState = cpuContext.getState(State::Forces | State::Energy); - referenceState = referenceContext.getState(State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(cpuState.getForces()[i], referenceState.getForces()[i], tol); - ASSERT_EQUAL_TOL(cpuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); -} - -void testSwitchingFunction(NonbondedForce::NonbondedMethod method) { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(0, 1.2, 1); - nonbonded->addParticle(0, 1.4, 2); - nonbonded->setNonbondedMethod(method); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - nonbonded->setUseDispersionCorrection(false); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - double eps = SQRT_TWO; - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double x = 1.3/r; - double expectedEnergy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - -int main(int argc, char* argv[]) { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testCoulomb(); - testLJ(); - testExclusionsAnd14(); - testCutoff(); - testCutoff14(); - testPeriodic(); - testTriclinic(); - testLargeSystem(); - testDispersionCorrection(); - testChangingParameters(); - testSwitchingFunction(NonbondedForce::CutoffNonPeriodic); - testSwitchingFunction(NonbondedForce::PME); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cpu/tests/TestCpuSettle.cpp b/platforms/cpu/tests/TestCpuSettle.cpp index 9cf9a2b3d..e5a9315c3 100644 --- a/platforms/cpu/tests/TestCpuSettle.cpp +++ b/platforms/cpu/tests/TestCpuSettle.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,91 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CPU implementation of the SETTLE algorithm. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CpuPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -void testConstraints() { - const int numMolecules = 10; - const int numParticles = numMolecules*3; - const int numConstraints = numMolecules*3; - const double temp = 100.0; - CpuPlatform platform; - System system; - LangevinIntegrator integrator(temp, 2.0, 0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numMolecules; ++i) { - system.addParticle(16.0); - system.addParticle(1.0); - system.addParticle(1.0); - forceField->addParticle(-0.82, 0.317, 0.65); - forceField->addParticle(0.41, 1.0, 0.0); - forceField->addParticle(0.41, 1.0, 0.0); - system.addConstraint(i*3, i*3+1, 0.1); - system.addConstraint(i*3, i*3+2, 0.1); - system.addConstraint(i*3+1, i*3+2, 0.163); - } - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; ++i) { - positions[i*3] = Vec3((i%4)*0.4, (i/4)*0.4, 0); - positions[i*3+1] = positions[i*3]+Vec3(0.1, 0, 0); - positions[i*3+2] = positions[i*3]+Vec3(-0.03333, 0.09428, 0); - velocities[i*3] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+1] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+2] = 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) { - integrator.step(1); - State state = context.getState(State::Positions | State::Forces); - 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-5); - } - } -} +#include "CpuTests.h" +#include "TestSettle.h" -int main(int argc, char* argv[]) { - try { - if (!CpuPlatform::isProcessorSupported()) { - cout << "CPU is not supported. Exiting." << endl; - return 0; - } - testConstraints(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaCheckpoints.cpp b/platforms/cuda/tests/TestCudaCheckpoints.cpp index ee72c6b72..3ed747e6e 100644 --- a/platforms/cuda/tests/TestCudaCheckpoints.cpp +++ b/platforms/cuda/tests/TestCudaCheckpoints.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2013 Stanford University and the Authors. * + * Portions copyright (c) 2012-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,45 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests creating and loading checkpoints with the CUDA platform. - */ - -#include "CudaPlatform.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/Context.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -const double TOL = 1e-5; - -CudaPlatform platform; - -void compareStates(State& s1, State& s2) { - ASSERT_EQUAL_TOL(s1.getTime(), s2.getTime(), TOL); - int numParticles = s1.getPositions().size(); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], TOL); - ASSERT_EQUAL_VEC(s1.getVelocities()[i], s2.getVelocities()[i], TOL); - Vec3 a1, b1, c1, a2, b2, c2; - s1.getPeriodicBoxVectors(a1, b1, c1); - s2.getPeriodicBoxVectors(a2, b2, c2); - ASSERT_EQUAL_VEC(a1, a2, TOL); - ASSERT_EQUAL_VEC(b1, b2, TOL); - ASSERT_EQUAL_VEC(c1, c2, TOL); - for (map::const_iterator iter = s1.getParameters().begin(); iter != s1.getParameters().end(); ++iter) - ASSERT_EQUAL(iter->second, (*s2.getParameters().find(iter->first)).second); - } -} +#include "CudaTests.h" +#include "TestCheckpoints.h" void testCheckpoint() { const int numParticles = 100; @@ -159,71 +122,6 @@ void testCheckpoint() { compareStates(s6, s8); } -void testSetState() { - const int numParticles = 10; - const double boxSize = 3.0; - const double temperature = 200.0; - System system; - system.addForce(new AndersenThermostat(0.0, 100.0)); - NonbondedForce* nonbonded = new NonbondedForce(); - system.addForce(nonbonded); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1); - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - } - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - context.setParameter(AndersenThermostat::Temperature(), temperature); - - // Run for a little while. - - integrator.step(100); - - // Record the current state. - - State s1 = context.getState(State::Positions | State::Velocities | State::Parameters); - - // Continue the simulation for a few more steps and record a partial state. - - integrator.step(10); - State s2 = context.getState(State::Positions); - - // Restore the original state and see if everything gets restored correctly. - - context.setPeriodicBoxVectors(Vec3(2*boxSize, 0, 0), Vec3(0, 2*boxSize, 0), Vec3(0, 0, 2*boxSize)); - context.setParameter(AndersenThermostat::Temperature(), temperature+10); - context.setState(s1); - State s3 = context.getState(State::Positions | State::Velocities | State::Parameters); - compareStates(s1, s3); - - // Set the partial state and see if the correct things were set. - - context.setState(s2); - State s4 = context.getState(State::Positions | State::Velocities | State::Parameters); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(s2.getPositions()[i], s4.getPositions()[i], TOL); - ASSERT_EQUAL_VEC(s1.getVelocities()[i], s4.getVelocities()[i], TOL); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testCheckpoint(); - testSetState(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testCheckpoint(); } diff --git a/platforms/cuda/tests/TestCudaEwald.cpp b/platforms/cuda/tests/TestCudaEwald.cpp index 6f8aca66f..9efc4eaa4 100644 --- a/platforms/cuda/tests/TestCudaEwald.cpp +++ b/platforms/cuda/tests/TestCudaEwald.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,358 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the Ewald summation method CUDA implementation of NonbondedForce. - */ +#include "CudaTests.h" +#include "TestEwald.h" -#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 "openmm/internal/NonbondedForceImpl.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -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; - - 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 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 cuContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - cuContext.setPositions(positions); - referenceContext.setPositions(positions); - State cuState = cuContext.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], cuState.getForces()[i], tol); - } - tol = 1e-5; - ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cuState.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 = cuState.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 = cuState.getForces()[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - } - VerletIntegrator integrator3(0.01); - Context cuContext2(system, integrator3, platform); - cuContext2.setPositions(positions); - - tol = 1e-2; - State cuState2 = cuContext2.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (cuState2.getPotentialEnergy()-cuState.getPotentialEnergy())/delta, tol) - -// (3) Check whether the Reference and CUDA platforms agree when using PME - - nonbonded->setNonbondedMethod(NonbondedForce::PME); - cuContext.reinitialize(); - referenceContext.reinitialize(); - cuContext.setPositions(positions); - referenceContext.setPositions(positions); - cuState = cuContext.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], cuState.getForces()[i], tol); - } - tol = 1e-5; - ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cuState.getPotentialEnergy(), tol); - -// (4) Check whether PME method in CUDA is self-consistent - - norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = cuState.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 = cuState.getForces()[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - } - VerletIntegrator integrator4(0.01); - Context cuContext3(system, integrator4, platform); - cuContext3.setPositions(positions); - - tol = 1e-2; - State cuState3 = cuContext3.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (cuState3.getPotentialEnergy()-cuState.getPotentialEnergy())/delta, tol) -} - -void testEwald2Ions() { - 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 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& 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 testTriclinic() { - // Create a triclinic box containing eight particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(2.5, 0, 0), Vec3(0.5, 3.0, 0), Vec3(0.7, 0.9, 3.5)); - for (int i = 0; i < 8; i++) - system.addParticle(1.0); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - force->setNonbondedMethod(NonbondedForce::PME); - force->setCutoffDistance(1.0); - force->setPMEParameters(3.45891, 32, 40, 48); - for (int i = 0; i < 4; i++) - force->addParticle(-1, 0.440104, 0.4184); // Cl parameters - for (int i = 0; i < 4; i++) - force->addParticle(1, 0.332840, 0.0115897); // Na parameters - vector positions(8); - positions[0] = Vec3(1.744, 2.788, 3.162); - positions[1] = Vec3(1.048, 0.762, 2.340); - positions[2] = Vec3(2.489, 1.570, 2.817); - positions[3] = Vec3(1.027, 1.893, 3.271); - positions[4] = Vec3(0.937, 0.825, 0.009); - positions[5] = Vec3(2.290, 1.887, 3.352); - positions[6] = Vec3(1.266, 1.111, 2.894); - positions[7] = Vec3(0.933, 1.862, 3.490); - - // Compute the forces and energy. - - VerletIntegrator integ(0.001); - Context context(system, integ, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // Compare them to values computed by Gromacs. - - double expectedEnergy = -963.370; - vector expectedForce(8); - expectedForce[0] = Vec3(4.25253e+01, -1.23503e+02, 1.22139e+02); - expectedForce[1] = Vec3(9.74752e+01, 1.68213e+02, 1.93169e+02); - expectedForce[2] = Vec3(-1.50348e+02, 1.29165e+02, 3.70435e+02); - expectedForce[3] = Vec3(9.18644e+02, -3.52571e+00, -1.34772e+03); - expectedForce[4] = Vec3(-1.61193e+02, 9.01528e+01, -7.12904e+01); - expectedForce[5] = Vec3(2.82630e+02, 2.78029e+01, -3.72864e+02); - expectedForce[6] = Vec3(-1.47454e+02, -2.14448e+02, -3.55789e+02); - expectedForce[7] = Vec3(-8.82195e+02, -7.39132e+01, 1.46202e+03); - for (int i = 0; i < 8; i++) { - ASSERT_EQUAL_VEC(expectedForce[i], state.getForces()[i], 1e-4); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-4); -} - -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 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); - - // 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 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); - } - if (method == NonbondedForce::PME) { - // See if the PME parameters were calculated correctly. - - double expectedAlpha, actualAlpha; - int expectedSize[3], actualSize[3]; - NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); - force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); - ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); - for (int i = 0; i < 3; i++) { - ASSERT(actualSize[i] >= expectedSize[i]); - ASSERT(actualSize[i] < expectedSize[i]+10); - } - } - } - } -} - -void testPMEParameters() { - // Create a cloud of random point charges. - - const int numParticles = 51; - const double boxWidth = 4.7; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth)); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - vector 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(NonbondedForce::PME); - - // Compute the energy with an error tolerance of 1e-3. - - force->setEwaldErrorTolerance(1e-3); - VerletIntegrator integrator1(0.01); - Context context1(system, integrator1, platform); - context1.setPositions(positions); - double energy1 = context1.getState(State::Energy).getPotentialEnergy(); - - // Try again with an error tolerance of 1e-4. - - force->setEwaldErrorTolerance(1e-4); - VerletIntegrator integrator2(0.01); - Context context2(system, integrator2, platform); - context2.setPositions(positions); - double energy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // Now explicitly set the parameters. These should match the values that were - // used for tolerance 1e-3. - - force->setPMEParameters(2.49291157051793, 32, 32, 32); - VerletIntegrator integrator3(0.01); - Context context3(system, integrator3, platform); - context3.setPositions(positions); - double energy3 = context3.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(energy1, energy3, 1e-6); - ASSERT(fabs((energy1-energy2)/energy1) > 1e-5); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testEwaldPME(false); - testEwaldPME(true); -// testEwald2Ions(); - testTriclinic(); - testErrorTolerance(NonbondedForce::Ewald); - testErrorTolerance(NonbondedForce::PME); - testPMEParameters(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaGBSAOBCForce.cpp b/platforms/cuda/tests/TestCudaGBSAOBCForce.cpp index 87e01f19a..6efdd1a7e 100644 --- a/platforms/cuda/tests/TestCudaGBSAOBCForce.cpp +++ b/platforms/cuda/tests/TestCudaGBSAOBCForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,245 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of GBSAOBCForce. - */ +#include "CudaTests.h" +#include "TestGBSAOBCForce.h" -#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 "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include "openmm/NonbondedForce.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testSingleParticle() { - 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 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 = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); - - // Change the parameters and see if it is still correct. - - gbsa->setParticleParameters(0, 0.4, 0.25, 1); - gbsa->updateParametersInContext(context); - state = context.getState(State::Energy); - bornRadius = 0.25-0.009; // dielectric offset - bornEnergy = (-0.4*0.4/(8*PI_M*eps0))*(1.0/gbsa->getSoluteDielectric()-1.0/gbsa->getSolventDielectric())/bornRadius; - extendedRadius = 0.25+0.14; - nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.25/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testGlobalSettings() { - System system; - system.addParticle(2.0); - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - forceField->addParticle(0.5, 0.15, 1); - const double soluteDielectric = 2.1; - const double solventDielectric = 35.0; - const double surfaceAreaEnergy = 0.75; - forceField->setSoluteDielectric(soluteDielectric); - forceField->setSolventDielectric(solventDielectric); - forceField->setSurfaceAreaEnergy(surfaceAreaEnergy); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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/soluteDielectric-1.0/solventDielectric)/bornRadius; - double extendedRadius = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*surfaceAreaEnergy*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testCutoffAndPeriodic() { - 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 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, platform); - 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 runPlatformTests() { } - -void testForce(int numParticles, NonbondedForce::NonbondedMethod method, GBSAOBCForce::NonbondedMethod method2) { - 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, platform); - Context refContext(system, integrator2, reference); - - // Set random (but uniformly distributed) positions for all the particles. - - vector 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 and see whether the potential energy changes by the expected amount. - // (This doesn't work with cutoffs, since the energy changes discontinuously at the cutoff distance.) - - if (method == NonbondedForce::NoCutoff) - { - const double delta = 0.3; - double step = 0.5*delta/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < numParticles; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-2) - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleParticle(); - testGlobalSettings(); - 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; -} - diff --git a/platforms/cuda/tests/TestCudaLangevinIntegrator.cpp b/platforms/cuda/tests/TestCudaLangevinIntegrator.cpp index 2b2e2e6e1..6e0eb66ac 100644 --- a/platforms/cuda/tests/TestCudaLangevinIntegrator.cpp +++ b/platforms/cuda/tests/TestCudaLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,256 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of LangevinIntegrator. - */ +#include "CudaTests.h" +#include "TestLangevinIntegrator.h" -#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 "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - 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 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; - 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 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; - 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 positions(numParticles); - vector 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 testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - LangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaLocalEnergyMinimizer.cpp b/platforms/cuda/tests/TestCudaLocalEnergyMinimizer.cpp index fc1108fa1..1a99b37cb 100644 --- a/platforms/cuda/tests/TestCudaLocalEnergyMinimizer.cpp +++ b/platforms/cuda/tests/TestCudaLocalEnergyMinimizer.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2010-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,187 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -#include "openmm/internal/AssertionUtilities.h" -#include "CudaPlatform.h" -#include "openmm/Context.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/LocalEnergyMinimizer.h" -#include "openmm/NonbondedForce.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/VirtualSite.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -void testHarmonicBonds() { - const int numParticles = 10; - System system; - HarmonicBondForce* bonds = new HarmonicBondForce(); - system.addForce(bonds); - - // Create a chain of particles connected by harmonic bonds. - - vector positions(numParticles); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - positions[i] = Vec3(i, 0, 0); - if (i > 0) - bonds->addBond(i-1, i, 1+0.1*i, 1); - } - - // Minimize it and check that all bonds are at their equilibrium distances. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - LocalEnergyMinimizer::minimize(context, 1e-5); - State state = context.getState(State::Positions); - for (int i = 1; i < numParticles; i++) { - Vec3 delta = state.getPositions()[i]-state.getPositions()[i-1]; - ASSERT_EQUAL_TOL(1+0.1*i, sqrt(delta.dot(delta)), 1e-4); - } -} - -void testLargeSystem() { - const int numMolecules = 25; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 4.0; - const double tolerance = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setCutoffDistance(cutoff); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Create a cloud of molecules. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < numMolecules; i++) { - system.addParticle(1.0); - system.addParticle(1.0); - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.2, 0.2); - 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]); - system.addConstraint(2*i, 2*i+1, 1.0); - } - - // Minimize it and verify that the energy has decreased. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State initialState = context.getState(State::Forces | State::Energy); - LocalEnergyMinimizer::minimize(context, tolerance); - State finalState = context.getState(State::Forces | State::Energy | State::Positions); - ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); - - // Compute the force magnitude, subtracting off any component parallel to a constraint, and - // check that it satisfies the requested tolerance. - - double forceNorm = 0.0; - for (int i = 0; i < numParticles; i += 2) { - Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; - double distance = sqrt(dir.dot(dir)); - dir *= 1.0/distance; - Vec3 f = finalState.getForces()[i]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - f = finalState.getForces()[i+1]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - } - forceNorm = sqrt(forceNorm/(5*numMolecules)); - ASSERT(forceNorm < 2*tolerance); -} - -void testVirtualSites() { - const int numMolecules = 25; - const int numParticles = numMolecules*3; - const double cutoff = 2.0; - const double boxSize = 4.0; - const double tolerance = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setCutoffDistance(cutoff); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Create a cloud of molecules. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < numMolecules; i++) { - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(0.5, 0.2, 0.2); - nonbonded->addParticle(0.5, 0.2, 0.2); - positions[3*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - positions[3*i+1] = Vec3(positions[3*i][0]+1.0, positions[3*i][1], positions[3*i][2]); - positions[3*i+2] = Vec3(); - system.addConstraint(3*i, 3*i+1, 1.0); - system.setVirtualSite(3*i+2, new TwoParticleAverageSite(3*i, 3*i+1, 0.5, 0.5)); - } - - // Minimize it and verify that the energy has decreased. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.applyConstraints(1e-5); - State initialState = context.getState(State::Forces | State::Energy); - LocalEnergyMinimizer::minimize(context, tolerance); - State finalState = context.getState(State::Forces | State::Energy | State::Positions); - ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); - - // Compute the force magnitude, subtracting off any component parallel to a constraint, and - // check that it satisfies the requested tolerance. - - double forceNorm = 0.0; - for (int i = 0; i < numParticles; i += 3) { - Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; - double distance = sqrt(dir.dot(dir)); - dir *= 1.0/distance; - Vec3 f = finalState.getForces()[i]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - f = finalState.getForces()[i+1]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - - // Check the virtual site location. - - ASSERT_EQUAL_VEC((finalState.getPositions()[i+1]+finalState.getPositions()[i])*0.5, finalState.getPositions()[i+2], 1e-5); - } - forceNorm = sqrt(forceNorm/(5*numMolecules)); - ASSERT(forceNorm < 2*tolerance); -} +#include "CudaTests.h" +#include "TestLocalEnergyMinimizer.h" -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testHarmonicBonds(); - testLargeSystem(); - testVirtualSites(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaMonteCarloAnisotropicBarostat.cpp b/platforms/cuda/tests/TestCudaMonteCarloAnisotropicBarostat.cpp index 8c2501481..84a7f5711 100644 --- a/platforms/cuda/tests/TestCudaMonteCarloAnisotropicBarostat.cpp +++ b/platforms/cuda/tests/TestCudaMonteCarloAnisotropicBarostat.cpp @@ -6,8 +6,8 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * - * Authors: Peter Eastman, Lee-Ping Wang * + * Portions copyright (c) 2015 Stanford University and the Authors. * + * Authors: Peter Eastman * * Contributors: * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -29,449 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of MonteCarloAnisotropicBarostat. - */ +#include "CudaTests.h" +#include "TestMonteCarloAnisotropicBarostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/MonteCarloBarostat.h" -#include "openmm/MonteCarloAnisotropicBarostat.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -void testIdealGas() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], true, true, true, frequency); - system.addForce(barostat); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - } -} - -void testIdealGasAxis(int axis) { - // Test scaling just one axis. - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - const bool scaleX = (axis == 0); - const bool scaleY = (axis == 1); - const bool scaleZ = (axis == 2); - double boxX; - double boxY; - double boxZ; - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], scaleX, scaleY, scaleZ, frequency); - system.addForce(barostat); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - boxX = box[0][0]; - boxY = box[1][1]; - boxZ = box[2][2]; - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - if (!scaleX) { - ASSERT(boxX == initialLength); - } - if (!scaleY) { - ASSERT(boxY == 0.5*initialLength); - } - if (!scaleZ) { - ASSERT(boxZ == 2*initialLength); - } - } -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double pressure = 1.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - 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); - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp, true, true, true, 1); - system.addForce(barostat); - vector positions(numParticles); - vector 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. - - barostat->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. - - barostat->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]); - } - } -} - -void testTriclinic() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temperature = 300.0; - const double initialVolume = numParticles*BOLTZ*temperature/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - Vec3 initialBox[3]; - initialBox[0] = Vec3(initialLength, 0, 0); - initialBox[1] = Vec3(0.2*initialLength, initialLength, 0); - initialBox[2] = Vec3(0.1*initialLength, 0.3*initialLength, initialLength); - system.setDefaultPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temperature, true, true, true, frequency); - system.addForce(barostat); - - // Run a simulation - - LangevinIntegrator integrator(temperature, 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temperature/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - - // Make sure the box vectors have been scaled consistently. - - State state = context.getState(State::Positions); - Vec3 box[3]; - state.getPeriodicBoxVectors(box[0], box[1], box[2]); - double xscale = box[2][0]/(0.1*initialLength); - double yscale = box[2][1]/(0.3*initialLength); - double zscale = box[2][2]/(1.0*initialLength); - for (int i = 0; i < 3; i++) { - ASSERT_EQUAL_VEC(Vec3(xscale*initialBox[i][0], yscale*initialBox[i][1], zscale*initialBox[i][2]), box[i], 1e-5); - } - - // The barostat should have put all particles inside the first periodic box. One integration step - // has happened since then, so they may have moved slightly outside it. - - for (int i = 0; i < numParticles; i++) { - Vec3 pos = state.getPositions()[i]; - ASSERT(pos[2]/box[2][2] > -1 && pos[2]/box[2][2] < 2); - pos -= box[2]*floor(pos[2]/box[2][2]); - ASSERT(pos[1]/box[1][1] > -1 && pos[1]/box[1][1] < 2); - pos -= box[1]*floor(pos[1]/box[1][1]); - ASSERT(pos[0]/box[0][0] > -1 && pos[0]/box[0][0] < 2); - } -} - -/** - * Run a constant pressure simulation on an anisotropic Einstein crystal - * using isotropic and anisotropic barostats. There are a total of 15 simulations: - * - * 1) 3 pressures: 9.0, 10.0, 11.0 bar, for each of the following groups: - * 2) 3 groups of simulations that scale just one axis: x, y, z - * 3) 1 group of simulations that scales all three axes in the anisotropic barostat - * 4) 1 group of simulations that scales all three axes in the isotropic barostat - * - * Results that we will check: - * - * a) In each group of simulations, the volume should decrease with increasing pressure - * b) In the three simulation groups that scale just one axis, the compressibility (i.e. incremental volume change - * with increasing pressure) should go like kx > ky > kz (because the spring constant is largest in the z-direction) - * c) The anisotropic barostat should produce the same result as the isotropic barostat when all three axes are scaled - */ -void testEinsteinCrystal() { - const int numParticles = 64; - const int frequency = 2; - const int equil = 10000; - const int steps = 5000; - const double pressure = 10.0; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp = 300.0; // Only test one temperature since we're looking at three pressures. - const double pres3[] = {2.0, 8.0, 15.0}; - const double initialVolume = numParticles*BOLTZ*temp/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - vector initialPositions(3); - vector results; - // Run four groups of anisotropic simulations; scaling just x, y, z, then all three. - for (int a = 0; a < 4; a++) { - // Test barostat for three different pressures. - for (int p = 0; p < 3; p++) { - // Create a system of noninteracting particles attached by harmonic springs to their initial positions. - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - // Anisotropic force constants. - CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); - initialPositions[0] = positions[i][0]; - initialPositions[1] = positions[i][1]; - initialPositions[2] = positions[i][2]; - force->addParticle(i, initialPositions); - nb->addParticle(0, initialLength/6, 0.1); - } - system.addForce(force); - system.addForce(nb); - // Create the barostat. - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pres3[p], pres3[p], pres3[p]), temp, (a==0||a==3), (a==1||a==3), (a==2||a==3), frequency); - system.addForce(barostat); - barostat->setTemperature(temp); - LangevinIntegrator integrator(temp, 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - // Let it equilibrate. - integrator.step(equil); - // Now run it for a while and see if the volume is correct. - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - results.push_back(volume); - } - } - for (int p = 0; p < 3; p++) { - // Create a system of noninteracting particles attached by harmonic springs to their initial positions. - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - // Anisotropic force constants. - CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); - initialPositions[0] = positions[i][0]; - initialPositions[1] = positions[i][1]; - initialPositions[2] = positions[i][2]; - force->addParticle(i, initialPositions); - nb->addParticle(0, initialLength/6, 0.1); - } - system.addForce(force); - system.addForce(nb); - // Create the barostat. - MonteCarloBarostat* barostat = new MonteCarloBarostat(pres3[p], temp, frequency); - system.addForce(barostat); - barostat->setTemperature(temp); - LangevinIntegrator integrator(temp, 0.1, 0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - // Let it equilibrate. - integrator.step(equil); - // Now run it for a while and see if the volume is correct. - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - results.push_back(volume); - } - - // Check to see if volumes decrease with increasing pressure. - ASSERT_USUALLY_TRUE(results[0] > results[1]); - ASSERT_USUALLY_TRUE(results[1] > results[2]); - ASSERT_USUALLY_TRUE(results[3] > results[4]); - ASSERT_USUALLY_TRUE(results[4] > results[5]); - ASSERT_USUALLY_TRUE(results[6] > results[7]); - ASSERT_USUALLY_TRUE(results[7] > results[8]); - - // Check to see if incremental volume changes with increasing pressure go like kx > ky > kz. - ASSERT_USUALLY_TRUE((results[0] - results[1]) > (results[3] - results[4])); - ASSERT_USUALLY_TRUE((results[1] - results[2]) > (results[4] - results[5])); - ASSERT_USUALLY_TRUE((results[3] - results[4]) > (results[6] - results[7])); - ASSERT_USUALLY_TRUE((results[4] - results[5]) > (results[7] - results[8])); - - // Check to see if the volumes are equal for isotropic and anisotropic (all axis). - ASSERT_USUALLY_EQUAL_TOL(results[9], results[12], 3/std::sqrt((double) steps)); - ASSERT_USUALLY_EQUAL_TOL(results[10], results[13], 3/std::sqrt((double) steps)); - ASSERT_USUALLY_EQUAL_TOL(results[11], results[14], 3/std::sqrt((double) steps)); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testIdealGas(); - testIdealGasAxis(0); - testIdealGasAxis(1); - testIdealGasAxis(2); - testRandomSeed(); - testTriclinic(); - //testEinsteinCrystal(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaMonteCarloBarostat.cpp b/platforms/cuda/tests/TestCudaMonteCarloBarostat.cpp index 08db822f1..836d0532b 100644 --- a/platforms/cuda/tests/TestCudaMonteCarloBarostat.cpp +++ b/platforms/cuda/tests/TestCudaMonteCarloBarostat.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,261 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of MonteCarloBarostat. - */ +#include "CudaTests.h" +#include "TestMonteCarloBarostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/MonteCarloBarostat.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -void testChangingBoxSize() { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 5, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nb->setCutoffDistance(2.0); - nb->addParticle(1, 0.5, 0.5); - system.addForce(nb); - LangevinIntegrator integrator(300.0, 1.0, 0.01); - Context context(system, integrator, platform); - vector positions; - positions.push_back(Vec3()); - context.setPositions(positions); - Vec3 x, y, z; - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ASSERT_EQUAL_VEC(Vec3(4, 0, 0), x, 0); - ASSERT_EQUAL_VEC(Vec3(0, 5, 0), y, 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 6), z, 0); - context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 9)); - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ASSERT_EQUAL_VEC(Vec3(7, 0, 0), x, 0); - ASSERT_EQUAL_VEC(Vec3(0, 8, 0), y, 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 9), z, 0); - - // Shrinking the box too small should produce an exception. - - context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 3.9, 0), Vec3(0, 0, 9)); - bool ok = true; - try { - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ok = false; - } - catch (exception& ex) { - } - ASSERT(ok); -} - -void testIdealGas() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp[0], frequency); - system.addForce(barostat); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - ASSERT_EQUAL_TOL(0.5*box[0][0], box[1][1], 1e-5); - ASSERT_EQUAL_TOL(2*box[0][0], box[2][2], 1e-5); - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - } -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double pressure = 1.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - 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); - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, 1); - system.addForce(barostat); - vector positions(numParticles); - vector 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. - - barostat->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. - - barostat->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]); - } - } -} - -void testWater() { - const int gridSize = 8; - const int numMolecules = gridSize*gridSize*gridSize; - const int frequency = 10; - const int steps = 400; - const double temp = 273.15; - const double pressure = 3; - const double spacing = 0.32; - const double angle = 109.47*M_PI/180; - const double dOH = 0.1; - const double dHH = dOH*2*std::sin(0.5*angle); - - // Create a box of SPC water molecules. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(gridSize*spacing, 0, 0), Vec3(0, gridSize*spacing, 0), Vec3(0, 0, gridSize*spacing)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setUseDispersionCorrection(true); - vector positions; - Vec3 offset1(dOH, 0, 0); - Vec3 offset2(dOH*std::cos(angle), dOH*std::sin(angle), 0); - for (int i = 0; i < gridSize; ++i) { - for (int j = 0; j < gridSize; ++j) { - for (int k = 0; k < gridSize; ++k) { - int firstParticle = system.getNumParticles(); - system.addParticle(16.0); - system.addParticle(1.0); - system.addParticle(1.0); - nonbonded->addParticle(-0.82, 0.316557, 0.650194); - nonbonded->addParticle(0.41, 1, 0); - nonbonded->addParticle(0.41, 1, 0); - Vec3 pos = Vec3(spacing*i, spacing*j, spacing*k); - positions.push_back(pos); - positions.push_back(pos+offset1); - positions.push_back(pos+offset2); - system.addConstraint(firstParticle, firstParticle+1, dOH); - system.addConstraint(firstParticle, firstParticle+2, dOH); - system.addConstraint(firstParticle+1, firstParticle+2, dHH); - nonbonded->addException(firstParticle, firstParticle+1, 0, 1, 0); - nonbonded->addException(firstParticle, firstParticle+2, 0, 1, 0); - nonbonded->addException(firstParticle+1, firstParticle+2, 0, 1, 0); - } - } - } - system.addForce(nonbonded); - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, frequency); - system.addForce(barostat); - - // Simulate it and see if the density matches the expected value (1 g/mL). - - LangevinIntegrator integrator(temp, 1.0, 0.002); - Context context(system, integrator, platform); - context.setPositions(positions); - integrator.step(2000); - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double density = numMolecules*18/(AVOGADRO*volume*1e-21); - ASSERT_USUALLY_EQUAL_TOL(1.0, density, 0.02); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testChangingBoxSize(); - testIdealGas(); - testRandomSeed(); - testWater(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testWater(); } diff --git a/platforms/cuda/tests/TestCudaNonbondedForce.cpp b/platforms/cuda/tests/TestCudaNonbondedForce.cpp index 602d51ed2..989c2c38e 100644 --- a/platforms/cuda/tests/TestCudaNonbondedForce.cpp +++ b/platforms/cuda/tests/TestCudaNonbondedForce.cpp @@ -29,785 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the CUDA implementation of NonbondedForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/internal/ContextImpl.h" -#include "CudaArray.h" -#include "CudaNonbondedUtilities.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testCoulomb() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0.5, 1, 0); - forceField->addParticle(-1.5, 1, 0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double force = ONE_4PI_EPS0*(-0.75)/4.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(-0.75)/2.0, state.getPotentialEnergy(), TOL); -} - -void testLJ() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0, 1.2, 1); - forceField->addParticle(0, 1.4, 2); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double x = 1.3/2.0; - double eps = SQRT_TWO; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL); -} - -void testExclusionsAnd14() { - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - for (int i = 0; i < 5; ++i) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - vector positions(5); - const double r = 1.0; - for (int j = 0; j < 5; ++j) { - nonbonded->setParticleParameters(j, 0, 1.5, 0); - positions[j] = Vec3(0, j, 0); - } - nonbonded->setParticleParameters(0, 0, 1.5, 1); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - positions[i] = Vec3(r, 0, 0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double x = 1.5/r; - double eps = 1.0; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - nonbonded->setParticleParameters(0, 2, 1.5, 0); - nonbonded->setParticleParameters(i, 2, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - context.reinitialize(); - context.setPositions(positions); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*4/(r*r); - energy = ONE_4PI_EPS0*4/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - const double cutoff = 2.9; - forceField->setCutoffDistance(cutoff); - const double eps = 50.0; - forceField->setReactionFieldDielectric(eps); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force1 = ONE_4PI_EPS0*(1.0)*(0.25-2.0*krf*2.0); - const double force2 = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL); - const double energy1 = ONE_4PI_EPS0*(1.0)*(0.5+krf*4.0-crf); - const double energy2 = ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf); - ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL); -} - -void testCutoff14() { - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - for (int i = 0; i < 5; ++i) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - const double cutoff = 3.5; - nonbonded->setCutoffDistance(cutoff); - const double eps = 30.0; - nonbonded->setReactionFieldDielectric(eps); - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(5); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(2, 0, 0); - positions[3] = Vec3(3, 0, 0); - positions[4] = Vec3(4, 0, 0); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - nonbonded->setParticleParameters(0, 0, 1.5, 1); - for (int j = 1; j < 5; ++j) - nonbonded->setParticleParameters(j, 0, 1.5, 0); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double r = positions[i][0]; - double x = 1.5/r; - double e = 1.0; - double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - const double q = 0.7; - nonbonded->setParticleParameters(0, q, 1.5, 0); - nonbonded->setParticleParameters(i, q, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - context.reinitialize(); - context.setPositions(positions); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*q*q/(r*r); - energy = ONE_4PI_EPS0*q*q/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testPeriodic() { - System system; - system.addParticle(1.0); - 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->addParticle(1.0, 1, 0); - nonbonded->addException(0, 1, 0.0, 1.0, 0.0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 2.0; - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(2, 0, 0); - positions[2] = Vec3(3, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(2*ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL); -} - -void testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta*ONE_4PI_EPS0*(-1.0/(distance*distance*distance)+2.0*krf); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(1.0/distance+krf*distance*distance-crf), state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); - } - } -} - -void testLargeSystem() { - const int numMolecules = 600; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 20.0; - const double tol = 2e-3; - ReferencePlatform reference; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - HarmonicBondForce* bonds = new HarmonicBondForce(); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - nonbonded->addParticle(-1.0, 0.2, 0.1); - nonbonded->addParticle(1.0, 0.1, 0.1); - } - else { - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.1, 0.2); - } - 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)); - bonds->addBond(2*i, 2*i+1, 1.0, 0.1); - nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); - } - - // Try with cutoffs but not periodic boundary conditions, and make sure the cl and Reference - // platforms agree. - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - system.addForce(bonds); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context cuContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - cuContext.setPositions(positions); - cuContext.setVelocities(velocities); - referenceContext.setPositions(positions); - referenceContext.setVelocities(velocities); - State cuState = cuContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - State referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(cuState.getPositions()[i], referenceState.getPositions()[i], tol); - ASSERT_EQUAL_VEC(cuState.getVelocities()[i], referenceState.getVelocities()[i], tol); - ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); - } - ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); - - // Now do the same thing with periodic boundary conditions. - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - cuContext.reinitialize(); - referenceContext.reinitialize(); - cuContext.setPositions(positions); - cuContext.setVelocities(velocities); - referenceContext.setPositions(positions); - referenceContext.setVelocities(velocities); - cuState = cuContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) { - double dx = cuState.getPositions()[i][0]-referenceState.getPositions()[i][0]; - double dy = cuState.getPositions()[i][1]-referenceState.getPositions()[i][1]; - double dz = cuState.getPositions()[i][2]-referenceState.getPositions()[i][2]; - ASSERT_EQUAL_TOL(fmod(cuState.getPositions()[i][0]-referenceState.getPositions()[i][0], boxSize), 0, tol); - ASSERT_EQUAL_TOL(fmod(cuState.getPositions()[i][1]-referenceState.getPositions()[i][1], boxSize), 0, tol); - ASSERT_EQUAL_TOL(fmod(cuState.getPositions()[i][2]-referenceState.getPositions()[i][2], boxSize), 0, tol); - ASSERT_EQUAL_VEC(cuState.getVelocities()[i], referenceState.getVelocities()[i], tol); - ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); - } - ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); -} -/* -void testBlockInteractions(bool periodic) { - const int blockSize = CudaContext::TileSize; - const int numBlocks = 100; - const int numParticles = blockSize*numBlocks; - const double cutoff = 1.0; - const double boxSize = (periodic ? 5.1 : 1.1); - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(1.0, 0.2, 0.2); - positions[i] = Vec3(boxSize*(3*genrand_real2(sfmt)-1), boxSize*(3*genrand_real2(sfmt)-1), boxSize*(3*genrand_real2(sfmt)-1)); - } - nonbonded->setNonbondedMethod(periodic ? NonbondedForce::CutoffPeriodic : NonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - Context context(system, integrator, platform); - context.setPositions(positions); - ContextImpl* contextImpl = *reinterpret_cast(&context); - CudaPlatform::PlatformData& data = *static_cast(contextImpl->getPlatformData()); - CudaContext& cuContext = *data.contexts[0]; - CudaNonbondedUtilities& nb = cuContext.getNonbondedUtilities(); - State state = context.getState(State::Positions | State::Velocities | State::Forces); - nb.updateNeighborListSize(); - state = context.getState(State::Positions | State::Velocities | State::Forces); - - // Verify that the bounds of each block were calculated correctly. - - vector posq(cuContext.getPosq().getSize()); - vector blockCenters(numBlocks); - vector blockBoundingBoxes(numBlocks); - if (cuContext.getUseDoublePrecision()) { - cuContext.getPosq().download(posq); - nb.getBlockCenters().download(blockCenters); - nb.getBlockBoundingBoxes().download(blockBoundingBoxes); - } - else { - vector posqf(cuContext.getPosq().getSize()); - vector blockCentersf(numBlocks); - vector blockBoundingBoxesf(numBlocks); - cuContext.getPosq().download(posqf); - nb.getBlockCenters().download(blockCentersf); - nb.getBlockBoundingBoxes().download(blockBoundingBoxesf); - for (int i = 0; i < numParticles; i++) - posq[i] = make_double4(posqf[i].x, posqf[i].y, posqf[i].z, posqf[i].w); - for (int i = 0; i < numBlocks; i++) { - blockCenters[i] = make_double4(blockCentersf[i].x, blockCentersf[i].y, blockCentersf[i].z, blockCentersf[i].w); - blockBoundingBoxes[i] = make_double4(blockBoundingBoxesf[i].x, blockBoundingBoxesf[i].y, blockBoundingBoxesf[i].z, blockBoundingBoxesf[i].w); - } - } - for (int i = 0; i < numBlocks; i++) { - double4 gridSize = blockBoundingBoxes[i]; - double4 center = blockCenters[i]; - if (periodic) { - ASSERT(gridSize.x < 0.5*boxSize); - ASSERT(gridSize.y < 0.5*boxSize); - ASSERT(gridSize.z < 0.5*boxSize); - } - double minx = 0.0, maxx = 0.0, miny = 0.0, maxy = 0.0, minz = 0.0, maxz = 0.0, radius = 0.0; - for (int j = 0; j < blockSize; j++) { - double4 pos = posq[i*blockSize+j]; - double dx = pos.x-center.x; - double dy = pos.y-center.y; - double dz = pos.z-center.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - ASSERT(abs(dx) < gridSize.x+TOL); - ASSERT(abs(dy) < gridSize.y+TOL); - ASSERT(abs(dz) < gridSize.z+TOL); - minx = min(minx, dx); - maxx = max(maxx, dx); - miny = min(miny, dy); - maxy = max(maxy, dy); - minz = min(minz, dz); - maxz = max(maxz, dz); - } - ASSERT_EQUAL_TOL(-minx, gridSize.x, TOL); - ASSERT_EQUAL_TOL(maxx, gridSize.x, TOL); - ASSERT_EQUAL_TOL(-miny, gridSize.y, TOL); - ASSERT_EQUAL_TOL(maxy, gridSize.y, TOL); - ASSERT_EQUAL_TOL(-minz, gridSize.z, TOL); - ASSERT_EQUAL_TOL(maxz, gridSize.z, TOL); - } - - // Verify that interactions were identified correctly. - - vector interactionCount; - vector interactingTiles; - vector interactionFlags; - nb.getInteractionCount().download(interactionCount); - int numWithInteractions = interactionCount[0]; - vector hasInteractions(numBlocks*(numBlocks+1)/2, false); - nb.getInteractingTiles().download(interactingTiles); - nb.getInteractionFlags().download(interactionFlags); - const unsigned int dim = cuContext.getNumAtomBlocks(); - for (int i = 0; i < numWithInteractions; i++) { - unsigned int x = interactingTiles[i].x; - unsigned int y = interactingTiles[i].y; - int index = (x > y ? x+y*dim-y*(y+1)/2 : y+x*dim-x*(x+1)/2); - hasInteractions[index] = true; - - // Make sure this tile really should have been flagged based on bounding volumes. - - double4 gridSize1 = blockBoundingBoxes[x]; - double4 gridSize2 = blockBoundingBoxes[y]; - double4 center1 = blockCenters[x]; - double4 center2 = blockCenters[y]; - double dx = center1.x-center2.x; - double dy = center1.y-center2.y; - double dz = center1.z-center2.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - dx = max(0.0, abs(dx)-gridSize1.x-gridSize2.x); - dy = max(0.0, abs(dy)-gridSize1.y-gridSize2.y); - dz = max(0.0, abs(dz)-gridSize1.z-gridSize2.z); - ASSERT(sqrt(dx*dx+dy*dy+dz*dz) < cutoff+TOL); - - // Check the interaction flags. - - unsigned int flags = interactionFlags[i]; - for (int atom2 = 0; atom2 < 32; atom2++) { - if ((flags & 1) == 0) { - double4 pos2 = posq[y*blockSize+atom2]; - for (int atom1 = 0; atom1 < blockSize; ++atom1) { - double4 pos1 = posq[x*blockSize+atom1]; - double dx = pos2.x-pos1.x; - double dy = pos2.y-pos1.y; - double dz = pos2.z-pos1.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - ASSERT(dx*dx+dy*dy+dz*dz > cutoff*cutoff); - } - } - flags >>= 1; - } - } - - // Check the tiles that did not have interactions to make sure all atoms are beyond the cutoff. - - for (int i = 0; i < (int) hasInteractions.size(); i++) - if (!hasInteractions[i]) { - unsigned int y = (unsigned int) std::floor(numBlocks+0.5-std::sqrt((numBlocks+0.5)*(numBlocks+0.5)-2*i)); - unsigned int x = (i-y*numBlocks+y*(y+1)/2); - if (x == y) - continue; // This block has exclusions, so it will not be in the neighbor list. - for (int atom1 = 0; atom1 < blockSize; ++atom1) { - double4 pos1 = posq[x*blockSize+atom1]; - for (int atom2 = 0; atom2 < blockSize; ++atom2) { - double4 pos2 = posq[y*blockSize+atom2]; - double dx = pos1.x-pos2.x; - double dy = pos1.y-pos2.y; - double dz = pos1.z-pos2.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - ASSERT(dx*dx+dy*dy+dz*dz > cutoff*cutoff); - } - } - } -}*/ - -void testDispersionCorrection() { - // Create a box full of identical particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - int index = 0; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.1, 0.5); - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - // See if the correction has the correct value. - - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(false); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); - - // Now modify half the particles to be different, and see if it is still correct. - - int numType2 = 0; - for (int i = 0; i < numParticles; i += 2) { - nonbonded->setParticleParameters(i, 0, 1, 1); - numType2++; - } - int numType1 = numParticles-numType2; - nonbonded->updateParametersInContext(context); - energy2 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(true); - context.reinitialize(); - context.setPositions(positions); - energy1 = context.getState(State::Energy).getPotentialEnergy(); - term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9; - term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3; - double combinedSigma = 0.5*(1+1.1); - double combinedEpsilon = sqrt(1*0.5); - term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9; - term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3; - term1 /= (numParticles*(numParticles+1))/2; - term2 /= (numParticles*(numParticles+1))/2; - expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); -} - -void testChangingParameters() { - const int numMolecules = 600; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 20.0; - const double tol = 2e-3; - ReferencePlatform reference; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - nonbonded->addParticle(-1.0, 0.2, 0.1); - nonbonded->addParticle(1.0, 0.1, 0.1); - } - else { - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.1, 0.2); - } - 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]); - system.addConstraint(2*i, 2*i+1, 1.0); - nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); - } - nonbonded->setNonbondedMethod(NonbondedForce::PME); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - - // See if Reference and Cuda give the same forces and energies. - - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context cuContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - cuContext.setPositions(positions); - referenceContext.setPositions(positions); - State cuState = cuContext.getState(State::Forces | State::Energy); - State referenceState = referenceContext.getState(State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); - ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); - - // Now modify parameters and see if they still agree. - - for (int i = 0; i < numParticles; i += 5) { - double charge, sigma, epsilon; - nonbonded->getParticleParameters(i, charge, sigma, epsilon); - nonbonded->setParticleParameters(i, 1.5*charge, 1.1*sigma, 1.7*epsilon); - } - nonbonded->updateParametersInContext(cuContext); - nonbonded->updateParametersInContext(referenceContext); - cuState = cuContext.getState(State::Forces | State::Energy); - referenceState = referenceContext.getState(State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); - ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); -} +#include "CudaTests.h" +#include "TestNonbondedForce.h" void testParallelComputation(NonbondedForce::NonbondedMethod method) { System system; @@ -868,61 +91,6 @@ void testParallelComputation(NonbondedForce::NonbondedMethod method) { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testSwitchingFunction(NonbondedForce::NonbondedMethod method) { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(0, 1.2, 1); - nonbonded->addParticle(0, 1.4, 2); - nonbonded->setNonbondedMethod(method); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - nonbonded->setUseDispersionCorrection(false); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - double eps = SQRT_TWO; - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double x = 1.3/r; - double expectedEnergy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - void testReordering() { // Check that reordering of atoms doesn't alter their positions. @@ -950,33 +118,9 @@ void testReordering() { } } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testCoulomb(); - testLJ(); - testExclusionsAnd14(); - testCutoff(); - testCutoff14(); - testPeriodic(); - testTriclinic(); - testLargeSystem(); - //testBlockInteractions(false); - //testBlockInteractions(true); - testDispersionCorrection(); - testChangingParameters(); - testParallelComputation(NonbondedForce::NoCutoff); - testParallelComputation(NonbondedForce::Ewald); - testParallelComputation(NonbondedForce::PME); - testSwitchingFunction(NonbondedForce::CutoffNonPeriodic); - testSwitchingFunction(NonbondedForce::PME); - testReordering(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(NonbondedForce::NoCutoff); + testParallelComputation(NonbondedForce::Ewald); + testParallelComputation(NonbondedForce::PME); + testReordering(); } diff --git a/platforms/cuda/tests/TestCudaSettle.cpp b/platforms/cuda/tests/TestCudaSettle.cpp index 925d0c039..878b88427 100644 --- a/platforms/cuda/tests/TestCudaSettle.cpp +++ b/platforms/cuda/tests/TestCudaSettle.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,90 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of the SETTLE algorithm. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -void testConstraints() { - const int numMolecules = 10; - const int numParticles = numMolecules*3; - const int numConstraints = numMolecules*3; - const double temp = 100.0; - System system; - LangevinIntegrator integrator(temp, 2.0, 0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numMolecules; ++i) { - system.addParticle(16.0); - system.addParticle(1.0); - system.addParticle(1.0); - forceField->addParticle(-0.82, 0.317, 0.65); - forceField->addParticle(0.41, 1.0, 0.0); - forceField->addParticle(0.41, 1.0, 0.0); - system.addConstraint(i*3, i*3+1, 0.1); - system.addConstraint(i*3, i*3+2, 0.1); - system.addConstraint(i*3+1, i*3+2, 0.163); - } - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; ++i) { - positions[i*3] = Vec3((i%4)*0.4, (i/4)*0.4, 0); - positions[i*3+1] = positions[i*3]+Vec3(0.1, 0, 0); - positions[i*3+2] = positions[i*3]+Vec3(-0.03333, 0.09428, 0); - velocities[i*3] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+1] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+2] = 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) { - integrator.step(1); - State state = context.getState(State::Positions | State::Forces); - 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-5); - } - } -} +#include "CudaTests.h" +#include "TestSettle.h" -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testConstraints(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/nacl_amorph.dat b/platforms/cuda/tests/nacl_amorph.dat deleted file mode 100644 index 7e8cbafdf..000000000 --- a/platforms/cuda/tests/nacl_amorph.dat +++ /dev/null @@ -1,894 +0,0 @@ -positions[0] = Vec3(1.066000,1.628000,0.835000); -positions[1] = Vec3(1.072000,0.428000,0.190000); -positions[2] = Vec3(0.524000,1.442000,1.160000); -positions[3] = Vec3(2.383000,1.524000,1.119000); -positions[4] = Vec3(0.390000,1.441000,0.575000); -positions[5] = Vec3(0.618000,0.399000,0.819000); -positions[6] = Vec3(1.003000,1.257000,1.543000); -positions[7] = Vec3(2.933000,1.569000,0.642000); -positions[8] = Vec3(0.849000,0.739000,0.089000); -positions[9] = Vec3(0.060000,0.794000,0.766000); -positions[10] = Vec3(1.652000,1.405000,1.010000); -positions[11] = Vec3(2.843000,1.533000,1.781000); -positions[12] = Vec3(0.952000,1.309000,0.996000); -positions[13] = Vec3(1.847000,1.402000,0.313000); -positions[14] = Vec3(2.674000,0.083000,1.691000); -positions[15] = Vec3(1.763000,2.104000,0.728000); -positions[16] = Vec3(0.914000,0.574000,0.982000); -positions[17] = Vec3(0.514000,0.078000,0.891000); -positions[18] = Vec3(0.538000,0.766000,1.110000); -positions[19] = Vec3(0.808000,0.676000,0.570000); -positions[20] = Vec3(0.178000,0.014000,0.628000); -positions[21] = Vec3(1.329000,1.333000,0.339000); -positions[22] = Vec3(1.029000,1.678000,0.503000); -positions[23] = Vec3(1.423000,1.767000,1.104000); -positions[24] = Vec3(1.966000,1.051000,0.282000); -positions[25] = Vec3(1.596000,1.971000,0.194000); -positions[26] = Vec3(1.025000,1.043000,2.809000); -positions[27] = Vec3(1.628000,2.614000,0.088000); -positions[28] = Vec3(0.440000,0.606000,0.141000); -positions[29] = Vec3(1.050000,2.821000,2.517000); -positions[30] = Vec3(0.644000,1.604000,0.770000); -positions[31] = Vec3(0.637000,0.917000,0.392000); -positions[32] = Vec3(0.611000,2.768000,0.013000); -positions[33] = Vec3(1.892000,0.660000,0.473000); -positions[34] = Vec3(1.052000,2.081000,0.982000); -positions[35] = Vec3(1.508000,2.300000,0.439000); -positions[36] = Vec3(2.617000,0.328000,1.099000); -positions[37] = Vec3(0.910000,0.040000,0.259000); -positions[38] = Vec3(1.195000,1.494000,1.202000); -positions[39] = Vec3(2.657000,0.997000,0.564000); -positions[40] = Vec3(1.465000,1.580000,0.648000); -positions[41] = Vec3(0.154000,2.538000,1.331000); -positions[42] = Vec3(0.849000,1.476000,1.365000); -positions[43] = Vec3(0.898000,0.987000,1.178000); -positions[44] = Vec3(0.958000,0.656000,1.358000); -positions[45] = Vec3(1.067000,0.934000,0.211000); -positions[46] = Vec3(1.030000,0.319000,1.281000); -positions[47] = Vec3(2.709000,0.807000,0.240000); -positions[48] = Vec3(0.837000,1.362000,0.588000); -positions[49] = Vec3(2.080000,0.791000,2.947000); -positions[50] = Vec3(0.200000,0.266000,1.474000); -positions[51] = Vec3(0.848000,0.379000,1.625000); -positions[52] = Vec3(0.637000,1.071000,0.821000); -positions[53] = Vec3(1.324000,0.757000,2.951000); -positions[54] = Vec3(2.666000,0.935000,1.373000); -positions[55] = Vec3(1.584000,1.025000,1.703000); -positions[56] = Vec3(1.699000,0.636000,0.038000); -positions[57] = Vec3(1.099000,1.644000,1.879000); -positions[58] = Vec3(2.897000,1.302000,1.522000); -positions[59] = Vec3(1.753000,0.949000,2.885000); -positions[60] = Vec3(2.502000,1.321000,0.752000); -positions[61] = Vec3(0.545000,0.193000,1.959000); -positions[62] = Vec3(1.098000,2.646000,1.706000); -positions[63] = Vec3(0.001000,1.205000,0.670000); -positions[64] = Vec3(2.997000,0.061000,1.040000); -positions[65] = Vec3(0.662000,0.828000,1.535000); -positions[66] = Vec3(1.252000,1.246000,0.780000); -positions[67] = Vec3(1.173000,0.472000,0.810000); -positions[68] = Vec3(0.124000,0.622000,2.992000); -positions[69] = Vec3(1.036000,0.883000,0.848000); -positions[70] = Vec3(1.423000,2.146000,1.340000); -positions[71] = Vec3(2.391000,1.136000,1.165000); -positions[72] = Vec3(1.189000,2.961000,0.425000); -positions[73] = Vec3(1.584000,2.500000,0.782000); -positions[74] = Vec3(0.565000,1.122000,1.240000); -positions[75] = Vec3(1.733000,1.716000,1.763000); -positions[76] = Vec3(1.548000,1.522000,0.041000); -positions[77] = Vec3(1.485000,0.561000,0.369000); -positions[78] = Vec3(0.350000,1.661000,0.928000); -positions[79] = Vec3(1.653000,1.223000,0.578000); -positions[80] = Vec3(0.648000,1.349000,0.253000); -positions[81] = Vec3(0.340000,1.820000,0.483000); -positions[82] = Vec3(2.926000,0.119000,1.421000); -positions[83] = Vec3(1.512000,1.084000,0.156000); -positions[84] = Vec3(1.600000,2.115000,1.792000); -positions[85] = Vec3(1.089000,0.934000,1.584000); -positions[86] = Vec3(1.276000,1.104000,1.230000); -positions[87] = Vec3(0.485000,0.305000,0.428000); -positions[88] = Vec3(1.317000,1.261000,1.795000); -positions[89] = Vec3(0.039000,1.413000,1.085000); -positions[90] = Vec3(0.453000,0.701000,0.605000); -positions[91] = Vec3(1.283000,1.937000,0.752000); -positions[92] = Vec3(0.212000,1.416000,1.447000); -positions[93] = Vec3(0.203000,0.358000,0.723000); -positions[94] = Vec3(0.556000,0.445000,1.364000); -positions[95] = Vec3(1.436000,0.861000,0.911000); -positions[96] = Vec3(0.358000,0.966000,0.176000); -positions[97] = Vec3(1.478000,2.715000,0.427000); -positions[98] = Vec3(1.581000,0.575000,0.809000); -positions[99] = Vec3(1.007000,2.153000,2.887000); -positions[100] = Vec3(2.343000,0.663000,2.513000); -positions[101] = Vec3(2.105000,0.649000,1.635000); -positions[102] = Vec3(0.875000,0.743000,2.459000); -positions[103] = Vec3(0.229000,1.315000,1.879000); -positions[104] = Vec3(0.285000,0.935000,1.700000); -positions[105] = Vec3(2.269000,1.284000,2.234000); -positions[106] = Vec3(1.406000,1.149000,2.767000); -positions[107] = Vec3(1.076000,0.220000,1.849000); -positions[108] = Vec3(2.001000,1.532000,2.881000); -positions[109] = Vec3(2.893000,0.485000,1.860000); -positions[110] = Vec3(1.621000,1.786000,2.624000); -positions[111] = Vec3(0.500000,0.616000,1.818000); -positions[112] = Vec3(0.938000,2.978000,2.104000); -positions[113] = Vec3(0.550000,2.081000,0.454000); -positions[114] = Vec3(1.121000,0.685000,2.196000); -positions[115] = Vec3(1.088000,1.385000,2.184000); -positions[116] = Vec3(1.122000,2.705000,2.080000); -positions[117] = Vec3(0.918000,1.767000,2.861000); -positions[118] = Vec3(2.748000,0.232000,2.126000); -positions[119] = Vec3(1.238000,2.766000,0.109000); -positions[120] = Vec3(1.380000,0.785000,1.961000); -positions[121] = Vec3(1.236000,1.757000,0.150000); -positions[122] = Vec3(1.339000,2.187000,2.592000); -positions[123] = Vec3(1.414000,0.342000,2.714000); -positions[124] = Vec3(1.310000,0.770000,2.589000); -positions[125] = Vec3(1.686000,0.765000,2.321000); -positions[126] = Vec3(1.659000,1.367000,2.780000); -positions[127] = Vec3(0.141000,0.095000,1.903000); -positions[128] = Vec3(2.084000,1.002000,2.520000); -positions[129] = Vec3(2.819000,1.286000,2.626000); -positions[130] = Vec3(1.257000,1.044000,2.401000); -positions[131] = Vec3(1.064000,0.546000,2.839000); -positions[132] = Vec3(0.078000,1.246000,0.010000); -positions[133] = Vec3(1.506000,0.420000,2.223000); -positions[134] = Vec3(1.778000,0.699000,1.920000); -positions[135] = Vec3(1.315000,1.721000,2.733000); -positions[136] = Vec3(0.114000,0.281000,0.279000); -positions[137] = Vec3(1.082000,1.421000,2.596000); -positions[138] = Vec3(3.001000,0.592000,2.276000); -positions[139] = Vec3(1.384000,2.227000,2.992000); -positions[140] = Vec3(1.353000,0.044000,1.985000); -positions[141] = Vec3(1.367000,1.832000,2.383000); -positions[142] = Vec3(0.853000,1.119000,2.230000); -positions[143] = Vec3(1.675000,1.482000,2.295000); -positions[144] = Vec3(1.334000,1.890000,1.904000); -positions[145] = Vec3(1.630000,0.140000,2.939000); -positions[146] = Vec3(0.195000,1.290000,2.300000); -positions[147] = Vec3(2.178000,1.173000,3.001000); -positions[148] = Vec3(0.637000,0.655000,2.126000); -positions[149] = Vec3(0.993000,1.796000,2.529000); -positions[150] = Vec3(0.910000,0.701000,1.845000); -positions[151] = Vec3(0.191000,2.128000,0.355000); -positions[152] = Vec3(0.692000,1.163000,2.578000); -positions[153] = Vec3(1.154000,1.052000,1.974000); -positions[154] = Vec3(1.682000,0.335000,2.509000); -positions[155] = Vec3(0.569000,1.032000,1.895000); -positions[156] = Vec3(1.800000,2.796000,1.295000); -positions[157] = Vec3(2.517000,2.347000,2.878000); -positions[158] = Vec3(0.639000,2.470000,1.678000); -positions[159] = Vec3(0.634000,2.006000,1.829000); -positions[160] = Vec3(0.892000,0.215000,0.566000); -positions[161] = Vec3(1.800000,2.143000,1.491000); -positions[162] = Vec3(1.898000,0.226000,2.765000); -positions[163] = Vec3(0.791000,1.738000,0.260000); -positions[164] = Vec3(0.437000,1.740000,2.048000); -positions[165] = Vec3(1.687000,2.438000,1.166000); -positions[166] = Vec3(1.337000,2.304000,1.643000); -positions[167] = Vec3(1.270000,2.397000,1.033000); -positions[168] = Vec3(0.702000,2.429000,0.591000); -positions[169] = Vec3(0.842000,1.976000,0.724000); -positions[170] = Vec3(1.965000,0.095000,1.206000); -positions[171] = Vec3(0.355000,2.710000,0.618000); -positions[172] = Vec3(0.745000,1.434000,2.781000); -positions[173] = Vec3(0.707000,2.171000,1.502000); -positions[174] = Vec3(1.294000,2.696000,0.847000); -positions[175] = Vec3(1.143000,2.075000,0.276000); -positions[176] = Vec3(1.111000,2.474000,0.312000); -positions[177] = Vec3(1.144000,2.316000,0.633000); -positions[178] = Vec3(1.335000,0.292000,0.515000); -positions[179] = Vec3(1.926000,2.813000,2.703000); -positions[180] = Vec3(0.559000,2.314000,2.904000); -positions[181] = Vec3(1.308000,1.605000,1.534000); -positions[182] = Vec3(0.773000,2.913000,1.217000); -positions[183] = Vec3(1.612000,0.082000,1.027000); -positions[184] = Vec3(1.510000,0.287000,1.787000); -positions[185] = Vec3(0.716000,1.424000,1.843000); -positions[186] = Vec3(1.267000,0.685000,1.160000); -positions[187] = Vec3(0.306000,1.653000,1.717000); -positions[188] = Vec3(0.349000,0.020000,1.275000); -positions[189] = Vec3(0.166000,1.979000,0.804000); -positions[190] = Vec3(1.523000,2.992000,0.711000); -positions[191] = Vec3(1.998000,2.146000,0.088000); -positions[192] = Vec3(0.047000,2.513000,0.642000); -positions[193] = Vec3(0.501000,1.793000,1.438000); -positions[194] = Vec3(1.099000,2.010000,1.626000); -positions[195] = Vec3(2.580000,2.854000,1.328000); -positions[196] = Vec3(1.080000,2.779000,1.190000); -positions[197] = Vec3(0.901000,2.561000,0.948000); -positions[198] = Vec3(0.920000,2.990000,0.844000); -positions[199] = Vec3(0.819000,2.924000,1.711000); -positions[200] = Vec3(0.434000,1.516000,0.063000); -positions[201] = Vec3(1.470000,0.058000,0.231000); -positions[202] = Vec3(0.530000,3.005000,1.550000); -positions[203] = Vec3(0.447000,2.330000,1.277000); -positions[204] = Vec3(1.632000,2.683000,1.593000); -positions[205] = Vec3(0.885000,1.835000,2.072000); -positions[206] = Vec3(0.868000,2.601000,1.425000); -positions[207] = Vec3(0.720000,2.242000,0.907000); -positions[208] = Vec3(1.194000,0.144000,1.065000); -positions[209] = Vec3(0.448000,2.485000,0.959000); -positions[210] = Vec3(1.377000,2.694000,1.352000); -positions[211] = Vec3(1.305000,2.928000,2.713000); -positions[212] = Vec3(1.784000,2.456000,1.981000); -positions[213] = Vec3(0.354000,2.136000,1.563000); -positions[214] = Vec3(0.489000,2.000000,1.108000); -positions[215] = Vec3(1.884000,2.221000,0.461000); -positions[216] = Vec3(1.860000,2.540000,0.306000); -positions[217] = Vec3(1.753000,2.335000,2.768000); -positions[218] = Vec3(1.536000,2.441000,2.344000); -positions[219] = Vec3(0.531000,0.025000,2.235000); -positions[220] = Vec3(0.809000,0.011000,2.834000); -positions[221] = Vec3(0.289000,2.614000,2.879000); -positions[222] = Vec3(0.613000,1.891000,2.337000); -positions[223] = Vec3(0.507000,0.037000,2.694000); -positions[224] = Vec3(0.882000,2.185000,2.583000); -positions[225] = Vec3(0.503000,2.051000,2.615000); -positions[226] = Vec3(1.907000,1.956000,2.831000); -positions[227] = Vec3(2.833000,2.769000,1.644000); -positions[228] = Vec3(1.141000,0.113000,2.945000); -positions[229] = Vec3(0.600000,1.338000,2.200000); -positions[230] = Vec3(0.904000,2.360000,1.952000); -positions[231] = Vec3(0.738000,1.568000,2.437000); -positions[232] = Vec3(1.136000,2.535000,2.805000); -positions[233] = Vec3(1.430000,2.767000,2.321000); -positions[234] = Vec3(1.078000,2.470000,2.385000); -positions[235] = Vec3(0.296000,2.376000,2.560000); -positions[236] = Vec3(0.719000,0.300000,0.075000); -positions[237] = Vec3(0.518000,1.911000,0.080000); -positions[238] = Vec3(0.381000,1.570000,2.450000); -positions[239] = Vec3(0.716000,2.581000,2.697000); -positions[240] = Vec3(1.473000,2.617000,1.936000); -positions[241] = Vec3(0.421000,2.449000,0.229000); -positions[242] = Vec3(0.425000,2.817000,1.910000); -positions[243] = Vec3(1.312000,2.294000,2.057000); -positions[244] = Vec3(1.239000,0.007000,1.539000); -positions[245] = Vec3(0.822000,0.379000,2.086000); -positions[246] = Vec3(0.560000,2.562000,2.227000); -positions[247] = Vec3(0.863000,2.417000,0.050000); -positions[248] = Vec3(1.263000,0.151000,2.332000); -positions[249] = Vec3(0.237000,0.208000,2.336000); -positions[250] = Vec3(0.437000,2.370000,1.910000); -positions[251] = Vec3(1.119000,2.058000,2.207000); -positions[252] = Vec3(1.960000,1.749000,0.118000); -positions[253] = Vec3(2.415000,0.870000,2.757000); -positions[254] = Vec3(1.781000,0.342000,0.366000); -positions[255] = Vec3(2.172000,1.279000,1.421000); -positions[256] = Vec3(1.986000,0.715000,1.301000); -positions[257] = Vec3(1.657000,1.804000,0.810000); -positions[258] = Vec3(2.405000,1.202000,0.416000); -positions[259] = Vec3(1.932000,1.457000,0.786000); -positions[260] = Vec3(1.901000,1.271000,1.207000); -positions[261] = Vec3(1.864000,0.301000,0.810000); -positions[262] = Vec3(1.658000,0.673000,1.558000); -positions[263] = Vec3(2.637000,2.247000,0.396000); -positions[264] = Vec3(1.353000,0.369000,1.438000); -positions[265] = Vec3(0.530000,2.688000,1.346000); -positions[266] = Vec3(0.237000,0.485000,1.047000); -positions[267] = Vec3(2.806000,0.601000,0.822000); -positions[268] = Vec3(1.617000,2.018000,2.136000); -positions[269] = Vec3(2.000000,2.898000,0.022000); -positions[270] = Vec3(2.049000,1.883000,1.001000); -positions[271] = Vec3(2.477000,0.355000,1.786000); -positions[272] = Vec3(1.646000,0.983000,1.266000); -positions[273] = Vec3(1.683000,2.097000,1.114000); -positions[274] = Vec3(2.161000,0.921000,1.065000); -positions[275] = Vec3(2.099000,0.463000,1.942000); -positions[276] = Vec3(2.561000,1.638000,0.572000); -positions[277] = Vec3(2.205000,0.395000,1.005000); -positions[278] = Vec3(2.836000,0.203000,0.698000); -positions[279] = Vec3(2.662000,0.909000,0.966000); -positions[280] = Vec3(0.334000,0.350000,2.767000); -positions[281] = Vec3(2.241000,2.934000,1.248000); -positions[282] = Vec3(2.599000,2.953000,0.921000); -positions[283] = Vec3(2.219000,0.262000,0.058000); -positions[284] = Vec3(0.274000,0.656000,1.456000); -positions[285] = Vec3(1.814000,1.008000,0.882000); -positions[286] = Vec3(2.793000,1.395000,0.316000); -positions[287] = Vec3(0.773000,1.753000,1.639000); -positions[288] = Vec3(2.321000,0.994000,1.591000); -positions[289] = Vec3(2.243000,2.255000,1.690000); -positions[290] = Vec3(0.178000,1.342000,0.327000); -positions[291] = Vec3(1.623000,1.756000,1.426000); -positions[292] = Vec3(2.252000,0.109000,0.375000); -positions[293] = Vec3(3.003000,1.895000,1.895000); -positions[294] = Vec3(0.407000,0.831000,2.756000); -positions[295] = Vec3(2.193000,0.956000,0.632000); -positions[296] = Vec3(2.405000,0.641000,1.107000); -positions[297] = Vec3(2.361000,0.958000,0.162000); -positions[298] = Vec3(2.173000,1.544000,0.528000); -positions[299] = Vec3(1.565000,1.380000,1.428000); -positions[300] = Vec3(2.342000,0.538000,0.253000); -positions[301] = Vec3(1.910000,0.701000,0.954000); -positions[302] = Vec3(2.910000,0.288000,2.938000); -positions[303] = Vec3(0.257000,1.189000,0.958000); -positions[304] = Vec3(0.134000,1.775000,1.243000); -positions[305] = Vec3(2.476000,1.583000,1.956000); -positions[306] = Vec3(1.838000,1.791000,2.354000); -positions[307] = Vec3(1.906000,1.338000,1.696000); -positions[308] = Vec3(2.413000,2.869000,0.166000); -positions[309] = Vec3(3.006000,1.038000,1.322000); -positions[310] = Vec3(1.961000,0.962000,1.605000); -positions[311] = Vec3(0.082000,2.857000,0.020000); -positions[312] = Vec3(2.408000,1.499000,0.062000); -positions[313] = Vec3(2.349000,0.267000,1.415000); -positions[314] = Vec3(2.327000,1.717000,2.350000); -positions[315] = Vec3(2.928000,0.810000,1.582000); -positions[316] = Vec3(2.150000,0.336000,0.576000); -positions[317] = Vec3(2.664000,1.085000,2.962000); -positions[318] = Vec3(2.851000,0.670000,1.174000); -positions[319] = Vec3(1.954000,1.013000,1.975000); -positions[320] = Vec3(2.474000,1.542000,1.545000); -positions[321] = Vec3(2.826000,0.455000,1.490000); -positions[322] = Vec3(2.140000,2.826000,0.558000); -positions[323] = Vec3(2.151000,1.684000,1.780000); -positions[324] = Vec3(0.174000,0.673000,0.397000); -positions[325] = Vec3(0.066000,1.708000,0.160000); -positions[326] = Vec3(2.158000,0.303000,2.582000); -positions[327] = Vec3(2.602000,1.611000,2.632000); -positions[328] = Vec3(2.566000,1.138000,2.465000); -positions[329] = Vec3(2.026000,1.443000,2.477000); -positions[330] = Vec3(2.365000,0.309000,2.255000); -positions[331] = Vec3(1.636000,1.107000,2.058000); -positions[332] = Vec3(2.522000,2.584000,2.399000); -positions[333] = Vec3(2.537000,2.900000,2.158000); -positions[334] = Vec3(2.660000,0.537000,2.577000); -positions[335] = Vec3(2.679000,1.158000,1.724000); -positions[336] = Vec3(0.220000,1.894000,2.498000); -positions[337] = Vec3(2.266000,1.248000,1.837000); -positions[338] = Vec3(0.055000,1.656000,2.128000); -positions[339] = Vec3(2.899000,1.902000,2.823000); -positions[340] = Vec3(0.085000,2.994000,2.720000); -positions[341] = Vec3(0.013000,0.889000,2.468000); -positions[342] = Vec3(1.804000,0.372000,1.636000); -positions[343] = Vec3(0.201000,1.616000,2.824000); -positions[344] = Vec3(0.369000,1.273000,2.699000); -positions[345] = Vec3(2.996000,0.355000,2.596000); -positions[346] = Vec3(2.867000,1.314000,2.107000); -positions[347] = Vec3(2.611000,0.563000,2.140000); -positions[348] = Vec3(2.676000,2.954000,2.955000); -positions[349] = Vec3(0.256000,0.848000,2.062000); -positions[350] = Vec3(2.530000,0.028000,2.528000); -positions[351] = Vec3(0.537000,1.273000,1.596000); -positions[352] = Vec3(0.004000,1.004000,0.401000); -positions[353] = Vec3(1.676000,1.060000,2.463000); -positions[354] = Vec3(2.622000,1.473000,2.257000); -positions[355] = Vec3(2.917000,2.991000,2.316000); -positions[356] = Vec3(0.672000,1.123000,2.984000); -positions[357] = Vec3(2.229000,1.806000,2.673000); -positions[358] = Vec3(0.463000,0.951000,2.383000); -positions[359] = Vec3(2.126000,0.049000,2.037000); -positions[360] = Vec3(2.868000,0.876000,2.015000); -positions[361] = Vec3(2.720000,2.582000,0.079000); -positions[362] = Vec3(1.966000,0.693000,2.624000); -positions[363] = Vec3(1.971000,0.398000,2.318000); -positions[364] = Vec3(0.337000,0.630000,2.458000); -positions[365] = Vec3(2.562000,1.044000,2.040000); -positions[366] = Vec3(2.817000,1.485000,2.963000); -positions[367] = Vec3(2.514000,0.621000,2.992000); -positions[368] = Vec3(3.000000,1.551000,2.496000); -positions[369] = Vec3(0.698000,2.167000,2.180000); -positions[370] = Vec3(2.693000,0.849000,2.389000); -positions[371] = Vec3(2.092000,2.565000,2.986000); -positions[372] = Vec3(2.010000,3.001000,0.819000); -positions[373] = Vec3(2.392000,2.622000,1.636000); -positions[374] = Vec3(2.086000,2.325000,1.340000); -positions[375] = Vec3(2.578000,2.971000,0.502000); -positions[376] = Vec3(1.871000,2.789000,2.225000); -positions[377] = Vec3(2.230000,2.985000,1.594000); -positions[378] = Vec3(2.860000,2.788000,0.729000); -positions[379] = Vec3(2.051000,1.928000,1.472000); -positions[380] = Vec3(2.307000,2.219000,1.067000); -positions[381] = Vec3(2.369000,2.572000,1.289000); -positions[382] = Vec3(2.206000,1.924000,0.693000); -positions[383] = Vec3(1.984000,2.058000,2.005000); -positions[384] = Vec3(2.287000,1.854000,0.317000); -positions[385] = Vec3(2.525000,0.345000,0.686000); -positions[386] = Vec3(2.933000,1.920000,1.053000); -positions[387] = Vec3(0.324000,2.324000,0.601000); -positions[388] = Vec3(2.042000,1.576000,1.277000); -positions[389] = Vec3(0.031000,2.376000,0.949000); -positions[390] = Vec3(2.519000,2.250000,1.465000); -positions[391] = Vec3(0.221000,2.722000,1.652000); -positions[392] = Vec3(2.409000,2.361000,2.051000); -positions[393] = Vec3(2.472000,1.917000,1.673000); -positions[394] = Vec3(0.999000,2.715000,0.562000); -positions[395] = Vec3(1.669000,0.017000,1.508000); -positions[396] = Vec3(1.924000,1.777000,0.542000); -positions[397] = Vec3(2.635000,2.634000,1.905000); -positions[398] = Vec3(2.042000,2.628000,1.025000); -positions[399] = Vec3(2.694000,1.974000,2.009000); -positions[400] = Vec3(2.988000,2.221000,1.333000); -positions[401] = Vec3(1.772000,0.196000,1.978000); -positions[402] = Vec3(2.893000,2.961000,0.283000); -positions[403] = Vec3(2.615000,0.261000,0.245000); -positions[404] = Vec3(2.797000,2.521000,1.412000); -positions[405] = Vec3(0.013000,2.497000,0.246000); -positions[406] = Vec3(1.875000,2.861000,1.801000); -positions[407] = Vec3(2.800000,2.617000,1.049000); -positions[408] = Vec3(2.824000,1.858000,1.487000); -positions[409] = Vec3(2.434000,1.868000,1.275000); -positions[410] = Vec3(2.814000,0.526000,0.384000); -positions[411] = Vec3(2.844000,2.545000,2.246000); -positions[412] = Vec3(1.896000,2.587000,0.719000); -positions[413] = Vec3(0.350000,0.055000,0.076000); -positions[414] = Vec3(2.686000,1.784000,0.222000); -positions[415] = Vec3(2.724000,1.604000,0.989000); -positions[416] = Vec3(0.807000,1.761000,1.122000); -positions[417] = Vec3(2.120000,2.382000,2.226000); -positions[418] = Vec3(2.058000,1.587000,2.067000); -positions[419] = Vec3(2.904000,2.571000,2.686000); -positions[420] = Vec3(2.228000,2.910000,2.410000); -positions[421] = Vec3(2.797000,2.142000,0.114000); -positions[422] = Vec3(2.905000,1.875000,0.480000); -positions[423] = Vec3(1.881000,2.565000,2.469000); -positions[424] = Vec3(2.404000,1.929000,2.999000); -positions[425] = Vec3(2.389000,2.814000,2.782000); -positions[426] = Vec3(2.520000,0.301000,2.815000); -positions[427] = Vec3(2.726000,1.907000,2.339000); -positions[428] = Vec3(2.880000,2.273000,2.500000); -positions[429] = Vec3(2.574000,2.045000,2.716000); -positions[430] = Vec3(2.988000,2.288000,2.001000); -positions[431] = Vec3(0.011000,2.341000,2.904000); -positions[432] = Vec3(0.215000,2.265000,2.257000); -positions[433] = Vec3(2.268000,2.311000,0.234000); -positions[434] = Vec3(2.462000,2.621000,0.550000); -positions[435] = Vec3(1.530000,2.540000,2.728000); -positions[436] = Vec3(2.162000,2.306000,2.687000); -positions[437] = Vec3(2.748000,2.301000,1.734000); -positions[438] = Vec3(2.334000,1.976000,2.041000); -positions[439] = Vec3(1.981000,2.076000,2.443000); -positions[440] = Vec3(2.301000,1.367000,2.665000); -positions[441] = Vec3(2.399000,2.164000,2.403000); -positions[442] = Vec3(0.244000,2.713000,2.257000); -positions[443] = Vec3(0.683000,0.488000,2.781000); -positions[444] = Vec3(2.194000,2.711000,1.993000); -positions[445] = Vec3(2.947000,2.848000,2.001000); -positions[446] = Vec3(0.223000,1.981000,2.913000); -positions[447] = Vec3(0.010000,1.226000,0.917000); -positions[448] = Vec3(1.911000,0.426000,0.582000); -positions[449] = Vec3(2.204000,0.015000,0.136000); -positions[450] = Vec3(0.927000,0.138000,1.645000); -positions[451] = Vec3(0.155000,0.885000,1.479000); -positions[452] = Vec3(1.550000,1.933000,1.261000); -positions[453] = Vec3(1.304000,0.407000,0.287000); -positions[454] = Vec3(0.270000,1.384000,2.910000); -positions[455] = Vec3(0.516000,1.817000,1.695000); -positions[456] = Vec3(1.458000,2.879000,1.523000); -positions[457] = Vec3(1.702000,1.670000,0.593000); -positions[458] = Vec3(1.974000,1.380000,0.534000); -positions[459] = Vec3(2.835000,1.185000,0.479000); -positions[460] = Vec3(0.548000,2.979000,1.126000); -positions[461] = Vec3(1.202000,2.174000,1.466000); -positions[462] = Vec3(1.237000,1.701000,0.653000); -positions[463] = Vec3(2.939000,0.761000,0.349000); -positions[464] = Vec3(1.667000,2.119000,0.377000); -positions[465] = Vec3(1.196000,0.552000,1.372000); -positions[466] = Vec3(1.416000,0.901000,1.178000); -positions[467] = Vec3(0.519000,1.577000,2.227000); -positions[468] = Vec3(1.214000,1.281000,1.063000); -positions[469] = Vec3(0.822000,0.433000,1.375000); -positions[470] = Vec3(0.095000,2.760000,0.604000); -positions[471] = Vec3(1.325000,2.144000,1.848000); -positions[472] = Vec3(0.681000,0.896000,1.285000); -positions[473] = Vec3(0.406000,2.936000,0.717000); -positions[474] = Vec3(0.565000,1.852000,0.349000); -positions[475] = Vec3(0.597000,1.651000,1.020000); -positions[476] = Vec3(1.236000,0.170000,1.335000); -positions[477] = Vec3(0.586000,0.441000,1.980000); -positions[478] = Vec3(1.443000,1.208000,1.575000); -positions[479] = Vec3(0.247000,0.243000,0.502000); -positions[480] = Vec3(1.386000,1.564000,0.236000); -positions[481] = Vec3(0.871000,1.063000,0.930000); -positions[482] = Vec3(0.136000,0.992000,0.621000); -positions[483] = Vec3(0.889000,0.986000,0.010000); -positions[484] = Vec3(1.107000,2.731000,1.452000); -positions[485] = Vec3(0.942000,2.471000,0.517000); -positions[486] = Vec3(0.989000,0.652000,0.747000); -positions[487] = Vec3(0.899000,1.235000,2.707000); -positions[488] = Vec3(1.105000,0.684000,0.068000); -positions[489] = Vec3(1.660000,1.235000,2.276000); -positions[490] = Vec3(1.593000,1.883000,1.915000); -positions[491] = Vec3(1.528000,1.613000,0.920000); -positions[492] = Vec3(0.459000,1.046000,1.011000); -positions[493] = Vec3(0.213000,0.612000,0.644000); -positions[494] = Vec3(0.078000,1.392000,1.676000); -positions[495] = Vec3(0.605000,0.491000,0.574000); -positions[496] = Vec3(0.990000,1.586000,1.076000); -positions[497] = Vec3(0.297000,1.434000,1.028000); -positions[498] = Vec3(1.101000,1.471000,1.443000); -positions[499] = Vec3(0.072000,0.139000,1.653000); -positions[500] = Vec3(0.633000,0.884000,0.645000); -positions[501] = Vec3(0.352000,2.841000,1.463000); -positions[502] = Vec3(0.418000,0.774000,0.350000); -positions[503] = Vec3(2.641000,0.198000,0.869000); -positions[504] = Vec3(0.608000,1.341000,0.695000); -positions[505] = Vec3(1.778000,1.151000,1.830000); -positions[506] = Vec3(1.669000,0.342000,2.768000); -positions[507] = Vec3(1.256000,0.994000,0.798000); -positions[508] = Vec3(1.068000,0.375000,1.036000); -positions[509] = Vec3(0.910000,0.758000,1.589000); -positions[510] = Vec3(0.243000,2.452000,0.805000); -positions[511] = Vec3(1.018000,0.764000,1.122000); -positions[512] = Vec3(2.464000,1.089000,1.404000); -positions[513] = Vec3(0.670000,0.564000,0.034000); -positions[514] = Vec3(0.030000,1.296000,1.310000); -positions[515] = Vec3(1.210000,1.785000,1.691000); -positions[516] = Vec3(0.022000,0.620000,0.974000); -positions[517] = Vec3(1.499000,1.277000,2.986000); -positions[518] = Vec3(1.227000,1.896000,1.006000); -positions[519] = Vec3(0.528000,1.022000,1.635000); -positions[520] = Vec3(1.887000,2.670000,0.089000); -positions[521] = Vec3(1.661000,0.825000,0.793000); -positions[522] = Vec3(0.831000,1.494000,0.374000); -positions[523] = Vec3(1.356000,0.613000,0.930000); -positions[524] = Vec3(0.667000,0.600000,0.968000); -positions[525] = Vec3(1.154000,1.702000,2.925000); -positions[526] = Vec3(1.420000,1.581000,1.289000); -positions[527] = Vec3(1.383000,0.041000,0.932000); -positions[528] = Vec3(1.727000,0.140000,1.725000); -positions[529] = Vec3(0.711000,1.215000,2.004000); -positions[530] = Vec3(1.061000,1.067000,1.366000); -positions[531] = Vec3(0.377000,0.597000,1.224000); -positions[532] = Vec3(0.274000,0.719000,1.842000); -positions[533] = Vec3(0.840000,1.658000,1.874000); -positions[534] = Vec3(0.877000,0.290000,0.311000); -positions[535] = Vec3(2.130000,1.153000,1.196000); -positions[536] = Vec3(1.028000,1.379000,0.747000); -positions[537] = Vec3(1.107000,2.450000,2.079000); -positions[538] = Vec3(1.419000,1.333000,0.585000); -positions[539] = Vec3(0.430000,1.305000,1.369000); -positions[540] = Vec3(0.775000,1.363000,1.596000); -positions[541] = Vec3(1.522000,2.009000,0.736000); -positions[542] = Vec3(0.857000,1.722000,0.696000); -positions[543] = Vec3(0.722000,2.831000,1.478000); -positions[544] = Vec3(0.411000,1.673000,0.681000); -positions[545] = Vec3(1.511000,0.456000,0.597000); -positions[546] = Vec3(2.684000,0.820000,2.996000); -positions[547] = Vec3(1.593000,1.713000,2.369000); -positions[548] = Vec3(1.113000,0.803000,1.958000); -positions[549] = Vec3(1.267000,1.095000,0.254000); -positions[550] = Vec3(2.120000,0.540000,2.477000); -positions[551] = Vec3(0.566000,1.409000,2.588000); -positions[552] = Vec3(0.261000,0.872000,2.546000); -positions[553] = Vec3(1.878000,1.446000,2.680000); -positions[554] = Vec3(0.878000,1.606000,2.658000); -positions[555] = Vec3(1.564000,0.749000,1.786000); -positions[556] = Vec3(1.412000,1.942000,2.625000); -positions[557] = Vec3(1.660000,1.114000,2.710000); -positions[558] = Vec3(1.118000,0.813000,2.424000); -positions[559] = Vec3(1.482000,0.893000,2.434000); -positions[560] = Vec3(1.093000,1.129000,1.740000); -positions[561] = Vec3(2.163000,0.849000,2.709000); -positions[562] = Vec3(1.201000,1.429000,1.957000); -positions[563] = Vec3(0.235000,2.258000,2.002000); -positions[564] = Vec3(0.413000,1.444000,0.314000); -positions[565] = Vec3(0.164000,0.450000,2.408000); -positions[566] = Vec3(1.551000,0.851000,0.033000); -positions[567] = Vec3(0.659000,0.228000,2.807000); -positions[568] = Vec3(0.741000,0.131000,2.124000); -positions[569] = Vec3(0.455000,0.567000,2.682000); -positions[570] = Vec3(0.729000,0.971000,2.408000); -positions[571] = Vec3(1.487000,2.820000,0.162000); -positions[572] = Vec3(1.855000,0.700000,2.858000); -positions[573] = Vec3(0.305000,1.074000,1.926000); -positions[574] = Vec3(1.300000,0.153000,1.747000); -positions[575] = Vec3(1.272000,1.249000,2.568000); -positions[576] = Vec3(0.431000,0.743000,2.238000); -positions[577] = Vec3(0.493000,0.240000,0.184000); -positions[578] = Vec3(1.734000,0.506000,2.317000); -positions[579] = Vec3(0.874000,0.631000,2.692000); -positions[580] = Vec3(0.473000,2.790000,2.161000); -positions[581] = Vec3(1.310000,0.571000,2.759000); -positions[582] = Vec3(0.677000,0.798000,1.916000); -positions[583] = Vec3(0.944000,0.442000,1.858000); -positions[584] = Vec3(3.006000,2.098000,2.976000); -positions[585] = Vec3(0.864000,0.592000,2.231000); -positions[586] = Vec3(1.366000,0.611000,2.147000); -positions[587] = Vec3(2.871000,1.217000,2.880000); -positions[588] = Vec3(1.674000,2.664000,2.336000); -positions[589] = Vec3(1.757000,0.879000,2.101000); -positions[590] = Vec3(1.293000,2.939000,2.457000); -positions[591] = Vec3(1.108000,1.131000,2.206000); -positions[592] = Vec3(1.207000,1.658000,2.498000); -positions[593] = Vec3(0.850000,1.373000,2.312000); -positions[594] = Vec3(1.413000,1.060000,1.939000); -positions[595] = Vec3(1.138000,0.140000,2.102000); -positions[596] = Vec3(0.752000,1.307000,1.190000); -positions[597] = Vec3(1.254000,0.942000,2.790000); -positions[598] = Vec3(1.544000,1.614000,2.800000); -positions[599] = Vec3(2.128000,0.302000,2.833000); -positions[600] = Vec3(0.300000,1.744000,0.027000); -positions[601] = Vec3(1.878000,2.986000,2.060000); -positions[602] = Vec3(1.528000,0.233000,2.045000); -positions[603] = Vec3(1.146000,1.817000,2.067000); -positions[604] = Vec3(1.037000,2.746000,0.813000); -positions[605] = Vec3(0.524000,0.610000,1.566000); -positions[606] = Vec3(0.945000,2.964000,0.503000); -positions[607] = Vec3(1.788000,2.565000,0.965000); -positions[608] = Vec3(0.471000,2.510000,0.491000); -positions[609] = Vec3(0.512000,2.043000,1.371000); -positions[610] = Vec3(2.316000,2.423000,1.494000); -positions[611] = Vec3(1.575000,2.394000,2.953000); -positions[612] = Vec3(2.845000,2.869000,0.985000); -positions[613] = Vec3(1.016000,2.335000,1.003000); -positions[614] = Vec3(0.998000,2.830000,1.879000); -positions[615] = Vec3(0.624000,2.508000,0.075000); -positions[616] = Vec3(1.362000,2.808000,2.069000); -positions[617] = Vec3(1.747000,0.068000,0.810000); -positions[618] = Vec3(1.768000,2.355000,0.661000); -positions[619] = Vec3(1.535000,2.410000,2.085000); -positions[620] = Vec3(0.844000,2.004000,1.646000); -positions[621] = Vec3(1.124000,0.280000,0.649000); -positions[622] = Vec3(0.689000,2.170000,0.648000); -positions[623] = Vec3(0.849000,2.666000,1.175000); -positions[624] = Vec3(2.975000,1.963000,1.308000); -positions[625] = Vec3(1.074000,2.082000,0.714000); -positions[626] = Vec3(1.284000,2.651000,1.110000); -positions[627] = Vec3(1.669000,0.205000,0.180000); -positions[628] = Vec3(1.716000,0.047000,1.253000); -positions[629] = Vec3(0.501000,2.241000,1.043000); -positions[630] = Vec3(1.038000,1.833000,0.305000); -positions[631] = Vec3(0.646000,2.431000,1.424000); -positions[632] = Vec3(1.383000,2.059000,2.230000); -positions[633] = Vec3(0.370000,2.566000,1.192000); -positions[634] = Vec3(1.355000,2.006000,0.120000); -positions[635] = Vec3(2.113000,0.075000,0.589000); -positions[636] = Vec3(1.850000,0.448000,1.890000); -positions[637] = Vec3(1.215000,2.704000,0.405000); -positions[638] = Vec3(0.575000,2.997000,1.798000); -positions[639] = Vec3(0.967000,2.586000,2.603000); -positions[640] = Vec3(0.276000,1.669000,1.430000); -positions[641] = Vec3(1.483000,2.284000,1.128000); -positions[642] = Vec3(0.983000,3.003000,1.099000); -positions[643] = Vec3(0.539000,2.222000,1.720000); -positions[644] = Vec3(0.648000,2.826000,2.751000); -positions[645] = Vec3(0.803000,1.994000,0.993000); -positions[646] = Vec3(0.451000,0.216000,1.438000); -positions[647] = Vec3(1.604000,2.512000,0.334000); -positions[648] = Vec3(1.980000,2.022000,0.588000); -positions[649] = Vec3(1.843000,2.834000,1.544000); -positions[650] = Vec3(1.835000,3.005000,2.858000); -positions[651] = Vec3(0.679000,2.499000,0.838000); -positions[652] = Vec3(0.012000,2.637000,1.524000); -positions[653] = Vec3(0.314000,2.065000,0.602000); -positions[654] = Vec3(1.157000,0.004000,0.173000); -positions[655] = Vec3(0.736000,1.705000,1.382000); -positions[656] = Vec3(1.511000,2.736000,0.690000); -positions[657] = Vec3(1.330000,2.541000,1.735000); -positions[658] = Vec3(0.744000,0.170000,0.785000); -positions[659] = Vec3(2.593000,2.794000,0.703000); -positions[660] = Vec3(0.275000,1.872000,1.043000); -positions[661] = Vec3(1.624000,2.608000,1.341000); -positions[662] = Vec3(1.382000,0.122000,2.855000); -positions[663] = Vec3(1.326000,2.434000,0.783000); -positions[664] = Vec3(0.117000,0.116000,1.254000); -positions[665] = Vec3(1.045000,2.970000,2.748000); -positions[666] = Vec3(1.341000,2.692000,2.799000); -positions[667] = Vec3(1.797000,2.586000,2.709000); -positions[668] = Vec3(0.890000,2.484000,1.716000); -positions[669] = Vec3(2.373000,2.558000,1.889000); -positions[670] = Vec3(1.566000,2.323000,2.574000); -positions[671] = Vec3(1.257000,2.280000,0.399000); -positions[672] = Vec3(0.679000,2.130000,2.434000); -positions[673] = Vec3(2.016000,2.334000,2.462000); -positions[674] = Vec3(1.077000,2.213000,2.416000); -positions[675] = Vec3(0.581000,1.950000,2.081000); -positions[676] = Vec3(0.805000,2.315000,2.810000); -positions[677] = Vec3(0.844000,1.787000,2.322000); -positions[678] = Vec3(0.980000,2.205000,0.129000); -positions[679] = Vec3(2.468000,0.603000,2.740000); -positions[680] = Vec3(2.366000,2.403000,2.299000); -positions[681] = Vec3(0.337000,2.487000,2.329000); -positions[682] = Vec3(2.007000,2.793000,2.452000); -positions[683] = Vec3(1.072000,2.571000,0.063000); -positions[684] = Vec3(1.217000,2.283000,2.806000); -positions[685] = Vec3(0.459000,2.477000,2.728000); -positions[686] = Vec3(0.958000,1.975000,2.710000); -positions[687] = Vec3(0.914000,2.111000,2.052000); -positions[688] = Vec3(0.768000,2.958000,0.075000); -positions[689] = Vec3(0.474000,1.805000,2.533000); -positions[690] = Vec3(1.313000,2.552000,2.395000); -positions[691] = Vec3(1.853000,2.014000,2.229000); -positions[692] = Vec3(2.405000,2.230000,2.658000); -positions[693] = Vec3(0.727000,1.781000,0.016000); -positions[694] = Vec3(0.974000,2.791000,2.271000); -positions[695] = Vec3(0.438000,0.096000,2.457000); -positions[696] = Vec3(0.652000,2.392000,2.064000); -positions[697] = Vec3(1.972000,2.209000,2.834000); -positions[698] = Vec3(0.333000,0.141000,2.088000); -positions[699] = Vec3(1.813000,1.952000,0.063000); -positions[700] = Vec3(0.166000,2.838000,1.877000); -positions[701] = Vec3(1.772000,0.487000,0.951000); -positions[702] = Vec3(1.924000,1.404000,1.434000); -positions[703] = Vec3(2.734000,0.348000,1.712000); -positions[704] = Vec3(2.874000,0.729000,1.811000); -positions[705] = Vec3(1.841000,0.877000,1.137000); -positions[706] = Vec3(2.327000,1.491000,1.768000); -positions[707] = Vec3(1.916000,1.483000,1.057000); -positions[708] = Vec3(2.783000,0.850000,0.745000); -positions[709] = Vec3(1.829000,1.526000,0.085000); -positions[710] = Vec3(2.426000,1.082000,0.652000); -positions[711] = Vec3(1.645000,1.241000,1.217000); -positions[712] = Vec3(2.286000,0.725000,0.084000); -positions[713] = Vec3(2.755000,0.691000,1.421000); -positions[714] = Vec3(2.651000,0.591000,1.023000); -positions[715] = Vec3(2.040000,0.863000,0.442000); -positions[716] = Vec3(0.035000,0.109000,2.497000); -positions[717] = Vec3(0.127000,1.410000,0.572000); -positions[718] = Vec3(2.174000,0.357000,0.307000); -positions[719] = Vec3(2.705000,1.508000,0.758000); -positions[720] = Vec3(2.223000,1.407000,2.913000); -positions[721] = Vec3(2.528000,1.722000,1.088000); -positions[722] = Vec3(2.860000,0.345000,0.198000); -positions[723] = Vec3(2.580000,1.789000,1.479000); -positions[724] = Vec3(2.779000,0.295000,1.295000); -positions[725] = Vec3(0.097000,0.434000,2.826000); -positions[726] = Vec3(2.952000,1.654000,1.091000); -positions[727] = Vec3(0.119000,1.878000,0.343000); -positions[728] = Vec3(1.718000,1.173000,0.327000); -positions[729] = Vec3(2.833000,0.016000,0.527000); -positions[730] = Vec3(2.085000,1.779000,2.888000); -positions[731] = Vec3(2.754000,2.952000,1.485000); -positions[732] = Vec3(2.826000,0.935000,1.162000); -positions[733] = Vec3(1.564000,1.585000,1.615000); -positions[734] = Vec3(2.132000,0.645000,1.093000); -positions[735] = Vec3(2.294000,1.490000,1.350000); -positions[736] = Vec3(0.081000,0.490000,1.479000); -positions[737] = Vec3(2.118000,1.165000,1.642000); -positions[738] = Vec3(2.141000,0.121000,1.390000); -positions[739] = Vec3(2.385000,0.389000,1.196000); -positions[740] = Vec3(0.049000,0.166000,0.817000); -positions[741] = Vec3(1.993000,0.806000,1.814000); -positions[742] = Vec3(0.006000,1.450000,0.171000); -positions[743] = Vec3(2.297000,0.428000,0.764000); -positions[744] = Vec3(2.851000,0.469000,2.114000); -positions[745] = Vec3(1.814000,1.957000,0.945000); -positions[746] = Vec3(0.386000,0.327000,0.902000); -positions[747] = Vec3(2.452000,1.070000,1.807000); -positions[748] = Vec3(2.309000,1.537000,2.159000); -positions[749] = Vec3(2.712000,1.497000,2.007000); -positions[750] = Vec3(1.727000,0.924000,1.503000); -positions[751] = Vec3(0.861000,0.801000,0.344000); -positions[752] = Vec3(1.740000,1.245000,0.819000); -positions[753] = Vec3(0.117000,0.042000,0.197000); -positions[754] = Vec3(2.557000,0.996000,0.317000); -positions[755] = Vec3(2.228000,1.588000,2.548000); -positions[756] = Vec3(2.849000,1.557000,2.708000); -positions[757] = Vec3(0.152000,1.107000,0.219000); -positions[758] = Vec3(2.460000,1.318000,1.002000); -positions[759] = Vec3(2.405000,1.436000,0.528000); -positions[760] = Vec3(2.135000,1.179000,2.046000); -positions[761] = Vec3(1.726000,0.588000,0.286000); -positions[762] = Vec3(2.831000,1.053000,1.538000); -positions[763] = Vec3(1.932000,1.556000,1.833000); -positions[764] = Vec3(2.423000,0.900000,1.064000); -positions[765] = Vec3(3.001000,1.807000,0.709000); -positions[766] = Vec3(0.578000,1.095000,0.223000); -positions[767] = Vec3(2.215000,1.160000,0.252000); -positions[768] = Vec3(2.050000,0.921000,0.835000); -positions[769] = Vec3(2.080000,1.682000,0.738000); -positions[770] = Vec3(2.851000,1.753000,0.027000); -positions[771] = Vec3(0.203000,0.509000,0.202000); -positions[772] = Vec3(1.967000,1.018000,0.018000); -positions[773] = Vec3(1.869000,0.878000,2.472000); -positions[774] = Vec3(1.917000,0.228000,2.507000); -positions[775] = Vec3(0.316000,0.795000,2.991000); -positions[776] = Vec3(2.175000,1.229000,2.472000); -positions[777] = Vec3(2.405000,1.062000,2.931000); -positions[778] = Vec3(2.501000,0.511000,2.369000); -positions[779] = Vec3(2.641000,0.819000,2.141000); -positions[780] = Vec3(0.649000,1.384000,3.006000); -positions[781] = Vec3(1.012000,0.329000,2.963000); -positions[782] = Vec3(2.755000,0.350000,2.718000); -positions[783] = Vec3(2.315000,0.153000,2.454000); -positions[784] = Vec3(2.583000,1.696000,2.389000); -positions[785] = Vec3(0.439000,2.593000,1.776000); -positions[786] = Vec3(2.630000,1.390000,0.116000); -positions[787] = Vec3(2.854000,0.669000,2.478000); -positions[788] = Vec3(2.551000,1.342000,2.621000); -positions[789] = Vec3(2.533000,2.734000,2.987000); -positions[790] = Vec3(2.772000,2.446000,2.875000); -positions[791] = Vec3(2.817000,1.051000,2.498000); -positions[792] = Vec3(2.688000,1.404000,1.621000); -positions[793] = Vec3(0.083000,2.737000,2.775000); -positions[794] = Vec3(2.514000,0.322000,2.041000); -positions[795] = Vec3(2.470000,0.900000,2.504000); -positions[796] = Vec3(2.790000,0.444000,0.624000); -positions[797] = Vec3(0.040000,0.840000,2.202000); -positions[798] = Vec3(0.530000,1.067000,2.764000); -positions[799] = Vec3(0.191000,1.385000,2.541000); -positions[800] = Vec3(2.465000,0.363000,0.051000); -positions[801] = Vec3(1.850000,1.902000,2.592000); -positions[802] = Vec3(1.432000,0.306000,2.449000); -positions[803] = Vec3(2.259000,0.489000,1.753000); -positions[804] = Vec3(2.803000,1.118000,1.956000); -positions[805] = Vec3(2.426000,0.147000,1.636000); -positions[806] = Vec3(2.880000,1.846000,2.133000); -positions[807] = Vec3(2.862000,2.110000,1.867000); -positions[808] = Vec3(0.424000,1.184000,2.299000); -positions[809] = Vec3(2.518000,1.218000,2.228000); -positions[810] = Vec3(2.153000,0.834000,1.468000); -positions[811] = Vec3(0.105000,1.397000,2.088000); -positions[812] = Vec3(2.579000,0.601000,0.316000); -positions[813] = Vec3(2.594000,2.106000,2.968000); -positions[814] = Vec3(0.448000,1.435000,1.783000); -positions[815] = Vec3(2.125000,0.299000,2.132000); -positions[816] = Vec3(2.849000,1.402000,2.356000); -positions[817] = Vec3(2.956000,0.091000,2.078000); -positions[818] = Vec3(0.156000,1.696000,2.357000); -positions[819] = Vec3(1.566000,2.211000,1.557000); -positions[820] = Vec3(2.047000,0.194000,0.985000); -positions[821] = Vec3(1.947000,2.680000,0.488000); -positions[822] = Vec3(2.343000,2.796000,1.447000); -positions[823] = Vec3(2.006000,2.332000,0.265000); -positions[824] = Vec3(2.396000,1.834000,0.546000); -positions[825] = Vec3(2.538000,2.059000,2.207000); -positions[826] = Vec3(0.110000,2.360000,0.447000); -positions[827] = Vec3(2.198000,2.448000,1.136000); -positions[828] = Vec3(2.420000,2.121000,1.271000); -positions[829] = Vec3(0.422000,2.192000,0.260000); -positions[830] = Vec3(2.145000,2.767000,2.839000); -positions[831] = Vec3(2.434000,2.398000,0.421000); -positions[832] = Vec3(2.489000,2.175000,1.718000); -positions[833] = Vec3(2.870000,2.527000,0.814000); -positions[834] = Vec3(2.741000,2.016000,0.337000); -positions[835] = Vec3(1.997000,2.574000,2.107000); -positions[836] = Vec3(0.002000,2.128000,0.932000); -positions[837] = Vec3(2.787000,2.375000,0.234000); -positions[838] = Vec3(2.235000,1.852000,1.620000); -positions[839] = Vec3(2.782000,1.642000,0.422000); -positions[840] = Vec3(2.915000,1.760000,1.699000); -positions[841] = Vec3(2.047000,2.178000,1.549000); -positions[842] = Vec3(1.808000,1.878000,1.556000); -positions[843] = Vec3(2.224000,2.043000,0.913000); -positions[844] = Vec3(2.619000,2.611000,1.237000); -positions[845] = Vec3(2.916000,2.726000,0.168000); -positions[846] = Vec3(2.021000,2.833000,1.176000); -positions[847] = Vec3(2.967000,2.308000,2.258000); -positions[848] = Vec3(2.778000,2.270000,1.477000); -positions[849] = Vec3(2.121000,1.834000,2.002000); -positions[850] = Vec3(2.097000,2.752000,0.808000); -positions[851] = Vec3(1.897000,0.566000,1.501000); -positions[852] = Vec3(0.359000,2.802000,0.036000); -positions[853] = Vec3(2.966000,2.454000,1.186000); -positions[854] = Vec3(2.461000,2.964000,1.132000); -positions[855] = Vec3(2.093000,1.821000,1.243000); -positions[856] = Vec3(1.706000,2.659000,1.841000); -positions[857] = Vec3(2.074000,1.709000,0.342000); -positions[858] = Vec3(2.137000,2.894000,1.813000); -positions[859] = Vec3(0.223000,2.293000,1.417000); -positions[860] = Vec3(2.637000,0.007000,0.197000); -positions[861] = Vec3(1.416000,0.050000,0.483000); -positions[862] = Vec3(1.845000,2.250000,1.251000); -positions[863] = Vec3(2.906000,0.034000,2.896000); -positions[864] = Vec3(2.481000,0.204000,0.474000); -positions[865] = Vec3(2.234000,2.051000,0.158000); -positions[866] = Vec3(0.185000,2.453000,0.055000); -positions[867] = Vec3(2.509000,0.048000,2.786000); -positions[868] = Vec3(2.202000,2.206000,2.027000); -positions[869] = Vec3(0.061000,2.367000,2.656000); -positions[870] = Vec3(3.003000,2.755000,2.241000); -positions[871] = Vec3(0.297000,2.131000,2.463000); -positions[872] = Vec3(1.553000,0.429000,1.573000); -positions[873] = Vec3(2.506000,1.832000,1.911000); -positions[874] = Vec3(2.472000,1.814000,2.759000); -positions[875] = Vec3(1.922000,1.563000,2.278000); -positions[876] = Vec3(2.623000,2.666000,2.169000); -positions[877] = Vec3(0.120000,1.834000,2.723000); -positions[878] = Vec3(0.294000,0.103000,2.826000); -positions[879] = Vec3(2.364000,2.821000,0.417000); -positions[880] = Vec3(2.446000,1.734000,0.153000); -positions[881] = Vec3(2.777000,2.037000,2.565000); -positions[882] = Vec3(2.837000,2.477000,1.924000); -positions[883] = Vec3(2.221000,1.961000,2.443000); -positions[884] = Vec3(2.284000,2.895000,2.157000); -positions[885] = Vec3(2.728000,2.880000,1.861000); -positions[886] = Vec3(0.454000,2.080000,2.868000); -positions[887] = Vec3(2.430000,2.790000,2.524000); -positions[888] = Vec3(1.808000,2.213000,1.899000); -positions[889] = Vec3(2.666000,0.053000,2.309000); -positions[890] = Vec3(2.290000,2.408000,2.995000); -positions[891] = Vec3(2.646000,2.592000,1.625000); -positions[892] = Vec3(2.750000,2.508000,2.489000); -positions[893] = Vec3(0.211000,1.753000,1.939000); diff --git a/platforms/opencl/tests/TestOpenCLCheckpoints.cpp b/platforms/opencl/tests/TestOpenCLCheckpoints.cpp index a03a57d76..97c440afc 100644 --- a/platforms/opencl/tests/TestOpenCLCheckpoints.cpp +++ b/platforms/opencl/tests/TestOpenCLCheckpoints.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2013 Stanford University and the Authors. * + * Portions copyright (c) 2012-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,45 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests creating and loading checkpoints with the OpenCL platform. - */ - -#include "OpenCLPlatform.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/Context.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void compareStates(State& s1, State& s2) { - ASSERT_EQUAL_TOL(s1.getTime(), s2.getTime(), TOL); - int numParticles = s1.getPositions().size(); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], TOL); - ASSERT_EQUAL_VEC(s1.getVelocities()[i], s2.getVelocities()[i], TOL); - Vec3 a1, b1, c1, a2, b2, c2; - s1.getPeriodicBoxVectors(a1, b1, c1); - s2.getPeriodicBoxVectors(a2, b2, c2); - ASSERT_EQUAL_VEC(a1, a2, TOL); - ASSERT_EQUAL_VEC(b1, b2, TOL); - ASSERT_EQUAL_VEC(c1, c2, TOL); - for (map::const_iterator iter = s1.getParameters().begin(); iter != s1.getParameters().end(); ++iter) - ASSERT_EQUAL(iter->second, (*s2.getParameters().find(iter->first)).second); - } -} +#include "OpenCLTests.h" +#include "TestCheckpoints.h" void testCheckpoint() { const int numParticles = 100; @@ -159,71 +122,6 @@ void testCheckpoint() { compareStates(s6, s8); } -void testSetState() { - const int numParticles = 10; - const double boxSize = 3.0; - const double temperature = 200.0; - System system; - system.addForce(new AndersenThermostat(0.0, 100.0)); - NonbondedForce* nonbonded = new NonbondedForce(); - system.addForce(nonbonded); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1); - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - } - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - context.setParameter(AndersenThermostat::Temperature(), temperature); - - // Run for a little while. - - integrator.step(100); - - // Record the current state. - - State s1 = context.getState(State::Positions | State::Velocities | State::Parameters); - - // Continue the simulation for a few more steps and record a partial state. - - integrator.step(10); - State s2 = context.getState(State::Positions); - - // Restore the original state and see if everything gets restored correctly. - - context.setPeriodicBoxVectors(Vec3(2*boxSize, 0, 0), Vec3(0, 2*boxSize, 0), Vec3(0, 0, 2*boxSize)); - context.setParameter(AndersenThermostat::Temperature(), temperature+10); - context.setState(s1); - State s3 = context.getState(State::Positions | State::Velocities | State::Parameters); - compareStates(s1, s3); - - // Set the partial state and see if the correct things were set. - - context.setState(s2); - State s4 = context.getState(State::Positions | State::Velocities | State::Parameters); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(s2.getPositions()[i], s4.getPositions()[i], TOL); - ASSERT_EQUAL_VEC(s1.getVelocities()[i], s4.getVelocities()[i], TOL); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testCheckpoint(); - testSetState(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testCheckpoint(); } diff --git a/platforms/opencl/tests/TestOpenCLEwald.cpp b/platforms/opencl/tests/TestOpenCLEwald.cpp index f53b6f884..a9a05d9e6 100644 --- a/platforms/opencl/tests/TestOpenCLEwald.cpp +++ b/platforms/opencl/tests/TestOpenCLEwald.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,359 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the Ewald summation method OpenCL implementation of NonbondedForce. - */ +#include "OpenCLTests.h" +#include "TestEwald.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.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 "openmm/internal/NonbondedForceImpl.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -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; - - 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 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 OpenCL platforms agree when using Ewald Method - - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context clContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - clContext.setPositions(positions); - referenceContext.setPositions(positions); - State clState = clContext.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], clState.getForces()[i], tol); - } - tol = 1e-5; - ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), clState.getPotentialEnergy(), tol); - -// (2) Check whether Ewald method in OpenCL is self-consistent - - double norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = clState.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 = clState.getForces()[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - } - VerletIntegrator integrator3(0.01); - Context clContext2(system, integrator3, platform); - clContext2.setPositions(positions); - - tol = 1e-2; - State clState2 = clContext2.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (clState2.getPotentialEnergy()-clState.getPotentialEnergy())/delta, tol) - -// (3) Check whether the Reference and OpenCL platforms agree when using PME - - nonbonded->setNonbondedMethod(NonbondedForce::PME); - clContext.reinitialize(); - referenceContext.reinitialize(); - clContext.setPositions(positions); - referenceContext.setPositions(positions); - clState = clContext.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], clState.getForces()[i], tol); - } - tol = 1e-5; - ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), clState.getPotentialEnergy(), tol); - -// (4) Check whether PME method in OpenCL is self-consistent - - norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = clState.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 = clState.getForces()[i]; - positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - } - VerletIntegrator integrator4(0.01); - Context clContext3(system, integrator4, platform); - clContext3.setPositions(positions); - - tol = 1e-2; - State clState3 = clContext3.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (clState3.getPotentialEnergy()-clState.getPotentialEnergy())/delta, tol) -} - -void testEwald2Ions() { - 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 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& 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 runPlatformTests() { } - -void testTriclinic() { - // Create a triclinic box containing eight particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(2.5, 0, 0), Vec3(0.5, 3.0, 0), Vec3(0.7, 0.9, 3.5)); - for (int i = 0; i < 8; i++) - system.addParticle(1.0); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - force->setNonbondedMethod(NonbondedForce::PME); - force->setCutoffDistance(1.0); - force->setPMEParameters(3.45891, 32, 40, 48); - for (int i = 0; i < 4; i++) - force->addParticle(-1, 0.440104, 0.4184); // Cl parameters - for (int i = 0; i < 4; i++) - force->addParticle(1, 0.332840, 0.0115897); // Na parameters - vector positions(8); - positions[0] = Vec3(1.744, 2.788, 3.162); - positions[1] = Vec3(1.048, 0.762, 2.340); - positions[2] = Vec3(2.489, 1.570, 2.817); - positions[3] = Vec3(1.027, 1.893, 3.271); - positions[4] = Vec3(0.937, 0.825, 0.009); - positions[5] = Vec3(2.290, 1.887, 3.352); - positions[6] = Vec3(1.266, 1.111, 2.894); - positions[7] = Vec3(0.933, 1.862, 3.490); - - // Compute the forces and energy. - - VerletIntegrator integ(0.001); - Context context(system, integ, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // Compare them to values computed by Gromacs. - - double expectedEnergy = -963.370; - vector expectedForce(8); - expectedForce[0] = Vec3(4.25253e+01, -1.23503e+02, 1.22139e+02); - expectedForce[1] = Vec3(9.74752e+01, 1.68213e+02, 1.93169e+02); - expectedForce[2] = Vec3(-1.50348e+02, 1.29165e+02, 3.70435e+02); - expectedForce[3] = Vec3(9.18644e+02, -3.52571e+00, -1.34772e+03); - expectedForce[4] = Vec3(-1.61193e+02, 9.01528e+01, -7.12904e+01); - expectedForce[5] = Vec3(2.82630e+02, 2.78029e+01, -3.72864e+02); - expectedForce[6] = Vec3(-1.47454e+02, -2.14448e+02, -3.55789e+02); - expectedForce[7] = Vec3(-8.82195e+02, -7.39132e+01, 1.46202e+03); - for (int i = 0; i < 8; i++) { - ASSERT_EQUAL_VEC(expectedForce[i], state.getForces()[i], 1e-4); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-4); -} - -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 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); - - // 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 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); - } - if (method == NonbondedForce::PME) { - // See if the PME parameters were calculated correctly. - - double expectedAlpha, actualAlpha; - int expectedSize[3], actualSize[3]; - NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); - force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); - ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); - for (int i = 0; i < 3; i++) { - ASSERT(actualSize[i] >= expectedSize[i]); - ASSERT(actualSize[i] < expectedSize[i]+10); - } - } - } - } -} - -void testPMEParameters() { - // Create a cloud of random point charges. - - const int numParticles = 51; - const double boxWidth = 4.7; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth)); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - vector 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(NonbondedForce::PME); - - // Compute the energy with an error tolerance of 1e-3. - - force->setEwaldErrorTolerance(1e-3); - VerletIntegrator integrator1(0.01); - Context context1(system, integrator1, platform); - context1.setPositions(positions); - double energy1 = context1.getState(State::Energy).getPotentialEnergy(); - - // Try again with an error tolerance of 1e-4. - - force->setEwaldErrorTolerance(1e-4); - VerletIntegrator integrator2(0.01); - Context context2(system, integrator2, platform); - context2.setPositions(positions); - double energy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // Now explicitly set the parameters. These should match the values that were - // used for tolerance 1e-3. - - force->setPMEParameters(2.49291157051793, 32, 32, 32); - VerletIntegrator integrator3(0.01); - Context context3(system, integrator3, platform); - context3.setPositions(positions); - double energy3 = context3.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(energy1, energy3, 1e-6); - ASSERT(fabs((energy1-energy2)/energy1) > 1e-5); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testEwaldPME(false); - testEwaldPME(true); -// testEwald2Ions(); - testTriclinic(); - testErrorTolerance(NonbondedForce::Ewald); - testErrorTolerance(NonbondedForce::PME); - testPMEParameters(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/opencl/tests/TestOpenCLGBSAOBCForce.cpp b/platforms/opencl/tests/TestOpenCLGBSAOBCForce.cpp index d406c4c58..388c3ab4a 100644 --- a/platforms/opencl/tests/TestOpenCLGBSAOBCForce.cpp +++ b/platforms/opencl/tests/TestOpenCLGBSAOBCForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,243 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of GBSAOBCForce. - */ +#include "OpenCLTests.h" +#include "TestGBSAOBCForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "ReferencePlatform.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include "openmm/NonbondedForce.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSingleParticle() { - 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 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 = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); - - // Change the parameters and see if it is still correct. - - gbsa->setParticleParameters(0, 0.4, 0.25, 1); - gbsa->updateParametersInContext(context); - state = context.getState(State::Energy); - bornRadius = 0.25-0.009; // dielectric offset - bornEnergy = (-0.4*0.4/(8*PI_M*eps0))*(1.0/gbsa->getSoluteDielectric()-1.0/gbsa->getSolventDielectric())/bornRadius; - extendedRadius = 0.25+0.14; - nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.25/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testGlobalSettings() { - System system; - system.addParticle(2.0); - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - forceField->addParticle(0.5, 0.15, 1); - const double soluteDielectric = 2.1; - const double solventDielectric = 35.0; - const double surfaceAreaEnergy = 0.75; - forceField->setSoluteDielectric(soluteDielectric); - forceField->setSolventDielectric(solventDielectric); - forceField->setSurfaceAreaEnergy(surfaceAreaEnergy); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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/soluteDielectric-1.0/solventDielectric)/bornRadius; - double extendedRadius = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*surfaceAreaEnergy*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testCutoffAndPeriodic() { - 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 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, platform); - 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 runPlatformTests() { } - -void testForce(int numParticles, NonbondedForce::NonbondedMethod method, GBSAOBCForce::NonbondedMethod method2) { - 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, platform); - Context refContext(system, integrator2, reference); - - // Set random (but uniformly distributed) positions for all the particles. - - vector 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 OpenCL 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 and see whether the potential energy changes by the expected amount. - // (This doesn't work with cutoffs, since the energy changes discontinuously at the cutoff distance.) - - if (method == NonbondedForce::NoCutoff) - { - const double delta = 0.3; - double step = 0.5*delta/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < numParticles; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-2) - } -} - -int main() { - try { - testSingleParticle(); - testGlobalSettings(); - 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; -} - diff --git a/platforms/opencl/tests/TestOpenCLLangevinIntegrator.cpp b/platforms/opencl/tests/TestOpenCLLangevinIntegrator.cpp index d423cd5d3..ddbe4efee 100644 --- a/platforms/opencl/tests/TestOpenCLLangevinIntegrator.cpp +++ b/platforms/opencl/tests/TestOpenCLLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,256 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of LangevinIntegrator. - */ +#include "OpenCLTests.h" +#include "TestLangevinIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - 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 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; - 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 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; - 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 positions(numParticles); - vector 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 testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - LangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - 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 positions(numParticles); - vector 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(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLLocalEnergyMinimizer.cpp b/platforms/opencl/tests/TestOpenCLLocalEnergyMinimizer.cpp index 7ec3458cf..c7012c522 100644 --- a/platforms/opencl/tests/TestOpenCLLocalEnergyMinimizer.cpp +++ b/platforms/opencl/tests/TestOpenCLLocalEnergyMinimizer.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2010-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,188 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -#include "openmm/internal/AssertionUtilities.h" -#include "OpenCLPlatform.h" -#include "openmm/Context.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/LocalEnergyMinimizer.h" -#include "openmm/NonbondedForce.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/VirtualSite.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -void testHarmonicBonds() { - const int numParticles = 10; - System system; - HarmonicBondForce* bonds = new HarmonicBondForce(); - system.addForce(bonds); - - // Create a chain of particles connected by harmonic bonds. - - vector positions(numParticles); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - positions[i] = Vec3(i, 0, 0); - if (i > 0) - bonds->addBond(i-1, i, 1+0.1*i, 1); - } - - // Minimize it and check that all bonds are at their equilibrium distances. +#include "OpenCLTests.h" +#include "TestLocalEnergyMinimizer.h" - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - LocalEnergyMinimizer::minimize(context, 1e-5); - State state = context.getState(State::Positions); - for (int i = 1; i < numParticles; i++) { - Vec3 delta = state.getPositions()[i]-state.getPositions()[i-1]; - ASSERT_EQUAL_TOL(1+0.1*i, sqrt(delta.dot(delta)), 1e-4); - } +void runPlatformTests() { } - -void testLargeSystem() { - const int numMolecules = 25; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 4.0; - const double tolerance = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setCutoffDistance(cutoff); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Create a cloud of molecules. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < numMolecules; i++) { - system.addParticle(1.0); - system.addParticle(1.0); - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.2, 0.2); - 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]); - system.addConstraint(2*i, 2*i+1, 1.0); - } - - // Minimize it and verify that the energy has decreased. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State initialState = context.getState(State::Forces | State::Energy); - LocalEnergyMinimizer::minimize(context, tolerance); - State finalState = context.getState(State::Forces | State::Energy | State::Positions); - ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); - - // Compute the force magnitude, subtracting off any component parallel to a constraint, and - // check that it satisfies the requested tolerance. - - double forceNorm = 0.0; - for (int i = 0; i < numParticles; i += 2) { - Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; - double distance = sqrt(dir.dot(dir)); - dir *= 1.0/distance; - Vec3 f = finalState.getForces()[i]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - f = finalState.getForces()[i+1]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - } - forceNorm = sqrt(forceNorm/(5*numMolecules)); - ASSERT(forceNorm < 2*tolerance); -} - -void testVirtualSites() { - const int numMolecules = 25; - const int numParticles = numMolecules*3; - const double cutoff = 2.0; - const double boxSize = 4.0; - const double tolerance = 10; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setCutoffDistance(cutoff); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Create a cloud of molecules. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < numMolecules; i++) { - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(0.5, 0.2, 0.2); - nonbonded->addParticle(0.5, 0.2, 0.2); - positions[3*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - positions[3*i+1] = Vec3(positions[3*i][0]+1.0, positions[3*i][1], positions[3*i][2]); - positions[3*i+2] = Vec3(); - system.addConstraint(3*i, 3*i+1, 1.0); - system.setVirtualSite(3*i+2, new TwoParticleAverageSite(3*i, 3*i+1, 0.5, 0.5)); - } - - // Minimize it and verify that the energy has decreased. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.applyConstraints(1e-5); - State initialState = context.getState(State::Forces | State::Energy); - LocalEnergyMinimizer::minimize(context, tolerance); - State finalState = context.getState(State::Forces | State::Energy | State::Positions); - ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); - - // Compute the force magnitude, subtracting off any component parallel to a constraint, and - // check that it satisfies the requested tolerance. - - double forceNorm = 0.0; - for (int i = 0; i < numParticles; i += 3) { - Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; - double distance = sqrt(dir.dot(dir)); - dir *= 1.0/distance; - Vec3 f = finalState.getForces()[i]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - f = finalState.getForces()[i+1]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - - // Check the virtual site location. - - ASSERT_EQUAL_VEC((finalState.getPositions()[i+1]+finalState.getPositions()[i])*0.5, finalState.getPositions()[i+2], 1e-5); - } - forceNorm = sqrt(forceNorm/(5*numMolecules)); - ASSERT(forceNorm < 2*tolerance); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testHarmonicBonds(); - testLargeSystem(); - testVirtualSites(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/opencl/tests/TestOpenCLMonteCarloAnisotropicBarostat.cpp b/platforms/opencl/tests/TestOpenCLMonteCarloAnisotropicBarostat.cpp index 93da2412a..2fffb0b05 100644 --- a/platforms/opencl/tests/TestOpenCLMonteCarloAnisotropicBarostat.cpp +++ b/platforms/opencl/tests/TestOpenCLMonteCarloAnisotropicBarostat.cpp @@ -6,8 +6,8 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2015 Stanford University and the Authors. * - * Authors: Peter Eastman, Lee-Ping Wang * + * Portions copyright (c) 2015 Stanford University and the Authors. * + * Authors: Peter Eastman * * Contributors: * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -29,449 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of MonteCarloAnisotropicBarostat. - */ +#include "OpenCLTests.h" +#include "TestMonteCarloAnisotropicBarostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/MonteCarloBarostat.h" -#include "openmm/MonteCarloAnisotropicBarostat.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -OpenCLPlatform platform; - -void testIdealGas() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], true, true, true, frequency); - system.addForce(barostat); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - } -} - -void testIdealGasAxis(int axis) { - // Test scaling just one axis. - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - const bool scaleX = (axis == 0); - const bool scaleY = (axis == 1); - const bool scaleZ = (axis == 2); - double boxX; - double boxY; - double boxZ; - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], scaleX, scaleY, scaleZ, frequency); - system.addForce(barostat); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - boxX = box[0][0]; - boxY = box[1][1]; - boxZ = box[2][2]; - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - if (!scaleX) { - ASSERT(boxX == initialLength); - } - if (!scaleY) { - ASSERT(boxY == 0.5*initialLength); - } - if (!scaleZ) { - ASSERT(boxZ == 2*initialLength); - } - } -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double pressure = 1.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - 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); - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp, true, true, true, 1); - system.addForce(barostat); - vector positions(numParticles); - vector 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. - - barostat->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. - - barostat->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]); - } - } -} - -void testTriclinic() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temperature = 300.0; - const double initialVolume = numParticles*BOLTZ*temperature/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - Vec3 initialBox[3]; - initialBox[0] = Vec3(initialLength, 0, 0); - initialBox[1] = Vec3(0.2*initialLength, initialLength, 0); - initialBox[2] = Vec3(0.1*initialLength, 0.3*initialLength, initialLength); - system.setDefaultPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temperature, true, true, true, frequency); - system.addForce(barostat); - - // Run a simulation - - LangevinIntegrator integrator(temperature, 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temperature/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - - // Make sure the box vectors have been scaled consistently. - - State state = context.getState(State::Positions); - Vec3 box[3]; - state.getPeriodicBoxVectors(box[0], box[1], box[2]); - double xscale = box[2][0]/(0.1*initialLength); - double yscale = box[2][1]/(0.3*initialLength); - double zscale = box[2][2]/(1.0*initialLength); - for (int i = 0; i < 3; i++) { - ASSERT_EQUAL_VEC(Vec3(xscale*initialBox[i][0], yscale*initialBox[i][1], zscale*initialBox[i][2]), box[i], 1e-5); - } - - // The barostat should have put all particles inside the first periodic box. One integration step - // has happened since then, so they may have moved slightly outside it. - - for (int i = 0; i < numParticles; i++) { - Vec3 pos = state.getPositions()[i]; - ASSERT(pos[2]/box[2][2] > -1 && pos[2]/box[2][2] < 2); - pos -= box[2]*floor(pos[2]/box[2][2]); - ASSERT(pos[1]/box[1][1] > -1 && pos[1]/box[1][1] < 2); - pos -= box[1]*floor(pos[1]/box[1][1]); - ASSERT(pos[0]/box[0][0] > -1 && pos[0]/box[0][0] < 2); - } -} - -/** - * Run a constant pressure simulation on an anisotropic Einstein crystal - * using isotropic and anisotropic barostats. There are a total of 15 simulations: - * - * 1) 3 pressures: 9.0, 10.0, 11.0 bar, for each of the following groups: - * 2) 3 groups of simulations that scale just one axis: x, y, z - * 3) 1 group of simulations that scales all three axes in the anisotropic barostat - * 4) 1 group of simulations that scales all three axes in the isotropic barostat - * - * Results that we will check: - * - * a) In each group of simulations, the volume should decrease with increasing pressure - * b) In the three simulation groups that scale just one axis, the compressibility (i.e. incremental volume change - * with increasing pressure) should go like kx > ky > kz (because the spring constant is largest in the z-direction) - * c) The anisotropic barostat should produce the same result as the isotropic barostat when all three axes are scaled - */ -void testEinsteinCrystal() { - const int numParticles = 64; - const int frequency = 2; - const int equil = 10000; - const int steps = 5000; - const double pressure = 10.0; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp = 300.0; // Only test one temperature since we're looking at three pressures. - const double pres3[] = {2.0, 8.0, 15.0}; - const double initialVolume = numParticles*BOLTZ*temp/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - vector initialPositions(3); - vector results; - // Run four groups of anisotropic simulations; scaling just x, y, z, then all three. - for (int a = 0; a < 4; a++) { - // Test barostat for three different pressures. - for (int p = 0; p < 3; p++) { - // Create a system of noninteracting particles attached by harmonic springs to their initial positions. - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - // Anisotropic force constants. - CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); - initialPositions[0] = positions[i][0]; - initialPositions[1] = positions[i][1]; - initialPositions[2] = positions[i][2]; - force->addParticle(i, initialPositions); - nb->addParticle(0, initialLength/6, 0.1); - } - system.addForce(force); - system.addForce(nb); - // Create the barostat. - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pres3[p], pres3[p], pres3[p]), temp, (a==0||a==3), (a==1||a==3), (a==2||a==3), frequency); - system.addForce(barostat); - barostat->setTemperature(temp); - LangevinIntegrator integrator(temp, 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - // Let it equilibrate. - integrator.step(equil); - // Now run it for a while and see if the volume is correct. - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - results.push_back(volume); - } - } - for (int p = 0; p < 3; p++) { - // Create a system of noninteracting particles attached by harmonic springs to their initial positions. - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - // Anisotropic force constants. - CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); - initialPositions[0] = positions[i][0]; - initialPositions[1] = positions[i][1]; - initialPositions[2] = positions[i][2]; - force->addParticle(i, initialPositions); - nb->addParticle(0, initialLength/6, 0.1); - } - system.addForce(force); - system.addForce(nb); - // Create the barostat. - MonteCarloBarostat* barostat = new MonteCarloBarostat(pres3[p], temp, frequency); - system.addForce(barostat); - barostat->setTemperature(temp); - LangevinIntegrator integrator(temp, 0.1, 0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - // Let it equilibrate. - integrator.step(equil); - // Now run it for a while and see if the volume is correct. - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - results.push_back(volume); - } - - // Check to see if volumes decrease with increasing pressure. - ASSERT_USUALLY_TRUE(results[0] > results[1]); - ASSERT_USUALLY_TRUE(results[1] > results[2]); - ASSERT_USUALLY_TRUE(results[3] > results[4]); - ASSERT_USUALLY_TRUE(results[4] > results[5]); - ASSERT_USUALLY_TRUE(results[6] > results[7]); - ASSERT_USUALLY_TRUE(results[7] > results[8]); - - // Check to see if incremental volume changes with increasing pressure go like kx > ky > kz. - ASSERT_USUALLY_TRUE((results[0] - results[1]) > (results[3] - results[4])); - ASSERT_USUALLY_TRUE((results[1] - results[2]) > (results[4] - results[5])); - ASSERT_USUALLY_TRUE((results[3] - results[4]) > (results[6] - results[7])); - ASSERT_USUALLY_TRUE((results[4] - results[5]) > (results[7] - results[8])); - - // Check to see if the volumes are equal for isotropic and anisotropic (all axis). - ASSERT_USUALLY_EQUAL_TOL(results[9], results[12], 3/std::sqrt((double) steps)); - ASSERT_USUALLY_EQUAL_TOL(results[10], results[13], 3/std::sqrt((double) steps)); - ASSERT_USUALLY_EQUAL_TOL(results[11], results[14], 3/std::sqrt((double) steps)); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testIdealGas(); - testIdealGasAxis(0); - testIdealGasAxis(1); - testIdealGasAxis(2); - testRandomSeed(); - testTriclinic(); - //testEinsteinCrystal(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLMonteCarloBarostat.cpp b/platforms/opencl/tests/TestOpenCLMonteCarloBarostat.cpp index 72053c5ec..d8025599b 100644 --- a/platforms/opencl/tests/TestOpenCLMonteCarloBarostat.cpp +++ b/platforms/opencl/tests/TestOpenCLMonteCarloBarostat.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,263 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of MonteCarloBarostat. - */ +#include "OpenCLTests.h" +#include "TestMonteCarloBarostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/MonteCarloBarostat.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -void testChangingBoxSize() { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 5, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nb->setCutoffDistance(2.0); - nb->addParticle(1, 0.5, 0.5); - system.addForce(nb); - LangevinIntegrator integrator(300.0, 1.0, 0.01); - Context context(system, integrator, platform); - vector positions; - positions.push_back(Vec3()); - context.setPositions(positions); - Vec3 x, y, z; - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ASSERT_EQUAL_VEC(Vec3(4, 0, 0), x, 0); - ASSERT_EQUAL_VEC(Vec3(0, 5, 0), y, 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 6), z, 0); - context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 9)); - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ASSERT_EQUAL_VEC(Vec3(7, 0, 0), x, 0); - ASSERT_EQUAL_VEC(Vec3(0, 8, 0), y, 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 9), z, 0); - - // Shrinking the box too small should produce an exception. - - context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 3.9, 0), Vec3(0, 0, 9)); - bool ok = true; - try { - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ok = false; - } - catch (exception& ex) { - } - ASSERT(ok); -} - -void testIdealGas() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp[0], frequency); - system.addForce(barostat); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - ASSERT_EQUAL_TOL(0.5*box[0][0], box[1][1], 1e-5); - ASSERT_EQUAL_TOL(2*box[0][0], box[2][2], 1e-5); - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - } +void runPlatformTests() { + testWater(); } - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double pressure = 1.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - 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); - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, 1); - system.addForce(barostat); - vector positions(numParticles); - vector 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. - - barostat->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. - - barostat->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]); - } - } -} - -void testWater() { - const int gridSize = 8; - const int numMolecules = gridSize*gridSize*gridSize; - const int frequency = 10; - const int steps = 400; - const double temp = 273.15; - const double pressure = 3; - const double spacing = 0.32; - const double angle = 109.47*M_PI/180; - const double dOH = 0.1; - const double dHH = dOH*2*std::sin(0.5*angle); - - // Create a box of SPC water molecules. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(gridSize*spacing, 0, 0), Vec3(0, gridSize*spacing, 0), Vec3(0, 0, gridSize*spacing)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setUseDispersionCorrection(true); - vector positions; - Vec3 offset1(dOH, 0, 0); - Vec3 offset2(dOH*std::cos(angle), dOH*std::sin(angle), 0); - for (int i = 0; i < gridSize; ++i) { - for (int j = 0; j < gridSize; ++j) { - for (int k = 0; k < gridSize; ++k) { - int firstParticle = system.getNumParticles(); - system.addParticle(16.0); - system.addParticle(1.0); - system.addParticle(1.0); - nonbonded->addParticle(-0.82, 0.316557, 0.650194); - nonbonded->addParticle(0.41, 1, 0); - nonbonded->addParticle(0.41, 1, 0); - Vec3 pos = Vec3(spacing*i, spacing*j, spacing*k); - positions.push_back(pos); - positions.push_back(pos+offset1); - positions.push_back(pos+offset2); - system.addConstraint(firstParticle, firstParticle+1, dOH); - system.addConstraint(firstParticle, firstParticle+2, dOH); - system.addConstraint(firstParticle+1, firstParticle+2, dHH); - nonbonded->addException(firstParticle, firstParticle+1, 0, 1, 0); - nonbonded->addException(firstParticle, firstParticle+2, 0, 1, 0); - nonbonded->addException(firstParticle+1, firstParticle+2, 0, 1, 0); - } - } - } - system.addForce(nonbonded); - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, frequency); - system.addForce(barostat); - - // Simulate it and see if the density matches the expected value (1 g/mL). - - LangevinIntegrator integrator(temp, 1.0, 0.002); - Context context(system, integrator, platform); - context.setPositions(positions); - integrator.step(2000); - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double density = numMolecules*18/(AVOGADRO*volume*1e-21); - ASSERT_USUALLY_EQUAL_TOL(1.0, density, 0.02); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testChangingBoxSize(); - testIdealGas(); - testRandomSeed(); - testWater(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - - diff --git a/platforms/opencl/tests/TestOpenCLNonbondedForce.cpp b/platforms/opencl/tests/TestOpenCLNonbondedForce.cpp index 16ea4cd0a..7ed2003dd 100644 --- a/platforms/opencl/tests/TestOpenCLNonbondedForce.cpp +++ b/platforms/opencl/tests/TestOpenCLNonbondedForce.cpp @@ -29,788 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of NonbondedForce. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/internal/ContextImpl.h" -#include "OpenCLArray.h" -#include "OpenCLNonbondedUtilities.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testCoulomb() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - LangevinIntegrator integrator(0.0, 0.1, 0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0.5, 1, 0); - forceField->addParticle(-1.5, 1, 0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double force = ONE_4PI_EPS0*(-0.75)/4.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(-0.75)/2.0, state.getPotentialEnergy(), TOL); -} - -void testLJ() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - LangevinIntegrator integrator(0.0, 0.1, 0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0, 1.2, 1); - forceField->addParticle(0, 1.4, 2); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double x = 1.3/2.0; - double eps = SQRT_TWO; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL); -} - -void testExclusionsAnd14() { - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - for (int i = 0; i < 5; ++i) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - LangevinIntegrator integrator(0.0, 0.1, 0.01); - Context context(system, integrator, platform); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - vector positions(5); - const double r = 1.0; - for (int j = 0; j < 5; ++j) { - nonbonded->setParticleParameters(j, 0, 1.5, 0); - positions[j] = Vec3(0, j, 0); - } - nonbonded->setParticleParameters(0, 0, 1.5, 1); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - positions[i] = Vec3(r, 0, 0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double x = 1.5/r; - double eps = 1.0; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - nonbonded->setParticleParameters(0, 2, 1.5, 0); - nonbonded->setParticleParameters(i, 2, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - context.reinitialize(); - context.setPositions(positions); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*4/(r*r); - energy = ONE_4PI_EPS0*4/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - LangevinIntegrator integrator(0.0, 0.1, 0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - const double cutoff = 2.9; - forceField->setCutoffDistance(cutoff); - const double eps = 50.0; - forceField->setReactionFieldDielectric(eps); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force1 = ONE_4PI_EPS0*(1.0)*(0.25-2.0*krf*2.0); - const double force2 = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL); - const double energy1 = ONE_4PI_EPS0*(1.0)*(0.5+krf*4.0-crf); - const double energy2 = ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf); - ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL); -} - -void testCutoff14() { - System system; - LangevinIntegrator integrator(0.0, 0.1, 0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - for (int i = 0; i < 5; ++i) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - const double cutoff = 3.5; - nonbonded->setCutoffDistance(cutoff); - const double eps = 30.0; - nonbonded->setReactionFieldDielectric(eps); - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(5); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(2, 0, 0); - positions[3] = Vec3(3, 0, 0); - positions[4] = Vec3(4, 0, 0); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - nonbonded->setParticleParameters(0, 0, 1.5, 1); - for (int j = 1; j < 5; ++j) - nonbonded->setParticleParameters(j, 0, 1.5, 0); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double r = positions[i][0]; - double x = 1.5/r; - double e = 1.0; - double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - const double q = 0.7; - nonbonded->setParticleParameters(0, q, 1.5, 0); - nonbonded->setParticleParameters(i, q, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - context.reinitialize(); - context.setPositions(positions); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*q*q/(r*r); - energy = ONE_4PI_EPS0*q*q/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testPeriodic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - LangevinIntegrator integrator(0.0, 0.1, 0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addException(0, 1, 0.0, 1.0, 0.0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 2.0; - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(2, 0, 0); - positions[2] = Vec3(3, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(2*ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL); -} - -void testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta*ONE_4PI_EPS0*(-1.0/(distance*distance*distance)+2.0*krf); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(1.0/distance+krf*distance*distance-crf), state.getPotentialEnergy(), 1e-4); - ASSERT_EQUAL_VEC(force, state.getForces()[0], 1e-4); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], 1e-4); - } - } -} - -void testLargeSystem() { - const int numMolecules = 600; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 20.0; - const double tol = 2e-3; - ReferencePlatform reference; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - HarmonicBondForce* bonds = new HarmonicBondForce(); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - nonbonded->addParticle(-1.0, 0.2, 0.1); - nonbonded->addParticle(1.0, 0.1, 0.1); - } - else { - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.1, 0.2); - } - 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)); - bonds->addBond(2*i, 2*i+1, 1.0, 0.1); - nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); - } - - // Try with cutoffs but not periodic boundary conditions, and make sure the cl and Reference - // platforms agree. - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - system.addForce(bonds); - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context clContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - clContext.setPositions(positions); - clContext.setVelocities(velocities); - referenceContext.setPositions(positions); - referenceContext.setVelocities(velocities); - State clState = clContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - State referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(clState.getPositions()[i], referenceState.getPositions()[i], tol); - ASSERT_EQUAL_VEC(clState.getVelocities()[i], referenceState.getVelocities()[i], tol); - ASSERT_EQUAL_VEC(clState.getForces()[i], referenceState.getForces()[i], tol); - } - ASSERT_EQUAL_TOL(clState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); - - // Now do the same thing with periodic boundary conditions. - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - clContext.reinitialize(); - referenceContext.reinitialize(); - clContext.setPositions(positions); - clContext.setVelocities(velocities); - referenceContext.setPositions(positions); - referenceContext.setVelocities(velocities); - clState = clContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) { - double dx = clState.getPositions()[i][0]-referenceState.getPositions()[i][0]; - double dy = clState.getPositions()[i][1]-referenceState.getPositions()[i][1]; - double dz = clState.getPositions()[i][2]-referenceState.getPositions()[i][2]; - ASSERT_EQUAL_TOL(dx-floor(dx/boxSize+0.5)*boxSize, 0, tol); - ASSERT_EQUAL_TOL(dy-floor(dy/boxSize+0.5)*boxSize, 0, tol); - ASSERT_EQUAL_TOL(dz-floor(dz/boxSize+0.5)*boxSize, 0, tol); - ASSERT_EQUAL_VEC(clState.getVelocities()[i], referenceState.getVelocities()[i], tol); - ASSERT_EQUAL_VEC(clState.getForces()[i], referenceState.getForces()[i], tol); - } - ASSERT_EQUAL_TOL(clState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); -} -/* -void testBlockInteractions(bool periodic) { - const int blockSize = 32; - const int numBlocks = 100; - const int numParticles = blockSize*numBlocks; - const double cutoff = 1.0; - const double boxSize = (periodic ? 5.1 : 1.1); - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(1.0, 0.2, 0.2); - positions[i] = Vec3(boxSize*(3*genrand_real2(sfmt)-1), boxSize*(3*genrand_real2(sfmt)-1), boxSize*(3*genrand_real2(sfmt)-1)); - } - nonbonded->setNonbondedMethod(periodic ? NonbondedForce::CutoffPeriodic : NonbondedForce::CutoffNonPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - Context context(system, integrator, platform); - context.setPositions(positions); - ContextImpl* contextImpl = *reinterpret_cast(&context); - OpenCLPlatform::PlatformData& data = *static_cast(contextImpl->getPlatformData()); - OpenCLContext& clcontext = *data.contexts[0]; - OpenCLNonbondedUtilities& nb = clcontext.getNonbondedUtilities(); - State state = context.getState(State::Positions | State::Velocities | State::Forces); - nb.updateNeighborListSize(); - state = context.getState(State::Positions | State::Velocities | State::Forces); - - // Verify that the bounds of each block were calculated correctly. - - vector posq(clcontext.getPosq().getSize()); - vector blockCenters(numBlocks); - vector blockBoundingBoxes(numBlocks); - if (clcontext.getUseDoublePrecision()) { - clcontext.getPosq().download(posq); - nb.getBlockCenters().download(blockCenters); - nb.getBlockBoundingBoxes().download(blockBoundingBoxes); - } - else { - vector posqf(clcontext.getPosq().getSize()); - vector blockCentersf(numBlocks); - vector blockBoundingBoxesf(numBlocks); - clcontext.getPosq().download(posqf); - nb.getBlockCenters().download(blockCentersf); - nb.getBlockBoundingBoxes().download(blockBoundingBoxesf); - for (int i = 0; i < numParticles; i++) - posq[i] = mm_double4(posqf[i].x, posqf[i].y, posqf[i].z, posqf[i].w); - for (int i = 0; i < numBlocks; i++) { - blockCenters[i] = mm_double4(blockCentersf[i].x, blockCentersf[i].y, blockCentersf[i].z, blockCentersf[i].w); - blockBoundingBoxes[i] = mm_double4(blockBoundingBoxesf[i].x, blockBoundingBoxesf[i].y, blockBoundingBoxesf[i].z, blockBoundingBoxesf[i].w); - } - } - for (int i = 0; i < numBlocks; i++) { - mm_double4 gridSize = blockBoundingBoxes[i]; - mm_double4 center = blockCenters[i]; - if (periodic) { - ASSERT(gridSize.x < 0.5*boxSize); - ASSERT(gridSize.y < 0.5*boxSize); - ASSERT(gridSize.z < 0.5*boxSize); - } - double minx = 0.0, maxx = 0.0, miny = 0.0, maxy = 0.0, minz = 0.0, maxz = 0.0, radius = 0.0; - for (int j = 0; j < blockSize; j++) { - mm_double4 pos = posq[i*blockSize+j]; - double dx = pos.x-center.x; - double dy = pos.y-center.y; - double dz = pos.z-center.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - ASSERT(abs(dx) < gridSize.x+TOL); - ASSERT(abs(dy) < gridSize.y+TOL); - ASSERT(abs(dz) < gridSize.z+TOL); - minx = min(minx, dx); - maxx = max(maxx, dx); - miny = min(miny, dy); - maxy = max(maxy, dy); - minz = min(minz, dz); - maxz = max(maxz, dz); - } - ASSERT_EQUAL_TOL(-minx, gridSize.x, TOL); - ASSERT_EQUAL_TOL(maxx, gridSize.x, TOL); - ASSERT_EQUAL_TOL(-miny, gridSize.y, TOL); - ASSERT_EQUAL_TOL(maxy, gridSize.y, TOL); - ASSERT_EQUAL_TOL(-minz, gridSize.z, TOL); - ASSERT_EQUAL_TOL(maxz, gridSize.z, TOL); - } - - // Verify that interactions were identified correctly. - - vector interactionCount; - vector interactingTiles; - vector interactionFlags; - nb.getInteractionCount().download(interactionCount); - int numWithInteractions = interactionCount[0]; - vector hasInteractions(numBlocks*(numBlocks+1)/2, false); - nb.getInteractingTiles().download(interactingTiles); - if (clcontext.getSIMDWidth() == 32) - nb.getInteractionFlags().download(interactionFlags); - const unsigned int atoms = clcontext.getPaddedNumAtoms(); - const unsigned int grid = OpenCLContext::TileSize; - const unsigned int dim = clcontext.getNumAtomBlocks(); - for (int i = 0; i < numWithInteractions; i++) { - unsigned int x = interactingTiles[i].x; - unsigned int y = interactingTiles[i].y; - int index = (x > y ? x+y*dim-y*(y+1)/2 : y+x*dim-x*(x+1)/2); - hasInteractions[index] = true; - - // Make sure this tile really should have been flagged based on bounding volumes. - - mm_double4 gridSize1 = blockBoundingBoxes[x]; - mm_double4 gridSize2 = blockBoundingBoxes[y]; - mm_double4 center1 = blockCenters[x]; - mm_double4 center2 = blockCenters[y]; - double dx = center1.x-center2.x; - double dy = center1.y-center2.y; - double dz = center1.z-center2.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - dx = max(0.0, abs(dx)-gridSize1.x-gridSize2.x); - dy = max(0.0, abs(dy)-gridSize1.y-gridSize2.y); - dz = max(0.0, abs(dz)-gridSize1.z-gridSize2.z); - ASSERT(sqrt(dx*dx+dy*dy+dz*dz) < cutoff+TOL); - - // Check the interaction flags. - - if (clcontext.getSIMDWidth() == 32) { - unsigned int flags = interactionFlags[i]; - for (int atom2 = 0; atom2 < 32; atom2++) { - if ((flags & 1) == 0) { - mm_double4 pos2 = posq[y*blockSize+atom2]; - for (int atom1 = 0; atom1 < blockSize; ++atom1) { - mm_double4 pos1 = posq[x*blockSize+atom1]; - double dx = pos2.x-pos1.x; - double dy = pos2.y-pos1.y; - double dz = pos2.z-pos1.z; - if (periodic) { - dx -= floor(0.5+dx/boxSize)*boxSize; - dy -= floor(0.5+dy/boxSize)*boxSize; - dz -= floor(0.5+dz/boxSize)*boxSize; - } - ASSERT(dx*dx+dy*dy+dz*dz > cutoff*cutoff); - } - } - flags >>= 1; - } - } - } - - // Check the tiles that did not have interactions to make sure all atoms are beyond the cutoff. - - for (int i = 0; i < (int) hasInteractions.size(); i++) - if (!hasInteractions[i]) { - unsigned int y = (unsigned int) std::floor(numBlocks+0.5-std::sqrt((numBlocks+0.5)*(numBlocks+0.5)-2*i)); - unsigned int x = (i-y*numBlocks+y*(y+1)/2); - for (int atom1 = 0; atom1 < blockSize; ++atom1) { - mm_double4 pos1 = posq[x*blockSize+atom1]; - for (int atom2 = 0; atom2 < blockSize; ++atom2) { - mm_double4 pos2 = posq[y*blockSize+atom2]; - double dx = pos1.x-pos2.x; - double dy = pos1.y-pos2.y; - double dz = pos1.z-pos2.z; - if (periodic) { - dx -= (floor(0.5+dx/boxSize)*boxSize); - dy -= (floor(0.5+dy/boxSize)*boxSize); - dz -= (floor(0.5+dz/boxSize)*boxSize); - } - ASSERT(dx*dx+dy*dy+dz*dz > cutoff*cutoff); - } - } - } -} -*/ -void testDispersionCorrection() { - // Create a box full of identical particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - int index = 0; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.1, 0.5); - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - // See if the correction has the correct value. - - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(false); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); - - // Now modify half the particles to be different, and see if it is still correct. - - int numType2 = 0; - for (int i = 0; i < numParticles; i += 2) { - nonbonded->setParticleParameters(i, 0, 1, 1); - numType2++; - } - int numType1 = numParticles-numType2; - nonbonded->updateParametersInContext(context); - energy2 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(true); - context.reinitialize(); - context.setPositions(positions); - energy1 = context.getState(State::Energy).getPotentialEnergy(); - term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9; - term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3; - double combinedSigma = 0.5*(1+1.1); - double combinedEpsilon = sqrt(1*0.5); - term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9; - term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3; - term1 /= (numParticles*(numParticles+1))/2; - term2 /= (numParticles*(numParticles+1))/2; - expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); -} - -void testChangingParameters() { - const int numMolecules = 600; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 20.0; - const double tol = 2e-3; - ReferencePlatform reference; - System system; - for (int i = 0; i < numParticles; i++) - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; i++) { - if (i < numMolecules/2) { - nonbonded->addParticle(-1.0, 0.2, 0.1); - nonbonded->addParticle(1.0, 0.1, 0.1); - } - else { - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.1, 0.2); - } - 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]); - system.addConstraint(2*i, 2*i+1, 1.0); - nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); - } - nonbonded->setNonbondedMethod(NonbondedForce::PME); - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - - // See if Reference and OpenCL give the same forces and energies. - - VerletIntegrator integrator1(0.01); - VerletIntegrator integrator2(0.01); - Context clContext(system, integrator1, platform); - Context referenceContext(system, integrator2, reference); - clContext.setPositions(positions); - referenceContext.setPositions(positions); - State clState = clContext.getState(State::Forces | State::Energy); - State referenceState = referenceContext.getState(State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(clState.getForces()[i], referenceState.getForces()[i], tol); - ASSERT_EQUAL_TOL(clState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); - - // Now modify parameters and see if they still agree. - - for (int i = 0; i < numParticles; i += 5) { - double charge, sigma, epsilon; - nonbonded->getParticleParameters(i, charge, sigma, epsilon); - nonbonded->setParticleParameters(i, 1.5*charge, 1.1*sigma, 1.7*epsilon); - } - nonbonded->updateParametersInContext(clContext); - nonbonded->updateParametersInContext(referenceContext); - clState = clContext.getState(State::Forces | State::Energy); - referenceState = referenceContext.getState(State::Forces | State::Energy); - for (int i = 0; i < numParticles; i++) - ASSERT_EQUAL_VEC(clState.getForces()[i], referenceState.getForces()[i], tol); - ASSERT_EQUAL_TOL(clState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); -} +#include "OpenCLTests.h" +#include "TestNonbondedForce.h" void testParallelComputation(NonbondedForce::NonbondedMethod method) { System system; @@ -871,61 +91,6 @@ void testParallelComputation(NonbondedForce::NonbondedMethod method) { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); } -void testSwitchingFunction(NonbondedForce::NonbondedMethod method) { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(0, 1.2, 1); - nonbonded->addParticle(0, 1.4, 2); - nonbonded->setNonbondedMethod(method); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - nonbonded->setUseDispersionCorrection(false); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - double eps = SQRT_TWO; - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double x = 1.3/r; - double expectedEnergy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - void testReordering() { // Check that reordering of atoms doesn't alter their positions. @@ -953,34 +118,9 @@ void testReordering() { } } -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testCoulomb(); - testLJ(); - testExclusionsAnd14(); - testCutoff(); - testCutoff14(); - testPeriodic(); - testTriclinic(); - testLargeSystem(); -// testBlockInteractions(false); -// testBlockInteractions(true); - testDispersionCorrection(); - testChangingParameters(); - testParallelComputation(NonbondedForce::NoCutoff); - testParallelComputation(NonbondedForce::Ewald); - testParallelComputation(NonbondedForce::PME); - testSwitchingFunction(NonbondedForce::CutoffNonPeriodic); - testSwitchingFunction(NonbondedForce::PME); - testReordering(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testParallelComputation(NonbondedForce::NoCutoff); + testParallelComputation(NonbondedForce::Ewald); + testParallelComputation(NonbondedForce::PME); + testReordering(); } - diff --git a/platforms/opencl/tests/TestOpenCLSettle.cpp b/platforms/opencl/tests/TestOpenCLSettle.cpp index 919d5647c..93d89da27 100644 --- a/platforms/opencl/tests/TestOpenCLSettle.cpp +++ b/platforms/opencl/tests/TestOpenCLSettle.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,90 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of the SETTLE algorithm. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -void testConstraints() { - const int numMolecules = 10; - const int numParticles = numMolecules*3; - const int numConstraints = numMolecules*3; - const double temp = 100.0; - System system; - LangevinIntegrator integrator(temp, 2.0, 0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numMolecules; ++i) { - system.addParticle(16.0); - system.addParticle(1.0); - system.addParticle(1.0); - forceField->addParticle(-0.82, 0.317, 0.65); - forceField->addParticle(0.41, 1.0, 0.0); - forceField->addParticle(0.41, 1.0, 0.0); - system.addConstraint(i*3, i*3+1, 0.1); - system.addConstraint(i*3, i*3+2, 0.1); - system.addConstraint(i*3+1, i*3+2, 0.163); - } - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; ++i) { - positions[i*3] = Vec3((i%4)*0.4, (i/4)*0.4, 0); - positions[i*3+1] = positions[i*3]+Vec3(0.1, 0, 0); - positions[i*3+2] = positions[i*3]+Vec3(-0.03333, 0.09428, 0); - velocities[i*3] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+1] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+2] = 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) { - integrator.step(1); - State state = context.getState(State::Positions | State::Forces); - 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-5); - } - } -} +#include "OpenCLTests.h" +#include "TestSettle.h" -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testConstraints(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/nacl_amorph.dat b/platforms/opencl/tests/nacl_amorph.dat deleted file mode 100644 index 7e8cbafdf..000000000 --- a/platforms/opencl/tests/nacl_amorph.dat +++ /dev/null @@ -1,894 +0,0 @@ -positions[0] = Vec3(1.066000,1.628000,0.835000); -positions[1] = Vec3(1.072000,0.428000,0.190000); -positions[2] = Vec3(0.524000,1.442000,1.160000); -positions[3] = Vec3(2.383000,1.524000,1.119000); -positions[4] = Vec3(0.390000,1.441000,0.575000); -positions[5] = Vec3(0.618000,0.399000,0.819000); -positions[6] = Vec3(1.003000,1.257000,1.543000); -positions[7] = Vec3(2.933000,1.569000,0.642000); -positions[8] = Vec3(0.849000,0.739000,0.089000); -positions[9] = Vec3(0.060000,0.794000,0.766000); -positions[10] = Vec3(1.652000,1.405000,1.010000); -positions[11] = Vec3(2.843000,1.533000,1.781000); -positions[12] = Vec3(0.952000,1.309000,0.996000); -positions[13] = Vec3(1.847000,1.402000,0.313000); -positions[14] = Vec3(2.674000,0.083000,1.691000); -positions[15] = Vec3(1.763000,2.104000,0.728000); -positions[16] = Vec3(0.914000,0.574000,0.982000); -positions[17] = Vec3(0.514000,0.078000,0.891000); -positions[18] = Vec3(0.538000,0.766000,1.110000); -positions[19] = Vec3(0.808000,0.676000,0.570000); -positions[20] = Vec3(0.178000,0.014000,0.628000); -positions[21] = Vec3(1.329000,1.333000,0.339000); -positions[22] = Vec3(1.029000,1.678000,0.503000); -positions[23] = Vec3(1.423000,1.767000,1.104000); -positions[24] = Vec3(1.966000,1.051000,0.282000); -positions[25] = Vec3(1.596000,1.971000,0.194000); -positions[26] = Vec3(1.025000,1.043000,2.809000); -positions[27] = Vec3(1.628000,2.614000,0.088000); -positions[28] = Vec3(0.440000,0.606000,0.141000); -positions[29] = Vec3(1.050000,2.821000,2.517000); -positions[30] = Vec3(0.644000,1.604000,0.770000); -positions[31] = Vec3(0.637000,0.917000,0.392000); -positions[32] = Vec3(0.611000,2.768000,0.013000); -positions[33] = Vec3(1.892000,0.660000,0.473000); -positions[34] = Vec3(1.052000,2.081000,0.982000); -positions[35] = Vec3(1.508000,2.300000,0.439000); -positions[36] = Vec3(2.617000,0.328000,1.099000); -positions[37] = Vec3(0.910000,0.040000,0.259000); -positions[38] = Vec3(1.195000,1.494000,1.202000); -positions[39] = Vec3(2.657000,0.997000,0.564000); -positions[40] = Vec3(1.465000,1.580000,0.648000); -positions[41] = Vec3(0.154000,2.538000,1.331000); -positions[42] = Vec3(0.849000,1.476000,1.365000); -positions[43] = Vec3(0.898000,0.987000,1.178000); -positions[44] = Vec3(0.958000,0.656000,1.358000); -positions[45] = Vec3(1.067000,0.934000,0.211000); -positions[46] = Vec3(1.030000,0.319000,1.281000); -positions[47] = Vec3(2.709000,0.807000,0.240000); -positions[48] = Vec3(0.837000,1.362000,0.588000); -positions[49] = Vec3(2.080000,0.791000,2.947000); -positions[50] = Vec3(0.200000,0.266000,1.474000); -positions[51] = Vec3(0.848000,0.379000,1.625000); -positions[52] = Vec3(0.637000,1.071000,0.821000); -positions[53] = Vec3(1.324000,0.757000,2.951000); -positions[54] = Vec3(2.666000,0.935000,1.373000); -positions[55] = Vec3(1.584000,1.025000,1.703000); -positions[56] = Vec3(1.699000,0.636000,0.038000); -positions[57] = Vec3(1.099000,1.644000,1.879000); -positions[58] = Vec3(2.897000,1.302000,1.522000); -positions[59] = Vec3(1.753000,0.949000,2.885000); -positions[60] = Vec3(2.502000,1.321000,0.752000); -positions[61] = Vec3(0.545000,0.193000,1.959000); -positions[62] = Vec3(1.098000,2.646000,1.706000); -positions[63] = Vec3(0.001000,1.205000,0.670000); -positions[64] = Vec3(2.997000,0.061000,1.040000); -positions[65] = Vec3(0.662000,0.828000,1.535000); -positions[66] = Vec3(1.252000,1.246000,0.780000); -positions[67] = Vec3(1.173000,0.472000,0.810000); -positions[68] = Vec3(0.124000,0.622000,2.992000); -positions[69] = Vec3(1.036000,0.883000,0.848000); -positions[70] = Vec3(1.423000,2.146000,1.340000); -positions[71] = Vec3(2.391000,1.136000,1.165000); -positions[72] = Vec3(1.189000,2.961000,0.425000); -positions[73] = Vec3(1.584000,2.500000,0.782000); -positions[74] = Vec3(0.565000,1.122000,1.240000); -positions[75] = Vec3(1.733000,1.716000,1.763000); -positions[76] = Vec3(1.548000,1.522000,0.041000); -positions[77] = Vec3(1.485000,0.561000,0.369000); -positions[78] = Vec3(0.350000,1.661000,0.928000); -positions[79] = Vec3(1.653000,1.223000,0.578000); -positions[80] = Vec3(0.648000,1.349000,0.253000); -positions[81] = Vec3(0.340000,1.820000,0.483000); -positions[82] = Vec3(2.926000,0.119000,1.421000); -positions[83] = Vec3(1.512000,1.084000,0.156000); -positions[84] = Vec3(1.600000,2.115000,1.792000); -positions[85] = Vec3(1.089000,0.934000,1.584000); -positions[86] = Vec3(1.276000,1.104000,1.230000); -positions[87] = Vec3(0.485000,0.305000,0.428000); -positions[88] = Vec3(1.317000,1.261000,1.795000); -positions[89] = Vec3(0.039000,1.413000,1.085000); -positions[90] = Vec3(0.453000,0.701000,0.605000); -positions[91] = Vec3(1.283000,1.937000,0.752000); -positions[92] = Vec3(0.212000,1.416000,1.447000); -positions[93] = Vec3(0.203000,0.358000,0.723000); -positions[94] = Vec3(0.556000,0.445000,1.364000); -positions[95] = Vec3(1.436000,0.861000,0.911000); -positions[96] = Vec3(0.358000,0.966000,0.176000); -positions[97] = Vec3(1.478000,2.715000,0.427000); -positions[98] = Vec3(1.581000,0.575000,0.809000); -positions[99] = Vec3(1.007000,2.153000,2.887000); -positions[100] = Vec3(2.343000,0.663000,2.513000); -positions[101] = Vec3(2.105000,0.649000,1.635000); -positions[102] = Vec3(0.875000,0.743000,2.459000); -positions[103] = Vec3(0.229000,1.315000,1.879000); -positions[104] = Vec3(0.285000,0.935000,1.700000); -positions[105] = Vec3(2.269000,1.284000,2.234000); -positions[106] = Vec3(1.406000,1.149000,2.767000); -positions[107] = Vec3(1.076000,0.220000,1.849000); -positions[108] = Vec3(2.001000,1.532000,2.881000); -positions[109] = Vec3(2.893000,0.485000,1.860000); -positions[110] = Vec3(1.621000,1.786000,2.624000); -positions[111] = Vec3(0.500000,0.616000,1.818000); -positions[112] = Vec3(0.938000,2.978000,2.104000); -positions[113] = Vec3(0.550000,2.081000,0.454000); -positions[114] = Vec3(1.121000,0.685000,2.196000); -positions[115] = Vec3(1.088000,1.385000,2.184000); -positions[116] = Vec3(1.122000,2.705000,2.080000); -positions[117] = Vec3(0.918000,1.767000,2.861000); -positions[118] = Vec3(2.748000,0.232000,2.126000); -positions[119] = Vec3(1.238000,2.766000,0.109000); -positions[120] = Vec3(1.380000,0.785000,1.961000); -positions[121] = Vec3(1.236000,1.757000,0.150000); -positions[122] = Vec3(1.339000,2.187000,2.592000); -positions[123] = Vec3(1.414000,0.342000,2.714000); -positions[124] = Vec3(1.310000,0.770000,2.589000); -positions[125] = Vec3(1.686000,0.765000,2.321000); -positions[126] = Vec3(1.659000,1.367000,2.780000); -positions[127] = Vec3(0.141000,0.095000,1.903000); -positions[128] = Vec3(2.084000,1.002000,2.520000); -positions[129] = Vec3(2.819000,1.286000,2.626000); -positions[130] = Vec3(1.257000,1.044000,2.401000); -positions[131] = Vec3(1.064000,0.546000,2.839000); -positions[132] = Vec3(0.078000,1.246000,0.010000); -positions[133] = Vec3(1.506000,0.420000,2.223000); -positions[134] = Vec3(1.778000,0.699000,1.920000); -positions[135] = Vec3(1.315000,1.721000,2.733000); -positions[136] = Vec3(0.114000,0.281000,0.279000); -positions[137] = Vec3(1.082000,1.421000,2.596000); -positions[138] = Vec3(3.001000,0.592000,2.276000); -positions[139] = Vec3(1.384000,2.227000,2.992000); -positions[140] = Vec3(1.353000,0.044000,1.985000); -positions[141] = Vec3(1.367000,1.832000,2.383000); -positions[142] = Vec3(0.853000,1.119000,2.230000); -positions[143] = Vec3(1.675000,1.482000,2.295000); -positions[144] = Vec3(1.334000,1.890000,1.904000); -positions[145] = Vec3(1.630000,0.140000,2.939000); -positions[146] = Vec3(0.195000,1.290000,2.300000); -positions[147] = Vec3(2.178000,1.173000,3.001000); -positions[148] = Vec3(0.637000,0.655000,2.126000); -positions[149] = Vec3(0.993000,1.796000,2.529000); -positions[150] = Vec3(0.910000,0.701000,1.845000); -positions[151] = Vec3(0.191000,2.128000,0.355000); -positions[152] = Vec3(0.692000,1.163000,2.578000); -positions[153] = Vec3(1.154000,1.052000,1.974000); -positions[154] = Vec3(1.682000,0.335000,2.509000); -positions[155] = Vec3(0.569000,1.032000,1.895000); -positions[156] = Vec3(1.800000,2.796000,1.295000); -positions[157] = Vec3(2.517000,2.347000,2.878000); -positions[158] = Vec3(0.639000,2.470000,1.678000); -positions[159] = Vec3(0.634000,2.006000,1.829000); -positions[160] = Vec3(0.892000,0.215000,0.566000); -positions[161] = Vec3(1.800000,2.143000,1.491000); -positions[162] = Vec3(1.898000,0.226000,2.765000); -positions[163] = Vec3(0.791000,1.738000,0.260000); -positions[164] = Vec3(0.437000,1.740000,2.048000); -positions[165] = Vec3(1.687000,2.438000,1.166000); -positions[166] = Vec3(1.337000,2.304000,1.643000); -positions[167] = Vec3(1.270000,2.397000,1.033000); -positions[168] = Vec3(0.702000,2.429000,0.591000); -positions[169] = Vec3(0.842000,1.976000,0.724000); -positions[170] = Vec3(1.965000,0.095000,1.206000); -positions[171] = Vec3(0.355000,2.710000,0.618000); -positions[172] = Vec3(0.745000,1.434000,2.781000); -positions[173] = Vec3(0.707000,2.171000,1.502000); -positions[174] = Vec3(1.294000,2.696000,0.847000); -positions[175] = Vec3(1.143000,2.075000,0.276000); -positions[176] = Vec3(1.111000,2.474000,0.312000); -positions[177] = Vec3(1.144000,2.316000,0.633000); -positions[178] = Vec3(1.335000,0.292000,0.515000); -positions[179] = Vec3(1.926000,2.813000,2.703000); -positions[180] = Vec3(0.559000,2.314000,2.904000); -positions[181] = Vec3(1.308000,1.605000,1.534000); -positions[182] = Vec3(0.773000,2.913000,1.217000); -positions[183] = Vec3(1.612000,0.082000,1.027000); -positions[184] = Vec3(1.510000,0.287000,1.787000); -positions[185] = Vec3(0.716000,1.424000,1.843000); -positions[186] = Vec3(1.267000,0.685000,1.160000); -positions[187] = Vec3(0.306000,1.653000,1.717000); -positions[188] = Vec3(0.349000,0.020000,1.275000); -positions[189] = Vec3(0.166000,1.979000,0.804000); -positions[190] = Vec3(1.523000,2.992000,0.711000); -positions[191] = Vec3(1.998000,2.146000,0.088000); -positions[192] = Vec3(0.047000,2.513000,0.642000); -positions[193] = Vec3(0.501000,1.793000,1.438000); -positions[194] = Vec3(1.099000,2.010000,1.626000); -positions[195] = Vec3(2.580000,2.854000,1.328000); -positions[196] = Vec3(1.080000,2.779000,1.190000); -positions[197] = Vec3(0.901000,2.561000,0.948000); -positions[198] = Vec3(0.920000,2.990000,0.844000); -positions[199] = Vec3(0.819000,2.924000,1.711000); -positions[200] = Vec3(0.434000,1.516000,0.063000); -positions[201] = Vec3(1.470000,0.058000,0.231000); -positions[202] = Vec3(0.530000,3.005000,1.550000); -positions[203] = Vec3(0.447000,2.330000,1.277000); -positions[204] = Vec3(1.632000,2.683000,1.593000); -positions[205] = Vec3(0.885000,1.835000,2.072000); -positions[206] = Vec3(0.868000,2.601000,1.425000); -positions[207] = Vec3(0.720000,2.242000,0.907000); -positions[208] = Vec3(1.194000,0.144000,1.065000); -positions[209] = Vec3(0.448000,2.485000,0.959000); -positions[210] = Vec3(1.377000,2.694000,1.352000); -positions[211] = Vec3(1.305000,2.928000,2.713000); -positions[212] = Vec3(1.784000,2.456000,1.981000); -positions[213] = Vec3(0.354000,2.136000,1.563000); -positions[214] = Vec3(0.489000,2.000000,1.108000); -positions[215] = Vec3(1.884000,2.221000,0.461000); -positions[216] = Vec3(1.860000,2.540000,0.306000); -positions[217] = Vec3(1.753000,2.335000,2.768000); -positions[218] = Vec3(1.536000,2.441000,2.344000); -positions[219] = Vec3(0.531000,0.025000,2.235000); -positions[220] = Vec3(0.809000,0.011000,2.834000); -positions[221] = Vec3(0.289000,2.614000,2.879000); -positions[222] = Vec3(0.613000,1.891000,2.337000); -positions[223] = Vec3(0.507000,0.037000,2.694000); -positions[224] = Vec3(0.882000,2.185000,2.583000); -positions[225] = Vec3(0.503000,2.051000,2.615000); -positions[226] = Vec3(1.907000,1.956000,2.831000); -positions[227] = Vec3(2.833000,2.769000,1.644000); -positions[228] = Vec3(1.141000,0.113000,2.945000); -positions[229] = Vec3(0.600000,1.338000,2.200000); -positions[230] = Vec3(0.904000,2.360000,1.952000); -positions[231] = Vec3(0.738000,1.568000,2.437000); -positions[232] = Vec3(1.136000,2.535000,2.805000); -positions[233] = Vec3(1.430000,2.767000,2.321000); -positions[234] = Vec3(1.078000,2.470000,2.385000); -positions[235] = Vec3(0.296000,2.376000,2.560000); -positions[236] = Vec3(0.719000,0.300000,0.075000); -positions[237] = Vec3(0.518000,1.911000,0.080000); -positions[238] = Vec3(0.381000,1.570000,2.450000); -positions[239] = Vec3(0.716000,2.581000,2.697000); -positions[240] = Vec3(1.473000,2.617000,1.936000); -positions[241] = Vec3(0.421000,2.449000,0.229000); -positions[242] = Vec3(0.425000,2.817000,1.910000); -positions[243] = Vec3(1.312000,2.294000,2.057000); -positions[244] = Vec3(1.239000,0.007000,1.539000); -positions[245] = Vec3(0.822000,0.379000,2.086000); -positions[246] = Vec3(0.560000,2.562000,2.227000); -positions[247] = Vec3(0.863000,2.417000,0.050000); -positions[248] = Vec3(1.263000,0.151000,2.332000); -positions[249] = Vec3(0.237000,0.208000,2.336000); -positions[250] = Vec3(0.437000,2.370000,1.910000); -positions[251] = Vec3(1.119000,2.058000,2.207000); -positions[252] = Vec3(1.960000,1.749000,0.118000); -positions[253] = Vec3(2.415000,0.870000,2.757000); -positions[254] = Vec3(1.781000,0.342000,0.366000); -positions[255] = Vec3(2.172000,1.279000,1.421000); -positions[256] = Vec3(1.986000,0.715000,1.301000); -positions[257] = Vec3(1.657000,1.804000,0.810000); -positions[258] = Vec3(2.405000,1.202000,0.416000); -positions[259] = Vec3(1.932000,1.457000,0.786000); -positions[260] = Vec3(1.901000,1.271000,1.207000); -positions[261] = Vec3(1.864000,0.301000,0.810000); -positions[262] = Vec3(1.658000,0.673000,1.558000); -positions[263] = Vec3(2.637000,2.247000,0.396000); -positions[264] = Vec3(1.353000,0.369000,1.438000); -positions[265] = Vec3(0.530000,2.688000,1.346000); -positions[266] = Vec3(0.237000,0.485000,1.047000); -positions[267] = Vec3(2.806000,0.601000,0.822000); -positions[268] = Vec3(1.617000,2.018000,2.136000); -positions[269] = Vec3(2.000000,2.898000,0.022000); -positions[270] = Vec3(2.049000,1.883000,1.001000); -positions[271] = Vec3(2.477000,0.355000,1.786000); -positions[272] = Vec3(1.646000,0.983000,1.266000); -positions[273] = Vec3(1.683000,2.097000,1.114000); -positions[274] = Vec3(2.161000,0.921000,1.065000); -positions[275] = Vec3(2.099000,0.463000,1.942000); -positions[276] = Vec3(2.561000,1.638000,0.572000); -positions[277] = Vec3(2.205000,0.395000,1.005000); -positions[278] = Vec3(2.836000,0.203000,0.698000); -positions[279] = Vec3(2.662000,0.909000,0.966000); -positions[280] = Vec3(0.334000,0.350000,2.767000); -positions[281] = Vec3(2.241000,2.934000,1.248000); -positions[282] = Vec3(2.599000,2.953000,0.921000); -positions[283] = Vec3(2.219000,0.262000,0.058000); -positions[284] = Vec3(0.274000,0.656000,1.456000); -positions[285] = Vec3(1.814000,1.008000,0.882000); -positions[286] = Vec3(2.793000,1.395000,0.316000); -positions[287] = Vec3(0.773000,1.753000,1.639000); -positions[288] = Vec3(2.321000,0.994000,1.591000); -positions[289] = Vec3(2.243000,2.255000,1.690000); -positions[290] = Vec3(0.178000,1.342000,0.327000); -positions[291] = Vec3(1.623000,1.756000,1.426000); -positions[292] = Vec3(2.252000,0.109000,0.375000); -positions[293] = Vec3(3.003000,1.895000,1.895000); -positions[294] = Vec3(0.407000,0.831000,2.756000); -positions[295] = Vec3(2.193000,0.956000,0.632000); -positions[296] = Vec3(2.405000,0.641000,1.107000); -positions[297] = Vec3(2.361000,0.958000,0.162000); -positions[298] = Vec3(2.173000,1.544000,0.528000); -positions[299] = Vec3(1.565000,1.380000,1.428000); -positions[300] = Vec3(2.342000,0.538000,0.253000); -positions[301] = Vec3(1.910000,0.701000,0.954000); -positions[302] = Vec3(2.910000,0.288000,2.938000); -positions[303] = Vec3(0.257000,1.189000,0.958000); -positions[304] = Vec3(0.134000,1.775000,1.243000); -positions[305] = Vec3(2.476000,1.583000,1.956000); -positions[306] = Vec3(1.838000,1.791000,2.354000); -positions[307] = Vec3(1.906000,1.338000,1.696000); -positions[308] = Vec3(2.413000,2.869000,0.166000); -positions[309] = Vec3(3.006000,1.038000,1.322000); -positions[310] = Vec3(1.961000,0.962000,1.605000); -positions[311] = Vec3(0.082000,2.857000,0.020000); -positions[312] = Vec3(2.408000,1.499000,0.062000); -positions[313] = Vec3(2.349000,0.267000,1.415000); -positions[314] = Vec3(2.327000,1.717000,2.350000); -positions[315] = Vec3(2.928000,0.810000,1.582000); -positions[316] = Vec3(2.150000,0.336000,0.576000); -positions[317] = Vec3(2.664000,1.085000,2.962000); -positions[318] = Vec3(2.851000,0.670000,1.174000); -positions[319] = Vec3(1.954000,1.013000,1.975000); -positions[320] = Vec3(2.474000,1.542000,1.545000); -positions[321] = Vec3(2.826000,0.455000,1.490000); -positions[322] = Vec3(2.140000,2.826000,0.558000); -positions[323] = Vec3(2.151000,1.684000,1.780000); -positions[324] = Vec3(0.174000,0.673000,0.397000); -positions[325] = Vec3(0.066000,1.708000,0.160000); -positions[326] = Vec3(2.158000,0.303000,2.582000); -positions[327] = Vec3(2.602000,1.611000,2.632000); -positions[328] = Vec3(2.566000,1.138000,2.465000); -positions[329] = Vec3(2.026000,1.443000,2.477000); -positions[330] = Vec3(2.365000,0.309000,2.255000); -positions[331] = Vec3(1.636000,1.107000,2.058000); -positions[332] = Vec3(2.522000,2.584000,2.399000); -positions[333] = Vec3(2.537000,2.900000,2.158000); -positions[334] = Vec3(2.660000,0.537000,2.577000); -positions[335] = Vec3(2.679000,1.158000,1.724000); -positions[336] = Vec3(0.220000,1.894000,2.498000); -positions[337] = Vec3(2.266000,1.248000,1.837000); -positions[338] = Vec3(0.055000,1.656000,2.128000); -positions[339] = Vec3(2.899000,1.902000,2.823000); -positions[340] = Vec3(0.085000,2.994000,2.720000); -positions[341] = Vec3(0.013000,0.889000,2.468000); -positions[342] = Vec3(1.804000,0.372000,1.636000); -positions[343] = Vec3(0.201000,1.616000,2.824000); -positions[344] = Vec3(0.369000,1.273000,2.699000); -positions[345] = Vec3(2.996000,0.355000,2.596000); -positions[346] = Vec3(2.867000,1.314000,2.107000); -positions[347] = Vec3(2.611000,0.563000,2.140000); -positions[348] = Vec3(2.676000,2.954000,2.955000); -positions[349] = Vec3(0.256000,0.848000,2.062000); -positions[350] = Vec3(2.530000,0.028000,2.528000); -positions[351] = Vec3(0.537000,1.273000,1.596000); -positions[352] = Vec3(0.004000,1.004000,0.401000); -positions[353] = Vec3(1.676000,1.060000,2.463000); -positions[354] = Vec3(2.622000,1.473000,2.257000); -positions[355] = Vec3(2.917000,2.991000,2.316000); -positions[356] = Vec3(0.672000,1.123000,2.984000); -positions[357] = Vec3(2.229000,1.806000,2.673000); -positions[358] = Vec3(0.463000,0.951000,2.383000); -positions[359] = Vec3(2.126000,0.049000,2.037000); -positions[360] = Vec3(2.868000,0.876000,2.015000); -positions[361] = Vec3(2.720000,2.582000,0.079000); -positions[362] = Vec3(1.966000,0.693000,2.624000); -positions[363] = Vec3(1.971000,0.398000,2.318000); -positions[364] = Vec3(0.337000,0.630000,2.458000); -positions[365] = Vec3(2.562000,1.044000,2.040000); -positions[366] = Vec3(2.817000,1.485000,2.963000); -positions[367] = Vec3(2.514000,0.621000,2.992000); -positions[368] = Vec3(3.000000,1.551000,2.496000); -positions[369] = Vec3(0.698000,2.167000,2.180000); -positions[370] = Vec3(2.693000,0.849000,2.389000); -positions[371] = Vec3(2.092000,2.565000,2.986000); -positions[372] = Vec3(2.010000,3.001000,0.819000); -positions[373] = Vec3(2.392000,2.622000,1.636000); -positions[374] = Vec3(2.086000,2.325000,1.340000); -positions[375] = Vec3(2.578000,2.971000,0.502000); -positions[376] = Vec3(1.871000,2.789000,2.225000); -positions[377] = Vec3(2.230000,2.985000,1.594000); -positions[378] = Vec3(2.860000,2.788000,0.729000); -positions[379] = Vec3(2.051000,1.928000,1.472000); -positions[380] = Vec3(2.307000,2.219000,1.067000); -positions[381] = Vec3(2.369000,2.572000,1.289000); -positions[382] = Vec3(2.206000,1.924000,0.693000); -positions[383] = Vec3(1.984000,2.058000,2.005000); -positions[384] = Vec3(2.287000,1.854000,0.317000); -positions[385] = Vec3(2.525000,0.345000,0.686000); -positions[386] = Vec3(2.933000,1.920000,1.053000); -positions[387] = Vec3(0.324000,2.324000,0.601000); -positions[388] = Vec3(2.042000,1.576000,1.277000); -positions[389] = Vec3(0.031000,2.376000,0.949000); -positions[390] = Vec3(2.519000,2.250000,1.465000); -positions[391] = Vec3(0.221000,2.722000,1.652000); -positions[392] = Vec3(2.409000,2.361000,2.051000); -positions[393] = Vec3(2.472000,1.917000,1.673000); -positions[394] = Vec3(0.999000,2.715000,0.562000); -positions[395] = Vec3(1.669000,0.017000,1.508000); -positions[396] = Vec3(1.924000,1.777000,0.542000); -positions[397] = Vec3(2.635000,2.634000,1.905000); -positions[398] = Vec3(2.042000,2.628000,1.025000); -positions[399] = Vec3(2.694000,1.974000,2.009000); -positions[400] = Vec3(2.988000,2.221000,1.333000); -positions[401] = Vec3(1.772000,0.196000,1.978000); -positions[402] = Vec3(2.893000,2.961000,0.283000); -positions[403] = Vec3(2.615000,0.261000,0.245000); -positions[404] = Vec3(2.797000,2.521000,1.412000); -positions[405] = Vec3(0.013000,2.497000,0.246000); -positions[406] = Vec3(1.875000,2.861000,1.801000); -positions[407] = Vec3(2.800000,2.617000,1.049000); -positions[408] = Vec3(2.824000,1.858000,1.487000); -positions[409] = Vec3(2.434000,1.868000,1.275000); -positions[410] = Vec3(2.814000,0.526000,0.384000); -positions[411] = Vec3(2.844000,2.545000,2.246000); -positions[412] = Vec3(1.896000,2.587000,0.719000); -positions[413] = Vec3(0.350000,0.055000,0.076000); -positions[414] = Vec3(2.686000,1.784000,0.222000); -positions[415] = Vec3(2.724000,1.604000,0.989000); -positions[416] = Vec3(0.807000,1.761000,1.122000); -positions[417] = Vec3(2.120000,2.382000,2.226000); -positions[418] = Vec3(2.058000,1.587000,2.067000); -positions[419] = Vec3(2.904000,2.571000,2.686000); -positions[420] = Vec3(2.228000,2.910000,2.410000); -positions[421] = Vec3(2.797000,2.142000,0.114000); -positions[422] = Vec3(2.905000,1.875000,0.480000); -positions[423] = Vec3(1.881000,2.565000,2.469000); -positions[424] = Vec3(2.404000,1.929000,2.999000); -positions[425] = Vec3(2.389000,2.814000,2.782000); -positions[426] = Vec3(2.520000,0.301000,2.815000); -positions[427] = Vec3(2.726000,1.907000,2.339000); -positions[428] = Vec3(2.880000,2.273000,2.500000); -positions[429] = Vec3(2.574000,2.045000,2.716000); -positions[430] = Vec3(2.988000,2.288000,2.001000); -positions[431] = Vec3(0.011000,2.341000,2.904000); -positions[432] = Vec3(0.215000,2.265000,2.257000); -positions[433] = Vec3(2.268000,2.311000,0.234000); -positions[434] = Vec3(2.462000,2.621000,0.550000); -positions[435] = Vec3(1.530000,2.540000,2.728000); -positions[436] = Vec3(2.162000,2.306000,2.687000); -positions[437] = Vec3(2.748000,2.301000,1.734000); -positions[438] = Vec3(2.334000,1.976000,2.041000); -positions[439] = Vec3(1.981000,2.076000,2.443000); -positions[440] = Vec3(2.301000,1.367000,2.665000); -positions[441] = Vec3(2.399000,2.164000,2.403000); -positions[442] = Vec3(0.244000,2.713000,2.257000); -positions[443] = Vec3(0.683000,0.488000,2.781000); -positions[444] = Vec3(2.194000,2.711000,1.993000); -positions[445] = Vec3(2.947000,2.848000,2.001000); -positions[446] = Vec3(0.223000,1.981000,2.913000); -positions[447] = Vec3(0.010000,1.226000,0.917000); -positions[448] = Vec3(1.911000,0.426000,0.582000); -positions[449] = Vec3(2.204000,0.015000,0.136000); -positions[450] = Vec3(0.927000,0.138000,1.645000); -positions[451] = Vec3(0.155000,0.885000,1.479000); -positions[452] = Vec3(1.550000,1.933000,1.261000); -positions[453] = Vec3(1.304000,0.407000,0.287000); -positions[454] = Vec3(0.270000,1.384000,2.910000); -positions[455] = Vec3(0.516000,1.817000,1.695000); -positions[456] = Vec3(1.458000,2.879000,1.523000); -positions[457] = Vec3(1.702000,1.670000,0.593000); -positions[458] = Vec3(1.974000,1.380000,0.534000); -positions[459] = Vec3(2.835000,1.185000,0.479000); -positions[460] = Vec3(0.548000,2.979000,1.126000); -positions[461] = Vec3(1.202000,2.174000,1.466000); -positions[462] = Vec3(1.237000,1.701000,0.653000); -positions[463] = Vec3(2.939000,0.761000,0.349000); -positions[464] = Vec3(1.667000,2.119000,0.377000); -positions[465] = Vec3(1.196000,0.552000,1.372000); -positions[466] = Vec3(1.416000,0.901000,1.178000); -positions[467] = Vec3(0.519000,1.577000,2.227000); -positions[468] = Vec3(1.214000,1.281000,1.063000); -positions[469] = Vec3(0.822000,0.433000,1.375000); -positions[470] = Vec3(0.095000,2.760000,0.604000); -positions[471] = Vec3(1.325000,2.144000,1.848000); -positions[472] = Vec3(0.681000,0.896000,1.285000); -positions[473] = Vec3(0.406000,2.936000,0.717000); -positions[474] = Vec3(0.565000,1.852000,0.349000); -positions[475] = Vec3(0.597000,1.651000,1.020000); -positions[476] = Vec3(1.236000,0.170000,1.335000); -positions[477] = Vec3(0.586000,0.441000,1.980000); -positions[478] = Vec3(1.443000,1.208000,1.575000); -positions[479] = Vec3(0.247000,0.243000,0.502000); -positions[480] = Vec3(1.386000,1.564000,0.236000); -positions[481] = Vec3(0.871000,1.063000,0.930000); -positions[482] = Vec3(0.136000,0.992000,0.621000); -positions[483] = Vec3(0.889000,0.986000,0.010000); -positions[484] = Vec3(1.107000,2.731000,1.452000); -positions[485] = Vec3(0.942000,2.471000,0.517000); -positions[486] = Vec3(0.989000,0.652000,0.747000); -positions[487] = Vec3(0.899000,1.235000,2.707000); -positions[488] = Vec3(1.105000,0.684000,0.068000); -positions[489] = Vec3(1.660000,1.235000,2.276000); -positions[490] = Vec3(1.593000,1.883000,1.915000); -positions[491] = Vec3(1.528000,1.613000,0.920000); -positions[492] = Vec3(0.459000,1.046000,1.011000); -positions[493] = Vec3(0.213000,0.612000,0.644000); -positions[494] = Vec3(0.078000,1.392000,1.676000); -positions[495] = Vec3(0.605000,0.491000,0.574000); -positions[496] = Vec3(0.990000,1.586000,1.076000); -positions[497] = Vec3(0.297000,1.434000,1.028000); -positions[498] = Vec3(1.101000,1.471000,1.443000); -positions[499] = Vec3(0.072000,0.139000,1.653000); -positions[500] = Vec3(0.633000,0.884000,0.645000); -positions[501] = Vec3(0.352000,2.841000,1.463000); -positions[502] = Vec3(0.418000,0.774000,0.350000); -positions[503] = Vec3(2.641000,0.198000,0.869000); -positions[504] = Vec3(0.608000,1.341000,0.695000); -positions[505] = Vec3(1.778000,1.151000,1.830000); -positions[506] = Vec3(1.669000,0.342000,2.768000); -positions[507] = Vec3(1.256000,0.994000,0.798000); -positions[508] = Vec3(1.068000,0.375000,1.036000); -positions[509] = Vec3(0.910000,0.758000,1.589000); -positions[510] = Vec3(0.243000,2.452000,0.805000); -positions[511] = Vec3(1.018000,0.764000,1.122000); -positions[512] = Vec3(2.464000,1.089000,1.404000); -positions[513] = Vec3(0.670000,0.564000,0.034000); -positions[514] = Vec3(0.030000,1.296000,1.310000); -positions[515] = Vec3(1.210000,1.785000,1.691000); -positions[516] = Vec3(0.022000,0.620000,0.974000); -positions[517] = Vec3(1.499000,1.277000,2.986000); -positions[518] = Vec3(1.227000,1.896000,1.006000); -positions[519] = Vec3(0.528000,1.022000,1.635000); -positions[520] = Vec3(1.887000,2.670000,0.089000); -positions[521] = Vec3(1.661000,0.825000,0.793000); -positions[522] = Vec3(0.831000,1.494000,0.374000); -positions[523] = Vec3(1.356000,0.613000,0.930000); -positions[524] = Vec3(0.667000,0.600000,0.968000); -positions[525] = Vec3(1.154000,1.702000,2.925000); -positions[526] = Vec3(1.420000,1.581000,1.289000); -positions[527] = Vec3(1.383000,0.041000,0.932000); -positions[528] = Vec3(1.727000,0.140000,1.725000); -positions[529] = Vec3(0.711000,1.215000,2.004000); -positions[530] = Vec3(1.061000,1.067000,1.366000); -positions[531] = Vec3(0.377000,0.597000,1.224000); -positions[532] = Vec3(0.274000,0.719000,1.842000); -positions[533] = Vec3(0.840000,1.658000,1.874000); -positions[534] = Vec3(0.877000,0.290000,0.311000); -positions[535] = Vec3(2.130000,1.153000,1.196000); -positions[536] = Vec3(1.028000,1.379000,0.747000); -positions[537] = Vec3(1.107000,2.450000,2.079000); -positions[538] = Vec3(1.419000,1.333000,0.585000); -positions[539] = Vec3(0.430000,1.305000,1.369000); -positions[540] = Vec3(0.775000,1.363000,1.596000); -positions[541] = Vec3(1.522000,2.009000,0.736000); -positions[542] = Vec3(0.857000,1.722000,0.696000); -positions[543] = Vec3(0.722000,2.831000,1.478000); -positions[544] = Vec3(0.411000,1.673000,0.681000); -positions[545] = Vec3(1.511000,0.456000,0.597000); -positions[546] = Vec3(2.684000,0.820000,2.996000); -positions[547] = Vec3(1.593000,1.713000,2.369000); -positions[548] = Vec3(1.113000,0.803000,1.958000); -positions[549] = Vec3(1.267000,1.095000,0.254000); -positions[550] = Vec3(2.120000,0.540000,2.477000); -positions[551] = Vec3(0.566000,1.409000,2.588000); -positions[552] = Vec3(0.261000,0.872000,2.546000); -positions[553] = Vec3(1.878000,1.446000,2.680000); -positions[554] = Vec3(0.878000,1.606000,2.658000); -positions[555] = Vec3(1.564000,0.749000,1.786000); -positions[556] = Vec3(1.412000,1.942000,2.625000); -positions[557] = Vec3(1.660000,1.114000,2.710000); -positions[558] = Vec3(1.118000,0.813000,2.424000); -positions[559] = Vec3(1.482000,0.893000,2.434000); -positions[560] = Vec3(1.093000,1.129000,1.740000); -positions[561] = Vec3(2.163000,0.849000,2.709000); -positions[562] = Vec3(1.201000,1.429000,1.957000); -positions[563] = Vec3(0.235000,2.258000,2.002000); -positions[564] = Vec3(0.413000,1.444000,0.314000); -positions[565] = Vec3(0.164000,0.450000,2.408000); -positions[566] = Vec3(1.551000,0.851000,0.033000); -positions[567] = Vec3(0.659000,0.228000,2.807000); -positions[568] = Vec3(0.741000,0.131000,2.124000); -positions[569] = Vec3(0.455000,0.567000,2.682000); -positions[570] = Vec3(0.729000,0.971000,2.408000); -positions[571] = Vec3(1.487000,2.820000,0.162000); -positions[572] = Vec3(1.855000,0.700000,2.858000); -positions[573] = Vec3(0.305000,1.074000,1.926000); -positions[574] = Vec3(1.300000,0.153000,1.747000); -positions[575] = Vec3(1.272000,1.249000,2.568000); -positions[576] = Vec3(0.431000,0.743000,2.238000); -positions[577] = Vec3(0.493000,0.240000,0.184000); -positions[578] = Vec3(1.734000,0.506000,2.317000); -positions[579] = Vec3(0.874000,0.631000,2.692000); -positions[580] = Vec3(0.473000,2.790000,2.161000); -positions[581] = Vec3(1.310000,0.571000,2.759000); -positions[582] = Vec3(0.677000,0.798000,1.916000); -positions[583] = Vec3(0.944000,0.442000,1.858000); -positions[584] = Vec3(3.006000,2.098000,2.976000); -positions[585] = Vec3(0.864000,0.592000,2.231000); -positions[586] = Vec3(1.366000,0.611000,2.147000); -positions[587] = Vec3(2.871000,1.217000,2.880000); -positions[588] = Vec3(1.674000,2.664000,2.336000); -positions[589] = Vec3(1.757000,0.879000,2.101000); -positions[590] = Vec3(1.293000,2.939000,2.457000); -positions[591] = Vec3(1.108000,1.131000,2.206000); -positions[592] = Vec3(1.207000,1.658000,2.498000); -positions[593] = Vec3(0.850000,1.373000,2.312000); -positions[594] = Vec3(1.413000,1.060000,1.939000); -positions[595] = Vec3(1.138000,0.140000,2.102000); -positions[596] = Vec3(0.752000,1.307000,1.190000); -positions[597] = Vec3(1.254000,0.942000,2.790000); -positions[598] = Vec3(1.544000,1.614000,2.800000); -positions[599] = Vec3(2.128000,0.302000,2.833000); -positions[600] = Vec3(0.300000,1.744000,0.027000); -positions[601] = Vec3(1.878000,2.986000,2.060000); -positions[602] = Vec3(1.528000,0.233000,2.045000); -positions[603] = Vec3(1.146000,1.817000,2.067000); -positions[604] = Vec3(1.037000,2.746000,0.813000); -positions[605] = Vec3(0.524000,0.610000,1.566000); -positions[606] = Vec3(0.945000,2.964000,0.503000); -positions[607] = Vec3(1.788000,2.565000,0.965000); -positions[608] = Vec3(0.471000,2.510000,0.491000); -positions[609] = Vec3(0.512000,2.043000,1.371000); -positions[610] = Vec3(2.316000,2.423000,1.494000); -positions[611] = Vec3(1.575000,2.394000,2.953000); -positions[612] = Vec3(2.845000,2.869000,0.985000); -positions[613] = Vec3(1.016000,2.335000,1.003000); -positions[614] = Vec3(0.998000,2.830000,1.879000); -positions[615] = Vec3(0.624000,2.508000,0.075000); -positions[616] = Vec3(1.362000,2.808000,2.069000); -positions[617] = Vec3(1.747000,0.068000,0.810000); -positions[618] = Vec3(1.768000,2.355000,0.661000); -positions[619] = Vec3(1.535000,2.410000,2.085000); -positions[620] = Vec3(0.844000,2.004000,1.646000); -positions[621] = Vec3(1.124000,0.280000,0.649000); -positions[622] = Vec3(0.689000,2.170000,0.648000); -positions[623] = Vec3(0.849000,2.666000,1.175000); -positions[624] = Vec3(2.975000,1.963000,1.308000); -positions[625] = Vec3(1.074000,2.082000,0.714000); -positions[626] = Vec3(1.284000,2.651000,1.110000); -positions[627] = Vec3(1.669000,0.205000,0.180000); -positions[628] = Vec3(1.716000,0.047000,1.253000); -positions[629] = Vec3(0.501000,2.241000,1.043000); -positions[630] = Vec3(1.038000,1.833000,0.305000); -positions[631] = Vec3(0.646000,2.431000,1.424000); -positions[632] = Vec3(1.383000,2.059000,2.230000); -positions[633] = Vec3(0.370000,2.566000,1.192000); -positions[634] = Vec3(1.355000,2.006000,0.120000); -positions[635] = Vec3(2.113000,0.075000,0.589000); -positions[636] = Vec3(1.850000,0.448000,1.890000); -positions[637] = Vec3(1.215000,2.704000,0.405000); -positions[638] = Vec3(0.575000,2.997000,1.798000); -positions[639] = Vec3(0.967000,2.586000,2.603000); -positions[640] = Vec3(0.276000,1.669000,1.430000); -positions[641] = Vec3(1.483000,2.284000,1.128000); -positions[642] = Vec3(0.983000,3.003000,1.099000); -positions[643] = Vec3(0.539000,2.222000,1.720000); -positions[644] = Vec3(0.648000,2.826000,2.751000); -positions[645] = Vec3(0.803000,1.994000,0.993000); -positions[646] = Vec3(0.451000,0.216000,1.438000); -positions[647] = Vec3(1.604000,2.512000,0.334000); -positions[648] = Vec3(1.980000,2.022000,0.588000); -positions[649] = Vec3(1.843000,2.834000,1.544000); -positions[650] = Vec3(1.835000,3.005000,2.858000); -positions[651] = Vec3(0.679000,2.499000,0.838000); -positions[652] = Vec3(0.012000,2.637000,1.524000); -positions[653] = Vec3(0.314000,2.065000,0.602000); -positions[654] = Vec3(1.157000,0.004000,0.173000); -positions[655] = Vec3(0.736000,1.705000,1.382000); -positions[656] = Vec3(1.511000,2.736000,0.690000); -positions[657] = Vec3(1.330000,2.541000,1.735000); -positions[658] = Vec3(0.744000,0.170000,0.785000); -positions[659] = Vec3(2.593000,2.794000,0.703000); -positions[660] = Vec3(0.275000,1.872000,1.043000); -positions[661] = Vec3(1.624000,2.608000,1.341000); -positions[662] = Vec3(1.382000,0.122000,2.855000); -positions[663] = Vec3(1.326000,2.434000,0.783000); -positions[664] = Vec3(0.117000,0.116000,1.254000); -positions[665] = Vec3(1.045000,2.970000,2.748000); -positions[666] = Vec3(1.341000,2.692000,2.799000); -positions[667] = Vec3(1.797000,2.586000,2.709000); -positions[668] = Vec3(0.890000,2.484000,1.716000); -positions[669] = Vec3(2.373000,2.558000,1.889000); -positions[670] = Vec3(1.566000,2.323000,2.574000); -positions[671] = Vec3(1.257000,2.280000,0.399000); -positions[672] = Vec3(0.679000,2.130000,2.434000); -positions[673] = Vec3(2.016000,2.334000,2.462000); -positions[674] = Vec3(1.077000,2.213000,2.416000); -positions[675] = Vec3(0.581000,1.950000,2.081000); -positions[676] = Vec3(0.805000,2.315000,2.810000); -positions[677] = Vec3(0.844000,1.787000,2.322000); -positions[678] = Vec3(0.980000,2.205000,0.129000); -positions[679] = Vec3(2.468000,0.603000,2.740000); -positions[680] = Vec3(2.366000,2.403000,2.299000); -positions[681] = Vec3(0.337000,2.487000,2.329000); -positions[682] = Vec3(2.007000,2.793000,2.452000); -positions[683] = Vec3(1.072000,2.571000,0.063000); -positions[684] = Vec3(1.217000,2.283000,2.806000); -positions[685] = Vec3(0.459000,2.477000,2.728000); -positions[686] = Vec3(0.958000,1.975000,2.710000); -positions[687] = Vec3(0.914000,2.111000,2.052000); -positions[688] = Vec3(0.768000,2.958000,0.075000); -positions[689] = Vec3(0.474000,1.805000,2.533000); -positions[690] = Vec3(1.313000,2.552000,2.395000); -positions[691] = Vec3(1.853000,2.014000,2.229000); -positions[692] = Vec3(2.405000,2.230000,2.658000); -positions[693] = Vec3(0.727000,1.781000,0.016000); -positions[694] = Vec3(0.974000,2.791000,2.271000); -positions[695] = Vec3(0.438000,0.096000,2.457000); -positions[696] = Vec3(0.652000,2.392000,2.064000); -positions[697] = Vec3(1.972000,2.209000,2.834000); -positions[698] = Vec3(0.333000,0.141000,2.088000); -positions[699] = Vec3(1.813000,1.952000,0.063000); -positions[700] = Vec3(0.166000,2.838000,1.877000); -positions[701] = Vec3(1.772000,0.487000,0.951000); -positions[702] = Vec3(1.924000,1.404000,1.434000); -positions[703] = Vec3(2.734000,0.348000,1.712000); -positions[704] = Vec3(2.874000,0.729000,1.811000); -positions[705] = Vec3(1.841000,0.877000,1.137000); -positions[706] = Vec3(2.327000,1.491000,1.768000); -positions[707] = Vec3(1.916000,1.483000,1.057000); -positions[708] = Vec3(2.783000,0.850000,0.745000); -positions[709] = Vec3(1.829000,1.526000,0.085000); -positions[710] = Vec3(2.426000,1.082000,0.652000); -positions[711] = Vec3(1.645000,1.241000,1.217000); -positions[712] = Vec3(2.286000,0.725000,0.084000); -positions[713] = Vec3(2.755000,0.691000,1.421000); -positions[714] = Vec3(2.651000,0.591000,1.023000); -positions[715] = Vec3(2.040000,0.863000,0.442000); -positions[716] = Vec3(0.035000,0.109000,2.497000); -positions[717] = Vec3(0.127000,1.410000,0.572000); -positions[718] = Vec3(2.174000,0.357000,0.307000); -positions[719] = Vec3(2.705000,1.508000,0.758000); -positions[720] = Vec3(2.223000,1.407000,2.913000); -positions[721] = Vec3(2.528000,1.722000,1.088000); -positions[722] = Vec3(2.860000,0.345000,0.198000); -positions[723] = Vec3(2.580000,1.789000,1.479000); -positions[724] = Vec3(2.779000,0.295000,1.295000); -positions[725] = Vec3(0.097000,0.434000,2.826000); -positions[726] = Vec3(2.952000,1.654000,1.091000); -positions[727] = Vec3(0.119000,1.878000,0.343000); -positions[728] = Vec3(1.718000,1.173000,0.327000); -positions[729] = Vec3(2.833000,0.016000,0.527000); -positions[730] = Vec3(2.085000,1.779000,2.888000); -positions[731] = Vec3(2.754000,2.952000,1.485000); -positions[732] = Vec3(2.826000,0.935000,1.162000); -positions[733] = Vec3(1.564000,1.585000,1.615000); -positions[734] = Vec3(2.132000,0.645000,1.093000); -positions[735] = Vec3(2.294000,1.490000,1.350000); -positions[736] = Vec3(0.081000,0.490000,1.479000); -positions[737] = Vec3(2.118000,1.165000,1.642000); -positions[738] = Vec3(2.141000,0.121000,1.390000); -positions[739] = Vec3(2.385000,0.389000,1.196000); -positions[740] = Vec3(0.049000,0.166000,0.817000); -positions[741] = Vec3(1.993000,0.806000,1.814000); -positions[742] = Vec3(0.006000,1.450000,0.171000); -positions[743] = Vec3(2.297000,0.428000,0.764000); -positions[744] = Vec3(2.851000,0.469000,2.114000); -positions[745] = Vec3(1.814000,1.957000,0.945000); -positions[746] = Vec3(0.386000,0.327000,0.902000); -positions[747] = Vec3(2.452000,1.070000,1.807000); -positions[748] = Vec3(2.309000,1.537000,2.159000); -positions[749] = Vec3(2.712000,1.497000,2.007000); -positions[750] = Vec3(1.727000,0.924000,1.503000); -positions[751] = Vec3(0.861000,0.801000,0.344000); -positions[752] = Vec3(1.740000,1.245000,0.819000); -positions[753] = Vec3(0.117000,0.042000,0.197000); -positions[754] = Vec3(2.557000,0.996000,0.317000); -positions[755] = Vec3(2.228000,1.588000,2.548000); -positions[756] = Vec3(2.849000,1.557000,2.708000); -positions[757] = Vec3(0.152000,1.107000,0.219000); -positions[758] = Vec3(2.460000,1.318000,1.002000); -positions[759] = Vec3(2.405000,1.436000,0.528000); -positions[760] = Vec3(2.135000,1.179000,2.046000); -positions[761] = Vec3(1.726000,0.588000,0.286000); -positions[762] = Vec3(2.831000,1.053000,1.538000); -positions[763] = Vec3(1.932000,1.556000,1.833000); -positions[764] = Vec3(2.423000,0.900000,1.064000); -positions[765] = Vec3(3.001000,1.807000,0.709000); -positions[766] = Vec3(0.578000,1.095000,0.223000); -positions[767] = Vec3(2.215000,1.160000,0.252000); -positions[768] = Vec3(2.050000,0.921000,0.835000); -positions[769] = Vec3(2.080000,1.682000,0.738000); -positions[770] = Vec3(2.851000,1.753000,0.027000); -positions[771] = Vec3(0.203000,0.509000,0.202000); -positions[772] = Vec3(1.967000,1.018000,0.018000); -positions[773] = Vec3(1.869000,0.878000,2.472000); -positions[774] = Vec3(1.917000,0.228000,2.507000); -positions[775] = Vec3(0.316000,0.795000,2.991000); -positions[776] = Vec3(2.175000,1.229000,2.472000); -positions[777] = Vec3(2.405000,1.062000,2.931000); -positions[778] = Vec3(2.501000,0.511000,2.369000); -positions[779] = Vec3(2.641000,0.819000,2.141000); -positions[780] = Vec3(0.649000,1.384000,3.006000); -positions[781] = Vec3(1.012000,0.329000,2.963000); -positions[782] = Vec3(2.755000,0.350000,2.718000); -positions[783] = Vec3(2.315000,0.153000,2.454000); -positions[784] = Vec3(2.583000,1.696000,2.389000); -positions[785] = Vec3(0.439000,2.593000,1.776000); -positions[786] = Vec3(2.630000,1.390000,0.116000); -positions[787] = Vec3(2.854000,0.669000,2.478000); -positions[788] = Vec3(2.551000,1.342000,2.621000); -positions[789] = Vec3(2.533000,2.734000,2.987000); -positions[790] = Vec3(2.772000,2.446000,2.875000); -positions[791] = Vec3(2.817000,1.051000,2.498000); -positions[792] = Vec3(2.688000,1.404000,1.621000); -positions[793] = Vec3(0.083000,2.737000,2.775000); -positions[794] = Vec3(2.514000,0.322000,2.041000); -positions[795] = Vec3(2.470000,0.900000,2.504000); -positions[796] = Vec3(2.790000,0.444000,0.624000); -positions[797] = Vec3(0.040000,0.840000,2.202000); -positions[798] = Vec3(0.530000,1.067000,2.764000); -positions[799] = Vec3(0.191000,1.385000,2.541000); -positions[800] = Vec3(2.465000,0.363000,0.051000); -positions[801] = Vec3(1.850000,1.902000,2.592000); -positions[802] = Vec3(1.432000,0.306000,2.449000); -positions[803] = Vec3(2.259000,0.489000,1.753000); -positions[804] = Vec3(2.803000,1.118000,1.956000); -positions[805] = Vec3(2.426000,0.147000,1.636000); -positions[806] = Vec3(2.880000,1.846000,2.133000); -positions[807] = Vec3(2.862000,2.110000,1.867000); -positions[808] = Vec3(0.424000,1.184000,2.299000); -positions[809] = Vec3(2.518000,1.218000,2.228000); -positions[810] = Vec3(2.153000,0.834000,1.468000); -positions[811] = Vec3(0.105000,1.397000,2.088000); -positions[812] = Vec3(2.579000,0.601000,0.316000); -positions[813] = Vec3(2.594000,2.106000,2.968000); -positions[814] = Vec3(0.448000,1.435000,1.783000); -positions[815] = Vec3(2.125000,0.299000,2.132000); -positions[816] = Vec3(2.849000,1.402000,2.356000); -positions[817] = Vec3(2.956000,0.091000,2.078000); -positions[818] = Vec3(0.156000,1.696000,2.357000); -positions[819] = Vec3(1.566000,2.211000,1.557000); -positions[820] = Vec3(2.047000,0.194000,0.985000); -positions[821] = Vec3(1.947000,2.680000,0.488000); -positions[822] = Vec3(2.343000,2.796000,1.447000); -positions[823] = Vec3(2.006000,2.332000,0.265000); -positions[824] = Vec3(2.396000,1.834000,0.546000); -positions[825] = Vec3(2.538000,2.059000,2.207000); -positions[826] = Vec3(0.110000,2.360000,0.447000); -positions[827] = Vec3(2.198000,2.448000,1.136000); -positions[828] = Vec3(2.420000,2.121000,1.271000); -positions[829] = Vec3(0.422000,2.192000,0.260000); -positions[830] = Vec3(2.145000,2.767000,2.839000); -positions[831] = Vec3(2.434000,2.398000,0.421000); -positions[832] = Vec3(2.489000,2.175000,1.718000); -positions[833] = Vec3(2.870000,2.527000,0.814000); -positions[834] = Vec3(2.741000,2.016000,0.337000); -positions[835] = Vec3(1.997000,2.574000,2.107000); -positions[836] = Vec3(0.002000,2.128000,0.932000); -positions[837] = Vec3(2.787000,2.375000,0.234000); -positions[838] = Vec3(2.235000,1.852000,1.620000); -positions[839] = Vec3(2.782000,1.642000,0.422000); -positions[840] = Vec3(2.915000,1.760000,1.699000); -positions[841] = Vec3(2.047000,2.178000,1.549000); -positions[842] = Vec3(1.808000,1.878000,1.556000); -positions[843] = Vec3(2.224000,2.043000,0.913000); -positions[844] = Vec3(2.619000,2.611000,1.237000); -positions[845] = Vec3(2.916000,2.726000,0.168000); -positions[846] = Vec3(2.021000,2.833000,1.176000); -positions[847] = Vec3(2.967000,2.308000,2.258000); -positions[848] = Vec3(2.778000,2.270000,1.477000); -positions[849] = Vec3(2.121000,1.834000,2.002000); -positions[850] = Vec3(2.097000,2.752000,0.808000); -positions[851] = Vec3(1.897000,0.566000,1.501000); -positions[852] = Vec3(0.359000,2.802000,0.036000); -positions[853] = Vec3(2.966000,2.454000,1.186000); -positions[854] = Vec3(2.461000,2.964000,1.132000); -positions[855] = Vec3(2.093000,1.821000,1.243000); -positions[856] = Vec3(1.706000,2.659000,1.841000); -positions[857] = Vec3(2.074000,1.709000,0.342000); -positions[858] = Vec3(2.137000,2.894000,1.813000); -positions[859] = Vec3(0.223000,2.293000,1.417000); -positions[860] = Vec3(2.637000,0.007000,0.197000); -positions[861] = Vec3(1.416000,0.050000,0.483000); -positions[862] = Vec3(1.845000,2.250000,1.251000); -positions[863] = Vec3(2.906000,0.034000,2.896000); -positions[864] = Vec3(2.481000,0.204000,0.474000); -positions[865] = Vec3(2.234000,2.051000,0.158000); -positions[866] = Vec3(0.185000,2.453000,0.055000); -positions[867] = Vec3(2.509000,0.048000,2.786000); -positions[868] = Vec3(2.202000,2.206000,2.027000); -positions[869] = Vec3(0.061000,2.367000,2.656000); -positions[870] = Vec3(3.003000,2.755000,2.241000); -positions[871] = Vec3(0.297000,2.131000,2.463000); -positions[872] = Vec3(1.553000,0.429000,1.573000); -positions[873] = Vec3(2.506000,1.832000,1.911000); -positions[874] = Vec3(2.472000,1.814000,2.759000); -positions[875] = Vec3(1.922000,1.563000,2.278000); -positions[876] = Vec3(2.623000,2.666000,2.169000); -positions[877] = Vec3(0.120000,1.834000,2.723000); -positions[878] = Vec3(0.294000,0.103000,2.826000); -positions[879] = Vec3(2.364000,2.821000,0.417000); -positions[880] = Vec3(2.446000,1.734000,0.153000); -positions[881] = Vec3(2.777000,2.037000,2.565000); -positions[882] = Vec3(2.837000,2.477000,1.924000); -positions[883] = Vec3(2.221000,1.961000,2.443000); -positions[884] = Vec3(2.284000,2.895000,2.157000); -positions[885] = Vec3(2.728000,2.880000,1.861000); -positions[886] = Vec3(0.454000,2.080000,2.868000); -positions[887] = Vec3(2.430000,2.790000,2.524000); -positions[888] = Vec3(1.808000,2.213000,1.899000); -positions[889] = Vec3(2.666000,0.053000,2.309000); -positions[890] = Vec3(2.290000,2.408000,2.995000); -positions[891] = Vec3(2.646000,2.592000,1.625000); -positions[892] = Vec3(2.750000,2.508000,2.489000); -positions[893] = Vec3(0.211000,1.753000,1.939000); diff --git a/platforms/reference/tests/TestReferenceCheckpoints.cpp b/platforms/reference/tests/TestReferenceCheckpoints.cpp index 4356494b2..b2c2d5a08 100644 --- a/platforms/reference/tests/TestReferenceCheckpoints.cpp +++ b/platforms/reference/tests/TestReferenceCheckpoints.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2013 Stanford University and the Authors. * + * Portions copyright (c) 2012-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,49 +29,12 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests creating and loading checkpoints with the reference platform. - */ - -#include "ReferencePlatform.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/AndersenThermostat.h" -#include "openmm/Context.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void compareStates(State& s1, State& s2) { - ASSERT_EQUAL_TOL(s1.getTime(), s2.getTime(), TOL); - int numParticles = s1.getPositions().size(); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], TOL); - ASSERT_EQUAL_VEC(s1.getVelocities()[i], s2.getVelocities()[i], TOL); - Vec3 a1, b1, c1, a2, b2, c2; - s1.getPeriodicBoxVectors(a1, b1, c1); - s2.getPeriodicBoxVectors(a2, b2, c2); - ASSERT_EQUAL_VEC(a1, a2, TOL); - ASSERT_EQUAL_VEC(b1, b2, TOL); - ASSERT_EQUAL_VEC(c1, c2, TOL); - for (map::const_iterator iter = s1.getParameters().begin(); iter != s1.getParameters().end(); ++iter) - ASSERT_EQUAL(iter->second, (*s2.getParameters().find(iter->first)).second); - } -} +#include "ReferenceTests.h" +#include "TestCheckpoints.h" void testCheckpoint() { - const int numParticles = 10; - const double boxSize = 3.0; + const int numParticles = 100; + const double boxSize = 5.0; const double temperature = 200.0; System system; system.addForce(new AndersenThermostat(0.0, 100.0)); @@ -84,7 +47,16 @@ void testCheckpoint() { for (int i = 0; i < numParticles; i++) { system.addParticle(1.0); nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1); - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + bool clash; + do { + clash = false; + positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + for (int j = 0; j < i; j++) { + Vec3 delta = positions[i]-positions[j]; + if (sqrt(delta.dot(delta)) < 0.1) + clash = true; + } + } while (clash); } VerletIntegrator integrator(0.001); Context context(system, integrator, platform); @@ -122,69 +94,6 @@ void testCheckpoint() { compareStates(s2, s4); } -void testSetState() { - const int numParticles = 10; - const double boxSize = 3.0; - const double temperature = 200.0; - System system; - system.addForce(new AndersenThermostat(0.0, 100.0)); - NonbondedForce* nonbonded = new NonbondedForce(); - system.addForce(nonbonded); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1); - positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - } - VerletIntegrator integrator(0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - context.setParameter(AndersenThermostat::Temperature(), temperature); - - // Run for a little while. - - integrator.step(100); - - // Record the current state. - - State s1 = context.getState(State::Positions | State::Velocities | State::Parameters); - - // Continue the simulation for a few more steps and record a partial state. - - integrator.step(10); - State s2 = context.getState(State::Positions); - - // Restore the original state and see if everything gets restored correctly. - - context.setPeriodicBoxVectors(Vec3(2*boxSize, 0, 0), Vec3(0, 2*boxSize, 0), Vec3(0, 0, 2*boxSize)); - context.setParameter(AndersenThermostat::Temperature(), temperature+10); - context.setState(s1); - State s3 = context.getState(State::Positions | State::Velocities | State::Parameters); - compareStates(s1, s3); - - // Set the partial state and see if the correct things were set. - - context.setState(s2); - State s4 = context.getState(State::Positions | State::Velocities | State::Parameters); - for (int i = 0; i < numParticles; i++) { - ASSERT_EQUAL_VEC(s2.getPositions()[i], s4.getPositions()[i], TOL); - ASSERT_EQUAL_VEC(s1.getVelocities()[i], s4.getVelocities()[i], TOL); - } -} - -int main() { - try { - testCheckpoint(); - testSetState(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testCheckpoint(); } diff --git a/platforms/reference/tests/TestReferenceEwald.cpp b/platforms/reference/tests/TestReferenceEwald.cpp index a7ebc7518..eb9e7a3ee 100644 --- a/platforms/reference/tests/TestReferenceEwald.cpp +++ b/platforms/reference/tests/TestReferenceEwald.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,455 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the Eewald summation method reference implementation of NonbondedForce. - */ +#include "ReferenceTests.h" +#include "TestEwald.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/internal/NonbondedForceImpl.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double EWALD_TOL = 1e-5; -const double PME_TOL = 5e-5; - -void testEwaldExact() { - -// Use a NaCl crystal to compare the calculated and Madelung energies - - const int numParticles = 1000; - const double cutoff = 1.0; - const double boxSize = 2.82; - - System system; - for (int i = 0; i < numParticles/2; i++) - system.addParticle(22.99); - for (int i = 0; i < numParticles/2; i++) - system.addParticle(35.45); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - 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); - nonbonded->setNonbondedMethod(NonbondedForce::Ewald); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - nonbonded->setEwaldErrorTolerance(EWALD_TOL); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - #include "nacl_crystal.dat" - context.setPositions(positions); - - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - -// The potential energy of an ion in a crystal is -// E = - (M*e^2/ 4*pi*epsilon0*a0), -// where -// M : Madelung constant (dimensionless, for FCC cells such as NaCl it is 1.7476) -// e : 1.6022 × 10−19 C -// 4*pi*epsilon0: 1.112 × 10−10 C²/(J m) -// a0 : 0.282 x 10-9 m (perfect cell) -// -// E is then the energy per pair of ions, so for our case -// E has to be divided by 2 (per ion), multiplied by N(avogadro), multiplied by number of particles, and divided by 1000 for kJ - double exactEnergy = - (1.7476 * 1.6022e-19 * 1.6022e-19 * 6.02214e+23 * numParticles) / (1.112e-10 * 0.282e-9 * 2 * 1000); - //cout << "exact\t\t: " << exactEnergy << endl; - //cout << "calc\t\t: " << state.getPotentialEnergy() << endl; - ASSERT_EQUAL_TOL(exactEnergy, state.getPotentialEnergy(), 100*EWALD_TOL); - -} - -void testEwaldPME() { - - double tol = 1e-5; - const double boxSize = 3.00646; - const double cutoff = 1.2; - const int numParticles = 894; - -// Use amorphous NaCl system -// The particles are simple charges, no VdW interactions - - System system; - for (int i = 0; i < numParticles/2; i++) - system.addParticle(22.99); - for (int i = 0; i < numParticles/2; i++) - system.addParticle(35.45); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - 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); - nonbonded->setNonbondedMethod(NonbondedForce::Ewald); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - nonbonded->setEwaldErrorTolerance(EWALD_TOL); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - #include "nacl_amorph.dat" - context.setPositions(positions); - - State state1 = context.getState(State::Forces | State::Energy); - const vector& forces1 = state1.getForces(); - -// (1) CHECK EXACT VALUE OF EWALD ENERGY (Against Gromacs output) - - tol = 1e-4; - ASSERT_EQUAL_TOL(-3.82047e+05, state1.getPotentialEnergy(), tol); - -// (2) CHECK WHETHER THE EWALD FORCES ARE THE SAME AS THE GROMACS OUTPUT -// these are forces for alpha: 2.82756, kmax(x/y/z) = 11 - - tol = 1e-2; -// #include "nacl_amorph_GromacsForcesEwald.dat" - -// (3) CHECK SELF-CONSISTENCY - - // Take a small step in the direction of the energy gradient. - - double norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = state1.getForces()[i]; - norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; - } - - - norm = std::sqrt(norm); - const double delta = 1e-2; - double step = delta/norm; - for (int i = 0; i < numParticles; ++i) { - Vec3 p = positions[i]; - Vec3 f = state1.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()-state1.getPotentialEnergy())/delta, fabs(EWALD_TOL*state2.getPotentialEnergy()/(state2.getPotentialEnergy()-state1.getPotentialEnergy()))) - -// (4) CHECK EXACT VALUE OF PME ENERGY - - nonbonded->setNonbondedMethod(NonbondedForce::PME); - nonbonded->setEwaldErrorTolerance(PME_TOL); - context.reinitialize(); - #include "nacl_amorph.dat" - context.setPositions(positions); - State state3 = context.getState(State::Forces | State::Energy); - -// Gromacs PME energy for the same mesh - tol = 1e-4; - ASSERT_EQUAL_TOL(-3.82047e+05, state3.getPotentialEnergy(), tol); - -// (5) CHECK WHETHER PME FORCES ARE THE SAME AS THE GROMACS OUTPUT USING EWALD - - tol = 1e-1; -// #include "nacl_amorph_GromacsForcesEwald.dat" - -// (6) CHECK PME FOR SELF-CONSISTENCY - - // Take a small step in the direction of the energy gradient. - - norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = state3.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 = state3.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 state4 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state4.getPotentialEnergy()-state3.getPotentialEnergy())/delta, fabs(PME_TOL*state4.getPotentialEnergy()/(state4.getPotentialEnergy()-state3.getPotentialEnergy()))) -} - -void testEwald2Ions() { - 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); - system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6)); - nonbonded->setEwaldErrorTolerance(EWALD_TOL); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*EWALD_TOL); - ASSERT_EQUAL_VEC(Vec3(123.711, -64.1877, 302.716), forces[1], 10*EWALD_TOL); - ASSERT_EQUAL_TOL(-217.276, state.getPotentialEnergy(), 10*EWALD_TOL); -} - -void testWaterSystem() { - System system; - static int numParticles = 648; - const double boxSize = 1.86206; - - for (int i = 0 ; i < numParticles ; i++) - { - system.addParticle(1.0); - } - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - for (int i = 0 ; i < numParticles/3 ; i++) - { - nonbonded->addParticle(-0.82, 1, 0); - nonbonded->addParticle(0.41, 1, 0); - nonbonded->addParticle(0.41, 1, 0); - } - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 0.8; - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - nonbonded->setEwaldErrorTolerance(EWALD_TOL); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(numParticles); - #include "water.dat" - context.setPositions(positions); - State state1 = context.getState(State::Forces | State::Energy); - const vector& forces = state1.getForces(); - -// Take a small step in the direction of the energy gradient. - - double norm = 0.0; - for (int i = 0; i < numParticles; ++i) { - Vec3 f = state1.getForces()[i]; - norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; - } - - - norm = std::sqrt(norm); - const double delta = 1e-3; - double step = delta/norm; - for (int i = 0; i < numParticles; ++i) { - Vec3 p = positions[i]; - Vec3 f = state1.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. - - nonbonded->setNonbondedMethod(NonbondedForce::Ewald); - State state2 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state1.getPotentialEnergy())/delta, 0.01) - - -} - -void testTriclinic() { - // Create a triclinic box containing eight particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(2.5, 0, 0), Vec3(0.5, 3.0, 0), Vec3(0.7, 0.9, 3.5)); - for (int i = 0; i < 8; i++) - system.addParticle(1.0); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - force->setNonbondedMethod(NonbondedForce::PME); - force->setCutoffDistance(1.0); - force->setPMEParameters(3.45891, 32, 40, 48); - for (int i = 0; i < 4; i++) - force->addParticle(-1, 0.440104, 0.4184); // Cl parameters - for (int i = 0; i < 4; i++) - force->addParticle(1, 0.332840, 0.0115897); // Na parameters - vector positions(8); - positions[0] = Vec3(1.744, 2.788, 3.162); - positions[1] = Vec3(1.048, 0.762, 2.340); - positions[2] = Vec3(2.489, 1.570, 2.817); - positions[3] = Vec3(1.027, 1.893, 3.271); - positions[4] = Vec3(0.937, 0.825, 0.009); - positions[5] = Vec3(2.290, 1.887, 3.352); - positions[6] = Vec3(1.266, 1.111, 2.894); - positions[7] = Vec3(0.933, 1.862, 3.490); - - // Compute the forces and energy. - - VerletIntegrator integ(0.001); - Context context(system, integ, platform); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // Compare them to values computed by Gromacs. - - double expectedEnergy = -963.370; - vector expectedForce(8); - expectedForce[0] = Vec3(4.25253e+01, -1.23503e+02, 1.22139e+02); - expectedForce[1] = Vec3(9.74752e+01, 1.68213e+02, 1.93169e+02); - expectedForce[2] = Vec3(-1.50348e+02, 1.29165e+02, 3.70435e+02); - expectedForce[3] = Vec3(9.18644e+02, -3.52571e+00, -1.34772e+03); - expectedForce[4] = Vec3(-1.61193e+02, 9.01528e+01, -7.12904e+01); - expectedForce[5] = Vec3(2.82630e+02, 2.78029e+01, -3.72864e+02); - expectedForce[6] = Vec3(-1.47454e+02, -2.14448e+02, -3.55789e+02); - expectedForce[7] = Vec3(-8.82195e+02, -7.39132e+01, 1.46202e+03); - for (int i = 0; i < 8; i++) { - ASSERT_EQUAL_VEC(expectedForce[i], state.getForces()[i], 1e-4); - } - ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-4); -} - -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 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); - - // 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 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); - } - if (method == NonbondedForce::PME) { - // See if the PME parameters were calculated correctly. - - double expectedAlpha, actualAlpha; - int expectedSize[3], actualSize[3]; - NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); - force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); - ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); - for (int i = 0; i < 3; i++) { - ASSERT(actualSize[i] >= expectedSize[i]); - ASSERT(actualSize[i] < expectedSize[i]+10); - } - } - } - } -} - -void testPMEParameters() { - // Create a cloud of random point charges. - - const int numParticles = 51; - const double boxWidth = 4.7; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth)); - NonbondedForce* force = new NonbondedForce(); - system.addForce(force); - vector 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(NonbondedForce::PME); - - // Compute the energy with an error tolerance of 1e-3. - - force->setEwaldErrorTolerance(1e-3); - VerletIntegrator integrator1(0.01); - Context context1(system, integrator1, platform); - context1.setPositions(positions); - double energy1 = context1.getState(State::Energy).getPotentialEnergy(); - - // Try again with an error tolerance of 1e-4. - - force->setEwaldErrorTolerance(1e-4); - VerletIntegrator integrator2(0.01); - Context context2(system, integrator2, platform); - context2.setPositions(positions); - double energy2 = context2.getState(State::Energy).getPotentialEnergy(); - - // Now explicitly set the parameters. These should match the values that were - // used for tolerance 1e-3. - - force->setPMEParameters(2.49291157051793, 32, 32, 32); - VerletIntegrator integrator3(0.01); - Context context3(system, integrator3, platform); - context3.setPositions(positions); - double energy3 = context3.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL(energy1, energy3, 1e-6); - ASSERT(fabs((energy1-energy2)/energy1) > 1e-5); -} - -int main() { - try { - testEwaldExact(); - testEwaldPME(); -// testEwald2Ions(); -// testWaterSystem(); - testTriclinic(); - testErrorTolerance(NonbondedForce::Ewald); - testErrorTolerance(NonbondedForce::PME); - testPMEParameters(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceGBSAOBCForce.cpp b/platforms/reference/tests/TestReferenceGBSAOBCForce.cpp index c50c64f96..d233ee3f0 100644 --- a/platforms/reference/tests/TestReferenceGBSAOBCForce.cpp +++ b/platforms/reference/tests/TestReferenceGBSAOBCForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,216 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of GBSAOBCForce. - */ +#include "ReferenceTests.h" +#include "TestGBSAOBCForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/GBSAOBCForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/NonbondedForce.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSingleParticle() { - System system; - system.addParticle(2.0); - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - forceField->addParticle(0.5, 0.15, 1); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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/forceField->getSoluteDielectric()-1.0/forceField->getSolventDielectric())/bornRadius; - double extendedRadius = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); - - // Change the parameters and see if it is still correct. - - forceField->setParticleParameters(0, 0.4, 0.25, 1); - forceField->updateParametersInContext(context); - state = context.getState(State::Energy); - bornRadius = 0.25-0.009; // dielectric offset - bornEnergy = (-0.4*0.4/(8*PI_M*eps0))*(1.0/forceField->getSoluteDielectric()-1.0/forceField->getSolventDielectric())/bornRadius; - extendedRadius = 0.25+0.14; - nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.25/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testGlobalSettings() { - System system; - system.addParticle(2.0); - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - forceField->addParticle(0.5, 0.15, 1); - const double soluteDielectric = 2.1; - const double solventDielectric = 35.0; - const double surfaceAreaEnergy = 0.75; - forceField->setSoluteDielectric(soluteDielectric); - forceField->setSolventDielectric(solventDielectric); - forceField->setSurfaceAreaEnergy(surfaceAreaEnergy); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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/soluteDielectric-1.0/solventDielectric)/bornRadius; - double extendedRadius = 0.15+0.14; // probe radius - double nonpolarEnergy = 4*PI_M*surfaceAreaEnergy*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); - ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); -} - -void testCutoffAndPeriodic() { - 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 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); - ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(!gbsa->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - context.setPositions(positions); - State state1 = context.getState(State::Forces); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic); - ASSERT(nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(gbsa->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - context.reinitialize(); - context.setPositions(positions); - State state2 = context.getState(State::Forces); - positions[1][0]+= boxSize; - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic); - ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(!gbsa->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - context.reinitialize(); - context.setPositions(positions); - State state3 = context.getState(State::Forces); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic); - ASSERT(nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(gbsa->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - 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() { - const int numParticles = 10; - System system; - LangevinIntegrator integrator(0, 0.1, 0.01); - GBSAOBCForce* forceField = new GBSAOBCForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - forceField->addParticle(i%2 == 0 ? -1 : 1, 0.15, 1); - } - system.addForce(forceField); - Context context(system, integrator, platform); - - // Set random positions for all the particles. - - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - positions[i] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 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]; - } - norm = std::sqrt(norm); - const double delta = 1e-2; - double step = 0.5*delta/norm; - vector positions2(numParticles), positions3(numParticles); - for (int i = 0; i < numParticles; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-3) -} - -int main() { - try { - testSingleParticle(); - testGlobalSettings(); - testCutoffAndPeriodic(); - testForce(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceLangevinIntegrator.cpp b/platforms/reference/tests/TestReferenceLangevinIntegrator.cpp index c2ccefe20..d1ae238b8 100644 --- a/platforms/reference/tests/TestReferenceLangevinIntegrator.cpp +++ b/platforms/reference/tests/TestReferenceLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,248 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of LangevinIntegrator. - */ +#include "ReferenceTests.h" +#include "TestLangevinIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - 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 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; - 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 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 double temp = 100.0; - 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); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 < numParticles-1; ++j) { - Vec3 p1 = state.getPositions()[j]; - Vec3 p2 = state.getPositions()[j+1]; - 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(1.0, dist, 2e-5); - } - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - LangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double collisionFreq = 10.0; - 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 positions(numParticles); - vector 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(); - testConstrainedMasslessParticles(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceLocalEnergyMinimizer.cpp b/platforms/reference/tests/TestReferenceLocalEnergyMinimizer.cpp index 44e2da413..23df183f1 100644 --- a/platforms/reference/tests/TestReferenceLocalEnergyMinimizer.cpp +++ b/platforms/reference/tests/TestReferenceLocalEnergyMinimizer.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2010-2015 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,185 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -#include "openmm/internal/AssertionUtilities.h" -#include "ReferencePlatform.h" -#include "openmm/Context.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/LocalEnergyMinimizer.h" -#include "openmm/NonbondedForce.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/VirtualSite.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -void testHarmonicBonds() { - const int numParticles = 10; - System system; - HarmonicBondForce* bonds = new HarmonicBondForce(); - system.addForce(bonds); - - // Create a chain of particles connected by harmonic bonds. - - vector positions(numParticles); - for (int i = 0; i < numParticles; i++) { - system.addParticle(1.0); - positions[i] = Vec3(i, 0, 0); - if (i > 0) - bonds->addBond(i-1, i, 1+0.1*i, 1); - } - - // Minimize it and check that all bonds are at their equilibrium distances. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - LocalEnergyMinimizer::minimize(context, 1e-5); - State state = context.getState(State::Positions); - for (int i = 1; i < numParticles; i++) { - Vec3 delta = state.getPositions()[i]-state.getPositions()[i-1]; - ASSERT_EQUAL_TOL(1+0.1*i, sqrt(delta.dot(delta)), 1e-4); - } -} - -void testLargeSystem() { - const int numMolecules = 25; - const int numParticles = numMolecules*2; - const double cutoff = 2.0; - const double boxSize = 4.0; - const double tolerance = 5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setCutoffDistance(cutoff); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Create a cloud of molecules. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < numMolecules; i++) { - system.addParticle(1.0); - system.addParticle(1.0); - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(1.0, 0.2, 0.2); - 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]); - system.addConstraint(2*i, 2*i+1, 1.0); - } - - // Minimize it and verify that the energy has decreased. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - State initialState = context.getState(State::Forces | State::Energy); - LocalEnergyMinimizer::minimize(context, tolerance); - State finalState = context.getState(State::Forces | State::Energy | State::Positions); - ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); - - // Compute the force magnitude, subtracting off any component parallel to a constraint, and - // check that it satisfies the requested tolerance. - - double forceNorm = 0.0; - for (int i = 0; i < numParticles; i += 2) { - Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; - double distance = sqrt(dir.dot(dir)); - dir *= 1.0/distance; - Vec3 f = finalState.getForces()[i]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - f = finalState.getForces()[i+1]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - } - forceNorm = sqrt(forceNorm/(5*numMolecules)); - ASSERT(forceNorm < 2*tolerance); -} - -void testVirtualSites() { - const int numMolecules = 25; - const int numParticles = numMolecules*3; - const double cutoff = 2.0; - const double boxSize = 4.0; - const double tolerance = 5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->setCutoffDistance(cutoff); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - system.addForce(nonbonded); - - // Create a cloud of molecules. - - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - vector positions(numParticles); - for (int i = 0; i < numMolecules; i++) { - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - nonbonded->addParticle(-1.0, 0.2, 0.2); - nonbonded->addParticle(0.5, 0.2, 0.2); - nonbonded->addParticle(0.5, 0.2, 0.2); - positions[3*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); - positions[3*i+1] = Vec3(positions[3*i][0]+1.0, positions[3*i][1], positions[3*i][2]); - positions[3*i+2] = Vec3(); - system.addConstraint(3*i, 3*i+1, 1.0); - system.setVirtualSite(3*i+2, new TwoParticleAverageSite(3*i, 3*i+1, 0.5, 0.5)); - } - - // Minimize it and verify that the energy has decreased. - - VerletIntegrator integrator(0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - context.applyConstraints(1e-5); - State initialState = context.getState(State::Forces | State::Energy); - LocalEnergyMinimizer::minimize(context, tolerance); - State finalState = context.getState(State::Forces | State::Energy | State::Positions); - ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); - - // Compute the force magnitude, subtracting off any component parallel to a constraint, and - // check that it satisfies the requested tolerance. - - double forceNorm = 0.0; - for (int i = 0; i < numParticles; i += 3) { - Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; - double distance = sqrt(dir.dot(dir)); - dir *= 1.0/distance; - Vec3 f = finalState.getForces()[i]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - f = finalState.getForces()[i+1]; - f -= dir*dir.dot(f); - forceNorm += f.dot(f); - - // Check the virtual site location. - - ASSERT_EQUAL_VEC((finalState.getPositions()[i+1]+finalState.getPositions()[i])*0.5, finalState.getPositions()[i+2], 1e-5); - } - forceNorm = sqrt(forceNorm/(5*numMolecules)); - ASSERT(forceNorm < 2*tolerance); -} +#include "ReferenceTests.h" +#include "TestLocalEnergyMinimizer.h" -int main() { - try { - testHarmonicBonds(); - testLargeSystem(); - testVirtualSites(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceMonteCarloAnisotropicBarostat.cpp b/platforms/reference/tests/TestReferenceMonteCarloAnisotropicBarostat.cpp index 031b8c9f5..977e30f3e 100644 --- a/platforms/reference/tests/TestReferenceMonteCarloAnisotropicBarostat.cpp +++ b/platforms/reference/tests/TestReferenceMonteCarloAnisotropicBarostat.cpp @@ -6,8 +6,8 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * - * Authors: Peter Eastman, Lee-Ping Wang * + * Portions copyright (c) 2015 Stanford University and the Authors. * + * Authors: Peter Eastman * * Contributors: * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -29,454 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of MonteCarloAnisotropicBarostat. - */ +#include "ReferenceTests.h" +#include "TestMonteCarloAnisotropicBarostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/MonteCarloBarostat.h" -#include "openmm/MonteCarloAnisotropicBarostat.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -void testIdealGas() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], true, true, true, frequency); - system.addForce(barostat); - ASSERT(barostat->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - } -} - -void testIdealGasAxis(int axis) { - // Test scaling just one axis. - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - const bool scaleX = (axis == 0); - const bool scaleY = (axis == 1); - const bool scaleZ = (axis == 2); - double boxX; - double boxY; - double boxZ; - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], scaleX, scaleY, scaleZ, frequency); - system.addForce(barostat); - ASSERT(barostat->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - boxX = box[0][0]; - boxY = box[1][1]; - boxZ = box[2][2]; - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - if (!scaleX) { - ASSERT(boxX == initialLength); - } - if (!scaleY) { - ASSERT(boxY == 0.5*initialLength); - } - if (!scaleZ) { - ASSERT(boxZ == 2*initialLength); - } - } -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double pressure = 1.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - 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); - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp, true, true, true, 1); - system.addForce(barostat); - ASSERT(barostat->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - vector positions(numParticles); - vector 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. - - barostat->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. - - barostat->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]); - } - } +void runPlatformTests() { } - -void testTriclinic() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temperature = 300.0; - const double initialVolume = numParticles*BOLTZ*temperature/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - Vec3 initialBox[3]; - initialBox[0] = Vec3(initialLength, 0, 0); - initialBox[1] = Vec3(0.2*initialLength, initialLength, 0); - initialBox[2] = Vec3(0.1*initialLength, 0.3*initialLength, initialLength); - system.setDefaultPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt)); - } - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temperature, true, true, true, frequency); - system.addForce(barostat); - - // Run a simulation - - LangevinIntegrator integrator(temperature, 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temperature/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - - // Make sure the box vectors have been scaled consistently. - - State state = context.getState(State::Positions); - Vec3 box[3]; - state.getPeriodicBoxVectors(box[0], box[1], box[2]); - double xscale = box[2][0]/(0.1*initialLength); - double yscale = box[2][1]/(0.3*initialLength); - double zscale = box[2][2]/(1.0*initialLength); - for (int i = 0; i < 3; i++) { - ASSERT_EQUAL_VEC(Vec3(xscale*initialBox[i][0], yscale*initialBox[i][1], zscale*initialBox[i][2]), box[i], 1e-5); - } - - // The barostat should have put all particles inside the first periodic box. One integration step - // has happened since then, so they may have moved slightly outside it. - - for (int i = 0; i < numParticles; i++) { - Vec3 pos = state.getPositions()[i]; - ASSERT(pos[2]/box[2][2] > -1 && pos[2]/box[2][2] < 2); - pos -= box[2]*floor(pos[2]/box[2][2]); - ASSERT(pos[1]/box[1][1] > -1 && pos[1]/box[1][1] < 2); - pos -= box[1]*floor(pos[1]/box[1][1]); - ASSERT(pos[0]/box[0][0] > -1 && pos[0]/box[0][0] < 2); - } -} - -/** - * Run a constant pressure simulation on an anisotropic Einstein crystal - * using isotropic and anisotropic barostats. There are a total of 15 simulations: - * - * 1) 3 pressures: 9.0, 10.0, 11.0 bar, for each of the following groups: - * 2) 3 groups of simulations that scale just one axis: x, y, z - * 3) 1 group of simulations that scales all three axes in the anisotropic barostat - * 4) 1 group of simulations that scales all three axes in the isotropic barostat - * - * Results that we will check: - * - * a) In each group of simulations, the volume should decrease with increasing pressure - * b) In the three simulation groups that scale just one axis, the compressibility (i.e. incremental volume change - * with increasing pressure) should go like kx > ky > kz (because the spring constant is largest in the z-direction) - * c) The anisotropic barostat should produce the same result as the isotropic barostat when all three axes are scaled - */ -void testEinsteinCrystal() { - const int numParticles = 64; - const int frequency = 2; - const int equil = 10000; - const int steps = 5000; - const double pressure = 10.0; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp = 300.0; // Only test one temperature since we're looking at three pressures. - const double pres3[] = {2.0, 8.0, 15.0}; - const double initialVolume = numParticles*BOLTZ*temp/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - vector initialPositions(3); - vector results; - // Run four groups of anisotropic simulations; scaling just x, y, z, then all three. - for (int a = 0; a < 4; a++) { - // Test barostat for three different pressures. - for (int p = 0; p < 3; p++) { - // Create a system of noninteracting particles attached by harmonic springs to their initial positions. - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - // Anisotropic force constants. - CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); - initialPositions[0] = positions[i][0]; - initialPositions[1] = positions[i][1]; - initialPositions[2] = positions[i][2]; - force->addParticle(i, initialPositions); - nb->addParticle(0, initialLength/6, 0.1); - } - system.addForce(force); - system.addForce(nb); - // Create the barostat. - MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pres3[p], pres3[p], pres3[p]), temp, (a==0||a==3), (a==1||a==3), (a==2||a==3), frequency); - system.addForce(barostat); - barostat->setTemperature(temp); - LangevinIntegrator integrator(temp, 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - // Let it equilibrate. - integrator.step(equil); - // Now run it for a while and see if the volume is correct. - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - results.push_back(volume); - } - } - for (int p = 0; p < 3; p++) { - // Create a system of noninteracting particles attached by harmonic springs to their initial positions. - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - // Anisotropic force constants. - CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); - force->addPerParticleParameter("x0"); - force->addPerParticleParameter("y0"); - force->addPerParticleParameter("z0"); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); - initialPositions[0] = positions[i][0]; - initialPositions[1] = positions[i][1]; - initialPositions[2] = positions[i][2]; - force->addParticle(i, initialPositions); - nb->addParticle(0, initialLength/6, 0.1); - } - system.addForce(force); - system.addForce(nb); - // Create the barostat. - MonteCarloBarostat* barostat = new MonteCarloBarostat(pres3[p], temp, frequency); - system.addForce(barostat); - barostat->setTemperature(temp); - LangevinIntegrator integrator(temp, 0.1, 0.001); - Context context(system, integrator, platform); - context.setPositions(positions); - // Let it equilibrate. - integrator.step(equil); - // Now run it for a while and see if the volume is correct. - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - integrator.step(frequency); - } - volume /= steps; - results.push_back(volume); - } - - // Check to see if volumes decrease with increasing pressure. - ASSERT_USUALLY_TRUE(results[0] > results[1]); - ASSERT_USUALLY_TRUE(results[1] > results[2]); - ASSERT_USUALLY_TRUE(results[3] > results[4]); - ASSERT_USUALLY_TRUE(results[4] > results[5]); - ASSERT_USUALLY_TRUE(results[6] > results[7]); - ASSERT_USUALLY_TRUE(results[7] > results[8]); - - // Check to see if incremental volume changes with increasing pressure go like kx > ky > kz. - ASSERT_USUALLY_TRUE((results[0] - results[1]) > (results[3] - results[4])); - ASSERT_USUALLY_TRUE((results[1] - results[2]) > (results[4] - results[5])); - ASSERT_USUALLY_TRUE((results[3] - results[4]) > (results[6] - results[7])); - ASSERT_USUALLY_TRUE((results[4] - results[5]) > (results[7] - results[8])); - - // Check to see if the volumes are equal for isotropic and anisotropic (all axis). - ASSERT_USUALLY_EQUAL_TOL(results[9], results[12], 3/std::sqrt((double) steps)); - ASSERT_USUALLY_EQUAL_TOL(results[10], results[13], 3/std::sqrt((double) steps)); - ASSERT_USUALLY_EQUAL_TOL(results[11], results[14], 3/std::sqrt((double) steps)); -} - -int main() { - try { - testIdealGas(); - testIdealGasAxis(0); - testIdealGasAxis(1); - testIdealGasAxis(2); - testRandomSeed(); - testTriclinic(); - //testEinsteinCrystal(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferenceMonteCarloBarostat.cpp b/platforms/reference/tests/TestReferenceMonteCarloBarostat.cpp index 65c513e96..1bd119dfc 100644 --- a/platforms/reference/tests/TestReferenceMonteCarloBarostat.cpp +++ b/platforms/reference/tests/TestReferenceMonteCarloBarostat.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,196 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of MonteCarloBarostat. - */ +#include "ReferenceTests.h" +#include "TestMonteCarloBarostat.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/MonteCarloBarostat.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/VerletIntegrator.h" -#include "sfmt/SFMT.h" -#include "SimTKOpenMMRealType.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -void testChangingBoxSize() { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 5, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - NonbondedForce* nb = new NonbondedForce(); - nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nb->setCutoffDistance(2.0); - nb->addParticle(1, 0.5, 0.5); - system.addForce(nb); - LangevinIntegrator integrator(300.0, 1.0, 0.01); - Context context(system, integrator, platform); - vector positions; - positions.push_back(Vec3()); - context.setPositions(positions); - Vec3 x, y, z; - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ASSERT_EQUAL_VEC(Vec3(4, 0, 0), x, 0); - ASSERT_EQUAL_VEC(Vec3(0, 5, 0), y, 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 6), z, 0); - context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 9)); - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ASSERT_EQUAL_VEC(Vec3(7, 0, 0), x, 0); - ASSERT_EQUAL_VEC(Vec3(0, 8, 0), y, 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 9), z, 0); - - // Shrinking the box too small should produce an exception. - - context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 3.9, 0), Vec3(0, 0, 9)); - bool ok = true; - try { - context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); - ok = false; - } - catch (exception& ex) { - } - ASSERT(ok); -} - -void testIdealGas() { - const int numParticles = 64; - const int frequency = 10; - const int steps = 1000; - const double pressure = 1.5; - const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 - const double temp[] = {300.0, 600.0, 1000.0}; - const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; - const double initialLength = std::pow(initialVolume, 1.0/3.0); - - // Create a gas of noninteracting particles. - - System system; - system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); - vector positions(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(1.0); - positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); - } - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp[0], frequency); - system.addForce(barostat); - ASSERT(barostat->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - - // Test it for three different temperatures. - - for (int i = 0; i < 3; i++) { - barostat->setTemperature(temp[i]); - LangevinIntegrator integrator(temp[i], 0.1, 0.01); - Context context(system, integrator, platform); - context.setPositions(positions); - - // Let it equilibrate. - - integrator.step(10000); - - // Now run it for a while and see if the volume is correct. - - double volume = 0.0; - for (int j = 0; j < steps; ++j) { - Vec3 box[3]; - context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); - volume += box[0][0]*box[1][1]*box[2][2]; - ASSERT_EQUAL_TOL(0.5*box[0][0], box[1][1], 1e-5); - ASSERT_EQUAL_TOL(2*box[0][0], box[2][2], 1e-5); - integrator.step(frequency); - } - volume /= steps; - double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; - ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); - } -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - const double pressure = 1.5; - System system; - system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - 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); - MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, 1); - system.addForce(barostat); - ASSERT(barostat->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - vector positions(numParticles); - vector 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. - - barostat->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. - - barostat->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]); - } - } +void runPlatformTests() { } - -int main() { - try { - testChangingBoxSize(); - testIdealGas(); - testRandomSeed(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferenceNonbondedForce.cpp b/platforms/reference/tests/TestReferenceNonbondedForce.cpp index 2f3a52e57..20c51385e 100644 --- a/platforms/reference/tests/TestReferenceNonbondedForce.cpp +++ b/platforms/reference/tests/TestReferenceNonbondedForce.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2013 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,546 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests all the different force terms in the reference implementation of NonbondedForce. - */ +#include "ReferenceTests.h" +#include "TestNonbondedForce.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "openmm/HarmonicBondForce.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testCoulomb() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0.5, 1, 0); - forceField->addParticle(-1.5, 1, 0); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double force = ONE_4PI_EPS0*(-0.75)/4.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(-0.75)/2.0, state.getPotentialEnergy(), TOL); -} - -void testLJ() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(0, 1.2, 1); - forceField->addParticle(0, 1.4, 2); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - double x = 1.3/2.0; - double eps = SQRT_TWO; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0; - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL); -} - -void testExclusionsAnd14() { - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - for (int i = 0; i < 5; i++) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - Context context(system, integrator, platform); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - vector positions(5); - const double r = 1.0; - for (int j = 0; j < 5; ++j) { - nonbonded->setParticleParameters(j, 0, 1.5, 0); - positions[j] = Vec3(0, j, 0); - } - nonbonded->setParticleParameters(0, 0, 1.5, 1); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - positions[i] = Vec3(r, 0, 0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double x = 1.5/r; - double eps = 1.0; - double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - nonbonded->setParticleParameters(0, 2, 1.5, 0); - nonbonded->setParticleParameters(i, 2, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - nonbonded->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*4/(r*r); - energy = ONE_4PI_EPS0*4/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testCutoff() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* forceField = new NonbondedForce(); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->addParticle(1.0, 1, 0); - forceField->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - const double cutoff = 2.9; - forceField->setCutoffDistance(cutoff); - const double eps = 50.0; - forceField->setReactionFieldDielectric(eps); - system.addForce(forceField); - ASSERT(!forceField->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector 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& forces = state.getForces(); - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force1 = ONE_4PI_EPS0*(1.0)*(0.25-2.0*krf*2.0); - const double force2 = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL); - const double energy1 = ONE_4PI_EPS0*(1.0)*(0.5+krf*4.0-crf); - const double energy2 = ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf); - ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL); -} - -void testCutoff14() { - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - for (int i = 0; i < 5; i++) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.5, 0); - } - nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); - const double cutoff = 3.5; - nonbonded->setCutoffDistance(cutoff); - const double eps = 30.0; - nonbonded->setReactionFieldDielectric(eps); - vector > bonds; - bonds.push_back(pair(0, 1)); - bonds.push_back(pair(1, 2)); - bonds.push_back(pair(2, 3)); - bonds.push_back(pair(3, 4)); - nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); - int first14, second14; - for (int i = 0; i < nonbonded->getNumExceptions(); i++) { - int particle1, particle2; - double chargeProd, sigma, epsilon; - nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); - if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) - first14 = i; - if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) - second14 = i; - } - system.addForce(nonbonded); - ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector positions(5); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(2, 0, 0); - positions[3] = Vec3(3, 0, 0); - positions[4] = Vec3(4, 0, 0); - for (int i = 1; i < 5; ++i) { - - // Test LJ forces - - nonbonded->setParticleParameters(0, 0, 1.5, 1); - for (int j = 1; j < 5; ++j) - nonbonded->setParticleParameters(j, 0, 1.5, 0); - nonbonded->setParticleParameters(i, 0, 1.5, 1); - nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); - context.reinitialize(); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - double r = positions[i][0]; - double x = 1.5/r; - double e = 1.0; - double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; - double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0)); - if (i == 3) { - force *= 0.5; - energy *= 0.5; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - - // Test Coulomb forces - - const double q = 0.7; - nonbonded->setParticleParameters(0, q, 1.5, 0); - nonbonded->setParticleParameters(i, q, 1.5, 0); - nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0); - nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); - nonbonded->updateParametersInContext(context); - state = context.getState(State::Forces | State::Energy); - const vector& forces2 = state.getForces(); - force = ONE_4PI_EPS0*q*q/(r*r); - energy = ONE_4PI_EPS0*q*q/r; - if (i == 3) { - force /= 1.2; - energy /= 1.2; - } - if (i < 3 || r > cutoff) { - force = 0; - energy = 0; - } - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); - ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); - } -} - -void testPeriodic() { - System system; - system.addParticle(1.0); - 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->addParticle(1.0, 1, 0); - nonbonded->addException(0, 1, 0.0, 1.0, 0.0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 2.0; - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); - system.addForce(nonbonded); - ASSERT(nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(2, 0, 0); - positions[2] = Vec3(3, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - const vector& forces = state.getForces(); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - const double force = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); - ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); - ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL); - ASSERT_EQUAL_TOL(2*ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL); -} - -void testTriclinic() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - Vec3 a(3.1, 0, 0); - Vec3 b(0.4, 3.5, 0); - Vec3 c(-0.1, -0.5, 4.0); - system.setDefaultPeriodicBoxVectors(a, b, c); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->addParticle(1.0, 1, 0); - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - const double cutoff = 1.5; - nonbonded->setCutoffDistance(cutoff); - system.addForce(nonbonded); - Context context(system, integrator, platform); - vector positions(2); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const double eps = 78.3; - const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); - const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); - for (int iteration = 0; iteration < 50; iteration++) { - // Generate random positions for the two particles. - - positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); - context.setPositions(positions); - - // Loop over all possible periodic copies and find the nearest one. - - Vec3 delta; - double distance2 = 100.0; - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) - for (int k = -1; k < 2; k++) { - Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; - if (d.dot(d) < distance2) { - delta = d; - distance2 = d.dot(d); - } - } - double distance = sqrt(distance2); - - // See if the force and energy are correct. - - State state = context.getState(State::Forces | State::Energy); - if (distance >= cutoff) { - ASSERT_EQUAL(0.0, state.getPotentialEnergy()); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); - } - else { - const Vec3 force = delta*ONE_4PI_EPS0*(-1.0/(distance*distance*distance)+2.0*krf); - ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(1.0/distance+krf*distance*distance-crf), state.getPotentialEnergy(), TOL); - ASSERT_EQUAL_VEC(force, state.getForces()[0], TOL); - ASSERT_EQUAL_VEC(-force, state.getForces()[1], TOL); - } - } -} - -void testDispersionCorrection() { - // Create a box full of identical particles. - - int gridSize = 5; - int numParticles = gridSize*gridSize*gridSize; - double boxSize = gridSize*0.7; - double cutoff = boxSize/3; - System system; - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions(numParticles); - int index = 0; - for (int i = 0; i < gridSize; i++) - for (int j = 0; j < gridSize; j++) - for (int k = 0; k < gridSize; k++) { - system.addParticle(1.0); - nonbonded->addParticle(0, 1.1, 0.5); - positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); - index++; - } - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - ASSERT(nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - - // See if the correction has the correct value. - - Context context(system, integrator, platform); - context.setPositions(positions); - double energy1 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(false); - context.reinitialize(); - context.setPositions(positions); - double energy2 = context.getState(State::Energy).getPotentialEnergy(); - double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); - - // Now modify half the particles to be different, and see if it is still correct. - - int numType2 = 0; - for (int i = 0; i < numParticles; i += 2) { - nonbonded->setParticleParameters(i, 0, 1, 1); - numType2++; - } - int numType1 = numParticles-numType2; - nonbonded->updateParametersInContext(context); - energy2 = context.getState(State::Energy).getPotentialEnergy(); - nonbonded->setUseDispersionCorrection(true); - context.reinitialize(); - context.setPositions(positions); - energy1 = context.getState(State::Energy).getPotentialEnergy(); - term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9; - term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3; - term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9; - term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3; - double combinedSigma = 0.5*(1+1.1); - double combinedEpsilon = sqrt(1*0.5); - term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9; - term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3; - term1 /= (numParticles*(numParticles+1))/2; - term2 /= (numParticles*(numParticles+1))/2; - expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); - ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); -} - -void testSwitchingFunction(NonbondedForce::NonbondedMethod method) { - System system; - system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6)); - system.addParticle(1.0); - system.addParticle(1.0); - VerletIntegrator integrator(0.01); - NonbondedForce* nonbonded = new NonbondedForce(); - nonbonded->addParticle(0, 1.2, 1); - nonbonded->addParticle(0, 1.4, 2); - nonbonded->setNonbondedMethod(method); - nonbonded->setCutoffDistance(2.0); - nonbonded->setUseSwitchingFunction(true); - nonbonded->setSwitchingDistance(1.5); - nonbonded->setUseDispersionCorrection(false); - system.addForce(nonbonded); - if (method == NonbondedForce::PME) { - ASSERT(nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(system.usesPeriodicBoundaryConditions()); - } - else { - ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); - ASSERT(!system.usesPeriodicBoundaryConditions()); - } - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - double eps = SQRT_TWO; - - // Compute the interaction at various distances. - - for (double r = 1.0; r < 2.5; r += 0.1) { - positions[1] = Vec3(r, 0, 0); - context.setPositions(positions); - State state = context.getState(State::Forces | State::Energy); - - // See if the energy is correct. - - double x = 1.3/r; - double expectedEnergy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); - double switchValue; - if (r <= 1.5) - switchValue = 1; - else if (r >= 2.0) - switchValue = 0; - else { - double t = (r-1.5)/0.5; - switchValue = 1+t*t*t*(-10+t*(15-t*6)); - } - ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); - - // See if the force is the gradient of the energy. - - double delta = 1e-3; - positions[1] = Vec3(r-delta, 0, 0); - context.setPositions(positions); - double e1 = context.getState(State::Energy).getPotentialEnergy(); - positions[1] = Vec3(r+delta, 0, 0); - context.setPositions(positions); - double e2 = context.getState(State::Energy).getPotentialEnergy(); - ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); - } -} - -int main() { - try { - testCoulomb(); - testLJ(); - testExclusionsAnd14(); - testCutoff(); - testCutoff14(); - testPeriodic(); - testTriclinic(); - testDispersionCorrection(); - testSwitchingFunction(NonbondedForce::CutoffNonPeriodic); - testSwitchingFunction(NonbondedForce::PME); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceSettle.cpp b/platforms/reference/tests/TestReferenceSettle.cpp index e63892bd9..658e14be6 100644 --- a/platforms/reference/tests/TestReferenceSettle.cpp +++ b/platforms/reference/tests/TestReferenceSettle.cpp @@ -1,4 +1,3 @@ - /* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * @@ -7,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,88 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of the SETTLE algorithm. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/LangevinIntegrator.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -void testConstraints() { - const int numMolecules = 10; - const int numParticles = numMolecules*3; - const int numConstraints = numMolecules*3; - const double temp = 100.0; - System system; - LangevinIntegrator integrator(temp, 2.0, 0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numMolecules; ++i) { - system.addParticle(16.0); - system.addParticle(1.0); - system.addParticle(1.0); - forceField->addParticle(-0.82, 0.317, 0.65); - forceField->addParticle(0.41, 1.0, 0.0); - forceField->addParticle(0.41, 1.0, 0.0); - system.addConstraint(i*3, i*3+1, 0.1); - system.addConstraint(i*3, i*3+2, 0.1); - system.addConstraint(i*3+1, i*3+2, 0.163); - } - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numMolecules; ++i) { - positions[i*3] = Vec3((i%4)*0.4, (i/4)*0.4, 0); - positions[i*3+1] = positions[i*3]+Vec3(0.1, 0, 0); - positions[i*3+2] = positions[i*3]+Vec3(-0.03333, 0.09428, 0); - velocities[i*3] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+1] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); - velocities[i*3+2] = 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) { - integrator.step(1); - State state = context.getState(State::Positions | State::Forces); - 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-5); - } - } -} +#include "ReferenceTests.h" +#include "TestSettle.h" -int main(int argc, char* argv[]) { - try { - testConstraints(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/nacl_amorph.dat b/platforms/reference/tests/nacl_amorph.dat deleted file mode 100644 index 7e8cbafdf..000000000 --- a/platforms/reference/tests/nacl_amorph.dat +++ /dev/null @@ -1,894 +0,0 @@ -positions[0] = Vec3(1.066000,1.628000,0.835000); -positions[1] = Vec3(1.072000,0.428000,0.190000); -positions[2] = Vec3(0.524000,1.442000,1.160000); -positions[3] = Vec3(2.383000,1.524000,1.119000); -positions[4] = Vec3(0.390000,1.441000,0.575000); -positions[5] = Vec3(0.618000,0.399000,0.819000); -positions[6] = Vec3(1.003000,1.257000,1.543000); -positions[7] = Vec3(2.933000,1.569000,0.642000); -positions[8] = Vec3(0.849000,0.739000,0.089000); -positions[9] = Vec3(0.060000,0.794000,0.766000); -positions[10] = Vec3(1.652000,1.405000,1.010000); -positions[11] = Vec3(2.843000,1.533000,1.781000); -positions[12] = Vec3(0.952000,1.309000,0.996000); -positions[13] = Vec3(1.847000,1.402000,0.313000); -positions[14] = Vec3(2.674000,0.083000,1.691000); -positions[15] = Vec3(1.763000,2.104000,0.728000); -positions[16] = Vec3(0.914000,0.574000,0.982000); -positions[17] = Vec3(0.514000,0.078000,0.891000); -positions[18] = Vec3(0.538000,0.766000,1.110000); -positions[19] = Vec3(0.808000,0.676000,0.570000); -positions[20] = Vec3(0.178000,0.014000,0.628000); -positions[21] = Vec3(1.329000,1.333000,0.339000); -positions[22] = Vec3(1.029000,1.678000,0.503000); -positions[23] = Vec3(1.423000,1.767000,1.104000); -positions[24] = Vec3(1.966000,1.051000,0.282000); -positions[25] = Vec3(1.596000,1.971000,0.194000); -positions[26] = Vec3(1.025000,1.043000,2.809000); -positions[27] = Vec3(1.628000,2.614000,0.088000); -positions[28] = Vec3(0.440000,0.606000,0.141000); -positions[29] = Vec3(1.050000,2.821000,2.517000); -positions[30] = Vec3(0.644000,1.604000,0.770000); -positions[31] = Vec3(0.637000,0.917000,0.392000); -positions[32] = Vec3(0.611000,2.768000,0.013000); -positions[33] = Vec3(1.892000,0.660000,0.473000); -positions[34] = Vec3(1.052000,2.081000,0.982000); -positions[35] = Vec3(1.508000,2.300000,0.439000); -positions[36] = Vec3(2.617000,0.328000,1.099000); -positions[37] = Vec3(0.910000,0.040000,0.259000); -positions[38] = Vec3(1.195000,1.494000,1.202000); -positions[39] = Vec3(2.657000,0.997000,0.564000); -positions[40] = Vec3(1.465000,1.580000,0.648000); -positions[41] = Vec3(0.154000,2.538000,1.331000); -positions[42] = Vec3(0.849000,1.476000,1.365000); -positions[43] = Vec3(0.898000,0.987000,1.178000); -positions[44] = Vec3(0.958000,0.656000,1.358000); -positions[45] = Vec3(1.067000,0.934000,0.211000); -positions[46] = Vec3(1.030000,0.319000,1.281000); -positions[47] = Vec3(2.709000,0.807000,0.240000); -positions[48] = Vec3(0.837000,1.362000,0.588000); -positions[49] = Vec3(2.080000,0.791000,2.947000); -positions[50] = Vec3(0.200000,0.266000,1.474000); -positions[51] = Vec3(0.848000,0.379000,1.625000); -positions[52] = Vec3(0.637000,1.071000,0.821000); -positions[53] = Vec3(1.324000,0.757000,2.951000); -positions[54] = Vec3(2.666000,0.935000,1.373000); -positions[55] = Vec3(1.584000,1.025000,1.703000); -positions[56] = Vec3(1.699000,0.636000,0.038000); -positions[57] = Vec3(1.099000,1.644000,1.879000); -positions[58] = Vec3(2.897000,1.302000,1.522000); -positions[59] = Vec3(1.753000,0.949000,2.885000); -positions[60] = Vec3(2.502000,1.321000,0.752000); -positions[61] = Vec3(0.545000,0.193000,1.959000); -positions[62] = Vec3(1.098000,2.646000,1.706000); -positions[63] = Vec3(0.001000,1.205000,0.670000); -positions[64] = Vec3(2.997000,0.061000,1.040000); -positions[65] = Vec3(0.662000,0.828000,1.535000); -positions[66] = Vec3(1.252000,1.246000,0.780000); -positions[67] = Vec3(1.173000,0.472000,0.810000); -positions[68] = Vec3(0.124000,0.622000,2.992000); -positions[69] = Vec3(1.036000,0.883000,0.848000); -positions[70] = Vec3(1.423000,2.146000,1.340000); -positions[71] = Vec3(2.391000,1.136000,1.165000); -positions[72] = Vec3(1.189000,2.961000,0.425000); -positions[73] = Vec3(1.584000,2.500000,0.782000); -positions[74] = Vec3(0.565000,1.122000,1.240000); -positions[75] = Vec3(1.733000,1.716000,1.763000); -positions[76] = Vec3(1.548000,1.522000,0.041000); -positions[77] = Vec3(1.485000,0.561000,0.369000); -positions[78] = Vec3(0.350000,1.661000,0.928000); -positions[79] = Vec3(1.653000,1.223000,0.578000); -positions[80] = Vec3(0.648000,1.349000,0.253000); -positions[81] = Vec3(0.340000,1.820000,0.483000); -positions[82] = Vec3(2.926000,0.119000,1.421000); -positions[83] = Vec3(1.512000,1.084000,0.156000); -positions[84] = Vec3(1.600000,2.115000,1.792000); -positions[85] = Vec3(1.089000,0.934000,1.584000); -positions[86] = Vec3(1.276000,1.104000,1.230000); -positions[87] = Vec3(0.485000,0.305000,0.428000); -positions[88] = Vec3(1.317000,1.261000,1.795000); -positions[89] = Vec3(0.039000,1.413000,1.085000); -positions[90] = Vec3(0.453000,0.701000,0.605000); -positions[91] = Vec3(1.283000,1.937000,0.752000); -positions[92] = Vec3(0.212000,1.416000,1.447000); -positions[93] = Vec3(0.203000,0.358000,0.723000); -positions[94] = Vec3(0.556000,0.445000,1.364000); -positions[95] = Vec3(1.436000,0.861000,0.911000); -positions[96] = Vec3(0.358000,0.966000,0.176000); -positions[97] = Vec3(1.478000,2.715000,0.427000); -positions[98] = Vec3(1.581000,0.575000,0.809000); -positions[99] = Vec3(1.007000,2.153000,2.887000); -positions[100] = Vec3(2.343000,0.663000,2.513000); -positions[101] = Vec3(2.105000,0.649000,1.635000); -positions[102] = Vec3(0.875000,0.743000,2.459000); -positions[103] = Vec3(0.229000,1.315000,1.879000); -positions[104] = Vec3(0.285000,0.935000,1.700000); -positions[105] = Vec3(2.269000,1.284000,2.234000); -positions[106] = Vec3(1.406000,1.149000,2.767000); -positions[107] = Vec3(1.076000,0.220000,1.849000); -positions[108] = Vec3(2.001000,1.532000,2.881000); -positions[109] = Vec3(2.893000,0.485000,1.860000); -positions[110] = Vec3(1.621000,1.786000,2.624000); -positions[111] = Vec3(0.500000,0.616000,1.818000); -positions[112] = Vec3(0.938000,2.978000,2.104000); -positions[113] = Vec3(0.550000,2.081000,0.454000); -positions[114] = Vec3(1.121000,0.685000,2.196000); -positions[115] = Vec3(1.088000,1.385000,2.184000); -positions[116] = Vec3(1.122000,2.705000,2.080000); -positions[117] = Vec3(0.918000,1.767000,2.861000); -positions[118] = Vec3(2.748000,0.232000,2.126000); -positions[119] = Vec3(1.238000,2.766000,0.109000); -positions[120] = Vec3(1.380000,0.785000,1.961000); -positions[121] = Vec3(1.236000,1.757000,0.150000); -positions[122] = Vec3(1.339000,2.187000,2.592000); -positions[123] = Vec3(1.414000,0.342000,2.714000); -positions[124] = Vec3(1.310000,0.770000,2.589000); -positions[125] = Vec3(1.686000,0.765000,2.321000); -positions[126] = Vec3(1.659000,1.367000,2.780000); -positions[127] = Vec3(0.141000,0.095000,1.903000); -positions[128] = Vec3(2.084000,1.002000,2.520000); -positions[129] = Vec3(2.819000,1.286000,2.626000); -positions[130] = Vec3(1.257000,1.044000,2.401000); -positions[131] = Vec3(1.064000,0.546000,2.839000); -positions[132] = Vec3(0.078000,1.246000,0.010000); -positions[133] = Vec3(1.506000,0.420000,2.223000); -positions[134] = Vec3(1.778000,0.699000,1.920000); -positions[135] = Vec3(1.315000,1.721000,2.733000); -positions[136] = Vec3(0.114000,0.281000,0.279000); -positions[137] = Vec3(1.082000,1.421000,2.596000); -positions[138] = Vec3(3.001000,0.592000,2.276000); -positions[139] = Vec3(1.384000,2.227000,2.992000); -positions[140] = Vec3(1.353000,0.044000,1.985000); -positions[141] = Vec3(1.367000,1.832000,2.383000); -positions[142] = Vec3(0.853000,1.119000,2.230000); -positions[143] = Vec3(1.675000,1.482000,2.295000); -positions[144] = Vec3(1.334000,1.890000,1.904000); -positions[145] = Vec3(1.630000,0.140000,2.939000); -positions[146] = Vec3(0.195000,1.290000,2.300000); -positions[147] = Vec3(2.178000,1.173000,3.001000); -positions[148] = Vec3(0.637000,0.655000,2.126000); -positions[149] = Vec3(0.993000,1.796000,2.529000); -positions[150] = Vec3(0.910000,0.701000,1.845000); -positions[151] = Vec3(0.191000,2.128000,0.355000); -positions[152] = Vec3(0.692000,1.163000,2.578000); -positions[153] = Vec3(1.154000,1.052000,1.974000); -positions[154] = Vec3(1.682000,0.335000,2.509000); -positions[155] = Vec3(0.569000,1.032000,1.895000); -positions[156] = Vec3(1.800000,2.796000,1.295000); -positions[157] = Vec3(2.517000,2.347000,2.878000); -positions[158] = Vec3(0.639000,2.470000,1.678000); -positions[159] = Vec3(0.634000,2.006000,1.829000); -positions[160] = Vec3(0.892000,0.215000,0.566000); -positions[161] = Vec3(1.800000,2.143000,1.491000); -positions[162] = Vec3(1.898000,0.226000,2.765000); -positions[163] = Vec3(0.791000,1.738000,0.260000); -positions[164] = Vec3(0.437000,1.740000,2.048000); -positions[165] = Vec3(1.687000,2.438000,1.166000); -positions[166] = Vec3(1.337000,2.304000,1.643000); -positions[167] = Vec3(1.270000,2.397000,1.033000); -positions[168] = Vec3(0.702000,2.429000,0.591000); -positions[169] = Vec3(0.842000,1.976000,0.724000); -positions[170] = Vec3(1.965000,0.095000,1.206000); -positions[171] = Vec3(0.355000,2.710000,0.618000); -positions[172] = Vec3(0.745000,1.434000,2.781000); -positions[173] = Vec3(0.707000,2.171000,1.502000); -positions[174] = Vec3(1.294000,2.696000,0.847000); -positions[175] = Vec3(1.143000,2.075000,0.276000); -positions[176] = Vec3(1.111000,2.474000,0.312000); -positions[177] = Vec3(1.144000,2.316000,0.633000); -positions[178] = Vec3(1.335000,0.292000,0.515000); -positions[179] = Vec3(1.926000,2.813000,2.703000); -positions[180] = Vec3(0.559000,2.314000,2.904000); -positions[181] = Vec3(1.308000,1.605000,1.534000); -positions[182] = Vec3(0.773000,2.913000,1.217000); -positions[183] = Vec3(1.612000,0.082000,1.027000); -positions[184] = Vec3(1.510000,0.287000,1.787000); -positions[185] = Vec3(0.716000,1.424000,1.843000); -positions[186] = Vec3(1.267000,0.685000,1.160000); -positions[187] = Vec3(0.306000,1.653000,1.717000); -positions[188] = Vec3(0.349000,0.020000,1.275000); -positions[189] = Vec3(0.166000,1.979000,0.804000); -positions[190] = Vec3(1.523000,2.992000,0.711000); -positions[191] = Vec3(1.998000,2.146000,0.088000); -positions[192] = Vec3(0.047000,2.513000,0.642000); -positions[193] = Vec3(0.501000,1.793000,1.438000); -positions[194] = Vec3(1.099000,2.010000,1.626000); -positions[195] = Vec3(2.580000,2.854000,1.328000); -positions[196] = Vec3(1.080000,2.779000,1.190000); -positions[197] = Vec3(0.901000,2.561000,0.948000); -positions[198] = Vec3(0.920000,2.990000,0.844000); -positions[199] = Vec3(0.819000,2.924000,1.711000); -positions[200] = Vec3(0.434000,1.516000,0.063000); -positions[201] = Vec3(1.470000,0.058000,0.231000); -positions[202] = Vec3(0.530000,3.005000,1.550000); -positions[203] = Vec3(0.447000,2.330000,1.277000); -positions[204] = Vec3(1.632000,2.683000,1.593000); -positions[205] = Vec3(0.885000,1.835000,2.072000); -positions[206] = Vec3(0.868000,2.601000,1.425000); -positions[207] = Vec3(0.720000,2.242000,0.907000); -positions[208] = Vec3(1.194000,0.144000,1.065000); -positions[209] = Vec3(0.448000,2.485000,0.959000); -positions[210] = Vec3(1.377000,2.694000,1.352000); -positions[211] = Vec3(1.305000,2.928000,2.713000); -positions[212] = Vec3(1.784000,2.456000,1.981000); -positions[213] = Vec3(0.354000,2.136000,1.563000); -positions[214] = Vec3(0.489000,2.000000,1.108000); -positions[215] = Vec3(1.884000,2.221000,0.461000); -positions[216] = Vec3(1.860000,2.540000,0.306000); -positions[217] = Vec3(1.753000,2.335000,2.768000); -positions[218] = Vec3(1.536000,2.441000,2.344000); -positions[219] = Vec3(0.531000,0.025000,2.235000); -positions[220] = Vec3(0.809000,0.011000,2.834000); -positions[221] = Vec3(0.289000,2.614000,2.879000); -positions[222] = Vec3(0.613000,1.891000,2.337000); -positions[223] = Vec3(0.507000,0.037000,2.694000); -positions[224] = Vec3(0.882000,2.185000,2.583000); -positions[225] = Vec3(0.503000,2.051000,2.615000); -positions[226] = Vec3(1.907000,1.956000,2.831000); -positions[227] = Vec3(2.833000,2.769000,1.644000); -positions[228] = Vec3(1.141000,0.113000,2.945000); -positions[229] = Vec3(0.600000,1.338000,2.200000); -positions[230] = Vec3(0.904000,2.360000,1.952000); -positions[231] = Vec3(0.738000,1.568000,2.437000); -positions[232] = Vec3(1.136000,2.535000,2.805000); -positions[233] = Vec3(1.430000,2.767000,2.321000); -positions[234] = Vec3(1.078000,2.470000,2.385000); -positions[235] = Vec3(0.296000,2.376000,2.560000); -positions[236] = Vec3(0.719000,0.300000,0.075000); -positions[237] = Vec3(0.518000,1.911000,0.080000); -positions[238] = Vec3(0.381000,1.570000,2.450000); -positions[239] = Vec3(0.716000,2.581000,2.697000); -positions[240] = Vec3(1.473000,2.617000,1.936000); -positions[241] = Vec3(0.421000,2.449000,0.229000); -positions[242] = Vec3(0.425000,2.817000,1.910000); -positions[243] = Vec3(1.312000,2.294000,2.057000); -positions[244] = Vec3(1.239000,0.007000,1.539000); -positions[245] = Vec3(0.822000,0.379000,2.086000); -positions[246] = Vec3(0.560000,2.562000,2.227000); -positions[247] = Vec3(0.863000,2.417000,0.050000); -positions[248] = Vec3(1.263000,0.151000,2.332000); -positions[249] = Vec3(0.237000,0.208000,2.336000); -positions[250] = Vec3(0.437000,2.370000,1.910000); -positions[251] = Vec3(1.119000,2.058000,2.207000); -positions[252] = Vec3(1.960000,1.749000,0.118000); -positions[253] = Vec3(2.415000,0.870000,2.757000); -positions[254] = Vec3(1.781000,0.342000,0.366000); -positions[255] = Vec3(2.172000,1.279000,1.421000); -positions[256] = Vec3(1.986000,0.715000,1.301000); -positions[257] = Vec3(1.657000,1.804000,0.810000); -positions[258] = Vec3(2.405000,1.202000,0.416000); -positions[259] = Vec3(1.932000,1.457000,0.786000); -positions[260] = Vec3(1.901000,1.271000,1.207000); -positions[261] = Vec3(1.864000,0.301000,0.810000); -positions[262] = Vec3(1.658000,0.673000,1.558000); -positions[263] = Vec3(2.637000,2.247000,0.396000); -positions[264] = Vec3(1.353000,0.369000,1.438000); -positions[265] = Vec3(0.530000,2.688000,1.346000); -positions[266] = Vec3(0.237000,0.485000,1.047000); -positions[267] = Vec3(2.806000,0.601000,0.822000); -positions[268] = Vec3(1.617000,2.018000,2.136000); -positions[269] = Vec3(2.000000,2.898000,0.022000); -positions[270] = Vec3(2.049000,1.883000,1.001000); -positions[271] = Vec3(2.477000,0.355000,1.786000); -positions[272] = Vec3(1.646000,0.983000,1.266000); -positions[273] = Vec3(1.683000,2.097000,1.114000); -positions[274] = Vec3(2.161000,0.921000,1.065000); -positions[275] = Vec3(2.099000,0.463000,1.942000); -positions[276] = Vec3(2.561000,1.638000,0.572000); -positions[277] = Vec3(2.205000,0.395000,1.005000); -positions[278] = Vec3(2.836000,0.203000,0.698000); -positions[279] = Vec3(2.662000,0.909000,0.966000); -positions[280] = Vec3(0.334000,0.350000,2.767000); -positions[281] = Vec3(2.241000,2.934000,1.248000); -positions[282] = Vec3(2.599000,2.953000,0.921000); -positions[283] = Vec3(2.219000,0.262000,0.058000); -positions[284] = Vec3(0.274000,0.656000,1.456000); -positions[285] = Vec3(1.814000,1.008000,0.882000); -positions[286] = Vec3(2.793000,1.395000,0.316000); -positions[287] = Vec3(0.773000,1.753000,1.639000); -positions[288] = Vec3(2.321000,0.994000,1.591000); -positions[289] = Vec3(2.243000,2.255000,1.690000); -positions[290] = Vec3(0.178000,1.342000,0.327000); -positions[291] = Vec3(1.623000,1.756000,1.426000); -positions[292] = Vec3(2.252000,0.109000,0.375000); -positions[293] = Vec3(3.003000,1.895000,1.895000); -positions[294] = Vec3(0.407000,0.831000,2.756000); -positions[295] = Vec3(2.193000,0.956000,0.632000); -positions[296] = Vec3(2.405000,0.641000,1.107000); -positions[297] = Vec3(2.361000,0.958000,0.162000); -positions[298] = Vec3(2.173000,1.544000,0.528000); -positions[299] = Vec3(1.565000,1.380000,1.428000); -positions[300] = Vec3(2.342000,0.538000,0.253000); -positions[301] = Vec3(1.910000,0.701000,0.954000); -positions[302] = Vec3(2.910000,0.288000,2.938000); -positions[303] = Vec3(0.257000,1.189000,0.958000); -positions[304] = Vec3(0.134000,1.775000,1.243000); -positions[305] = Vec3(2.476000,1.583000,1.956000); -positions[306] = Vec3(1.838000,1.791000,2.354000); -positions[307] = Vec3(1.906000,1.338000,1.696000); -positions[308] = Vec3(2.413000,2.869000,0.166000); -positions[309] = Vec3(3.006000,1.038000,1.322000); -positions[310] = Vec3(1.961000,0.962000,1.605000); -positions[311] = Vec3(0.082000,2.857000,0.020000); -positions[312] = Vec3(2.408000,1.499000,0.062000); -positions[313] = Vec3(2.349000,0.267000,1.415000); -positions[314] = Vec3(2.327000,1.717000,2.350000); -positions[315] = Vec3(2.928000,0.810000,1.582000); -positions[316] = Vec3(2.150000,0.336000,0.576000); -positions[317] = Vec3(2.664000,1.085000,2.962000); -positions[318] = Vec3(2.851000,0.670000,1.174000); -positions[319] = Vec3(1.954000,1.013000,1.975000); -positions[320] = Vec3(2.474000,1.542000,1.545000); -positions[321] = Vec3(2.826000,0.455000,1.490000); -positions[322] = Vec3(2.140000,2.826000,0.558000); -positions[323] = Vec3(2.151000,1.684000,1.780000); -positions[324] = Vec3(0.174000,0.673000,0.397000); -positions[325] = Vec3(0.066000,1.708000,0.160000); -positions[326] = Vec3(2.158000,0.303000,2.582000); -positions[327] = Vec3(2.602000,1.611000,2.632000); -positions[328] = Vec3(2.566000,1.138000,2.465000); -positions[329] = Vec3(2.026000,1.443000,2.477000); -positions[330] = Vec3(2.365000,0.309000,2.255000); -positions[331] = Vec3(1.636000,1.107000,2.058000); -positions[332] = Vec3(2.522000,2.584000,2.399000); -positions[333] = Vec3(2.537000,2.900000,2.158000); -positions[334] = Vec3(2.660000,0.537000,2.577000); -positions[335] = Vec3(2.679000,1.158000,1.724000); -positions[336] = Vec3(0.220000,1.894000,2.498000); -positions[337] = Vec3(2.266000,1.248000,1.837000); -positions[338] = Vec3(0.055000,1.656000,2.128000); -positions[339] = Vec3(2.899000,1.902000,2.823000); -positions[340] = Vec3(0.085000,2.994000,2.720000); -positions[341] = Vec3(0.013000,0.889000,2.468000); -positions[342] = Vec3(1.804000,0.372000,1.636000); -positions[343] = Vec3(0.201000,1.616000,2.824000); -positions[344] = Vec3(0.369000,1.273000,2.699000); -positions[345] = Vec3(2.996000,0.355000,2.596000); -positions[346] = Vec3(2.867000,1.314000,2.107000); -positions[347] = Vec3(2.611000,0.563000,2.140000); -positions[348] = Vec3(2.676000,2.954000,2.955000); -positions[349] = Vec3(0.256000,0.848000,2.062000); -positions[350] = Vec3(2.530000,0.028000,2.528000); -positions[351] = Vec3(0.537000,1.273000,1.596000); -positions[352] = Vec3(0.004000,1.004000,0.401000); -positions[353] = Vec3(1.676000,1.060000,2.463000); -positions[354] = Vec3(2.622000,1.473000,2.257000); -positions[355] = Vec3(2.917000,2.991000,2.316000); -positions[356] = Vec3(0.672000,1.123000,2.984000); -positions[357] = Vec3(2.229000,1.806000,2.673000); -positions[358] = Vec3(0.463000,0.951000,2.383000); -positions[359] = Vec3(2.126000,0.049000,2.037000); -positions[360] = Vec3(2.868000,0.876000,2.015000); -positions[361] = Vec3(2.720000,2.582000,0.079000); -positions[362] = Vec3(1.966000,0.693000,2.624000); -positions[363] = Vec3(1.971000,0.398000,2.318000); -positions[364] = Vec3(0.337000,0.630000,2.458000); -positions[365] = Vec3(2.562000,1.044000,2.040000); -positions[366] = Vec3(2.817000,1.485000,2.963000); -positions[367] = Vec3(2.514000,0.621000,2.992000); -positions[368] = Vec3(3.000000,1.551000,2.496000); -positions[369] = Vec3(0.698000,2.167000,2.180000); -positions[370] = Vec3(2.693000,0.849000,2.389000); -positions[371] = Vec3(2.092000,2.565000,2.986000); -positions[372] = Vec3(2.010000,3.001000,0.819000); -positions[373] = Vec3(2.392000,2.622000,1.636000); -positions[374] = Vec3(2.086000,2.325000,1.340000); -positions[375] = Vec3(2.578000,2.971000,0.502000); -positions[376] = Vec3(1.871000,2.789000,2.225000); -positions[377] = Vec3(2.230000,2.985000,1.594000); -positions[378] = Vec3(2.860000,2.788000,0.729000); -positions[379] = Vec3(2.051000,1.928000,1.472000); -positions[380] = Vec3(2.307000,2.219000,1.067000); -positions[381] = Vec3(2.369000,2.572000,1.289000); -positions[382] = Vec3(2.206000,1.924000,0.693000); -positions[383] = Vec3(1.984000,2.058000,2.005000); -positions[384] = Vec3(2.287000,1.854000,0.317000); -positions[385] = Vec3(2.525000,0.345000,0.686000); -positions[386] = Vec3(2.933000,1.920000,1.053000); -positions[387] = Vec3(0.324000,2.324000,0.601000); -positions[388] = Vec3(2.042000,1.576000,1.277000); -positions[389] = Vec3(0.031000,2.376000,0.949000); -positions[390] = Vec3(2.519000,2.250000,1.465000); -positions[391] = Vec3(0.221000,2.722000,1.652000); -positions[392] = Vec3(2.409000,2.361000,2.051000); -positions[393] = Vec3(2.472000,1.917000,1.673000); -positions[394] = Vec3(0.999000,2.715000,0.562000); -positions[395] = Vec3(1.669000,0.017000,1.508000); -positions[396] = Vec3(1.924000,1.777000,0.542000); -positions[397] = Vec3(2.635000,2.634000,1.905000); -positions[398] = Vec3(2.042000,2.628000,1.025000); -positions[399] = Vec3(2.694000,1.974000,2.009000); -positions[400] = Vec3(2.988000,2.221000,1.333000); -positions[401] = Vec3(1.772000,0.196000,1.978000); -positions[402] = Vec3(2.893000,2.961000,0.283000); -positions[403] = Vec3(2.615000,0.261000,0.245000); -positions[404] = Vec3(2.797000,2.521000,1.412000); -positions[405] = Vec3(0.013000,2.497000,0.246000); -positions[406] = Vec3(1.875000,2.861000,1.801000); -positions[407] = Vec3(2.800000,2.617000,1.049000); -positions[408] = Vec3(2.824000,1.858000,1.487000); -positions[409] = Vec3(2.434000,1.868000,1.275000); -positions[410] = Vec3(2.814000,0.526000,0.384000); -positions[411] = Vec3(2.844000,2.545000,2.246000); -positions[412] = Vec3(1.896000,2.587000,0.719000); -positions[413] = Vec3(0.350000,0.055000,0.076000); -positions[414] = Vec3(2.686000,1.784000,0.222000); -positions[415] = Vec3(2.724000,1.604000,0.989000); -positions[416] = Vec3(0.807000,1.761000,1.122000); -positions[417] = Vec3(2.120000,2.382000,2.226000); -positions[418] = Vec3(2.058000,1.587000,2.067000); -positions[419] = Vec3(2.904000,2.571000,2.686000); -positions[420] = Vec3(2.228000,2.910000,2.410000); -positions[421] = Vec3(2.797000,2.142000,0.114000); -positions[422] = Vec3(2.905000,1.875000,0.480000); -positions[423] = Vec3(1.881000,2.565000,2.469000); -positions[424] = Vec3(2.404000,1.929000,2.999000); -positions[425] = Vec3(2.389000,2.814000,2.782000); -positions[426] = Vec3(2.520000,0.301000,2.815000); -positions[427] = Vec3(2.726000,1.907000,2.339000); -positions[428] = Vec3(2.880000,2.273000,2.500000); -positions[429] = Vec3(2.574000,2.045000,2.716000); -positions[430] = Vec3(2.988000,2.288000,2.001000); -positions[431] = Vec3(0.011000,2.341000,2.904000); -positions[432] = Vec3(0.215000,2.265000,2.257000); -positions[433] = Vec3(2.268000,2.311000,0.234000); -positions[434] = Vec3(2.462000,2.621000,0.550000); -positions[435] = Vec3(1.530000,2.540000,2.728000); -positions[436] = Vec3(2.162000,2.306000,2.687000); -positions[437] = Vec3(2.748000,2.301000,1.734000); -positions[438] = Vec3(2.334000,1.976000,2.041000); -positions[439] = Vec3(1.981000,2.076000,2.443000); -positions[440] = Vec3(2.301000,1.367000,2.665000); -positions[441] = Vec3(2.399000,2.164000,2.403000); -positions[442] = Vec3(0.244000,2.713000,2.257000); -positions[443] = Vec3(0.683000,0.488000,2.781000); -positions[444] = Vec3(2.194000,2.711000,1.993000); -positions[445] = Vec3(2.947000,2.848000,2.001000); -positions[446] = Vec3(0.223000,1.981000,2.913000); -positions[447] = Vec3(0.010000,1.226000,0.917000); -positions[448] = Vec3(1.911000,0.426000,0.582000); -positions[449] = Vec3(2.204000,0.015000,0.136000); -positions[450] = Vec3(0.927000,0.138000,1.645000); -positions[451] = Vec3(0.155000,0.885000,1.479000); -positions[452] = Vec3(1.550000,1.933000,1.261000); -positions[453] = Vec3(1.304000,0.407000,0.287000); -positions[454] = Vec3(0.270000,1.384000,2.910000); -positions[455] = Vec3(0.516000,1.817000,1.695000); -positions[456] = Vec3(1.458000,2.879000,1.523000); -positions[457] = Vec3(1.702000,1.670000,0.593000); -positions[458] = Vec3(1.974000,1.380000,0.534000); -positions[459] = Vec3(2.835000,1.185000,0.479000); -positions[460] = Vec3(0.548000,2.979000,1.126000); -positions[461] = Vec3(1.202000,2.174000,1.466000); -positions[462] = Vec3(1.237000,1.701000,0.653000); -positions[463] = Vec3(2.939000,0.761000,0.349000); -positions[464] = Vec3(1.667000,2.119000,0.377000); -positions[465] = Vec3(1.196000,0.552000,1.372000); -positions[466] = Vec3(1.416000,0.901000,1.178000); -positions[467] = Vec3(0.519000,1.577000,2.227000); -positions[468] = Vec3(1.214000,1.281000,1.063000); -positions[469] = Vec3(0.822000,0.433000,1.375000); -positions[470] = Vec3(0.095000,2.760000,0.604000); -positions[471] = Vec3(1.325000,2.144000,1.848000); -positions[472] = Vec3(0.681000,0.896000,1.285000); -positions[473] = Vec3(0.406000,2.936000,0.717000); -positions[474] = Vec3(0.565000,1.852000,0.349000); -positions[475] = Vec3(0.597000,1.651000,1.020000); -positions[476] = Vec3(1.236000,0.170000,1.335000); -positions[477] = Vec3(0.586000,0.441000,1.980000); -positions[478] = Vec3(1.443000,1.208000,1.575000); -positions[479] = Vec3(0.247000,0.243000,0.502000); -positions[480] = Vec3(1.386000,1.564000,0.236000); -positions[481] = Vec3(0.871000,1.063000,0.930000); -positions[482] = Vec3(0.136000,0.992000,0.621000); -positions[483] = Vec3(0.889000,0.986000,0.010000); -positions[484] = Vec3(1.107000,2.731000,1.452000); -positions[485] = Vec3(0.942000,2.471000,0.517000); -positions[486] = Vec3(0.989000,0.652000,0.747000); -positions[487] = Vec3(0.899000,1.235000,2.707000); -positions[488] = Vec3(1.105000,0.684000,0.068000); -positions[489] = Vec3(1.660000,1.235000,2.276000); -positions[490] = Vec3(1.593000,1.883000,1.915000); -positions[491] = Vec3(1.528000,1.613000,0.920000); -positions[492] = Vec3(0.459000,1.046000,1.011000); -positions[493] = Vec3(0.213000,0.612000,0.644000); -positions[494] = Vec3(0.078000,1.392000,1.676000); -positions[495] = Vec3(0.605000,0.491000,0.574000); -positions[496] = Vec3(0.990000,1.586000,1.076000); -positions[497] = Vec3(0.297000,1.434000,1.028000); -positions[498] = Vec3(1.101000,1.471000,1.443000); -positions[499] = Vec3(0.072000,0.139000,1.653000); -positions[500] = Vec3(0.633000,0.884000,0.645000); -positions[501] = Vec3(0.352000,2.841000,1.463000); -positions[502] = Vec3(0.418000,0.774000,0.350000); -positions[503] = Vec3(2.641000,0.198000,0.869000); -positions[504] = Vec3(0.608000,1.341000,0.695000); -positions[505] = Vec3(1.778000,1.151000,1.830000); -positions[506] = Vec3(1.669000,0.342000,2.768000); -positions[507] = Vec3(1.256000,0.994000,0.798000); -positions[508] = Vec3(1.068000,0.375000,1.036000); -positions[509] = Vec3(0.910000,0.758000,1.589000); -positions[510] = Vec3(0.243000,2.452000,0.805000); -positions[511] = Vec3(1.018000,0.764000,1.122000); -positions[512] = Vec3(2.464000,1.089000,1.404000); -positions[513] = Vec3(0.670000,0.564000,0.034000); -positions[514] = Vec3(0.030000,1.296000,1.310000); -positions[515] = Vec3(1.210000,1.785000,1.691000); -positions[516] = Vec3(0.022000,0.620000,0.974000); -positions[517] = Vec3(1.499000,1.277000,2.986000); -positions[518] = Vec3(1.227000,1.896000,1.006000); -positions[519] = Vec3(0.528000,1.022000,1.635000); -positions[520] = Vec3(1.887000,2.670000,0.089000); -positions[521] = Vec3(1.661000,0.825000,0.793000); -positions[522] = Vec3(0.831000,1.494000,0.374000); -positions[523] = Vec3(1.356000,0.613000,0.930000); -positions[524] = Vec3(0.667000,0.600000,0.968000); -positions[525] = Vec3(1.154000,1.702000,2.925000); -positions[526] = Vec3(1.420000,1.581000,1.289000); -positions[527] = Vec3(1.383000,0.041000,0.932000); -positions[528] = Vec3(1.727000,0.140000,1.725000); -positions[529] = Vec3(0.711000,1.215000,2.004000); -positions[530] = Vec3(1.061000,1.067000,1.366000); -positions[531] = Vec3(0.377000,0.597000,1.224000); -positions[532] = Vec3(0.274000,0.719000,1.842000); -positions[533] = Vec3(0.840000,1.658000,1.874000); -positions[534] = Vec3(0.877000,0.290000,0.311000); -positions[535] = Vec3(2.130000,1.153000,1.196000); -positions[536] = Vec3(1.028000,1.379000,0.747000); -positions[537] = Vec3(1.107000,2.450000,2.079000); -positions[538] = Vec3(1.419000,1.333000,0.585000); -positions[539] = Vec3(0.430000,1.305000,1.369000); -positions[540] = Vec3(0.775000,1.363000,1.596000); -positions[541] = Vec3(1.522000,2.009000,0.736000); -positions[542] = Vec3(0.857000,1.722000,0.696000); -positions[543] = Vec3(0.722000,2.831000,1.478000); -positions[544] = Vec3(0.411000,1.673000,0.681000); -positions[545] = Vec3(1.511000,0.456000,0.597000); -positions[546] = Vec3(2.684000,0.820000,2.996000); -positions[547] = Vec3(1.593000,1.713000,2.369000); -positions[548] = Vec3(1.113000,0.803000,1.958000); -positions[549] = Vec3(1.267000,1.095000,0.254000); -positions[550] = Vec3(2.120000,0.540000,2.477000); -positions[551] = Vec3(0.566000,1.409000,2.588000); -positions[552] = Vec3(0.261000,0.872000,2.546000); -positions[553] = Vec3(1.878000,1.446000,2.680000); -positions[554] = Vec3(0.878000,1.606000,2.658000); -positions[555] = Vec3(1.564000,0.749000,1.786000); -positions[556] = Vec3(1.412000,1.942000,2.625000); -positions[557] = Vec3(1.660000,1.114000,2.710000); -positions[558] = Vec3(1.118000,0.813000,2.424000); -positions[559] = Vec3(1.482000,0.893000,2.434000); -positions[560] = Vec3(1.093000,1.129000,1.740000); -positions[561] = Vec3(2.163000,0.849000,2.709000); -positions[562] = Vec3(1.201000,1.429000,1.957000); -positions[563] = Vec3(0.235000,2.258000,2.002000); -positions[564] = Vec3(0.413000,1.444000,0.314000); -positions[565] = Vec3(0.164000,0.450000,2.408000); -positions[566] = Vec3(1.551000,0.851000,0.033000); -positions[567] = Vec3(0.659000,0.228000,2.807000); -positions[568] = Vec3(0.741000,0.131000,2.124000); -positions[569] = Vec3(0.455000,0.567000,2.682000); -positions[570] = Vec3(0.729000,0.971000,2.408000); -positions[571] = Vec3(1.487000,2.820000,0.162000); -positions[572] = Vec3(1.855000,0.700000,2.858000); -positions[573] = Vec3(0.305000,1.074000,1.926000); -positions[574] = Vec3(1.300000,0.153000,1.747000); -positions[575] = Vec3(1.272000,1.249000,2.568000); -positions[576] = Vec3(0.431000,0.743000,2.238000); -positions[577] = Vec3(0.493000,0.240000,0.184000); -positions[578] = Vec3(1.734000,0.506000,2.317000); -positions[579] = Vec3(0.874000,0.631000,2.692000); -positions[580] = Vec3(0.473000,2.790000,2.161000); -positions[581] = Vec3(1.310000,0.571000,2.759000); -positions[582] = Vec3(0.677000,0.798000,1.916000); -positions[583] = Vec3(0.944000,0.442000,1.858000); -positions[584] = Vec3(3.006000,2.098000,2.976000); -positions[585] = Vec3(0.864000,0.592000,2.231000); -positions[586] = Vec3(1.366000,0.611000,2.147000); -positions[587] = Vec3(2.871000,1.217000,2.880000); -positions[588] = Vec3(1.674000,2.664000,2.336000); -positions[589] = Vec3(1.757000,0.879000,2.101000); -positions[590] = Vec3(1.293000,2.939000,2.457000); -positions[591] = Vec3(1.108000,1.131000,2.206000); -positions[592] = Vec3(1.207000,1.658000,2.498000); -positions[593] = Vec3(0.850000,1.373000,2.312000); -positions[594] = Vec3(1.413000,1.060000,1.939000); -positions[595] = Vec3(1.138000,0.140000,2.102000); -positions[596] = Vec3(0.752000,1.307000,1.190000); -positions[597] = Vec3(1.254000,0.942000,2.790000); -positions[598] = Vec3(1.544000,1.614000,2.800000); -positions[599] = Vec3(2.128000,0.302000,2.833000); -positions[600] = Vec3(0.300000,1.744000,0.027000); -positions[601] = Vec3(1.878000,2.986000,2.060000); -positions[602] = Vec3(1.528000,0.233000,2.045000); -positions[603] = Vec3(1.146000,1.817000,2.067000); -positions[604] = Vec3(1.037000,2.746000,0.813000); -positions[605] = Vec3(0.524000,0.610000,1.566000); -positions[606] = Vec3(0.945000,2.964000,0.503000); -positions[607] = Vec3(1.788000,2.565000,0.965000); -positions[608] = Vec3(0.471000,2.510000,0.491000); -positions[609] = Vec3(0.512000,2.043000,1.371000); -positions[610] = Vec3(2.316000,2.423000,1.494000); -positions[611] = Vec3(1.575000,2.394000,2.953000); -positions[612] = Vec3(2.845000,2.869000,0.985000); -positions[613] = Vec3(1.016000,2.335000,1.003000); -positions[614] = Vec3(0.998000,2.830000,1.879000); -positions[615] = Vec3(0.624000,2.508000,0.075000); -positions[616] = Vec3(1.362000,2.808000,2.069000); -positions[617] = Vec3(1.747000,0.068000,0.810000); -positions[618] = Vec3(1.768000,2.355000,0.661000); -positions[619] = Vec3(1.535000,2.410000,2.085000); -positions[620] = Vec3(0.844000,2.004000,1.646000); -positions[621] = Vec3(1.124000,0.280000,0.649000); -positions[622] = Vec3(0.689000,2.170000,0.648000); -positions[623] = Vec3(0.849000,2.666000,1.175000); -positions[624] = Vec3(2.975000,1.963000,1.308000); -positions[625] = Vec3(1.074000,2.082000,0.714000); -positions[626] = Vec3(1.284000,2.651000,1.110000); -positions[627] = Vec3(1.669000,0.205000,0.180000); -positions[628] = Vec3(1.716000,0.047000,1.253000); -positions[629] = Vec3(0.501000,2.241000,1.043000); -positions[630] = Vec3(1.038000,1.833000,0.305000); -positions[631] = Vec3(0.646000,2.431000,1.424000); -positions[632] = Vec3(1.383000,2.059000,2.230000); -positions[633] = Vec3(0.370000,2.566000,1.192000); -positions[634] = Vec3(1.355000,2.006000,0.120000); -positions[635] = Vec3(2.113000,0.075000,0.589000); -positions[636] = Vec3(1.850000,0.448000,1.890000); -positions[637] = Vec3(1.215000,2.704000,0.405000); -positions[638] = Vec3(0.575000,2.997000,1.798000); -positions[639] = Vec3(0.967000,2.586000,2.603000); -positions[640] = Vec3(0.276000,1.669000,1.430000); -positions[641] = Vec3(1.483000,2.284000,1.128000); -positions[642] = Vec3(0.983000,3.003000,1.099000); -positions[643] = Vec3(0.539000,2.222000,1.720000); -positions[644] = Vec3(0.648000,2.826000,2.751000); -positions[645] = Vec3(0.803000,1.994000,0.993000); -positions[646] = Vec3(0.451000,0.216000,1.438000); -positions[647] = Vec3(1.604000,2.512000,0.334000); -positions[648] = Vec3(1.980000,2.022000,0.588000); -positions[649] = Vec3(1.843000,2.834000,1.544000); -positions[650] = Vec3(1.835000,3.005000,2.858000); -positions[651] = Vec3(0.679000,2.499000,0.838000); -positions[652] = Vec3(0.012000,2.637000,1.524000); -positions[653] = Vec3(0.314000,2.065000,0.602000); -positions[654] = Vec3(1.157000,0.004000,0.173000); -positions[655] = Vec3(0.736000,1.705000,1.382000); -positions[656] = Vec3(1.511000,2.736000,0.690000); -positions[657] = Vec3(1.330000,2.541000,1.735000); -positions[658] = Vec3(0.744000,0.170000,0.785000); -positions[659] = Vec3(2.593000,2.794000,0.703000); -positions[660] = Vec3(0.275000,1.872000,1.043000); -positions[661] = Vec3(1.624000,2.608000,1.341000); -positions[662] = Vec3(1.382000,0.122000,2.855000); -positions[663] = Vec3(1.326000,2.434000,0.783000); -positions[664] = Vec3(0.117000,0.116000,1.254000); -positions[665] = Vec3(1.045000,2.970000,2.748000); -positions[666] = Vec3(1.341000,2.692000,2.799000); -positions[667] = Vec3(1.797000,2.586000,2.709000); -positions[668] = Vec3(0.890000,2.484000,1.716000); -positions[669] = Vec3(2.373000,2.558000,1.889000); -positions[670] = Vec3(1.566000,2.323000,2.574000); -positions[671] = Vec3(1.257000,2.280000,0.399000); -positions[672] = Vec3(0.679000,2.130000,2.434000); -positions[673] = Vec3(2.016000,2.334000,2.462000); -positions[674] = Vec3(1.077000,2.213000,2.416000); -positions[675] = Vec3(0.581000,1.950000,2.081000); -positions[676] = Vec3(0.805000,2.315000,2.810000); -positions[677] = Vec3(0.844000,1.787000,2.322000); -positions[678] = Vec3(0.980000,2.205000,0.129000); -positions[679] = Vec3(2.468000,0.603000,2.740000); -positions[680] = Vec3(2.366000,2.403000,2.299000); -positions[681] = Vec3(0.337000,2.487000,2.329000); -positions[682] = Vec3(2.007000,2.793000,2.452000); -positions[683] = Vec3(1.072000,2.571000,0.063000); -positions[684] = Vec3(1.217000,2.283000,2.806000); -positions[685] = Vec3(0.459000,2.477000,2.728000); -positions[686] = Vec3(0.958000,1.975000,2.710000); -positions[687] = Vec3(0.914000,2.111000,2.052000); -positions[688] = Vec3(0.768000,2.958000,0.075000); -positions[689] = Vec3(0.474000,1.805000,2.533000); -positions[690] = Vec3(1.313000,2.552000,2.395000); -positions[691] = Vec3(1.853000,2.014000,2.229000); -positions[692] = Vec3(2.405000,2.230000,2.658000); -positions[693] = Vec3(0.727000,1.781000,0.016000); -positions[694] = Vec3(0.974000,2.791000,2.271000); -positions[695] = Vec3(0.438000,0.096000,2.457000); -positions[696] = Vec3(0.652000,2.392000,2.064000); -positions[697] = Vec3(1.972000,2.209000,2.834000); -positions[698] = Vec3(0.333000,0.141000,2.088000); -positions[699] = Vec3(1.813000,1.952000,0.063000); -positions[700] = Vec3(0.166000,2.838000,1.877000); -positions[701] = Vec3(1.772000,0.487000,0.951000); -positions[702] = Vec3(1.924000,1.404000,1.434000); -positions[703] = Vec3(2.734000,0.348000,1.712000); -positions[704] = Vec3(2.874000,0.729000,1.811000); -positions[705] = Vec3(1.841000,0.877000,1.137000); -positions[706] = Vec3(2.327000,1.491000,1.768000); -positions[707] = Vec3(1.916000,1.483000,1.057000); -positions[708] = Vec3(2.783000,0.850000,0.745000); -positions[709] = Vec3(1.829000,1.526000,0.085000); -positions[710] = Vec3(2.426000,1.082000,0.652000); -positions[711] = Vec3(1.645000,1.241000,1.217000); -positions[712] = Vec3(2.286000,0.725000,0.084000); -positions[713] = Vec3(2.755000,0.691000,1.421000); -positions[714] = Vec3(2.651000,0.591000,1.023000); -positions[715] = Vec3(2.040000,0.863000,0.442000); -positions[716] = Vec3(0.035000,0.109000,2.497000); -positions[717] = Vec3(0.127000,1.410000,0.572000); -positions[718] = Vec3(2.174000,0.357000,0.307000); -positions[719] = Vec3(2.705000,1.508000,0.758000); -positions[720] = Vec3(2.223000,1.407000,2.913000); -positions[721] = Vec3(2.528000,1.722000,1.088000); -positions[722] = Vec3(2.860000,0.345000,0.198000); -positions[723] = Vec3(2.580000,1.789000,1.479000); -positions[724] = Vec3(2.779000,0.295000,1.295000); -positions[725] = Vec3(0.097000,0.434000,2.826000); -positions[726] = Vec3(2.952000,1.654000,1.091000); -positions[727] = Vec3(0.119000,1.878000,0.343000); -positions[728] = Vec3(1.718000,1.173000,0.327000); -positions[729] = Vec3(2.833000,0.016000,0.527000); -positions[730] = Vec3(2.085000,1.779000,2.888000); -positions[731] = Vec3(2.754000,2.952000,1.485000); -positions[732] = Vec3(2.826000,0.935000,1.162000); -positions[733] = Vec3(1.564000,1.585000,1.615000); -positions[734] = Vec3(2.132000,0.645000,1.093000); -positions[735] = Vec3(2.294000,1.490000,1.350000); -positions[736] = Vec3(0.081000,0.490000,1.479000); -positions[737] = Vec3(2.118000,1.165000,1.642000); -positions[738] = Vec3(2.141000,0.121000,1.390000); -positions[739] = Vec3(2.385000,0.389000,1.196000); -positions[740] = Vec3(0.049000,0.166000,0.817000); -positions[741] = Vec3(1.993000,0.806000,1.814000); -positions[742] = Vec3(0.006000,1.450000,0.171000); -positions[743] = Vec3(2.297000,0.428000,0.764000); -positions[744] = Vec3(2.851000,0.469000,2.114000); -positions[745] = Vec3(1.814000,1.957000,0.945000); -positions[746] = Vec3(0.386000,0.327000,0.902000); -positions[747] = Vec3(2.452000,1.070000,1.807000); -positions[748] = Vec3(2.309000,1.537000,2.159000); -positions[749] = Vec3(2.712000,1.497000,2.007000); -positions[750] = Vec3(1.727000,0.924000,1.503000); -positions[751] = Vec3(0.861000,0.801000,0.344000); -positions[752] = Vec3(1.740000,1.245000,0.819000); -positions[753] = Vec3(0.117000,0.042000,0.197000); -positions[754] = Vec3(2.557000,0.996000,0.317000); -positions[755] = Vec3(2.228000,1.588000,2.548000); -positions[756] = Vec3(2.849000,1.557000,2.708000); -positions[757] = Vec3(0.152000,1.107000,0.219000); -positions[758] = Vec3(2.460000,1.318000,1.002000); -positions[759] = Vec3(2.405000,1.436000,0.528000); -positions[760] = Vec3(2.135000,1.179000,2.046000); -positions[761] = Vec3(1.726000,0.588000,0.286000); -positions[762] = Vec3(2.831000,1.053000,1.538000); -positions[763] = Vec3(1.932000,1.556000,1.833000); -positions[764] = Vec3(2.423000,0.900000,1.064000); -positions[765] = Vec3(3.001000,1.807000,0.709000); -positions[766] = Vec3(0.578000,1.095000,0.223000); -positions[767] = Vec3(2.215000,1.160000,0.252000); -positions[768] = Vec3(2.050000,0.921000,0.835000); -positions[769] = Vec3(2.080000,1.682000,0.738000); -positions[770] = Vec3(2.851000,1.753000,0.027000); -positions[771] = Vec3(0.203000,0.509000,0.202000); -positions[772] = Vec3(1.967000,1.018000,0.018000); -positions[773] = Vec3(1.869000,0.878000,2.472000); -positions[774] = Vec3(1.917000,0.228000,2.507000); -positions[775] = Vec3(0.316000,0.795000,2.991000); -positions[776] = Vec3(2.175000,1.229000,2.472000); -positions[777] = Vec3(2.405000,1.062000,2.931000); -positions[778] = Vec3(2.501000,0.511000,2.369000); -positions[779] = Vec3(2.641000,0.819000,2.141000); -positions[780] = Vec3(0.649000,1.384000,3.006000); -positions[781] = Vec3(1.012000,0.329000,2.963000); -positions[782] = Vec3(2.755000,0.350000,2.718000); -positions[783] = Vec3(2.315000,0.153000,2.454000); -positions[784] = Vec3(2.583000,1.696000,2.389000); -positions[785] = Vec3(0.439000,2.593000,1.776000); -positions[786] = Vec3(2.630000,1.390000,0.116000); -positions[787] = Vec3(2.854000,0.669000,2.478000); -positions[788] = Vec3(2.551000,1.342000,2.621000); -positions[789] = Vec3(2.533000,2.734000,2.987000); -positions[790] = Vec3(2.772000,2.446000,2.875000); -positions[791] = Vec3(2.817000,1.051000,2.498000); -positions[792] = Vec3(2.688000,1.404000,1.621000); -positions[793] = Vec3(0.083000,2.737000,2.775000); -positions[794] = Vec3(2.514000,0.322000,2.041000); -positions[795] = Vec3(2.470000,0.900000,2.504000); -positions[796] = Vec3(2.790000,0.444000,0.624000); -positions[797] = Vec3(0.040000,0.840000,2.202000); -positions[798] = Vec3(0.530000,1.067000,2.764000); -positions[799] = Vec3(0.191000,1.385000,2.541000); -positions[800] = Vec3(2.465000,0.363000,0.051000); -positions[801] = Vec3(1.850000,1.902000,2.592000); -positions[802] = Vec3(1.432000,0.306000,2.449000); -positions[803] = Vec3(2.259000,0.489000,1.753000); -positions[804] = Vec3(2.803000,1.118000,1.956000); -positions[805] = Vec3(2.426000,0.147000,1.636000); -positions[806] = Vec3(2.880000,1.846000,2.133000); -positions[807] = Vec3(2.862000,2.110000,1.867000); -positions[808] = Vec3(0.424000,1.184000,2.299000); -positions[809] = Vec3(2.518000,1.218000,2.228000); -positions[810] = Vec3(2.153000,0.834000,1.468000); -positions[811] = Vec3(0.105000,1.397000,2.088000); -positions[812] = Vec3(2.579000,0.601000,0.316000); -positions[813] = Vec3(2.594000,2.106000,2.968000); -positions[814] = Vec3(0.448000,1.435000,1.783000); -positions[815] = Vec3(2.125000,0.299000,2.132000); -positions[816] = Vec3(2.849000,1.402000,2.356000); -positions[817] = Vec3(2.956000,0.091000,2.078000); -positions[818] = Vec3(0.156000,1.696000,2.357000); -positions[819] = Vec3(1.566000,2.211000,1.557000); -positions[820] = Vec3(2.047000,0.194000,0.985000); -positions[821] = Vec3(1.947000,2.680000,0.488000); -positions[822] = Vec3(2.343000,2.796000,1.447000); -positions[823] = Vec3(2.006000,2.332000,0.265000); -positions[824] = Vec3(2.396000,1.834000,0.546000); -positions[825] = Vec3(2.538000,2.059000,2.207000); -positions[826] = Vec3(0.110000,2.360000,0.447000); -positions[827] = Vec3(2.198000,2.448000,1.136000); -positions[828] = Vec3(2.420000,2.121000,1.271000); -positions[829] = Vec3(0.422000,2.192000,0.260000); -positions[830] = Vec3(2.145000,2.767000,2.839000); -positions[831] = Vec3(2.434000,2.398000,0.421000); -positions[832] = Vec3(2.489000,2.175000,1.718000); -positions[833] = Vec3(2.870000,2.527000,0.814000); -positions[834] = Vec3(2.741000,2.016000,0.337000); -positions[835] = Vec3(1.997000,2.574000,2.107000); -positions[836] = Vec3(0.002000,2.128000,0.932000); -positions[837] = Vec3(2.787000,2.375000,0.234000); -positions[838] = Vec3(2.235000,1.852000,1.620000); -positions[839] = Vec3(2.782000,1.642000,0.422000); -positions[840] = Vec3(2.915000,1.760000,1.699000); -positions[841] = Vec3(2.047000,2.178000,1.549000); -positions[842] = Vec3(1.808000,1.878000,1.556000); -positions[843] = Vec3(2.224000,2.043000,0.913000); -positions[844] = Vec3(2.619000,2.611000,1.237000); -positions[845] = Vec3(2.916000,2.726000,0.168000); -positions[846] = Vec3(2.021000,2.833000,1.176000); -positions[847] = Vec3(2.967000,2.308000,2.258000); -positions[848] = Vec3(2.778000,2.270000,1.477000); -positions[849] = Vec3(2.121000,1.834000,2.002000); -positions[850] = Vec3(2.097000,2.752000,0.808000); -positions[851] = Vec3(1.897000,0.566000,1.501000); -positions[852] = Vec3(0.359000,2.802000,0.036000); -positions[853] = Vec3(2.966000,2.454000,1.186000); -positions[854] = Vec3(2.461000,2.964000,1.132000); -positions[855] = Vec3(2.093000,1.821000,1.243000); -positions[856] = Vec3(1.706000,2.659000,1.841000); -positions[857] = Vec3(2.074000,1.709000,0.342000); -positions[858] = Vec3(2.137000,2.894000,1.813000); -positions[859] = Vec3(0.223000,2.293000,1.417000); -positions[860] = Vec3(2.637000,0.007000,0.197000); -positions[861] = Vec3(1.416000,0.050000,0.483000); -positions[862] = Vec3(1.845000,2.250000,1.251000); -positions[863] = Vec3(2.906000,0.034000,2.896000); -positions[864] = Vec3(2.481000,0.204000,0.474000); -positions[865] = Vec3(2.234000,2.051000,0.158000); -positions[866] = Vec3(0.185000,2.453000,0.055000); -positions[867] = Vec3(2.509000,0.048000,2.786000); -positions[868] = Vec3(2.202000,2.206000,2.027000); -positions[869] = Vec3(0.061000,2.367000,2.656000); -positions[870] = Vec3(3.003000,2.755000,2.241000); -positions[871] = Vec3(0.297000,2.131000,2.463000); -positions[872] = Vec3(1.553000,0.429000,1.573000); -positions[873] = Vec3(2.506000,1.832000,1.911000); -positions[874] = Vec3(2.472000,1.814000,2.759000); -positions[875] = Vec3(1.922000,1.563000,2.278000); -positions[876] = Vec3(2.623000,2.666000,2.169000); -positions[877] = Vec3(0.120000,1.834000,2.723000); -positions[878] = Vec3(0.294000,0.103000,2.826000); -positions[879] = Vec3(2.364000,2.821000,0.417000); -positions[880] = Vec3(2.446000,1.734000,0.153000); -positions[881] = Vec3(2.777000,2.037000,2.565000); -positions[882] = Vec3(2.837000,2.477000,1.924000); -positions[883] = Vec3(2.221000,1.961000,2.443000); -positions[884] = Vec3(2.284000,2.895000,2.157000); -positions[885] = Vec3(2.728000,2.880000,1.861000); -positions[886] = Vec3(0.454000,2.080000,2.868000); -positions[887] = Vec3(2.430000,2.790000,2.524000); -positions[888] = Vec3(1.808000,2.213000,1.899000); -positions[889] = Vec3(2.666000,0.053000,2.309000); -positions[890] = Vec3(2.290000,2.408000,2.995000); -positions[891] = Vec3(2.646000,2.592000,1.625000); -positions[892] = Vec3(2.750000,2.508000,2.489000); -positions[893] = Vec3(0.211000,1.753000,1.939000); diff --git a/platforms/reference/tests/nacl_amorph_GromacsForcesEwald.dat b/platforms/reference/tests/nacl_amorph_GromacsForcesEwald.dat deleted file mode 100644 index 1a48685b3..000000000 --- a/platforms/reference/tests/nacl_amorph_GromacsForcesEwald.dat +++ /dev/null @@ -1,894 +0,0 @@ -ASSERT_EQUAL_VEC(Vec3(-1.98249623e+02, -2.23814501e+02, -1.02563796e+02), forces1[0], tol); -ASSERT_EQUAL_VEC(Vec3( 4.44017199e+02, -3.90390764e+02, -8.09518867e+01), forces1[1], tol); -ASSERT_EQUAL_VEC(Vec3(-8.60789585e+01, -1.05598857e+01, -1.87798624e+02), forces1[2], tol); -ASSERT_EQUAL_VEC(Vec3( 7.05363534e+02, -1.69549058e+02, 2.72466252e+02), forces1[3], tol); -ASSERT_EQUAL_VEC(Vec3(-2.19333527e+01, 5.33284079e+02, -4.56197740e+01), forces1[4], tol); -ASSERT_EQUAL_VEC(Vec3(-3.04281837e+02, 2.02941152e+02, 1.20252918e+02), forces1[5], tol); -ASSERT_EQUAL_VEC(Vec3( 1.14210928e+02, 1.21079746e+02, 3.40929279e+02), forces1[6], tol); -ASSERT_EQUAL_VEC(Vec3(-4.02295448e+01, 3.78740176e+02, 1.07262493e+02), forces1[7], tol); -ASSERT_EQUAL_VEC(Vec3( 9.42807014e+01, 1.00891659e+01, 1.57729175e+02), forces1[8], tol); -ASSERT_EQUAL_VEC(Vec3( 2.98424830e+02, 1.18614285e+02, -4.17503362e+02), forces1[9], tol); -ASSERT_EQUAL_VEC(Vec3( 4.74881296e+01, -5.56206792e+00, -1.92332367e+02), forces1[10], tol); -ASSERT_EQUAL_VEC(Vec3(-3.61201909e+02, 4.00192313e+02, -3.38469181e+02), forces1[11], tol); -ASSERT_EQUAL_VEC(Vec3( 1.59855287e+02, -2.22184057e+02, -1.71814608e+02), forces1[12], tol); -ASSERT_EQUAL_VEC(Vec3( 8.02099562e+01, -2.46176977e+02, 1.49725960e+02), forces1[13], tol); -ASSERT_EQUAL_VEC(Vec3(-2.41478578e+02, -8.22327152e+01, -4.19802587e+02), forces1[14], tol); -ASSERT_EQUAL_VEC(Vec3(-2.42767767e+02, 4.99651070e+00, 1.89314504e+01), forces1[15], tol); -ASSERT_EQUAL_VEC(Vec3(-2.32048202e+02, 2.91141605e+02, -1.56147406e+02), forces1[16], tol); -ASSERT_EQUAL_VEC(Vec3(-8.77435572e+01, -4.75580602e+02, -2.02736231e+02), forces1[17], tol); -ASSERT_EQUAL_VEC(Vec3( 3.96101687e+02, -6.37149049e+02, 1.78647561e+02), forces1[18], tol); -ASSERT_EQUAL_VEC(Vec3( 3.72219707e+02, 1.17763530e+02, 2.14244129e+02), forces1[19], tol); -ASSERT_EQUAL_VEC(Vec3( 4.50062822e+02, -1.37575208e+01, 2.39948230e+02), forces1[20], tol); -ASSERT_EQUAL_VEC(Vec3( 2.00029587e+02, 3.30130171e+01, 8.51610501e+01), forces1[21], tol); -ASSERT_EQUAL_VEC(Vec3( 1.97192878e+02, 7.33293743e+02, 2.15221280e+01), forces1[22], tol); -ASSERT_EQUAL_VEC(Vec3(-1.44377368e+02, 9.15716307e+01, 3.18892747e+01), forces1[23], tol); -ASSERT_EQUAL_VEC(Vec3( 2.94552317e+02, -3.69040394e+02, 2.70288945e+00), forces1[24], tol); -ASSERT_EQUAL_VEC(Vec3( 3.23120142e+02, 8.86114454e+02, 3.24450894e+02), forces1[25], tol); -ASSERT_EQUAL_VEC(Vec3(-6.03295072e+01, 1.68456989e+02, 2.31869997e+02), forces1[26], tol); -ASSERT_EQUAL_VEC(Vec3( 2.93194241e+01, 5.76413549e+01, 3.64010103e+02), forces1[27], tol); -ASSERT_EQUAL_VEC(Vec3( 3.27452172e-01, 1.34469263e+02, -4.39755475e+01), forces1[28], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38717677e+02, -2.99570604e+02, -2.80339165e+02), forces1[29], tol); -ASSERT_EQUAL_VEC(Vec3(-8.27937873e+01, 4.40618490e+02, 9.65587062e+01), forces1[30], tol); -ASSERT_EQUAL_VEC(Vec3( 2.03855205e+01, -4.37745725e+01, -5.06881413e+01), forces1[31], tol); -ASSERT_EQUAL_VEC(Vec3(-2.60745980e+02, 3.70683505e+02, 1.28613276e+02), forces1[32], tol); -ASSERT_EQUAL_VEC(Vec3( 1.97960989e+02, -1.51970994e+01, -2.85732029e+02), forces1[33], tol); -ASSERT_EQUAL_VEC(Vec3(-2.63675933e+01, -1.29448310e+01, -2.36632787e+02), forces1[34], tol); -ASSERT_EQUAL_VEC(Vec3( 2.13614470e+02, -2.29632590e+02, -7.72843645e+02), forces1[35], tol); -ASSERT_EQUAL_VEC(Vec3(-4.26287747e+01, 9.00718113e+01, 3.48807737e+02), forces1[36], tol); -ASSERT_EQUAL_VEC(Vec3(-2.27779547e+02, -8.46450565e+00, -3.25578367e+02), forces1[37], tol); -ASSERT_EQUAL_VEC(Vec3(-8.32052751e+01, -2.50968185e+02, 5.80103845e+01), forces1[38], tol); -ASSERT_EQUAL_VEC(Vec3(-2.32232234e+02, 1.30470270e+02, 6.06495521e+00), forces1[39], tol); -ASSERT_EQUAL_VEC(Vec3(-1.14455494e+02, -3.48721419e+01, -8.76129455e+01), forces1[40], tol); -ASSERT_EQUAL_VEC(Vec3(-2.55340689e+02, -2.79204188e+02, -1.68792912e+02), forces1[41], tol); -ASSERT_EQUAL_VEC(Vec3(-2.02307452e+02, 1.47895858e+02, 1.75220456e+02), forces1[42], tol); -ASSERT_EQUAL_VEC(Vec3( 2.63185604e+01, -4.46985150e+02, -2.38821173e+00), forces1[43], tol); -ASSERT_EQUAL_VEC(Vec3( 2.55944000e+02, -2.93439747e+02, 3.28025974e+02), forces1[44], tol); -ASSERT_EQUAL_VEC(Vec3( 1.14311082e+02, 2.24380865e+02, -8.29696179e+01), forces1[45], tol); -ASSERT_EQUAL_VEC(Vec3( 1.43326861e+01, 2.46491923e+02, -3.75165407e+02), forces1[46], tol); -ASSERT_EQUAL_VEC(Vec3(-4.34792273e+02, -9.73250775e+01, -1.91085096e+02), forces1[47], tol); -ASSERT_EQUAL_VEC(Vec3( 5.23123306e+01, 5.50975366e+02, 2.90221875e+02), forces1[48], tol); -ASSERT_EQUAL_VEC(Vec3(-4.83894734e+01, 1.71476996e+02, -3.42294535e+02), forces1[49], tol); -ASSERT_EQUAL_VEC(Vec3(-2.61463419e+02, 9.01733107e+01, 3.64114372e+02), forces1[50], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43625180e+02, -5.19324924e+02, -7.74662441e+01), forces1[51], tol); -ASSERT_EQUAL_VEC(Vec3( 2.15611073e+02, -5.54577351e+02, 1.71371860e+02), forces1[52], tol); -ASSERT_EQUAL_VEC(Vec3(-2.14763168e+02, 3.56711285e+02, -3.71984643e+02), forces1[53], tol); -ASSERT_EQUAL_VEC(Vec3( 2.22124509e+02, 2.73223318e+02, 1.61942563e+02), forces1[54], tol); -ASSERT_EQUAL_VEC(Vec3( 2.85121911e+02, 3.19143598e+02, -1.98763562e+02), forces1[55], tol); -ASSERT_EQUAL_VEC(Vec3( 3.90039513e+02, 5.91179187e+02, 8.76217046e+01), forces1[56], tol); -ASSERT_EQUAL_VEC(Vec3( 1.69060954e+02, -9.43142940e+01, 3.42180838e+02), forces1[57], tol); -ASSERT_EQUAL_VEC(Vec3( 2.93242309e+01, -1.03060738e+02, 5.38025654e+01), forces1[58], tol); -ASSERT_EQUAL_VEC(Vec3( 4.09077298e+01, 1.30026064e+02, -7.16489622e+01), forces1[59], tol); -ASSERT_EQUAL_VEC(Vec3(-1.89926185e+02, 5.52058739e+00, 4.53549674e+02), forces1[60], tol); -ASSERT_EQUAL_VEC(Vec3(-1.11572641e+02, 1.24178624e+02, 4.53016222e+02), forces1[61], tol); -ASSERT_EQUAL_VEC(Vec3( 1.54599730e+02, -2.70150115e+02, -7.89492689e+01), forces1[62], tol); -ASSERT_EQUAL_VEC(Vec3( 2.84023026e+02, -8.89934391e+01, 3.24522873e+02), forces1[63], tol); -ASSERT_EQUAL_VEC(Vec3( 1.44364280e+02, -7.96613821e+01, -2.53253756e+02), forces1[64], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77719009e+02, 8.42958696e+01, -1.41078307e+02), forces1[65], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69676443e+02, -5.26499439e+02, -1.04061540e+02), forces1[66], tol); -ASSERT_EQUAL_VEC(Vec3(-2.41597419e+02, -9.41368613e+01, 3.30311173e+01), forces1[67], tol); -ASSERT_EQUAL_VEC(Vec3( 6.81038324e+02, -5.79215726e+02, -9.61706079e-01), forces1[68], tol); -ASSERT_EQUAL_VEC(Vec3( 2.88768459e+02, 2.41571264e+02, -1.90674774e+02), forces1[69], tol); -ASSERT_EQUAL_VEC(Vec3(-1.31534697e+01, 1.14188032e+01, 4.13763857e+01), forces1[70], tol); -ASSERT_EQUAL_VEC(Vec3( 5.14246004e+01, -9.72308438e+01, 1.27291275e+01), forces1[71], tol); -ASSERT_EQUAL_VEC(Vec3( 7.15804377e+01, -1.94144101e+02, -2.48994830e+02), forces1[72], tol); -ASSERT_EQUAL_VEC(Vec3(-9.16897832e+01, 1.23379998e+02, -2.86172337e+02), forces1[73], tol); -ASSERT_EQUAL_VEC(Vec3( 9.82636682e+01, -7.07069901e+01, -1.29205135e+02), forces1[74], tol); -ASSERT_EQUAL_VEC(Vec3(-2.15565256e+02, -1.43101075e+02, -1.96437192e+02), forces1[75], tol); -ASSERT_EQUAL_VEC(Vec3(-4.61171340e+02, -4.03099962e+02, -4.56004212e+01), forces1[76], tol); -ASSERT_EQUAL_VEC(Vec3( 1.52879441e+02, -9.37786956e+02, 2.93596349e+02), forces1[77], tol); -ASSERT_EQUAL_VEC(Vec3( 2.45712108e+02, 1.99809051e+01, 1.17930077e+02), forces1[78], tol); -ASSERT_EQUAL_VEC(Vec3(-2.37060951e+02, 2.49499642e+02, 2.13427566e+02), forces1[79], tol); -ASSERT_EQUAL_VEC(Vec3(-2.90549561e+02, 1.91148461e+02, -4.24254939e+02), forces1[80], tol); -ASSERT_EQUAL_VEC(Vec3( 2.98836434e+02, -5.77088507e+00, 2.66616885e+02), forces1[81], tol); -ASSERT_EQUAL_VEC(Vec3(-3.26780820e+02, -2.54755214e+02, -3.00078477e+02), forces1[82], tol); -ASSERT_EQUAL_VEC(Vec3(-2.95124543e+02, 1.21754917e+02, -2.83484560e+02), forces1[83], tol); -ASSERT_EQUAL_VEC(Vec3( 4.04593126e+02, 1.66803214e+02, -5.58277653e+01), forces1[84], tol); -ASSERT_EQUAL_VEC(Vec3(-8.21659385e+02, 5.19877016e+02, 5.32042741e+01), forces1[85], tol); -ASSERT_EQUAL_VEC(Vec3(-3.49440439e+02, -1.47667513e+02, -4.95516065e+02), forces1[86], tol); -ASSERT_EQUAL_VEC(Vec3(-4.48873387e+02, -7.41398759e+01, -4.28615258e+02), forces1[87], tol); -ASSERT_EQUAL_VEC(Vec3(-1.97035390e+02, -3.40619723e+02, 2.10014966e+00), forces1[88], tol); -ASSERT_EQUAL_VEC(Vec3( 9.52521998e+01, -4.20785075e+02, 5.76686444e+01), forces1[89], tol); -ASSERT_EQUAL_VEC(Vec3( 1.21817965e+02, -1.40423441e+02, -2.93286277e+02), forces1[90], tol); -ASSERT_EQUAL_VEC(Vec3( 2.10624944e+02, 5.87898789e+01, 7.23535437e+01), forces1[91], tol); -ASSERT_EQUAL_VEC(Vec3( 6.72728656e+01, -1.46951701e+02, -2.63713434e+02), forces1[92], tol); -ASSERT_EQUAL_VEC(Vec3( 3.96770378e+02, -4.38652663e+02, -2.57914104e+02), forces1[93], tol); -ASSERT_EQUAL_VEC(Vec3(-2.66188937e+01, 1.59124875e+01, 4.36635801e+02), forces1[94], tol); -ASSERT_EQUAL_VEC(Vec3(-3.00011356e+02, -6.20659688e+01, -4.29149613e+02), forces1[95], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77048319e+02, 5.58928761e+01, 1.05662322e+02), forces1[96], tol); -ASSERT_EQUAL_VEC(Vec3(-6.92523247e+01, -5.45436653e+02, -2.10975756e+01), forces1[97], tol); -ASSERT_EQUAL_VEC(Vec3(-3.90136268e+01, -1.21131977e+02, 1.68383284e+01), forces1[98], tol); -ASSERT_EQUAL_VEC(Vec3(-2.19709988e+01, 1.51713780e+02, -3.39192065e+01), forces1[99], tol); -ASSERT_EQUAL_VEC(Vec3( 9.20577922e+01, -4.22560191e+02, -1.80919327e+01), forces1[100], tol); -ASSERT_EQUAL_VEC(Vec3( 5.80665653e+01, 1.45405257e+02, -4.53162940e+01), forces1[101], tol); -ASSERT_EQUAL_VEC(Vec3( 6.12566193e+02, -1.41221826e+01, 2.13579029e+02), forces1[102], tol); -ASSERT_EQUAL_VEC(Vec3(-1.02954777e+02, -8.76455433e+01, 2.20912307e+02), forces1[103], tol); -ASSERT_EQUAL_VEC(Vec3( 1.44791352e+02, -2.88999813e+02, 1.68134104e+02), forces1[104], tol); -ASSERT_EQUAL_VEC(Vec3( 9.68813543e+01, -2.62260178e+02, -3.07286290e+02), forces1[105], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09040958e+02, -2.43241310e+02, -2.45238041e+02), forces1[106], tol); -ASSERT_EQUAL_VEC(Vec3( 1.89550491e+02, 1.49319105e+02, -3.74285248e+02), forces1[107], tol); -ASSERT_EQUAL_VEC(Vec3( 1.20763399e+02, -1.66082622e+02, -4.46381843e+02), forces1[108], tol); -ASSERT_EQUAL_VEC(Vec3(-6.91025497e+02, 6.62244311e+02, 3.06047534e+01), forces1[109], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61280438e+02, 8.89755700e+01, -3.35630671e+01), forces1[110], tol); -ASSERT_EQUAL_VEC(Vec3(-4.17338144e+02, 4.26061590e+01, -7.77158559e+01), forces1[111], tol); -ASSERT_EQUAL_VEC(Vec3(-4.01742893e+01, 8.24881666e+01, 4.51855292e+02), forces1[112], tol); -ASSERT_EQUAL_VEC(Vec3(-1.40970558e+01, -2.40647487e+02, -1.27598454e+02), forces1[113], tol); -ASSERT_EQUAL_VEC(Vec3( 2.83839724e+02, 2.31041423e+02, 1.33456841e+01), forces1[114], tol); -ASSERT_EQUAL_VEC(Vec3( 5.10867089e+01, -7.13361227e+02, -4.07617467e+02), forces1[115], tol); -ASSERT_EQUAL_VEC(Vec3(-1.56090473e+02, -1.33121120e+02, 2.25952345e+02), forces1[116], tol); -ASSERT_EQUAL_VEC(Vec3( 3.69607528e+01, -1.35106805e+01, 1.10579378e+02), forces1[117], tol); -ASSERT_EQUAL_VEC(Vec3( 3.37809441e+02, 8.10519215e+01, -5.39817090e+01), forces1[118], tol); -ASSERT_EQUAL_VEC(Vec3( 5.49975558e+01, 7.55006073e+01, 1.80545525e+02), forces1[119], tol); -ASSERT_EQUAL_VEC(Vec3( 1.10971245e+02, -3.83971391e+02, 2.77991517e+01), forces1[120], tol); -ASSERT_EQUAL_VEC(Vec3(-2.63190529e+02, -3.16285880e+02, -3.95218767e+02), forces1[121], tol); -ASSERT_EQUAL_VEC(Vec3( 3.42556090e+02, -2.35748098e+02, 4.60355306e+02), forces1[122], tol); -ASSERT_EQUAL_VEC(Vec3( 2.47668934e+02, 2.42870015e+02, 1.52218275e+02), forces1[123], tol); -ASSERT_EQUAL_VEC(Vec3(-2.70198409e+02, 2.08574994e+02, -1.86859372e+02), forces1[124], tol); -ASSERT_EQUAL_VEC(Vec3( 3.24104326e+02, 2.55001752e+02, -1.10880955e+02), forces1[125], tol); -ASSERT_EQUAL_VEC(Vec3( 5.16197105e+02, -5.06150948e+01, -2.80857737e+02), forces1[126], tol); -ASSERT_EQUAL_VEC(Vec3(-3.30849573e+02, -3.47291965e+02, 1.45237748e+02), forces1[127], tol); -ASSERT_EQUAL_VEC(Vec3(-1.28356764e+02, 7.69134918e+01, 2.14911544e+02), forces1[128], tol); -ASSERT_EQUAL_VEC(Vec3(-1.91469755e+02, -2.11473339e+02, 1.35333200e+02), forces1[129], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69887152e+02, 1.11337990e+02, -8.98463460e+01), forces1[130], tol); -ASSERT_EQUAL_VEC(Vec3(-1.36374172e+02, -2.14238377e+02, -5.83866682e+01), forces1[131], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38562455e+02, 2.36128851e+02, -2.08960526e+01), forces1[132], tol); -ASSERT_EQUAL_VEC(Vec3(-2.47599869e+02, 3.98208933e+02, -1.64765063e+02), forces1[133], tol); -ASSERT_EQUAL_VEC(Vec3(-8.37476276e+01, 4.07965070e+02, -1.24163988e+02), forces1[134], tol); -ASSERT_EQUAL_VEC(Vec3(-1.60159071e+02, -6.49998978e+00, 3.55060364e+02), forces1[135], tol); -ASSERT_EQUAL_VEC(Vec3( 3.58249937e+02, -2.81395872e+02, -1.28020722e+02), forces1[136], tol); -ASSERT_EQUAL_VEC(Vec3( 3.33746078e+02, -3.31207307e+02, -2.41631386e+01), forces1[137], tol); -ASSERT_EQUAL_VEC(Vec3(-3.00676509e+02, -1.70097272e+02, 8.30597971e+01), forces1[138], tol); -ASSERT_EQUAL_VEC(Vec3(-1.94891185e+01, 1.35846931e+02, -3.65144038e+02), forces1[139], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77181788e+02, 4.44531481e+01, 2.11474121e+02), forces1[140], tol); -ASSERT_EQUAL_VEC(Vec3( 4.59275521e+02, -3.23637233e+02, 3.67800802e+02), forces1[141], tol); -ASSERT_EQUAL_VEC(Vec3( 4.22121423e+02, 2.22068413e+02, 2.92465809e+02), forces1[142], tol); -ASSERT_EQUAL_VEC(Vec3( 2.83763316e+02, -2.92602600e+02, 8.18013996e+01), forces1[143], tol); -ASSERT_EQUAL_VEC(Vec3(-5.70559390e+01, 2.40295170e+02, -3.40862650e+01), forces1[144], tol); -ASSERT_EQUAL_VEC(Vec3( 1.04075222e+02, 1.58996510e+02, 1.10304777e+01), forces1[145], tol); -ASSERT_EQUAL_VEC(Vec3( 5.88502616e+02, 2.07880339e+02, -7.36908474e+01), forces1[146], tol); -ASSERT_EQUAL_VEC(Vec3( 2.82632623e+02, 2.25995810e+02, 2.16745828e+02), forces1[147], tol); -ASSERT_EQUAL_VEC(Vec3(-2.02435189e+02, 1.65899995e+02, -1.47471730e+02), forces1[148], tol); -ASSERT_EQUAL_VEC(Vec3(-2.96622169e+02, -4.87423685e+02, 1.60844164e+02), forces1[149], tol); -ASSERT_EQUAL_VEC(Vec3( 2.94715891e+02, 1.30347848e+02, 2.82729974e+01), forces1[150], tol); -ASSERT_EQUAL_VEC(Vec3( 3.70885287e+02, 3.22229123e+01, 8.74581871e+01), forces1[151], tol); -ASSERT_EQUAL_VEC(Vec3( 3.43994702e+02, -2.07935556e+02, 3.49067383e+02), forces1[152], tol); -ASSERT_EQUAL_VEC(Vec3( 1.43099882e+01, -2.80336001e+02, 5.69626314e+01), forces1[153], tol); -ASSERT_EQUAL_VEC(Vec3( 9.71948870e+01, 1.42192042e+01, 1.00139441e+02), forces1[154], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56990028e+02, -1.87993683e+01, -1.07611017e+02), forces1[155], tol); -ASSERT_EQUAL_VEC(Vec3( 4.20275466e+02, 1.16943633e+02, 4.29575935e+02), forces1[156], tol); -ASSERT_EQUAL_VEC(Vec3(-2.05593618e+02, -2.74949188e+02, 1.32851151e+02), forces1[157], tol); -ASSERT_EQUAL_VEC(Vec3( 2.88917359e+01, 1.07824736e+01, -2.09437913e+02), forces1[158], tol); -ASSERT_EQUAL_VEC(Vec3(-4.54601782e+02, -2.58268961e+01, -2.66964578e+02), forces1[159], tol); -ASSERT_EQUAL_VEC(Vec3( 5.91049307e+02, -7.76470493e+01, 9.29094217e+01), forces1[160], tol); -ASSERT_EQUAL_VEC(Vec3(-8.26256556e+00, 2.39614788e+02, 1.04874825e+02), forces1[161], tol); -ASSERT_EQUAL_VEC(Vec3( 4.79904829e+01, -1.73703832e+02, -5.98140813e+01), forces1[162], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26007450e+02, 1.64300309e+02, -4.23289873e+02), forces1[163], tol); -ASSERT_EQUAL_VEC(Vec3(-2.03205374e+02, 1.46921807e+02, 2.50701909e+02), forces1[164], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38813652e+02, 1.32930267e+02, 2.75556760e+02), forces1[165], tol); -ASSERT_EQUAL_VEC(Vec3( 9.19035624e+01, -1.55653738e+02, 1.24210719e+02), forces1[166], tol); -ASSERT_EQUAL_VEC(Vec3( 2.09938122e+02, 1.26973729e+02, -3.32817155e+02), forces1[167], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56206143e+02, 6.10122855e+00, 3.42771101e+02), forces1[168], tol); -ASSERT_EQUAL_VEC(Vec3( 3.11438984e+02, 9.42198048e+01, -8.51953228e+00), forces1[169], tol); -ASSERT_EQUAL_VEC(Vec3( 1.78692126e+02, -1.36964221e+01, -2.21830640e+01), forces1[170], tol); -ASSERT_EQUAL_VEC(Vec3(-4.69093086e+01, 5.77169523e+02, 1.04262190e+02), forces1[171], tol); -ASSERT_EQUAL_VEC(Vec3( 1.31254187e+02, 7.57774979e+01, -9.08207172e+01), forces1[172], tol); -ASSERT_EQUAL_VEC(Vec3(-1.69436483e+02, -3.62015361e+02, 2.68889227e+02), forces1[173], tol); -ASSERT_EQUAL_VEC(Vec3(-1.68463797e+02, -2.62627703e+02, 7.41106664e+01), forces1[174], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53154790e+02, 2.68914173e+02, -3.92489521e+02), forces1[175], tol); -ASSERT_EQUAL_VEC(Vec3( 1.95110073e+02, -5.76611142e+01, 3.91951958e+02), forces1[176], tol); -ASSERT_EQUAL_VEC(Vec3( 2.43338357e+02, -3.91477149e+02, -8.63953114e+01), forces1[177], tol); -ASSERT_EQUAL_VEC(Vec3(-1.34179863e+02, 1.46591166e+02, 1.19878040e+02), forces1[178], tol); -ASSERT_EQUAL_VEC(Vec3( 1.63174304e+02, -2.66960106e+02, 1.65770978e+02), forces1[179], tol); -ASSERT_EQUAL_VEC(Vec3( 5.46495327e+01, 6.58671492e+01, -4.94244139e+02), forces1[180], tol); -ASSERT_EQUAL_VEC(Vec3(-1.62957088e+02, 1.53806002e+02, 2.72147870e+01), forces1[181], tol); -ASSERT_EQUAL_VEC(Vec3(-1.97769720e+02, -9.08099669e+01, -5.59653565e+02), forces1[182], tol); -ASSERT_EQUAL_VEC(Vec3(-9.59272102e+01, -3.67219179e+02, -1.37098968e+02), forces1[183], tol); -ASSERT_EQUAL_VEC(Vec3(-3.13273853e+02, -4.77528382e+02, -2.82320271e+02), forces1[184], tol); -ASSERT_EQUAL_VEC(Vec3( 3.47090516e+01, -1.51861017e+02, -2.71782882e+02), forces1[185], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09985174e+02, 7.60658358e+01, -1.90751868e+02), forces1[186], tol); -ASSERT_EQUAL_VEC(Vec3( 3.49595143e+02, 1.52747707e+02, 4.22488620e+02), forces1[187], tol); -ASSERT_EQUAL_VEC(Vec3(-3.59725754e+01, 3.55475701e+01, -7.87334885e+01), forces1[188], tol); -ASSERT_EQUAL_VEC(Vec3(-5.53788647e+02, 1.58101235e+02, -5.47105678e+01), forces1[189], tol); -ASSERT_EQUAL_VEC(Vec3( 8.55520733e+01, -2.88444498e+02, 2.54318577e+01), forces1[190], tol); -ASSERT_EQUAL_VEC(Vec3( 1.96800399e+02, 1.69077439e+02, 2.41074010e+02), forces1[191], tol); -ASSERT_EQUAL_VEC(Vec3( 7.64011738e+01, 3.05710609e+02, 2.76162549e+02), forces1[192], tol); -ASSERT_EQUAL_VEC(Vec3( 1.23265853e+02, 8.57500919e+01, 3.46722858e+02), forces1[193], tol); -ASSERT_EQUAL_VEC(Vec3(-9.05651135e+01, 5.50685032e+01, -4.12462772e+02), forces1[194], tol); -ASSERT_EQUAL_VEC(Vec3(-2.70875191e+00, 1.30545633e+02, -1.55140021e+02), forces1[195], tol); -ASSERT_EQUAL_VEC(Vec3(-1.37389162e+02, -2.94304654e+02, -1.24611408e+02), forces1[196], tol); -ASSERT_EQUAL_VEC(Vec3(-3.56088703e+02, -9.03800091e+01, 3.14895993e+02), forces1[197], tol); -ASSERT_EQUAL_VEC(Vec3(-7.79280727e+01, 1.12179786e+02, 3.86364249e+02), forces1[198], tol); -ASSERT_EQUAL_VEC(Vec3( 2.43080372e+02, 5.36466609e+02, -9.47357535e+01), forces1[199], tol); -ASSERT_EQUAL_VEC(Vec3(-7.39441823e+01, -3.53188450e+02, 1.42886370e+01), forces1[200], tol); -ASSERT_EQUAL_VEC(Vec3( 6.56556933e+02, -2.80423857e+02, 2.95738831e+02), forces1[201], tol); -ASSERT_EQUAL_VEC(Vec3(-2.72306632e+02, -1.44066176e+02, 2.55684522e+02), forces1[202], tol); -ASSERT_EQUAL_VEC(Vec3(-3.75638941e+01, 2.99415967e+02, -4.12490294e+02), forces1[203], tol); -ASSERT_EQUAL_VEC(Vec3( 3.64685442e+02, 3.39117459e+02, -8.08643870e+01), forces1[204], tol); -ASSERT_EQUAL_VEC(Vec3( 4.32799610e+02, -1.78895030e+02, 3.86635331e+02), forces1[205], tol); -ASSERT_EQUAL_VEC(Vec3(-9.04462035e+01, 3.89960088e+02, -5.47950733e+02), forces1[206], tol); -ASSERT_EQUAL_VEC(Vec3(-6.35043448e+02, 1.85486756e+01, 3.17016236e+01), forces1[207], tol); -ASSERT_EQUAL_VEC(Vec3(-5.92896097e+01, -2.85274924e+02, -1.42348620e+02), forces1[208], tol); -ASSERT_EQUAL_VEC(Vec3(-1.35207298e+02, -3.56081009e+02, 1.07991189e+02), forces1[209], tol); -ASSERT_EQUAL_VEC(Vec3( 3.94900105e+02, 9.99453126e+01, -1.57827968e+02), forces1[210], tol); -ASSERT_EQUAL_VEC(Vec3(-1.56528334e+02, -1.66144237e+02, -4.78550980e+00), forces1[211], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77280437e+02, -9.51924294e+01, -3.42048132e+02), forces1[212], tol); -ASSERT_EQUAL_VEC(Vec3( 2.97739381e+02, 7.18137153e+02, -4.94774385e+02), forces1[213], tol); -ASSERT_EQUAL_VEC(Vec3(-5.12807812e+02, 7.63618980e+02, -5.44479748e+01), forces1[214], tol); -ASSERT_EQUAL_VEC(Vec3(-2.55718099e+02, -4.46413837e+02, -1.72488334e+02), forces1[215], tol); -ASSERT_EQUAL_VEC(Vec3( 3.15155213e+02, 5.62372598e+02, 2.42573447e+02), forces1[216], tol); -ASSERT_EQUAL_VEC(Vec3(-2.90686044e+01, 3.91008419e+02, 1.36603112e+02), forces1[217], tol); -ASSERT_EQUAL_VEC(Vec3(-4.26382270e+02, 5.13937396e+02, 8.38021440e+01), forces1[218], tol); -ASSERT_EQUAL_VEC(Vec3(-2.88415254e+02, 6.41404241e+01, 3.02418529e+02), forces1[219], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13264423e+01, -3.20432026e+02, 1.98735533e+02), forces1[220], tol); -ASSERT_EQUAL_VEC(Vec3(-1.73201040e+02, 2.09799717e+02, 2.60748570e+02), forces1[221], tol); -ASSERT_EQUAL_VEC(Vec3( 4.34181587e+02, -1.25026352e+02, 2.52906543e+02), forces1[222], tol); -ASSERT_EQUAL_VEC(Vec3(-3.09528945e+02, 2.63415228e+02, -2.33523213e+02), forces1[223], tol); -ASSERT_EQUAL_VEC(Vec3( 8.65524156e+01, -5.32178407e+02, -2.36443769e+02), forces1[224], tol); -ASSERT_EQUAL_VEC(Vec3(-1.74965243e+02, -2.30177295e+02, -1.33679144e+02), forces1[225], tol); -ASSERT_EQUAL_VEC(Vec3( 1.53826901e+02, -1.24391764e+02, -3.93679341e+01), forces1[226], tol); -ASSERT_EQUAL_VEC(Vec3(-4.51778358e+02, -7.75156480e+01, -5.36133859e+02), forces1[227], tol); -ASSERT_EQUAL_VEC(Vec3( 5.99205686e+01, 2.97292572e+02, 5.99156789e+01), forces1[228], tol); -ASSERT_EQUAL_VEC(Vec3(-3.10624444e+02, 2.94567470e+00, -3.63693136e+01), forces1[229], tol); -ASSERT_EQUAL_VEC(Vec3( 3.85876747e+02, 1.41639709e+02, 2.75108543e+02), forces1[230], tol); -ASSERT_EQUAL_VEC(Vec3( 5.43221531e+02, -3.20245253e+02, -3.02057882e+01), forces1[231], tol); -ASSERT_EQUAL_VEC(Vec3( 3.85583563e+02, 6.64091011e+01, -3.49559777e+01), forces1[232], tol); -ASSERT_EQUAL_VEC(Vec3(-4.52863518e+02, -3.40704717e+02, 1.28905508e+02), forces1[233], tol); -ASSERT_EQUAL_VEC(Vec3( 9.34276939e+02, -1.39482274e+02, 3.57869403e+02), forces1[234], tol); -ASSERT_EQUAL_VEC(Vec3(-2.03067148e+02, 7.44441061e+01, 9.27320006e+01), forces1[235], tol); -ASSERT_EQUAL_VEC(Vec3(-5.97531539e+02, 1.26804078e+02, 2.78893030e+02), forces1[236], tol); -ASSERT_EQUAL_VEC(Vec3( 5.67860193e+02, -5.34681659e+02, -1.84230283e+02), forces1[237], tol); -ASSERT_EQUAL_VEC(Vec3( 2.13190333e+02, 2.99783610e+02, -2.66458597e+02), forces1[238], tol); -ASSERT_EQUAL_VEC(Vec3( 3.11473403e+01, 4.54685224e+02, 3.81034869e+01), forces1[239], tol); -ASSERT_EQUAL_VEC(Vec3( 1.57514487e+02, 3.19318405e+01, -1.57720436e+02), forces1[240], tol); -ASSERT_EQUAL_VEC(Vec3( 4.34917141e+02, -4.69320639e+02, -3.96620193e+01), forces1[241], tol); -ASSERT_EQUAL_VEC(Vec3(-3.54127895e+01, -1.00145510e+02, 7.07653587e+01), forces1[242], tol); -ASSERT_EQUAL_VEC(Vec3( 3.29669760e+02, 3.63920894e+02, -3.89179023e+02), forces1[243], tol); -ASSERT_EQUAL_VEC(Vec3( 7.63985812e+02, 2.97343162e+02, -5.39992884e+01), forces1[244], tol); -ASSERT_EQUAL_VEC(Vec3(-2.67917290e+02, 2.23564800e+02, -1.67266290e+02), forces1[245], tol); -ASSERT_EQUAL_VEC(Vec3(-6.45289709e+02, -9.38444040e+00, -5.71116404e+02), forces1[246], tol); -ASSERT_EQUAL_VEC(Vec3( 1.48220582e+02, -1.78737448e+02, 8.43814640e+01), forces1[247], tol); -ASSERT_EQUAL_VEC(Vec3( 3.26731869e+02, -3.84524983e+02, 2.88339532e+02), forces1[248], tol); -ASSERT_EQUAL_VEC(Vec3( 2.58365914e+02, 5.43905231e+01, 3.38641536e+02), forces1[249], tol); -ASSERT_EQUAL_VEC(Vec3(-3.51600062e+02, -3.06740536e+02, -2.99454859e+01), forces1[250], tol); -ASSERT_EQUAL_VEC(Vec3(-2.78580097e+01, 2.36156123e+02, 1.06081152e+01), forces1[251], tol); -ASSERT_EQUAL_VEC(Vec3(-1.75899733e+02, -9.38608562e+00, 1.84207408e+02), forces1[252], tol); -ASSERT_EQUAL_VEC(Vec3(-5.60399133e+02, 1.90145998e+02, -2.90215623e+02), forces1[253], tol); -ASSERT_EQUAL_VEC(Vec3(-1.69434526e+02, 2.23702263e+02, -3.41994449e+02), forces1[254], tol); -ASSERT_EQUAL_VEC(Vec3(-6.96578236e+01, 1.66438449e+02, -6.77499321e+00), forces1[255], tol); -ASSERT_EQUAL_VEC(Vec3( 2.73655591e+02, 1.49071325e+00, 7.80565008e+01), forces1[256], tol); -ASSERT_EQUAL_VEC(Vec3(-2.58366132e+02, 8.46288614e+01, -9.42098129e+01), forces1[257], tol); -ASSERT_EQUAL_VEC(Vec3(-4.25847146e+02, 9.84292470e+00, 6.39709870e+01), forces1[258], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12083087e+02, 6.10255158e+01, -1.38662830e+02), forces1[259], tol); -ASSERT_EQUAL_VEC(Vec3( 3.21828259e+01, 3.67493765e+02, 6.86972453e+01), forces1[260], tol); -ASSERT_EQUAL_VEC(Vec3(-3.72206379e+02, 3.36289489e+02, 3.15273168e+02), forces1[261], tol); -ASSERT_EQUAL_VEC(Vec3( 4.28443395e+01, 5.93339946e+01, 4.86905134e+02), forces1[262], tol); -ASSERT_EQUAL_VEC(Vec3( 3.03267567e+01, 3.70293845e+02, -5.83420472e+02), forces1[263], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61738517e+02, 3.70576503e+02, -2.03659425e+01), forces1[264], tol); -ASSERT_EQUAL_VEC(Vec3(-6.67229637e+02, -1.24339105e+01, -9.41959187e+01), forces1[265], tol); -ASSERT_EQUAL_VEC(Vec3( 4.66955725e+02, 3.49515015e+02, 2.04652411e+02), forces1[266], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52483062e+02, -1.24093769e+01, 2.24828418e+01), forces1[267], tol); -ASSERT_EQUAL_VEC(Vec3( 4.58746968e+01, -2.20898924e+02, 7.64552584e+01), forces1[268], tol); -ASSERT_EQUAL_VEC(Vec3(-4.43630058e+01, -1.14899930e+02, -2.87900025e+02), forces1[269], tol); -ASSERT_EQUAL_VEC(Vec3(-9.22312443e+01, 6.40883419e+02, 3.17836134e+02), forces1[270], tol); -ASSERT_EQUAL_VEC(Vec3(-2.15623653e+02, -2.05460783e+02, 6.85627383e+01), forces1[271], tol); -ASSERT_EQUAL_VEC(Vec3( 2.24218604e+02, -1.43080040e+02, -4.17826551e+01), forces1[272], tol); -ASSERT_EQUAL_VEC(Vec3( 1.79823435e+02, -3.72425962e+02, 2.12155872e+02), forces1[273], tol); -ASSERT_EQUAL_VEC(Vec3( 9.74694224e+01, 7.66864835e+01, -5.04542197e+02), forces1[274], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18132641e+01, -5.76171362e+02, -3.23926383e+02), forces1[275], tol); -ASSERT_EQUAL_VEC(Vec3(-2.97073240e+02, -1.47150317e+02, -1.56565197e+02), forces1[276], tol); -ASSERT_EQUAL_VEC(Vec3( 4.21710637e+01, -2.91447830e+02, -1.50257335e+02), forces1[277], tol); -ASSERT_EQUAL_VEC(Vec3( 1.75442608e+02, -9.12859677e+01, 6.45491342e+01), forces1[278], tol); -ASSERT_EQUAL_VEC(Vec3( 1.50392869e+02, -1.42464974e+02, 2.67956841e+02), forces1[279], tol); -ASSERT_EQUAL_VEC(Vec3(-4.86651400e+02, -2.18667898e+01, 1.45713495e+02), forces1[280], tol); -ASSERT_EQUAL_VEC(Vec3( 9.28412896e+01, -6.94874667e+01, -8.89080435e+00), forces1[281], tol); -ASSERT_EQUAL_VEC(Vec3(-5.85240520e+01, 2.84901112e+02, 4.82507287e+02), forces1[282], tol); -ASSERT_EQUAL_VEC(Vec3(-2.83558886e+01, -1.73735212e+02, -3.77887550e+02), forces1[283], tol); -ASSERT_EQUAL_VEC(Vec3(-4.34949543e+02, -1.30350821e+02, -3.31882572e+02), forces1[284], tol); -ASSERT_EQUAL_VEC(Vec3( 3.85307564e+01, -2.54990214e+02, -5.18576435e+02), forces1[285], tol); -ASSERT_EQUAL_VEC(Vec3(-7.78941445e+01, 1.25379603e+02, -3.80663737e+02), forces1[286], tol); -ASSERT_EQUAL_VEC(Vec3(-1.27210929e+02, 3.88670263e+02, 9.40643492e+01), forces1[287], tol); -ASSERT_EQUAL_VEC(Vec3( 1.39431191e+02, 4.03532370e+02, -4.33316557e+02), forces1[288], tol); -ASSERT_EQUAL_VEC(Vec3(-2.89025871e+00, -2.06301323e+02, -7.48588265e+02), forces1[289], tol); -ASSERT_EQUAL_VEC(Vec3( 1.07859207e+01, 2.35870879e+02, -1.38371079e+02), forces1[290], tol); -ASSERT_EQUAL_VEC(Vec3( 8.60427044e+01, 5.74941322e+02, 1.95760444e+02), forces1[291], tol); -ASSERT_EQUAL_VEC(Vec3(-2.45607229e+02, 1.95528757e+02, 1.22011573e+02), forces1[292], tol); -ASSERT_EQUAL_VEC(Vec3(-3.33845399e+02, -2.71367745e+02, -3.43358433e+02), forces1[293], tol); -ASSERT_EQUAL_VEC(Vec3(-4.28617139e+02, 1.60904342e+02, 2.18072650e+02), forces1[294], tol); -ASSERT_EQUAL_VEC(Vec3(-5.40064874e+02, -1.47448303e+02, 4.35229212e+02), forces1[295], tol); -ASSERT_EQUAL_VEC(Vec3( 1.48815476e+02, 3.45639218e+01, -1.25812382e+02), forces1[296], tol); -ASSERT_EQUAL_VEC(Vec3( 3.39107837e+02, 3.68504225e+01, 2.99572367e+01), forces1[297], tol); -ASSERT_EQUAL_VEC(Vec3(-1.67736264e+02, -2.84608426e+02, 3.88526274e+01), forces1[298], tol); -ASSERT_EQUAL_VEC(Vec3(-3.21480824e+02, -4.49315290e+02, 1.41881616e+02), forces1[299], tol); -ASSERT_EQUAL_VEC(Vec3( 1.16232320e+02, 6.79621131e+00, -1.08227149e+02), forces1[300], tol); -ASSERT_EQUAL_VEC(Vec3(-1.85570778e+02, -2.95260833e+02, 5.01922551e+02), forces1[301], tol); -ASSERT_EQUAL_VEC(Vec3( 9.27568700e+01, -3.83929681e+02, -2.77944844e+02), forces1[302], tol); -ASSERT_EQUAL_VEC(Vec3(-3.97618765e+01, 2.84553517e+02, 2.33447892e+02), forces1[303], tol); -ASSERT_EQUAL_VEC(Vec3( 1.40428160e+00, 2.25397804e+02, 9.47967922e+01), forces1[304], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06100768e+02, 2.06346469e+02, -2.00231208e+02), forces1[305], tol); -ASSERT_EQUAL_VEC(Vec3(-3.33973365e+02, -3.09218137e+01, -9.23886091e+01), forces1[306], tol); -ASSERT_EQUAL_VEC(Vec3( 1.47272865e+01, 1.47732830e+02, 2.61213219e+02), forces1[307], tol); -ASSERT_EQUAL_VEC(Vec3( 4.44151506e+01, 1.15101400e+02, 1.21319924e+02), forces1[308], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53470761e+02, 2.00350042e+02, 3.38960006e+01), forces1[309], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06594777e+02, -1.16077611e+02, 5.96359334e+01), forces1[310], tol); -ASSERT_EQUAL_VEC(Vec3(-2.01610478e+02, 4.15967754e+01, 4.19293914e+02), forces1[311], tol); -ASSERT_EQUAL_VEC(Vec3( 4.40516207e+02, 1.34417352e+02, 7.74205210e+01), forces1[312], tol); -ASSERT_EQUAL_VEC(Vec3(-3.89160154e+02, -2.83344572e+02, -4.23546685e+02), forces1[313], tol); -ASSERT_EQUAL_VEC(Vec3( 2.42068089e+02, -6.45978033e+02, 3.91506210e+02), forces1[314], tol); -ASSERT_EQUAL_VEC(Vec3(-3.71531404e+02, -4.54039493e+01, 5.02846871e+02), forces1[315], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52589600e+02, 8.61061306e+01, 2.63798519e+02), forces1[316], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18337261e+01, -1.24898517e+02, -2.32012734e+02), forces1[317], tol); -ASSERT_EQUAL_VEC(Vec3(-4.28763733e+02, 2.69298277e+02, -1.63307373e+02), forces1[318], tol); -ASSERT_EQUAL_VEC(Vec3( 6.90348283e+01, 2.01119799e+02, -1.25394407e+02), forces1[319], tol); -ASSERT_EQUAL_VEC(Vec3( 4.42904652e+01, -1.48495330e+02, 9.26084336e+01), forces1[320], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52950825e+01, 1.28676758e+02, -3.63357597e+02), forces1[321], tol); -ASSERT_EQUAL_VEC(Vec3(-5.24105679e+02, -9.42729828e+01, 1.18442536e+01), forces1[322], tol); -ASSERT_EQUAL_VEC(Vec3( 2.26120919e+02, 3.21635617e+02, -3.90518982e+02), forces1[323], tol); -ASSERT_EQUAL_VEC(Vec3( 3.59312804e+01, -3.07405817e+02, -5.38361197e+01), forces1[324], tol); -ASSERT_EQUAL_VEC(Vec3(-1.17174424e+02, 2.29573805e+02, 1.57259382e+02), forces1[325], tol); -ASSERT_EQUAL_VEC(Vec3(-9.86427642e+01, -2.13494062e+02, 9.34926885e+01), forces1[326], tol); -ASSERT_EQUAL_VEC(Vec3( 2.32229566e+02, 6.06664996e+01, -3.57479293e+02), forces1[327], tol); -ASSERT_EQUAL_VEC(Vec3(-4.16211931e+01, 1.12554898e+02, -2.00660318e+02), forces1[328], tol); -ASSERT_EQUAL_VEC(Vec3(-5.14819799e+01, 2.96285849e+02, 3.68505357e+02), forces1[329], tol); -ASSERT_EQUAL_VEC(Vec3( 1.02082491e+02, -9.70741301e+01, 3.02493232e+01), forces1[330], tol); -ASSERT_EQUAL_VEC(Vec3(-1.03774260e+02, -1.54760894e+02, 2.10251674e+02), forces1[331], tol); -ASSERT_EQUAL_VEC(Vec3( 1.90529911e+02, 6.04211367e+01, -9.59263387e+01), forces1[332], tol); -ASSERT_EQUAL_VEC(Vec3(-1.16797386e+02, -5.22831328e+02, 5.66578589e+02), forces1[333], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18104094e+02, -1.37421044e+02, 1.53038417e+02), forces1[334], tol); -ASSERT_EQUAL_VEC(Vec3(-9.04351491e+01, -1.47606538e+02, 8.89490712e+01), forces1[335], tol); -ASSERT_EQUAL_VEC(Vec3( 2.09976599e+01, -2.05500194e+02, 1.26830512e+02), forces1[336], tol); -ASSERT_EQUAL_VEC(Vec3(-1.68042754e+02, -2.97763125e+02, -1.20743571e+02), forces1[337], tol); -ASSERT_EQUAL_VEC(Vec3( 3.99127236e+02, 2.95151794e+02, 3.91132406e+02), forces1[338], tol); -ASSERT_EQUAL_VEC(Vec3( 6.84892471e+02, -2.36108313e+02, 3.42251555e+02), forces1[339], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26672745e+02, 1.75724905e+02, 1.84788262e+02), forces1[340], tol); -ASSERT_EQUAL_VEC(Vec3(-1.32600337e+01, 4.13643381e+01, -7.23942729e+01), forces1[341], tol); -ASSERT_EQUAL_VEC(Vec3(-2.77915476e+02, 3.10253507e+02, 1.84685854e+01), forces1[342], tol); -ASSERT_EQUAL_VEC(Vec3( 1.17778181e+02, 2.88287609e+02, 2.83205737e+02), forces1[343], tol); -ASSERT_EQUAL_VEC(Vec3(-2.14268136e+01, 5.21209080e+02, 1.00248187e+02), forces1[344], tol); -ASSERT_EQUAL_VEC(Vec3( 1.24343155e+02, -1.12330818e+02, 2.11958643e+02), forces1[345], tol); -ASSERT_EQUAL_VEC(Vec3( 6.50667567e+00, 2.20334635e+02, -3.03866910e+02), forces1[346], tol); -ASSERT_EQUAL_VEC(Vec3( 3.27052657e+02, 1.14360733e+02, 4.53348042e+02), forces1[347], tol); -ASSERT_EQUAL_VEC(Vec3( 3.89440847e+01, 3.55283477e+02, 2.25739503e+01), forces1[348], tol); -ASSERT_EQUAL_VEC(Vec3(-2.25235013e+02, -2.30566443e+02, -2.32657384e+02), forces1[349], tol); -ASSERT_EQUAL_VEC(Vec3(-4.40565237e+02, -4.18860845e+01, -8.73230334e+01), forces1[350], tol); -ASSERT_EQUAL_VEC(Vec3( 2.03282144e+02, -7.41935514e+01, -3.11210179e+02), forces1[351], tol); -ASSERT_EQUAL_VEC(Vec3( 3.14039162e+02, -4.52223142e+01, 1.15692941e+02), forces1[352], tol); -ASSERT_EQUAL_VEC(Vec3(-3.05758853e+02, -8.44053388e+01, 2.77050868e+02), forces1[353], tol); -ASSERT_EQUAL_VEC(Vec3( 6.03148128e+02, 7.49868064e+01, 1.08098034e+02), forces1[354], tol); -ASSERT_EQUAL_VEC(Vec3( 1.19374260e+02, 3.21999447e+02, 1.19594257e+01), forces1[355], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06938874e+02, 2.87582961e+01, 2.37371892e+02), forces1[356], tol); -ASSERT_EQUAL_VEC(Vec3( 3.21431483e+02, -7.92928539e+02, 4.18517370e+01), forces1[357], tol); -ASSERT_EQUAL_VEC(Vec3(-1.08651668e+02, 2.36736551e+02, -5.75424218e+02), forces1[358], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53739502e+02, -4.66583392e+02, 3.71587906e+02), forces1[359], tol); -ASSERT_EQUAL_VEC(Vec3(-1.56290228e+02, -8.97065131e+01, -3.26308160e+02), forces1[360], tol); -ASSERT_EQUAL_VEC(Vec3( 3.42780206e+02, -3.18082387e+01, -4.08917799e+02), forces1[361], tol); -ASSERT_EQUAL_VEC(Vec3( 1.47584556e+02, 4.76918724e+02, 4.19802714e+01), forces1[362], tol); -ASSERT_EQUAL_VEC(Vec3( 6.13790369e-01, -4.13596811e+01, 4.39898790e+02), forces1[363], tol); -ASSERT_EQUAL_VEC(Vec3(-2.56833301e+02, -1.83037454e+02, 5.99913896e+01), forces1[364], tol); -ASSERT_EQUAL_VEC(Vec3( 2.48242646e+02, 5.50143719e+01, -1.55138787e+01), forces1[365], tol); -ASSERT_EQUAL_VEC(Vec3(-1.93628316e+02, -1.86534319e+01, 6.08100347e-01), forces1[366], tol); -ASSERT_EQUAL_VEC(Vec3(-1.63211080e+02, 1.90023269e+02, -4.93452441e+02), forces1[367], tol); -ASSERT_EQUAL_VEC(Vec3(-2.85383893e+01, -4.66032637e+02, -2.10849424e+02), forces1[368], tol); -ASSERT_EQUAL_VEC(Vec3( 2.27151522e+02, 1.52613464e+01, -1.64052797e+02), forces1[369], tol); -ASSERT_EQUAL_VEC(Vec3(-1.07153893e+02, 2.01257828e+01, 6.04845684e+01), forces1[370], tol); -ASSERT_EQUAL_VEC(Vec3( 2.41332167e+02, 4.05683718e+02, -8.71412268e+01), forces1[371], tol); -ASSERT_EQUAL_VEC(Vec3( 1.33799918e+02, 1.72174836e+02, -1.15342391e+02), forces1[372], tol); -ASSERT_EQUAL_VEC(Vec3( 4.19296496e+02, -4.68248373e+02, -3.30514440e+02), forces1[373], tol); -ASSERT_EQUAL_VEC(Vec3(-1.88005342e+02, -2.43525310e+02, 8.87016270e+01), forces1[374], tol); -ASSERT_EQUAL_VEC(Vec3( 1.54021861e+02, 2.52343848e+02, 1.76403306e+02), forces1[375], tol); -ASSERT_EQUAL_VEC(Vec3(-1.10645837e+02, 3.33150389e+01, 1.23771287e+02), forces1[376], tol); -ASSERT_EQUAL_VEC(Vec3( 1.64776571e+02, 8.96065400e-01, 1.56210970e+02), forces1[377], tol); -ASSERT_EQUAL_VEC(Vec3(-1.65400014e+02, -1.50236349e+02, 2.41793992e+02), forces1[378], tol); -ASSERT_EQUAL_VEC(Vec3( 4.78064936e+02, -2.36432797e+02, 4.04933329e+02), forces1[379], tol); -ASSERT_EQUAL_VEC(Vec3(-2.33366235e+02, -7.47065850e+02, 1.09704004e+02), forces1[380], tol); -ASSERT_EQUAL_VEC(Vec3( 1.09391089e+02, -3.37517532e+02, 1.99876556e+02), forces1[381], tol); -ASSERT_EQUAL_VEC(Vec3( 1.45367287e+02, 1.34686504e+02, 3.46411849e+02), forces1[382], tol); -ASSERT_EQUAL_VEC(Vec3(-8.86938780e+01, 1.70740693e+02, 1.86633045e+02), forces1[383], tol); -ASSERT_EQUAL_VEC(Vec3( 1.03267086e+02, -2.54994757e+02, -2.04500741e+01), forces1[384], tol); -ASSERT_EQUAL_VEC(Vec3(-5.06124981e+02, -3.72066492e+02, 9.10787327e+01), forces1[385], tol); -ASSERT_EQUAL_VEC(Vec3( 4.33830100e+02, 5.30903070e+02, 1.18187318e+02), forces1[386], tol); -ASSERT_EQUAL_VEC(Vec3(-3.34819970e+02, 2.29884568e+02, 1.73578789e+02), forces1[387], tol); -ASSERT_EQUAL_VEC(Vec3(-3.26221462e+00, 3.50944116e+02, -5.69053250e+00), forces1[388], tol); -ASSERT_EQUAL_VEC(Vec3(-3.18235913e+02, -4.16037121e+02, 3.93503581e+00), forces1[389], tol); -ASSERT_EQUAL_VEC(Vec3(-9.01641240e+01, -2.83129838e+02, -1.78590049e+02), forces1[390], tol); -ASSERT_EQUAL_VEC(Vec3(-1.86933795e+02, 2.96536275e+02, -1.29641779e+02), forces1[391], tol); -ASSERT_EQUAL_VEC(Vec3(-7.78116915e+02, 3.37770325e+02, 2.46251396e+02), forces1[392], tol); -ASSERT_EQUAL_VEC(Vec3(-4.88284661e+02, -3.62815567e+02, 1.09199755e+02), forces1[393], tol); -ASSERT_EQUAL_VEC(Vec3( 1.68815587e+02, -1.54091010e+02, 2.44129524e+02), forces1[394], tol); -ASSERT_EQUAL_VEC(Vec3( 8.59930047e+01, -4.73421243e+02, 1.81326697e+02), forces1[395], tol); -ASSERT_EQUAL_VEC(Vec3(-5.15421845e+01, 3.80615163e+01, 1.48495241e+02), forces1[396], tol); -ASSERT_EQUAL_VEC(Vec3( 4.40902491e+02, -9.36772951e+01, 2.19937945e+02), forces1[397], tol); -ASSERT_EQUAL_VEC(Vec3( 4.55969069e+01, 5.74615780e+02, -5.74937832e+01), forces1[398], tol); -ASSERT_EQUAL_VEC(Vec3( 1.07815006e+02, -3.19754972e+02, 1.16024132e+01), forces1[399], tol); -ASSERT_EQUAL_VEC(Vec3(-1.73815462e+02, -1.72653517e+02, 3.26124498e+02), forces1[400], tol); -ASSERT_EQUAL_VEC(Vec3(-4.48598839e+02, -4.95402699e+02, -1.37769354e+02), forces1[401], tol); -ASSERT_EQUAL_VEC(Vec3( 1.43484140e+02, -7.71666828e+01, 1.27161815e+02), forces1[402], tol); -ASSERT_EQUAL_VEC(Vec3( 1.26016451e+02, -3.81399993e+02, -2.85764454e+02), forces1[403], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53052241e+02, -2.67885549e+02, 1.51849847e+02), forces1[404], tol); -ASSERT_EQUAL_VEC(Vec3(-1.01063516e+02, -1.79837645e+02, -2.05759531e+02), forces1[405], tol); -ASSERT_EQUAL_VEC(Vec3( 1.32065714e+02, -2.56988983e+02, -4.06119988e+02), forces1[406], tol); -ASSERT_EQUAL_VEC(Vec3( 5.49845413e+01, 5.21020888e+01, -2.40829321e+01), forces1[407], tol); -ASSERT_EQUAL_VEC(Vec3(-3.04151550e+01, -3.45385052e+02, 3.52732396e+02), forces1[408], tol); -ASSERT_EQUAL_VEC(Vec3( 5.76196622e+02, 2.51408790e+02, -2.05694905e+02), forces1[409], tol); -ASSERT_EQUAL_VEC(Vec3(-5.46232631e+02, -3.81426810e+01, 1.55940692e+02), forces1[410], tol); -ASSERT_EQUAL_VEC(Vec3(-1.00759671e+02, 2.13338964e+02, 3.33068075e+02), forces1[411], tol); -ASSERT_EQUAL_VEC(Vec3( 8.00270910e+01, 1.85305844e+02, -4.43363841e+02), forces1[412], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53961901e+02, 1.76452569e+01, 5.07044493e+01), forces1[413], tol); -ASSERT_EQUAL_VEC(Vec3(-2.54074128e+01, -1.01739609e+02, -1.47118371e+02), forces1[414], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53018564e+02, 2.89709169e+02, -1.78282141e+02), forces1[415], tol); -ASSERT_EQUAL_VEC(Vec3(-1.30257510e+02, -4.66610129e+02, -3.53374887e+02), forces1[416], tol); -ASSERT_EQUAL_VEC(Vec3( 1.82472116e+02, 3.77974857e+02, 1.90476251e+02), forces1[417], tol); -ASSERT_EQUAL_VEC(Vec3(-2.59801797e+02, 3.29708022e+02, 3.93439213e+02), forces1[418], tol); -ASSERT_EQUAL_VEC(Vec3(-1.08573872e+01, -5.30931700e+02, -1.53102646e+01), forces1[419], tol); -ASSERT_EQUAL_VEC(Vec3(-3.27827015e+01, -3.45915139e+02, -1.45604367e+02), forces1[420], tol); -ASSERT_EQUAL_VEC(Vec3(-1.92424159e+02, 3.69087390e+00, -1.26537763e+02), forces1[421], tol); -ASSERT_EQUAL_VEC(Vec3( 2.61430852e+02, -1.63239575e+02, -1.22742408e+02), forces1[422], tol); -ASSERT_EQUAL_VEC(Vec3(-1.42902423e+02, 4.15429338e+02, 5.04220960e+02), forces1[423], tol); -ASSERT_EQUAL_VEC(Vec3( 3.36581855e+02, -1.06051528e+02, 4.54169047e+02), forces1[424], tol); -ASSERT_EQUAL_VEC(Vec3(-2.32221397e+02, -1.86391490e+00, 4.48412526e+01), forces1[425], tol); -ASSERT_EQUAL_VEC(Vec3( 4.12435657e+02, -5.04677016e+02, 4.00894902e+02), forces1[426], tol); -ASSERT_EQUAL_VEC(Vec3(-1.54630518e+02, -2.68571764e+02, -1.52962938e+01), forces1[427], tol); -ASSERT_EQUAL_VEC(Vec3( 2.69725750e+02, 2.18570974e+02, -1.75370463e+02), forces1[428], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77174496e+01, -4.66383654e+01, 6.24325771e+01), forces1[429], tol); -ASSERT_EQUAL_VEC(Vec3(-1.29891497e+02, 8.07513513e+01, 1.84796034e+01), forces1[430], tol); -ASSERT_EQUAL_VEC(Vec3( 1.76173623e+02, -3.20023221e+02, -2.47794470e+02), forces1[431], tol); -ASSERT_EQUAL_VEC(Vec3(-1.68165877e+02, 2.05742253e+02, -1.17371622e+02), forces1[432], tol); -ASSERT_EQUAL_VEC(Vec3(-1.93368937e+02, 7.77030375e+01, -1.60942447e+02), forces1[433], tol); -ASSERT_EQUAL_VEC(Vec3(-8.97795426e+01, 2.56568674e+02, -3.94711205e+02), forces1[434], tol); -ASSERT_EQUAL_VEC(Vec3(-2.33025806e+02, 9.53111817e+01, 3.02984350e+02), forces1[435], tol); -ASSERT_EQUAL_VEC(Vec3( 4.34416040e+01, -4.44341362e+02, -4.99903855e+00), forces1[436], tol); -ASSERT_EQUAL_VEC(Vec3( 3.32041110e+02, -4.10874874e+02, -6.13697373e+01), forces1[437], tol); -ASSERT_EQUAL_VEC(Vec3(-1.45971034e+02, -2.28311940e+02, -2.99006034e+02), forces1[438], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38544644e+02, -1.27394726e+02, -2.93844502e+02), forces1[439], tol); -ASSERT_EQUAL_VEC(Vec3( 2.97433737e+02, 3.38274025e+02, -2.14834485e+02), forces1[440], tol); -ASSERT_EQUAL_VEC(Vec3( 2.49325388e+01, 1.88464224e+02, -8.02957242e+01), forces1[441], tol); -ASSERT_EQUAL_VEC(Vec3(-1.32436289e+02, -3.86539713e+02, -6.69802109e+01), forces1[442], tol); -ASSERT_EQUAL_VEC(Vec3( 1.84591010e+01, 2.24796153e+02, -1.36943849e+02), forces1[443], tol); -ASSERT_EQUAL_VEC(Vec3( 2.15317088e+02, 1.06092575e+02, -1.25718903e+02), forces1[444], tol); -ASSERT_EQUAL_VEC(Vec3( 3.07793097e+02, 4.34340797e+02, 2.17184869e+01), forces1[445], tol); -ASSERT_EQUAL_VEC(Vec3( 8.06779109e+00, 4.99925960e+01, -3.14233384e+02), forces1[446], tol); -ASSERT_EQUAL_VEC(Vec3( 1.36943103e+03, 6.44803649e+02, -3.85109067e+02), forces1[447], tol); -ASSERT_EQUAL_VEC(Vec3( 3.32242272e+02, -1.04208324e+02, -4.08589589e+02), forces1[448], tol); -ASSERT_EQUAL_VEC(Vec3( 3.73255876e+02, 2.70951542e+02, 3.80697548e+02), forces1[449], tol); -ASSERT_EQUAL_VEC(Vec3(-2.09798900e+02, 4.29900198e+02, 8.40839028e+02), forces1[450], tol); -ASSERT_EQUAL_VEC(Vec3(-3.48538763e+02, -3.63130308e+02, 5.10379446e+02), forces1[451], tol); -ASSERT_EQUAL_VEC(Vec3(-3.28341714e+00, 4.69698489e-01, -6.05231376e+00), forces1[452], tol); -ASSERT_EQUAL_VEC(Vec3( 3.83253792e+01, 3.59830676e+02, 8.67060383e+02), forces1[453], tol); -ASSERT_EQUAL_VEC(Vec3(-1.57391804e+02, 5.68715567e+02, -1.87718510e+02), forces1[454], tol); -ASSERT_EQUAL_VEC(Vec3( 4.16155580e+02, 5.83079478e+01, -5.75730469e+02), forces1[455], tol); -ASSERT_EQUAL_VEC(Vec3( 2.58779906e+02, -1.00655656e+02, -4.43420159e+02), forces1[456], tol); -ASSERT_EQUAL_VEC(Vec3( 1.38953668e+02, 4.93490759e+02, 9.06786307e+02), forces1[457], tol); -ASSERT_EQUAL_VEC(Vec3(-4.81272447e+01, 9.53310029e+02, -1.83936453e+02), forces1[458], tol); -ASSERT_EQUAL_VEC(Vec3( 6.64523579e+02, -3.77321549e+02, 1.93098326e+02), forces1[459], tol); -ASSERT_EQUAL_VEC(Vec3( 8.34547360e+01, 1.77795489e+02, 4.70670853e+02), forces1[460], tol); -ASSERT_EQUAL_VEC(Vec3( 9.98948440e+02, -3.98575936e+02, 9.83617396e+02), forces1[461], tol); -ASSERT_EQUAL_VEC(Vec3(-5.06587875e+02, -4.10766357e+01, 4.75189712e+02), forces1[462], tol); -ASSERT_EQUAL_VEC(Vec3(-7.58615745e+01, 1.45234354e+02, 4.52909546e+01), forces1[463], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13502225e+02, 5.29861493e+02, -3.00954235e+02), forces1[464], tol); -ASSERT_EQUAL_VEC(Vec3(-1.46461752e+02, -3.86629519e+02, -6.42383694e+02), forces1[465], tol); -ASSERT_EQUAL_VEC(Vec3(-2.70141632e+02, 3.67195269e+02, -1.78826923e+02), forces1[466], tol); -ASSERT_EQUAL_VEC(Vec3(-1.23815721e+02, -1.77323218e+02, 2.37363709e+02), forces1[467], tol); -ASSERT_EQUAL_VEC(Vec3(-4.94036325e+02, 1.34870851e+02, 6.98764302e+02), forces1[468], tol); -ASSERT_EQUAL_VEC(Vec3( 7.08752797e+02, 1.85258249e+02, 5.51159246e+02), forces1[469], tol); -ASSERT_EQUAL_VEC(Vec3( 2.01291495e+02, -5.84720738e+02, 5.82921267e+02), forces1[470], tol); -ASSERT_EQUAL_VEC(Vec3( 5.29650511e+02, 4.07054187e+01, 9.99156291e+01), forces1[471], tol); -ASSERT_EQUAL_VEC(Vec3(-1.19707215e+02, 4.42978965e+02, -2.70437350e+02), forces1[472], tol); -ASSERT_EQUAL_VEC(Vec3(-6.87780787e+02, -1.32227443e+02, -7.35818874e+01), forces1[473], tol); -ASSERT_EQUAL_VEC(Vec3(-2.99625888e+02, 8.14649386e+02, 2.72145234e+01), forces1[474], tol); -ASSERT_EQUAL_VEC(Vec3(-2.26042622e+02, -3.49838280e+02, -2.73671757e+02), forces1[475], tol); -ASSERT_EQUAL_VEC(Vec3(-3.38859328e+02, 8.74208207e+02, 2.98575880e+02), forces1[476], tol); -ASSERT_EQUAL_VEC(Vec3( 5.63054826e+02, 1.51181551e+02, -1.10341988e+02), forces1[477], tol); -ASSERT_EQUAL_VEC(Vec3( 3.44122544e+02, 2.73292900e+02, 5.44577027e+02), forces1[478], tol); -ASSERT_EQUAL_VEC(Vec3( 3.29121922e+01, 3.66764263e+02, 3.30304492e+02), forces1[479], tol); -ASSERT_EQUAL_VEC(Vec3(-4.98111364e+01, -3.26335514e+02, -6.47508532e+02), forces1[480], tol); -ASSERT_EQUAL_VEC(Vec3( 6.05970391e+01, -1.41039500e+02, 4.05545963e+02), forces1[481], tol); -ASSERT_EQUAL_VEC(Vec3(-1.35191146e+03, 5.06763950e+01, -1.40076012e+02), forces1[482], tol); -ASSERT_EQUAL_VEC(Vec3( 7.70144671e+01, -2.68985491e+02, -1.75067707e+02), forces1[483], tol); -ASSERT_EQUAL_VEC(Vec3(-1.89547256e+02, -2.32975097e+02, -2.54877338e+02), forces1[484], tol); -ASSERT_EQUAL_VEC(Vec3( 2.37141279e+02, 6.49194662e+02, 1.01757997e+02), forces1[485], tol); -ASSERT_EQUAL_VEC(Vec3(-3.38583468e+02, 1.34692366e+02, 7.89810999e+02), forces1[486], tol); -ASSERT_EQUAL_VEC(Vec3(-5.59974436e+02, -1.46817839e+02, 3.62598852e+01), forces1[487], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52715734e+02, 1.16573021e+02, -4.55490471e+02), forces1[488], tol); -ASSERT_EQUAL_VEC(Vec3( 6.56757625e+01, 1.02550774e+02, -9.81490452e+01), forces1[489], tol); -ASSERT_EQUAL_VEC(Vec3(-4.22997875e+02, 8.89168040e+02, -9.19714230e+01), forces1[490], tol); -ASSERT_EQUAL_VEC(Vec3( 5.13351576e+02, 4.56111157e+02, -6.86014949e+01), forces1[491], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12137269e+02, 6.84704993e+02, 4.44636019e+01), forces1[492], tol); -ASSERT_EQUAL_VEC(Vec3( 2.15980740e+02, 3.33093803e+02, -4.41281918e+02), forces1[493], tol); -ASSERT_EQUAL_VEC(Vec3(-4.77801486e-01, -2.16935238e+02, -5.39082462e+02), forces1[494], tol); -ASSERT_EQUAL_VEC(Vec3(-3.91584043e+02, 2.80049288e+02, 4.50318805e+02), forces1[495], tol); -ASSERT_EQUAL_VEC(Vec3( 2.40458755e+02, -1.24624268e+02, -2.70106867e+02), forces1[496], tol); -ASSERT_EQUAL_VEC(Vec3( 7.23763468e+01, 1.59346249e+01, -5.23998896e+01), forces1[497], tol); -ASSERT_EQUAL_VEC(Vec3(-1.41166795e+02, -3.23959396e+02, -4.05099054e+02), forces1[498], tol); -ASSERT_EQUAL_VEC(Vec3( 3.93723518e+02, 3.77829620e+02, -4.56301133e+02), forces1[499], tol); -ASSERT_EQUAL_VEC(Vec3(-2.68009341e+02, -2.12736933e+02, -7.96445111e+02), forces1[500], tol); -ASSERT_EQUAL_VEC(Vec3( 9.59480600e+02, 1.74115813e+02, 1.16126031e+01), forces1[501], tol); -ASSERT_EQUAL_VEC(Vec3(-3.93575465e+01, 1.29079012e+01, -1.89350441e+02), forces1[502], tol); -ASSERT_EQUAL_VEC(Vec3( 2.49464458e+02, 7.84144311e+01, -4.78252942e+02), forces1[503], tol); -ASSERT_EQUAL_VEC(Vec3( 5.16031453e+02, 6.52899912e+02, -5.05259519e+02), forces1[504], tol); -ASSERT_EQUAL_VEC(Vec3( 5.10845388e+01, -5.19606468e+02, 6.82761515e+00), forces1[505], tol); -ASSERT_EQUAL_VEC(Vec3(-7.68910836e+01, -1.13215494e+03, -7.05213833e+02), forces1[506], tol); -ASSERT_EQUAL_VEC(Vec3(-2.13058157e+02, 1.70549578e+00, 8.26365735e+02), forces1[507], tol); -ASSERT_EQUAL_VEC(Vec3( 1.86647493e+01, 1.91383875e+02, 4.18426660e+02), forces1[508], tol); -ASSERT_EQUAL_VEC(Vec3( 2.35361629e+02, 3.79668975e+02, -3.13824585e+02), forces1[509], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26205360e+02, -2.59705171e+02, -6.76333230e+02), forces1[510], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38240856e+02, -3.38607085e+02, 2.20460843e+02), forces1[511], tol); -ASSERT_EQUAL_VEC(Vec3(-2.25429800e+02, -7.80817051e+02, -2.43643666e+02), forces1[512], tol); -ASSERT_EQUAL_VEC(Vec3(-3.10585529e+01, 4.16080403e+01, 6.15476974e+01), forces1[513], tol); -ASSERT_EQUAL_VEC(Vec3( 6.75639613e+01, 9.67778416e+01, 6.03424295e+02), forces1[514], tol); -ASSERT_EQUAL_VEC(Vec3(-1.27080812e+02, -4.74945218e+01, 4.67735437e+02), forces1[515], tol); -ASSERT_EQUAL_VEC(Vec3(-2.72716149e+02, 3.30769806e+01, -2.81976538e+02), forces1[516], tol); -ASSERT_EQUAL_VEC(Vec3( 4.78709091e+02, 8.27541480e+01, -3.32366235e+02), forces1[517], tol); -ASSERT_EQUAL_VEC(Vec3( 1.48574421e+02, 1.88635391e+02, -5.92117141e+02), forces1[518], tol); -ASSERT_EQUAL_VEC(Vec3(-9.24795792e+01, 6.86826191e+01, 5.16804407e+02), forces1[519], tol); -ASSERT_EQUAL_VEC(Vec3( 4.32902806e+02, -4.67485932e+02, 1.09369501e+02), forces1[520], tol); -ASSERT_EQUAL_VEC(Vec3(-2.19075642e+02, 2.09097287e+00, 1.05235595e+03), forces1[521], tol); -ASSERT_EQUAL_VEC(Vec3(-3.95717922e+02, -3.31346394e+02, 6.33930848e+02), forces1[522], tol); -ASSERT_EQUAL_VEC(Vec3( 2.29152652e+01, 5.34146722e+02, 3.47887307e+01), forces1[523], tol); -ASSERT_EQUAL_VEC(Vec3( 4.58874513e+02, -2.39333403e+02, 5.46784973e+01), forces1[524], tol); -ASSERT_EQUAL_VEC(Vec3( 9.97690238e+01, 6.32211339e+02, -2.38267224e+02), forces1[525], tol); -ASSERT_EQUAL_VEC(Vec3(-5.41815785e+02, 2.23592441e+02, 3.43988502e+02), forces1[526], tol); -ASSERT_EQUAL_VEC(Vec3( 6.66020295e+02, 4.01173887e+02, 3.95444004e+02), forces1[527], tol); -ASSERT_EQUAL_VEC(Vec3(-3.06415141e+02, 9.39706150e+02, -8.27903644e+01), forces1[528], tol); -ASSERT_EQUAL_VEC(Vec3(-6.74078464e+02, 3.08248161e+02, 3.73260958e+02), forces1[529], tol); -ASSERT_EQUAL_VEC(Vec3( 2.12314396e+02, -1.45381664e+02, 2.64300301e+02), forces1[530], tol); -ASSERT_EQUAL_VEC(Vec3( 5.45322328e+01, -8.21066892e+01, 1.51406100e+01), forces1[531], tol); -ASSERT_EQUAL_VEC(Vec3( 1.18910001e+03, 9.92330102e+02, 1.56915624e+02), forces1[532], tol); -ASSERT_EQUAL_VEC(Vec3( 4.27125646e+02, 1.57551086e+02, -3.44348874e+02), forces1[533], tol); -ASSERT_EQUAL_VEC(Vec3( 4.25889733e+02, -8.14519408e+02, -2.37525602e+02), forces1[534], tol); -ASSERT_EQUAL_VEC(Vec3( 1.28754744e+02, 2.55775344e+02, 4.07880224e+02), forces1[535], tol); -ASSERT_EQUAL_VEC(Vec3(-4.27463797e+02, 1.69782847e+02, 1.81381656e+02), forces1[536], tol); -ASSERT_EQUAL_VEC(Vec3(-1.35673145e+01, 6.03614577e+01, -2.72320347e+02), forces1[537], tol); -ASSERT_EQUAL_VEC(Vec3( 3.33191831e+02, 2.70237134e+02, -1.39415972e+02), forces1[538], tol); -ASSERT_EQUAL_VEC(Vec3( 4.27473593e+02, 1.39188845e+02, 1.50065516e+02), forces1[539], tol); -ASSERT_EQUAL_VEC(Vec3(-8.29214695e+01, -1.00138197e+02, -6.82077450e+01), forces1[540], tol); -ASSERT_EQUAL_VEC(Vec3( 4.42484380e+02, -8.63519014e+02, 5.13464509e+02), forces1[541], tol); -ASSERT_EQUAL_VEC(Vec3( 2.60684466e+02, -6.37356238e+01, 1.70982604e+02), forces1[542], tol); -ASSERT_EQUAL_VEC(Vec3(-3.90400226e+02, -6.79695956e+01, -2.36488456e+02), forces1[543], tol); -ASSERT_EQUAL_VEC(Vec3( 2.47126838e+02, -6.89575321e+02, 2.32358423e+02), forces1[544], tol); -ASSERT_EQUAL_VEC(Vec3(-5.36761583e+02, 2.88858194e+02, -6.13643573e+02), forces1[545], tol); -ASSERT_EQUAL_VEC(Vec3(-7.93525749e+02, 1.07662863e+02, 1.05022658e+03), forces1[546], tol); -ASSERT_EQUAL_VEC(Vec3( 5.82900512e+02, 1.51819356e+02, 4.23873744e+02), forces1[547], tol); -ASSERT_EQUAL_VEC(Vec3( 1.88325572e+02, 3.18360865e+02, 2.45830156e+02), forces1[548], tol); -ASSERT_EQUAL_VEC(Vec3( 2.61705414e+02, 2.14134022e+02, -1.84880999e+02), forces1[549], tol); -ASSERT_EQUAL_VEC(Vec3(-6.23192888e+01, -3.92071740e+02, 3.63685367e+02), forces1[550], tol); -ASSERT_EQUAL_VEC(Vec3( 2.19338376e+02, -3.09058211e+02, 2.60284559e+02), forces1[551], tol); -ASSERT_EQUAL_VEC(Vec3( 5.02128707e+02, -5.84024469e+02, -2.55784996e+02), forces1[552], tol); -ASSERT_EQUAL_VEC(Vec3( 3.03909158e+02, 8.14707135e+01, 3.89632253e+02), forces1[553], tol); -ASSERT_EQUAL_VEC(Vec3(-1.63583654e+01, -1.20664911e+02, -1.80828909e+02), forces1[554], tol); -ASSERT_EQUAL_VEC(Vec3( 5.41992468e+02, 1.88563930e+02, 1.13691301e+02), forces1[555], tol); -ASSERT_EQUAL_VEC(Vec3( 1.22553432e+01, -7.61799733e+02, -5.24485038e+02), forces1[556], tol); -ASSERT_EQUAL_VEC(Vec3(-4.66745376e+02, 1.60550422e+02, 1.60943530e+02), forces1[557], tol); -ASSERT_EQUAL_VEC(Vec3( 1.52464706e+02, -2.28608668e+02, -5.94662997e+01), forces1[558], tol); -ASSERT_EQUAL_VEC(Vec3( 1.80874781e+02, 2.02580348e+02, 2.57314201e+02), forces1[559], tol); -ASSERT_EQUAL_VEC(Vec3( 6.16836590e+02, -3.58505580e+02, -5.69821380e+02), forces1[560], tol); -ASSERT_EQUAL_VEC(Vec3(-1.57121513e+02, -1.13551528e+02, -1.64421656e+02), forces1[561], tol); -ASSERT_EQUAL_VEC(Vec3(-5.95579860e+02, 1.76709860e+02, -1.20420471e+02), forces1[562], tol); -ASSERT_EQUAL_VEC(Vec3(-6.71038012e+01, 7.56227414e+02, 5.71572718e+02), forces1[563], tol); -ASSERT_EQUAL_VEC(Vec3(-2.03114489e+02, -5.27279840e+02, -8.87711978e+01), forces1[564], tol); -ASSERT_EQUAL_VEC(Vec3(-1.55593136e+02, 2.45854044e+02, 3.01808246e+01), forces1[565], tol); -ASSERT_EQUAL_VEC(Vec3( 1.30686350e+02, -2.25620374e+02, -3.22214134e+02), forces1[566], tol); -ASSERT_EQUAL_VEC(Vec3( 8.49438622e+00, -1.67348790e+02, 1.64216652e+02), forces1[567], tol); -ASSERT_EQUAL_VEC(Vec3(-2.31492960e+02, -5.94613152e+00, -4.92415232e+02), forces1[568], tol); -ASSERT_EQUAL_VEC(Vec3(-1.99398672e+02, -1.39998676e+02, 2.20660038e+01), forces1[569], tol); -ASSERT_EQUAL_VEC(Vec3(-2.65259682e+02, 6.41897575e+02, 2.96772423e+01), forces1[570], tol); -ASSERT_EQUAL_VEC(Vec3(-6.43663438e+02, -9.18800569e+01, 4.59932589e+02), forces1[571], tol); -ASSERT_EQUAL_VEC(Vec3( 3.08969568e+02, 8.15568208e+02, 4.66102799e+02), forces1[572], tol); -ASSERT_EQUAL_VEC(Vec3( 3.27967531e+02, -3.65749496e+02, -7.14744561e+02), forces1[573], tol); -ASSERT_EQUAL_VEC(Vec3(-2.27124135e+01, 1.71611100e+02, 5.53831720e+02), forces1[574], tol); -ASSERT_EQUAL_VEC(Vec3(-3.66175366e+02, -4.26970546e+02, 4.19237233e+02), forces1[575], tol); -ASSERT_EQUAL_VEC(Vec3( 3.35350939e+02, 4.34257827e+02, 3.88519433e+02), forces1[576], tol); -ASSERT_EQUAL_VEC(Vec3( 1.92391997e+02, 3.19970198e+01, 2.85801367e+02), forces1[577], tol); -ASSERT_EQUAL_VEC(Vec3(-1.98802026e+02, -5.26322826e+02, 3.78354799e+02), forces1[578], tol); -ASSERT_EQUAL_VEC(Vec3( 1.45671139e+01, -4.73231557e+02, 1.99919499e+02), forces1[579], tol); -ASSERT_EQUAL_VEC(Vec3(-4.54983469e+02, -4.41701623e+02, -1.24425267e+01), forces1[580], tol); -ASSERT_EQUAL_VEC(Vec3(-4.14904603e+02, 2.39751623e+02, 1.50738334e+02), forces1[581], tol); -ASSERT_EQUAL_VEC(Vec3(-3.06008464e+02, -5.48479559e+02, 1.68208702e+02), forces1[582], tol); -ASSERT_EQUAL_VEC(Vec3(-4.75151928e+02, -5.13940177e+02, -3.05856025e+02), forces1[583], tol); -ASSERT_EQUAL_VEC(Vec3(-1.94335510e+02, 1.30203790e+02, -3.61867940e+02), forces1[584], tol); -ASSERT_EQUAL_VEC(Vec3(-3.90897312e+02, 9.91504462e+01, -5.15012540e+02), forces1[585], tol); -ASSERT_EQUAL_VEC(Vec3(-6.84365306e+01, 4.13335965e+01, -2.50193483e+02), forces1[586], tol); -ASSERT_EQUAL_VEC(Vec3(-1.33552662e+02, 4.37424563e+02, 3.93116748e+02), forces1[587], tol); -ASSERT_EQUAL_VEC(Vec3( 2.17908981e+02, -3.56944423e+02, -2.19072785e+01), forces1[588], tol); -ASSERT_EQUAL_VEC(Vec3(-6.71090167e+01, -2.85234245e+01, -4.77739167e+02), forces1[589], tol); -ASSERT_EQUAL_VEC(Vec3(-1.52916503e+02, 1.00727331e+02, 7.10681385e+01), forces1[590], tol); -ASSERT_EQUAL_VEC(Vec3(-4.51746452e+02, 3.40018663e+02, -4.62193306e+02), forces1[591], tol); -ASSERT_EQUAL_VEC(Vec3(-3.10163906e+02, 9.78195399e+02, 6.76387827e+02), forces1[592], tol); -ASSERT_EQUAL_VEC(Vec3(-3.27558084e+02, -1.79605758e+02, -2.92242524e+02), forces1[593], tol); -ASSERT_EQUAL_VEC(Vec3(-1.59840534e+02, 2.90890718e+01, -2.88814524e+02), forces1[594], tol); -ASSERT_EQUAL_VEC(Vec3( 2.51648228e+02, -6.16115272e+02, -2.74650686e+02), forces1[595], tol); -ASSERT_EQUAL_VEC(Vec3(-4.29795517e+02, 2.97846602e+02, 2.42790721e+02), forces1[596], tol); -ASSERT_EQUAL_VEC(Vec3(-6.54290494e+01, -3.71027774e+00, 1.09362533e+02), forces1[597], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13635998e+02, 1.22421969e+02, -1.64181430e+02), forces1[598], tol); -ASSERT_EQUAL_VEC(Vec3(-4.58014050e+02, -5.24237205e+02, -4.23517393e+02), forces1[599], tol); -ASSERT_EQUAL_VEC(Vec3(-4.01134799e+02, -3.10910001e+02, -4.86430772e+02), forces1[600], tol); -ASSERT_EQUAL_VEC(Vec3( 5.98531056e+02, 2.14442508e+02, -3.57310754e+02), forces1[601], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56644787e+02, 7.12047294e+01, -6.74281621e+02), forces1[602], tol); -ASSERT_EQUAL_VEC(Vec3(-4.29285173e+02, 3.33264141e+02, -9.12908079e+02), forces1[603], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69676355e+01, -1.31676984e+02, -3.65274088e+02), forces1[604], tol); -ASSERT_EQUAL_VEC(Vec3(-9.51192754e+00, 3.29563459e+02, 1.84451527e+01), forces1[605], tol); -ASSERT_EQUAL_VEC(Vec3( 1.01475969e+03, 8.03401303e+01, -6.28558583e+02), forces1[606], tol); -ASSERT_EQUAL_VEC(Vec3( 2.39384773e+02, -4.08077252e+02, -1.62875513e+02), forces1[607], tol); -ASSERT_EQUAL_VEC(Vec3(-3.93619429e+02, -5.17089524e+02, 5.21862274e+02), forces1[608], tol); -ASSERT_EQUAL_VEC(Vec3(-1.37188342e+02, -3.86301530e+01, 4.26852072e+02), forces1[609], tol); -ASSERT_EQUAL_VEC(Vec3( 4.56729328e+02, 1.63797747e+02, 1.01225457e+01), forces1[610], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53128373e+02, 1.02270086e+02, -7.27501148e+02), forces1[611], tol); -ASSERT_EQUAL_VEC(Vec3(-1.82095738e+02, 7.23918424e+00, -5.10663887e+02), forces1[612], tol); -ASSERT_EQUAL_VEC(Vec3( 3.54485642e+02, -8.64332815e+01, -4.10166872e+02), forces1[613], tol); -ASSERT_EQUAL_VEC(Vec3(-6.67557801e+01, -7.57917504e+01, 7.77239103e+01), forces1[614], tol); -ASSERT_EQUAL_VEC(Vec3( 5.34069903e+01, -3.49052174e+02, -4.41040697e+02), forces1[615], tol); -ASSERT_EQUAL_VEC(Vec3(-2.55993121e+02, -1.85106916e+02, -1.67700877e+01), forces1[616], tol); -ASSERT_EQUAL_VEC(Vec3(-2.60226735e+02, 4.50682021e+02, 6.87571461e+02), forces1[617], tol); -ASSERT_EQUAL_VEC(Vec3(-4.84797099e+01, -1.47670701e+02, 1.30460152e+02), forces1[618], tol); -ASSERT_EQUAL_VEC(Vec3(-5.03867743e+02, 3.00373068e+02, 2.90989581e+01), forces1[619], tol); -ASSERT_EQUAL_VEC(Vec3(-3.26901569e+02, -2.54115591e+02, -1.97292733e+02), forces1[620], tol); -ASSERT_EQUAL_VEC(Vec3( 2.23124353e+02, 4.31821924e+02, -3.45785529e+02), forces1[621], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69721533e+00, -7.70690632e+01, -4.19805145e-01), forces1[622], tol); -ASSERT_EQUAL_VEC(Vec3( 8.20412852e+02, 7.99595268e+02, 4.14368303e+02), forces1[623], tol); -ASSERT_EQUAL_VEC(Vec3(-6.20301649e+01, -4.27145295e+02, -3.70568508e+02), forces1[624], tol); -ASSERT_EQUAL_VEC(Vec3(-2.49452268e+01, -1.44630413e+02, 7.41551042e+02), forces1[625], tol); -ASSERT_EQUAL_VEC(Vec3(-6.41685916e+02, 6.29980324e+01, 1.57997582e+02), forces1[626], tol); -ASSERT_EQUAL_VEC(Vec3(-5.89339824e+02, -2.66715415e+02, 7.40290187e+01), forces1[627], tol); -ASSERT_EQUAL_VEC(Vec3( 5.26893408e+02, -4.19407888e+02, -2.37125726e+02), forces1[628], tol); -ASSERT_EQUAL_VEC(Vec3( 4.42841034e+02, -3.91060128e+00, 5.35417838e+02), forces1[629], tol); -ASSERT_EQUAL_VEC(Vec3( 2.38357324e+02, -5.34613334e+02, 2.63026026e+02), forces1[630], tol); -ASSERT_EQUAL_VEC(Vec3(-2.48018560e+02, -1.44967289e+01, 7.55539331e+02), forces1[631], tol); -ASSERT_EQUAL_VEC(Vec3(-8.06994987e+01, -4.42696335e+02, -4.11279013e+02), forces1[632], tol); -ASSERT_EQUAL_VEC(Vec3( 4.64135556e+02, -7.82576620e+02, 7.48567804e+02), forces1[633], tol); -ASSERT_EQUAL_VEC(Vec3( 3.75022611e+02, 3.06926438e+02, 2.76985876e+02), forces1[634], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43672142e+02, -1.70168440e+02, -2.61360725e+02), forces1[635], tol); -ASSERT_EQUAL_VEC(Vec3( 5.20775219e+02, -7.66015101e+00, -2.76123645e+02), forces1[636], tol); -ASSERT_EQUAL_VEC(Vec3(-2.28464032e+02, 5.33849652e+02, -3.58040265e+01), forces1[637], tol); -ASSERT_EQUAL_VEC(Vec3(-1.70105892e+02, -7.30464804e+01, -3.73115603e+02), forces1[638], tol); -ASSERT_EQUAL_VEC(Vec3( 1.90860772e+02, 1.53722926e+02, -9.75608771e+00), forces1[639], tol); -ASSERT_EQUAL_VEC(Vec3( 2.59606432e+02, 2.75260084e+01, -2.02338885e+02), forces1[640], tol); -ASSERT_EQUAL_VEC(Vec3( 3.25211743e+02, 2.78186538e+01, 5.21700978e+02), forces1[641], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12827984e+02, -6.70115666e+02, -7.85972574e+01), forces1[642], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09776266e+01, -4.90753809e+01, -2.91319708e+02), forces1[643], tol); -ASSERT_EQUAL_VEC(Vec3( 2.77337771e+02, 2.29328824e+02, 5.59770839e+02), forces1[644], tol); -ASSERT_EQUAL_VEC(Vec3( 4.59572121e+02, 1.21311799e+02, -4.79315463e+02), forces1[645], tol); -ASSERT_EQUAL_VEC(Vec3(-5.30617073e+02, -3.96120276e+02, -4.37634971e+01), forces1[646], tol); -ASSERT_EQUAL_VEC(Vec3( 5.87394968e+01, 3.74984490e+02, -4.60404623e+00), forces1[647], tol); -ASSERT_EQUAL_VEC(Vec3(-5.72051098e+02, -3.24819120e+02, -5.11080203e+01), forces1[648], tol); -ASSERT_EQUAL_VEC(Vec3(-1.51869992e+03, 1.63914081e+02, -7.68191132e+01), forces1[649], tol); -ASSERT_EQUAL_VEC(Vec3( 4.86996174e+02, 5.16874032e+02, -7.62783455e+01), forces1[650], tol); -ASSERT_EQUAL_VEC(Vec3( 2.48291844e+02, -8.90767951e+02, 6.71591151e+01), forces1[651], tol); -ASSERT_EQUAL_VEC(Vec3(-1.55902671e+00, 1.36945322e+02, -1.04198745e+02), forces1[652], tol); -ASSERT_EQUAL_VEC(Vec3(-1.20204512e+02, 2.89617545e+02, -6.63132635e+02), forces1[653], tol); -ASSERT_EQUAL_VEC(Vec3(-1.59431738e+02, -4.16178632e+02, 2.79410323e+02), forces1[654], tol); -ASSERT_EQUAL_VEC(Vec3(-2.98742818e+02, -2.96272331e+02, 3.36156942e+02), forces1[655], tol); -ASSERT_EQUAL_VEC(Vec3(-4.91918911e+02, -4.26618142e+01, 1.25349379e+01), forces1[656], tol); -ASSERT_EQUAL_VEC(Vec3(-2.47949202e+02, -2.67488422e+02, 2.21868927e+02), forces1[657], tol); -ASSERT_EQUAL_VEC(Vec3(-2.42806912e+01, 2.61371857e+01, -6.65056079e+01), forces1[658], tol); -ASSERT_EQUAL_VEC(Vec3( 3.64167110e+02, 4.13052005e+02, -5.51357152e+02), forces1[659], tol); -ASSERT_EQUAL_VEC(Vec3( 3.74835025e+02, -6.33613808e+02, 5.37740565e+00), forces1[660], tol); -ASSERT_EQUAL_VEC(Vec3( 6.51925635e+01, 5.97066743e+02, 2.54479164e+01), forces1[661], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53444698e+02, -7.31192246e-02, -3.64183108e+02), forces1[662], tol); -ASSERT_EQUAL_VEC(Vec3(-4.19912375e+01, 5.32489389e+02, 5.67529873e+02), forces1[663], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18364904e+01, -2.88671495e+02, 2.73914838e+02), forces1[664], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56684383e+02, 1.75277073e+02, 2.67819228e+02), forces1[665], tol); -ASSERT_EQUAL_VEC(Vec3(-1.42021939e+02, -1.93549789e+02, -4.45927086e+02), forces1[666], tol); -ASSERT_EQUAL_VEC(Vec3(-5.74451363e+01, -4.30855207e+02, -7.59667162e+02), forces1[667], tol); -ASSERT_EQUAL_VEC(Vec3(-4.90348302e+02, 2.12533193e+02, 1.21388630e+02), forces1[668], tol); -ASSERT_EQUAL_VEC(Vec3( 1.94617803e+02, 1.32085507e+02, 1.71425945e+02), forces1[669], tol); -ASSERT_EQUAL_VEC(Vec3(-2.73616831e+02, 7.78021634e+02, 2.78045494e+02), forces1[670], tol); -ASSERT_EQUAL_VEC(Vec3(-2.62086498e+02, 3.53986939e+02, 1.59714894e+02), forces1[671], tol); -ASSERT_EQUAL_VEC(Vec3( 3.73999411e+01, -6.21073575e+02, -1.89719863e+02), forces1[672], tol); -ASSERT_EQUAL_VEC(Vec3( 2.70260860e+02, -1.98707881e+02, -1.68446389e+02), forces1[673], tol); -ASSERT_EQUAL_VEC(Vec3(-3.72177189e+02, 2.16561917e+02, -7.51668953e+01), forces1[674], tol); -ASSERT_EQUAL_VEC(Vec3( 4.60661709e+02, -2.41016609e+02, 1.87547311e+02), forces1[675], tol); -ASSERT_EQUAL_VEC(Vec3(-8.64826359e+00, -4.96643240e+01, 4.14108827e+02), forces1[676], tol); -ASSERT_EQUAL_VEC(Vec3(-5.53564746e+02, 2.02028062e+02, 2.48782202e+02), forces1[677], tol); -ASSERT_EQUAL_VEC(Vec3( 4.12907277e+02, 3.97611070e+02, -7.77110932e+02), forces1[678], tol); -ASSERT_EQUAL_VEC(Vec3( 4.37842786e+02, 3.87794283e+02, -2.57117992e+02), forces1[679], tol); -ASSERT_EQUAL_VEC(Vec3(-1.99542679e+02, -5.31843337e+02, -7.08353449e+02), forces1[680], tol); -ASSERT_EQUAL_VEC(Vec3( 7.16866224e+01, 2.15343692e+02, -2.17970964e+02), forces1[681], tol); -ASSERT_EQUAL_VEC(Vec3(-2.27242549e+02, -3.33098733e+02, -8.95890783e+01), forces1[682], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12351413e+02, -2.81401181e+02, 1.84388002e+02), forces1[683], tol); -ASSERT_EQUAL_VEC(Vec3( 5.30452008e+01, -1.73617150e+02, 3.80454625e+02), forces1[684], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53115972e+02, -4.19542700e+02, 3.62046980e+02), forces1[685], tol); -ASSERT_EQUAL_VEC(Vec3(-8.25931831e+01, 1.22022997e+02, -2.05397162e+01), forces1[686], tol); -ASSERT_EQUAL_VEC(Vec3(-4.09536810e+02, 3.88110352e+01, 7.34591479e+02), forces1[687], tol); -ASSERT_EQUAL_VEC(Vec3( 2.30482332e+02, 4.58992821e+01, -3.44448449e+02), forces1[688], tol); -ASSERT_EQUAL_VEC(Vec3(-2.99021647e+02, 6.71173507e+02, -1.01234738e+03), forces1[689], tol); -ASSERT_EQUAL_VEC(Vec3( 2.93609447e+02, -1.62689588e+01, -5.52892039e+02), forces1[690], tol); -ASSERT_EQUAL_VEC(Vec3(-1.41608406e+02, -4.87778496e+02, 2.73057317e+02), forces1[691], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26623333e+02, -4.36398742e+02, 7.19789728e+01), forces1[692], tol); -ASSERT_EQUAL_VEC(Vec3( 1.33484619e+02, 2.25668941e+02, 5.65772889e+02), forces1[693], tol); -ASSERT_EQUAL_VEC(Vec3( 7.34328437e+02, 4.69241195e+02, -5.53029876e+02), forces1[694], tol); -ASSERT_EQUAL_VEC(Vec3(-6.36703964e+01, -2.05105546e+02, -4.73051447e+02), forces1[695], tol); -ASSERT_EQUAL_VEC(Vec3(-3.35917709e+02, -2.75962396e+02, 4.10424916e+02), forces1[696], tol); -ASSERT_EQUAL_VEC(Vec3(-1.98439482e+02, -2.81389872e+02, -1.48450243e+02), forces1[697], tol); -ASSERT_EQUAL_VEC(Vec3( 6.96988850e+02, -2.08391821e+02, -1.22085562e+02), forces1[698], tol); -ASSERT_EQUAL_VEC(Vec3( 6.16645748e+02, -2.04946166e+02, -2.28454418e+02), forces1[699], tol); -ASSERT_EQUAL_VEC(Vec3( 1.59003207e+02, 2.68316786e+02, -1.13415654e+02), forces1[700], tol); -ASSERT_EQUAL_VEC(Vec3( 2.52361394e+02, 3.78641684e+02, -1.30511196e+03), forces1[701], tol); -ASSERT_EQUAL_VEC(Vec3( 7.30824903e+02, -3.70993861e+02, -6.60674538e+02), forces1[702], tol); -ASSERT_EQUAL_VEC(Vec3(-4.64466620e+01, 1.28056043e+02, 8.75616746e+01), forces1[703], tol); -ASSERT_EQUAL_VEC(Vec3( 3.26209378e+02, -1.75823502e+02, 7.02935072e+01), forces1[704], tol); -ASSERT_EQUAL_VEC(Vec3( 9.80733438e+01, -2.26694393e+02, -2.00005470e+02), forces1[705], tol); -ASSERT_EQUAL_VEC(Vec3( 5.01964740e+01, 2.67230250e+02, 5.24657350e+02), forces1[706], tol); -ASSERT_EQUAL_VEC(Vec3(-2.52920558e+02, -8.04959983e+02, 4.03061082e+02), forces1[707], tol); -ASSERT_EQUAL_VEC(Vec3(-2.40233840e+02, -2.54317274e+02, 5.06457155e+02), forces1[708], tol); -ASSERT_EQUAL_VEC(Vec3( 4.48943662e+02, 3.49500783e+02, 2.88397394e+02), forces1[709], tol); -ASSERT_EQUAL_VEC(Vec3( 3.10154028e+02, 3.91036441e+02, -9.77447313e+02), forces1[710], tol); -ASSERT_EQUAL_VEC(Vec3( 7.63180049e+02, 2.06937000e+02, 1.03491184e+02), forces1[711], tol); -ASSERT_EQUAL_VEC(Vec3( 4.64445959e+02, 2.52682144e+02, 7.37736774e+01), forces1[712], tol); -ASSERT_EQUAL_VEC(Vec3( 9.14937811e+02, 3.40042036e+02, -2.99018712e+02), forces1[713], tol); -ASSERT_EQUAL_VEC(Vec3( 5.05299633e+02, 1.59569259e+02, -9.12327108e+00), forces1[714], tol); -ASSERT_EQUAL_VEC(Vec3(-3.46682702e+02, 1.40007400e+02, 1.54710821e+02), forces1[715], tol); -ASSERT_EQUAL_VEC(Vec3(-1.66209573e+01, -4.02206977e+01, -1.23824382e+02), forces1[716], tol); -ASSERT_EQUAL_VEC(Vec3(-7.57122358e+01, -4.48068180e+02, -4.21106487e+02), forces1[717], tol); -ASSERT_EQUAL_VEC(Vec3( 1.04054861e+03, -2.36054466e+02, 1.43176151e+01), forces1[718], tol); -ASSERT_EQUAL_VEC(Vec3(-2.65447945e+01, 6.06566369e+02, 4.91348853e+01), forces1[719], tol); -ASSERT_EQUAL_VEC(Vec3(-1.33799337e+02, -3.09748236e+02, 2.79834422e+01), forces1[720], tol); -ASSERT_EQUAL_VEC(Vec3(-9.76340308e+01, -1.13791543e+03, 4.60481356e+02), forces1[721], tol); -ASSERT_EQUAL_VEC(Vec3(-2.56814290e+02, 9.31514446e+01, 3.24980766e+02), forces1[722], tol); -ASSERT_EQUAL_VEC(Vec3(-8.66006627e+01, 5.60562069e+02, 2.96440803e+02), forces1[723], tol); -ASSERT_EQUAL_VEC(Vec3( 1.26231775e+02, 1.40946887e+02, 3.97459193e+02), forces1[724], tol); -ASSERT_EQUAL_VEC(Vec3( 1.03134630e+02, -1.43345076e+02, 1.91574929e+02), forces1[725], tol); -ASSERT_EQUAL_VEC(Vec3(-9.29586783e+01, 4.44777503e+01, -9.69828338e+01), forces1[726], tol); -ASSERT_EQUAL_VEC(Vec3(-1.07833245e+02, 4.40219598e+01, 2.20888632e+02), forces1[727], tol); -ASSERT_EQUAL_VEC(Vec3( 2.92915083e+02, 5.54179388e+02, 3.57016084e+02), forces1[728], tol); -ASSERT_EQUAL_VEC(Vec3(-6.11696651e+02, 1.34361189e+02, 4.74917740e+01), forces1[729], tol); -ASSERT_EQUAL_VEC(Vec3(-8.07629704e+02, 1.63946818e+01, -2.56529488e+02), forces1[730], tol); -ASSERT_EQUAL_VEC(Vec3( 5.08866790e+01, 1.35087356e+01, 4.82186568e+02), forces1[731], tol); -ASSERT_EQUAL_VEC(Vec3(-5.01056820e+02, -7.35300196e+02, 6.67917664e+02), forces1[732], tol); -ASSERT_EQUAL_VEC(Vec3(-1.75353826e+00, 6.70720055e+02, -1.03873923e+03), forces1[733], tol); -ASSERT_EQUAL_VEC(Vec3(-1.95461285e+02, 4.63755838e+02, 7.41243174e+01), forces1[734], tol); -ASSERT_EQUAL_VEC(Vec3(-2.73265807e+02, -4.33952751e+02, -5.86859952e+02), forces1[735], tol); -ASSERT_EQUAL_VEC(Vec3( 3.87492595e+02, -3.57416581e+02, -1.22674219e+02), forces1[736], tol); -ASSERT_EQUAL_VEC(Vec3( 2.10277679e+02, -8.24319147e+01, -3.92467268e+02), forces1[737], tol); -ASSERT_EQUAL_VEC(Vec3( 8.30183105e+02, -6.58248549e+02, -4.70873747e+02), forces1[738], tol); -ASSERT_EQUAL_VEC(Vec3( 1.32224273e+02, 1.07242154e+02, -2.42599632e+02), forces1[739], tol); -ASSERT_EQUAL_VEC(Vec3(-4.36748065e+02, 2.00463318e+01, -3.45993944e+02), forces1[740], tol); -ASSERT_EQUAL_VEC(Vec3(-5.77263697e+02, 1.27439720e+02, -4.58810491e+02), forces1[741], tol); -ASSERT_EQUAL_VEC(Vec3( 1.97481946e+02, -2.58388548e+02, 1.34658918e+02), forces1[742], tol); -ASSERT_EQUAL_VEC(Vec3( 3.87665419e+01, -8.11439393e+02, -2.37617083e+02), forces1[743], tol); -ASSERT_EQUAL_VEC(Vec3(-5.43756717e+02, 7.08678099e+01, -1.18510886e+02), forces1[744], tol); -ASSERT_EQUAL_VEC(Vec3(-4.18101023e+02, 9.12399127e+01, -3.26402702e+02), forces1[745], tol); -ASSERT_EQUAL_VEC(Vec3(-1.04715128e+02, 4.73092172e+02, -5.52394413e+02), forces1[746], tol); -ASSERT_EQUAL_VEC(Vec3( 1.50377202e+02, 6.74569790e+02, -8.65206460e+01), forces1[747], tol); -ASSERT_EQUAL_VEC(Vec3(-4.91854971e+01, 9.70238350e+01, 4.14795171e+01), forces1[748], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53136450e+02, -3.14704270e+02, 1.64509568e+02), forces1[749], tol); -ASSERT_EQUAL_VEC(Vec3( 5.38381589e-01, -2.20857586e+02, 2.62858346e+02), forces1[750], tol); -ASSERT_EQUAL_VEC(Vec3(-6.92118459e+02, 2.00416528e+02, -2.65829388e+02), forces1[751], tol); -ASSERT_EQUAL_VEC(Vec3( 3.79128765e+01, -1.05184233e+02, -3.82602540e+01), forces1[752], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53012338e+02, 2.11976275e+02, -3.81671037e+02), forces1[753], tol); -ASSERT_EQUAL_VEC(Vec3(-2.51271776e+02, -3.93332088e+02, -1.33288963e+01), forces1[754], tol); -ASSERT_EQUAL_VEC(Vec3(-3.01457396e+01, 1.45589903e+02, -6.30529431e+01), forces1[755], tol); -ASSERT_EQUAL_VEC(Vec3(-2.76296961e+02, -4.61689259e+02, -2.69337581e+02), forces1[756], tol); -ASSERT_EQUAL_VEC(Vec3( 6.48638526e+01, 3.68743791e+02, 2.32261042e+02), forces1[757], tol); -ASSERT_EQUAL_VEC(Vec3(-4.48058548e+02, 4.24011162e+02, 2.00613297e+02), forces1[758], tol); -ASSERT_EQUAL_VEC(Vec3( 1.50464122e+01, -7.33758427e+01, 4.00841100e+02), forces1[759], tol); -ASSERT_EQUAL_VEC(Vec3( 4.06782738e+02, 1.22303609e+02, -3.26339153e+02), forces1[760], tol); -ASSERT_EQUAL_VEC(Vec3(-3.55711012e+02, -4.23650736e+02, 1.92960061e+02), forces1[761], tol); -ASSERT_EQUAL_VEC(Vec3(-4.78915336e+01, 1.13386663e+02, -4.55722593e+02), forces1[762], tol); -ASSERT_EQUAL_VEC(Vec3( 5.50242083e+02, 3.20971060e+02, -2.04129569e+02), forces1[763], tol); -ASSERT_EQUAL_VEC(Vec3(-3.98415518e+01, 6.43149241e+01, 2.62918629e+02), forces1[764], tol); -ASSERT_EQUAL_VEC(Vec3(-7.85279974e+01, -7.50534137e+01, -7.62991530e+02), forces1[765], tol); -ASSERT_EQUAL_VEC(Vec3( 9.55632719e+00, -3.95488033e+02, -8.95724718e+01), forces1[766], tol); -ASSERT_EQUAL_VEC(Vec3( 4.83248484e+02, -7.40432533e+02, -5.32388436e+02), forces1[767], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61825590e+02, 8.15278549e+01, 4.71854738e+02), forces1[768], tol); -ASSERT_EQUAL_VEC(Vec3(-3.30808156e+02, -4.21996977e+01, -1.05047553e+03), forces1[769], tol); -ASSERT_EQUAL_VEC(Vec3( 3.34236506e+02, -1.34581292e+02, 3.33945615e+02), forces1[770], tol); -ASSERT_EQUAL_VEC(Vec3( 2.25548584e+01, 6.94629483e+02, 3.48264737e+01), forces1[771], tol); -ASSERT_EQUAL_VEC(Vec3( 4.92311713e+02, -3.56653650e+02, 7.11601228e+01), forces1[772], tol); -ASSERT_EQUAL_VEC(Vec3( 2.17161427e+02, 4.05017188e+01, 3.47168571e+02), forces1[773], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61160760e+01, 1.47265327e+03, 5.49839208e+02), forces1[774], tol); -ASSERT_EQUAL_VEC(Vec3( 8.39508346e+01, -4.18462111e+02, 2.34856125e+02), forces1[775], tol); -ASSERT_EQUAL_VEC(Vec3(-2.31363191e+02, 2.37282362e+02, 6.61594930e+01), forces1[776], tol); -ASSERT_EQUAL_VEC(Vec3(-6.23920550e+01, -7.00163723e+02, 4.91292544e+02), forces1[777], tol); -ASSERT_EQUAL_VEC(Vec3( 2.68222410e+01, 2.46989964e+02, 6.49012925e-01), forces1[778], tol); -ASSERT_EQUAL_VEC(Vec3( 5.26234504e+02, 1.10220781e+02, 3.46422754e+02), forces1[779], tol); -ASSERT_EQUAL_VEC(Vec3(-3.29262429e+02, -3.87187275e+02, 8.51736504e+01), forces1[780], tol); -ASSERT_EQUAL_VEC(Vec3( 6.42859552e+02, 2.34857815e+02, 3.71368125e+02), forces1[781], tol); -ASSERT_EQUAL_VEC(Vec3(-3.24691537e+02, 5.64035803e+02, -4.45828642e+01), forces1[782], tol); -ASSERT_EQUAL_VEC(Vec3( 5.74664181e+01, 1.20257138e+02, -5.84616728e+01), forces1[783], tol); -ASSERT_EQUAL_VEC(Vec3(-2.83822896e+02, -2.10782913e+02, 1.66012284e+02), forces1[784], tol); -ASSERT_EQUAL_VEC(Vec3( 4.01591578e+02, -2.85111660e+02, 2.49467396e+02), forces1[785], tol); -ASSERT_EQUAL_VEC(Vec3( 3.05502334e+02, 7.04806702e+02, -5.94571548e+01), forces1[786], tol); -ASSERT_EQUAL_VEC(Vec3(-5.06843754e+02, 3.13614505e+02, -7.30043017e+02), forces1[787], tol); -ASSERT_EQUAL_VEC(Vec3(-1.65622368e+02, -1.02579327e+02, -4.10521389e+02), forces1[788], tol); -ASSERT_EQUAL_VEC(Vec3( 2.50016463e+02, 9.82377276e+02, 3.08289476e+02), forces1[789], tol); -ASSERT_EQUAL_VEC(Vec3( 3.60198825e+02, 3.06200915e+02, 4.01455745e+02), forces1[790], tol); -ASSERT_EQUAL_VEC(Vec3(-5.15582709e+02, -3.80887100e+02, -2.65984423e+02), forces1[791], tol); -ASSERT_EQUAL_VEC(Vec3( 9.16914445e+02, -2.70992304e+02, 2.88892766e+02), forces1[792], tol); -ASSERT_EQUAL_VEC(Vec3( 5.58063411e+01, 1.28556880e+02, 4.36834411e+02), forces1[793], tol); -ASSERT_EQUAL_VEC(Vec3( 3.48855713e+02, 3.63953389e+02, 3.78554885e+02), forces1[794], tol); -ASSERT_EQUAL_VEC(Vec3( 6.36625415e+02, -1.91568531e+02, 4.14269326e+02), forces1[795], tol); -ASSERT_EQUAL_VEC(Vec3(-3.31399256e+01, -1.47717726e+02, 3.03791102e+02), forces1[796], tol); -ASSERT_EQUAL_VEC(Vec3(-8.19625890e+01, -5.66609696e+02, -7.77438618e+01), forces1[797], tol); -ASSERT_EQUAL_VEC(Vec3( 1.20348179e+02, 3.66643084e+02, -2.38052731e+02), forces1[798], tol); -ASSERT_EQUAL_VEC(Vec3( 3.60705602e+02, 4.45404187e+02, -6.03564902e+02), forces1[799], tol); -ASSERT_EQUAL_VEC(Vec3(-8.71394660e+01, 1.63937553e+02, -1.43929941e+02), forces1[800], tol); -ASSERT_EQUAL_VEC(Vec3(-9.99012969e+01, 1.96050644e+01, -5.85512840e+01), forces1[801], tol); -ASSERT_EQUAL_VEC(Vec3( 4.81464959e+02, -7.04133234e+01, -2.08003335e+02), forces1[802], tol); -ASSERT_EQUAL_VEC(Vec3(-7.69383659e+02, 5.40518266e+01, 5.38423746e+02), forces1[803], tol); -ASSERT_EQUAL_VEC(Vec3(-6.60834570e+02, -1.87942951e+02, 4.11979846e+02), forces1[804], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06277928e+02, 3.55317856e+02, -2.27807465e+02), forces1[805], tol); -ASSERT_EQUAL_VEC(Vec3(-2.66112993e+02, 2.41378629e+02, -4.99239330e+02), forces1[806], tol); -ASSERT_EQUAL_VEC(Vec3(-5.23091617e+01, 9.33588668e+01, 7.23830549e+02), forces1[807], tol); -ASSERT_EQUAL_VEC(Vec3( 2.82159908e+00, 6.04185043e+01, 1.65510623e+02), forces1[808], tol); -ASSERT_EQUAL_VEC(Vec3(-2.97249356e+02, -5.53850820e+01, 3.87132557e+02), forces1[809], tol); -ASSERT_EQUAL_VEC(Vec3(-8.18654835e+02, -2.66089588e+02, 1.07282779e+03), forces1[810], tol); -ASSERT_EQUAL_VEC(Vec3(-2.43727371e+02, -2.51641252e+02, 3.46339026e+02), forces1[811], tol); -ASSERT_EQUAL_VEC(Vec3( 4.04775249e+02, 1.12602806e+02, -6.66755260e+02), forces1[812], tol); -ASSERT_EQUAL_VEC(Vec3(-8.30889004e+01, -9.75627382e+01, -5.15294649e+02), forces1[813], tol); -ASSERT_EQUAL_VEC(Vec3(-8.88900158e+01, -2.43585030e+02, -4.28254176e+02), forces1[814], tol); -ASSERT_EQUAL_VEC(Vec3(-9.15239756e+01, 4.50356816e+02, -2.64185924e+02), forces1[815], tol); -ASSERT_EQUAL_VEC(Vec3(-9.11727906e+01, 4.24890801e+02, -1.85085639e+02), forces1[816], tol); -ASSERT_EQUAL_VEC(Vec3(-3.91190277e+02, -6.86391314e+02, 1.52743025e+02), forces1[817], tol); -ASSERT_EQUAL_VEC(Vec3(-8.21031361e+01, -2.49525239e+02, 5.27536153e+02), forces1[818], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09414974e+02, -6.29098191e+02, 3.34955724e+02), forces1[819], tol); -ASSERT_EQUAL_VEC(Vec3(-4.17387560e+02, -9.10777301e+01, -3.54885448e+01), forces1[820], tol); -ASSERT_EQUAL_VEC(Vec3( 2.79543439e+02, -5.39041840e+02, 5.07374351e+02), forces1[821], tol); -ASSERT_EQUAL_VEC(Vec3( 2.14822336e+02, 1.92270744e+01, -3.14848497e+02), forces1[822], tol); -ASSERT_EQUAL_VEC(Vec3(-1.92605165e+02, -4.26132560e+02, -6.22677382e+00), forces1[823], tol); -ASSERT_EQUAL_VEC(Vec3(-6.55145464e+02, -4.86073333e+02, -3.89399825e+02), forces1[824], tol); -ASSERT_EQUAL_VEC(Vec3(-1.89867341e+02, -3.77315894e+02, -1.36214663e+02), forces1[825], tol); -ASSERT_EQUAL_VEC(Vec3( 4.60001225e+02, 1.99094537e+02, 2.82584474e+02), forces1[826], tol); -ASSERT_EQUAL_VEC(Vec3( 1.21553284e+02, -1.21203683e+02, 7.24058067e+02), forces1[827], tol); -ASSERT_EQUAL_VEC(Vec3(-9.16986437e+01, 7.09307382e+01, 7.89267421e+01), forces1[828], tol); -ASSERT_EQUAL_VEC(Vec3(-3.83808972e+02, 8.44796287e+01, 1.09604935e+03), forces1[829], tol); -ASSERT_EQUAL_VEC(Vec3(-3.65392705e+02, -1.88802374e+02, 4.62347013e+02), forces1[830], tol); -ASSERT_EQUAL_VEC(Vec3( 5.76337730e+02, -9.41995570e+01, -1.98141882e+02), forces1[831], tol); -ASSERT_EQUAL_VEC(Vec3(-4.21540736e+02, -5.96961388e+01, -8.33517850e+02), forces1[832], tol); -ASSERT_EQUAL_VEC(Vec3( 1.20307619e+03, 4.53518250e+02, 2.29372510e+02), forces1[833], tol); -ASSERT_EQUAL_VEC(Vec3( 2.92097304e+02, 4.13164379e+01, -3.61110495e+02), forces1[834], tol); -ASSERT_EQUAL_VEC(Vec3( 2.49877930e+02, -1.26742169e+02, 2.01739900e+02), forces1[835], tol); -ASSERT_EQUAL_VEC(Vec3( 4.82075008e+02, -4.36717554e+02, 2.10931182e+02), forces1[836], tol); -ASSERT_EQUAL_VEC(Vec3( 7.40048230e+00, -3.07870679e+02, -2.19267744e+02), forces1[837], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77929397e+02, -1.78455309e+02, 3.27383377e+02), forces1[838], tol); -ASSERT_EQUAL_VEC(Vec3(-1.43502125e+02, 2.36677035e+02, 1.76250580e+02), forces1[839], tol); -ASSERT_EQUAL_VEC(Vec3(-3.11015280e+02, 3.30102369e+01, 2.29419157e+02), forces1[840], tol); -ASSERT_EQUAL_VEC(Vec3( 7.16636078e+01, -1.43182827e+00, -8.22939586e+02), forces1[841], tol); -ASSERT_EQUAL_VEC(Vec3(-2.21647238e+02, -4.50480586e+01, -4.49964194e+02), forces1[842], tol); -ASSERT_EQUAL_VEC(Vec3(-4.26322975e+02, -2.93336811e+02, 2.05038938e+02), forces1[843], tol); -ASSERT_EQUAL_VEC(Vec3( 8.06775958e+01, 3.83777410e+02, 4.54379037e+02), forces1[844], tol); -ASSERT_EQUAL_VEC(Vec3( 1.36404637e+01, -1.12124193e+02, -2.08562538e+02), forces1[845], tol); -ASSERT_EQUAL_VEC(Vec3(-4.31330496e+01, 1.28721913e+02, 2.41017400e+02), forces1[846], tol); -ASSERT_EQUAL_VEC(Vec3( 3.71916499e+02, 3.66494598e+02, -1.02567885e+02), forces1[847], tol); -ASSERT_EQUAL_VEC(Vec3(-2.30281354e+02, 7.54907643e+02, 1.07586282e+02), forces1[848], tol); -ASSERT_EQUAL_VEC(Vec3( 2.67865075e+02, -1.51751902e+01, -1.70086059e+02), forces1[849], tol); -ASSERT_EQUAL_VEC(Vec3(-9.39303971e+02, 5.64031361e+01, -2.22408474e+02), forces1[850], tol); -ASSERT_EQUAL_VEC(Vec3(-1.01324797e+02, 3.31075650e+02, 7.07373134e+02), forces1[851], tol); -ASSERT_EQUAL_VEC(Vec3( 1.78185244e+02, 8.50185531e+01, -6.39941165e+02), forces1[852], tol); -ASSERT_EQUAL_VEC(Vec3( 3.33075565e+02, 9.10263334e+01, 1.20466005e+02), forces1[853], tol); -ASSERT_EQUAL_VEC(Vec3( 4.22270537e+01, -7.37202915e+02, 6.08451352e+02), forces1[854], tol); -ASSERT_EQUAL_VEC(Vec3(-4.16913834e+02, -4.82510498e+02, 3.91902755e+01), forces1[855], tol); -ASSERT_EQUAL_VEC(Vec3(-4.09087109e+02, -1.95401814e+02, -1.49030786e+02), forces1[856], tol); -ASSERT_EQUAL_VEC(Vec3(-2.89287185e+01, 3.78198264e+02, 2.19689536e+02), forces1[857], tol); -ASSERT_EQUAL_VEC(Vec3(-2.77576965e+02, 7.90464050e+01, 3.49478331e+02), forces1[858], tol); -ASSERT_EQUAL_VEC(Vec3( 4.71047132e+02, -1.88937165e+02, -2.48124657e+02), forces1[859], tol); -ASSERT_EQUAL_VEC(Vec3(-1.51518383e+02, 4.96193568e+01, -2.65467571e+02), forces1[860], tol); -ASSERT_EQUAL_VEC(Vec3(-7.66418994e+02, 8.46521518e+01, -3.64791094e+02), forces1[861], tol); -ASSERT_EQUAL_VEC(Vec3(-5.09774310e+02, 2.10742961e+01, 3.01814635e+02), forces1[862], tol); -ASSERT_EQUAL_VEC(Vec3(-9.75620816e+00, 7.12587243e+01, 9.37836693e+01), forces1[863], tol); -ASSERT_EQUAL_VEC(Vec3( 9.17385110e+01, -4.41182772e+02, -1.00398188e+02), forces1[864], tol); -ASSERT_EQUAL_VEC(Vec3(-2.52943928e+01, -1.90239695e+02, 4.81670302e+01), forces1[865], tol); -ASSERT_EQUAL_VEC(Vec3(-5.44266700e+02, 2.54811263e+02, -1.75181268e+02), forces1[866], tol); -ASSERT_EQUAL_VEC(Vec3( 4.08120113e+02, -1.23559887e+02, -2.06942160e+02), forces1[867], tol); -ASSERT_EQUAL_VEC(Vec3( 4.38405816e+02, -1.73677702e+02, 4.68119374e+02), forces1[868], tol); -ASSERT_EQUAL_VEC(Vec3(-3.66077262e+02, 3.32534980e+02, 2.43501977e+02), forces1[869], tol); -ASSERT_EQUAL_VEC(Vec3( 2.09710096e+02, 2.98077408e+02, -4.55256035e+02), forces1[870], tol); -ASSERT_EQUAL_VEC(Vec3( 4.70548055e+01, -8.03931446e+01, 1.44535738e+02), forces1[871], tol); -ASSERT_EQUAL_VEC(Vec3( 4.51389996e+01, -3.68239965e+02, 2.65390908e+02), forces1[872], tol); -ASSERT_EQUAL_VEC(Vec3(-2.22430692e+02, 4.99756041e+02, 1.50958469e+02), forces1[873], tol); -ASSERT_EQUAL_VEC(Vec3(-3.32911574e+02, 7.08248783e+02, -2.53293033e+02), forces1[874], tol); -ASSERT_EQUAL_VEC(Vec3(-2.24293564e+02, 3.61202816e+02, 3.14067039e+02), forces1[875], tol); -ASSERT_EQUAL_VEC(Vec3( 2.85994423e+01, 3.62421372e+02, -2.25792435e+01), forces1[876], tol); -ASSERT_EQUAL_VEC(Vec3( 3.25319985e+02, -8.59870785e+01, 6.05364581e+02), forces1[877], tol); -ASSERT_EQUAL_VEC(Vec3( 3.08171871e+02, 2.08420326e+02, -3.04923980e+02), forces1[878], tol); -ASSERT_EQUAL_VEC(Vec3( 3.65570529e+02, 1.38310252e+02, 2.10363363e+02), forces1[879], tol); -ASSERT_EQUAL_VEC(Vec3( 6.56661313e+01, 4.58001752e+02, -1.05217312e+02), forces1[880], tol); -ASSERT_EQUAL_VEC(Vec3(-7.04591192e+02, 1.95857268e+02, 6.29174462e+01), forces1[881], tol); -ASSERT_EQUAL_VEC(Vec3(-5.03143865e+02, -4.91096731e+02, 2.40904263e+00), forces1[882], tol); -ASSERT_EQUAL_VEC(Vec3(-6.84583679e+01, 8.09254534e+01, 2.50188730e+02), forces1[883], tol); -ASSERT_EQUAL_VEC(Vec3(-5.35217316e+01, 1.91746428e+02, -1.93678243e+02), forces1[884], tol); -ASSERT_EQUAL_VEC(Vec3( 5.56342532e+02, -6.69136606e+02, -2.99835083e+02), forces1[885], tol); -ASSERT_EQUAL_VEC(Vec3(-3.35801693e+02, 5.18603710e+01, -2.16409061e+02), forces1[886], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13151480e+02, 6.23015348e+02, -1.73858304e+01), forces1[887], tol); -ASSERT_EQUAL_VEC(Vec3(-4.64256120e+02, -2.03157899e+02, 4.33730698e+02), forces1[888], tol); -ASSERT_EQUAL_VEC(Vec3( 5.74737750e+01, -4.61823893e+02, -4.22521242e+02), forces1[889], tol); -ASSERT_EQUAL_VEC(Vec3(-3.53693728e+02, 1.03991649e+02, 1.47435093e+02), forces1[890], tol); -ASSERT_EQUAL_VEC(Vec3( 9.55664834e+01, 4.15286634e+02, 1.37712413e+02), forces1[891], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43136857e+02, -3.70066034e+01, -4.01965849e+02), forces1[892], tol); -ASSERT_EQUAL_VEC(Vec3( 1.26699422e+02, -2.55274151e+02, 1.49229513e+02), forces1[893], tol); diff --git a/platforms/reference/tests/nacl_amorph_GromacsForcesPME.dat b/platforms/reference/tests/nacl_amorph_GromacsForcesPME.dat deleted file mode 100644 index 9eed18500..000000000 --- a/platforms/reference/tests/nacl_amorph_GromacsForcesPME.dat +++ /dev/null @@ -1,894 +0,0 @@ -ASSERT_EQUAL_VEC(Vec3(-1.98238e+02, -2.23819e+02, -1.02566e+02), forces1[0], tol); -ASSERT_EQUAL_VEC(Vec3( 4.44029e+02, -3.90395e+02, -8.09590e+01), forces1[1], tol); -ASSERT_EQUAL_VEC(Vec3(-8.60870e+01, -1.05622e+01, -1.87777e+02), forces1[2], tol); -ASSERT_EQUAL_VEC(Vec3( 7.05375e+02, -1.69584e+02, 2.72477e+02), forces1[3], tol); -ASSERT_EQUAL_VEC(Vec3(-2.19351e+01, 5.33294e+02, -4.56194e+01), forces1[4], tol); -ASSERT_EQUAL_VEC(Vec3(-3.04277e+02, 2.02922e+02, 1.20245e+02), forces1[5], tol); -ASSERT_EQUAL_VEC(Vec3( 1.14214e+02, 1.21102e+02, 3.40941e+02), forces1[6], tol); -ASSERT_EQUAL_VEC(Vec3(-4.02332e+01, 3.78737e+02, 1.07247e+02), forces1[7], tol); -ASSERT_EQUAL_VEC(Vec3( 9.42963e+01, 1.00871e+01, 1.57706e+02), forces1[8], tol); -ASSERT_EQUAL_VEC(Vec3( 2.98432e+02, 1.18617e+02, -4.17515e+02), forces1[9], tol); -ASSERT_EQUAL_VEC(Vec3( 4.75037e+01, -5.56223e+00, -1.92343e+02), forces1[10], tol); -ASSERT_EQUAL_VEC(Vec3(-3.61212e+02, 4.00194e+02, -3.38480e+02), forces1[11], tol); -ASSERT_EQUAL_VEC(Vec3( 1.59872e+02, -2.22188e+02, -1.71809e+02), forces1[12], tol); -ASSERT_EQUAL_VEC(Vec3( 8.02097e+01, -2.46192e+02, 1.49732e+02), forces1[13], tol); -ASSERT_EQUAL_VEC(Vec3(-2.41490e+02, -8.22349e+01, -4.19816e+02), forces1[14], tol); -ASSERT_EQUAL_VEC(Vec3(-2.42760e+02, 4.99404e+00, 1.89251e+01), forces1[15], tol); -ASSERT_EQUAL_VEC(Vec3(-2.32033e+02, 2.91123e+02, -1.56148e+02), forces1[16], tol); -ASSERT_EQUAL_VEC(Vec3(-8.77282e+01, -4.75575e+02, -2.02740e+02), forces1[17], tol); -ASSERT_EQUAL_VEC(Vec3( 3.96090e+02, -6.37135e+02, 1.78663e+02), forces1[18], tol); -ASSERT_EQUAL_VEC(Vec3( 3.72230e+02, 1.17758e+02, 2.14245e+02), forces1[19], tol); -ASSERT_EQUAL_VEC(Vec3( 4.50070e+02, -1.37646e+01, 2.39932e+02), forces1[20], tol); -ASSERT_EQUAL_VEC(Vec3( 2.00016e+02, 3.30198e+01, 8.51831e+01), forces1[21], tol); -ASSERT_EQUAL_VEC(Vec3( 1.97199e+02, 7.33301e+02, 2.15197e+01), forces1[22], tol); -ASSERT_EQUAL_VEC(Vec3(-1.44369e+02, 9.15743e+01, 3.18981e+01), forces1[23], tol); -ASSERT_EQUAL_VEC(Vec3( 2.94560e+02, -3.69029e+02, 2.70469e+00), forces1[24], tol); -ASSERT_EQUAL_VEC(Vec3( 3.23107e+02, 8.86120e+02, 3.24425e+02), forces1[25], tol); -ASSERT_EQUAL_VEC(Vec3(-6.03139e+01, 1.68441e+02, 2.31890e+02), forces1[26], tol); -ASSERT_EQUAL_VEC(Vec3( 2.93353e+01, 5.76451e+01, 3.63994e+02), forces1[27], tol); -ASSERT_EQUAL_VEC(Vec3( 3.18489e-01, 1.34475e+02, -4.39831e+01), forces1[28], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38709e+02, -2.99570e+02, -2.80326e+02), forces1[29], tol); -ASSERT_EQUAL_VEC(Vec3(-8.28155e+01, 4.40624e+02, 9.65531e+01), forces1[30], tol); -ASSERT_EQUAL_VEC(Vec3( 2.03774e+01, -4.37685e+01, -5.06727e+01), forces1[31], tol); -ASSERT_EQUAL_VEC(Vec3(-2.60759e+02, 3.70684e+02, 1.28621e+02), forces1[32], tol); -ASSERT_EQUAL_VEC(Vec3( 1.97964e+02, -1.52120e+01, -2.85728e+02), forces1[33], tol); -ASSERT_EQUAL_VEC(Vec3(-2.63683e+01, -1.29412e+01, -2.36630e+02), forces1[34], tol); -ASSERT_EQUAL_VEC(Vec3( 2.13607e+02, -2.29651e+02, -7.72846e+02), forces1[35], tol); -ASSERT_EQUAL_VEC(Vec3(-4.26326e+01, 9.00722e+01, 3.48806e+02), forces1[36], tol); -ASSERT_EQUAL_VEC(Vec3(-2.27760e+02, -8.49427e+00, -3.25568e+02), forces1[37], tol); -ASSERT_EQUAL_VEC(Vec3(-8.32014e+01, -2.50950e+02, 5.80192e+01), forces1[38], tol); -ASSERT_EQUAL_VEC(Vec3(-2.32232e+02, 1.30458e+02, 6.05363e+00), forces1[39], tol); -ASSERT_EQUAL_VEC(Vec3(-1.14431e+02, -3.48761e+01, -8.76148e+01), forces1[40], tol); -ASSERT_EQUAL_VEC(Vec3(-2.55342e+02, -2.79189e+02, -1.68749e+02), forces1[41], tol); -ASSERT_EQUAL_VEC(Vec3(-2.02321e+02, 1.47907e+02, 1.75227e+02), forces1[42], tol); -ASSERT_EQUAL_VEC(Vec3( 2.63248e+01, -4.46996e+02, -2.37737e+00), forces1[43], tol); -ASSERT_EQUAL_VEC(Vec3( 2.55965e+02, -2.93440e+02, 3.28023e+02), forces1[44], tol); -ASSERT_EQUAL_VEC(Vec3( 1.14323e+02, 2.24373e+02, -8.29717e+01), forces1[45], tol); -ASSERT_EQUAL_VEC(Vec3( 1.43347e+01, 2.46486e+02, -3.75145e+02), forces1[46], tol); -ASSERT_EQUAL_VEC(Vec3(-4.34804e+02, -9.73177e+01, -1.91079e+02), forces1[47], tol); -ASSERT_EQUAL_VEC(Vec3( 5.22940e+01, 5.50944e+02, 2.90237e+02), forces1[48], tol); -ASSERT_EQUAL_VEC(Vec3(-4.83950e+01, 1.71484e+02, -3.42302e+02), forces1[49], tol); -ASSERT_EQUAL_VEC(Vec3(-2.61453e+02, 9.01727e+01, 3.64102e+02), forces1[50], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43627e+02, -5.19312e+02, -7.74800e+01), forces1[51], tol); -ASSERT_EQUAL_VEC(Vec3( 2.15597e+02, -5.54586e+02, 1.71365e+02), forces1[52], tol); -ASSERT_EQUAL_VEC(Vec3(-2.14777e+02, 3.56724e+02, -3.71997e+02), forces1[53], tol); -ASSERT_EQUAL_VEC(Vec3( 2.22118e+02, 2.73200e+02, 1.61950e+02), forces1[54], tol); -ASSERT_EQUAL_VEC(Vec3( 2.85119e+02, 3.19144e+02, -1.98761e+02), forces1[55], tol); -ASSERT_EQUAL_VEC(Vec3( 3.90047e+02, 5.91187e+02, 8.76052e+01), forces1[56], tol); -ASSERT_EQUAL_VEC(Vec3( 1.69067e+02, -9.43258e+01, 3.42177e+02), forces1[57], tol); -ASSERT_EQUAL_VEC(Vec3( 2.93040e+01, -1.03068e+02, 5.37913e+01), forces1[58], tol); -ASSERT_EQUAL_VEC(Vec3( 4.08998e+01, 1.30025e+02, -7.16616e+01), forces1[59], tol); -ASSERT_EQUAL_VEC(Vec3(-1.89925e+02, 5.51894e+00, 4.53550e+02), forces1[60], tol); -ASSERT_EQUAL_VEC(Vec3(-1.11554e+02, 1.24171e+02, 4.53012e+02), forces1[61], tol); -ASSERT_EQUAL_VEC(Vec3( 1.54597e+02, -2.70144e+02, -7.89501e+01), forces1[62], tol); -ASSERT_EQUAL_VEC(Vec3( 2.84029e+02, -8.89897e+01, 3.24511e+02), forces1[63], tol); -ASSERT_EQUAL_VEC(Vec3( 1.44360e+02, -7.96586e+01, -2.53245e+02), forces1[64], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77734e+02, 8.42945e+01, -1.41070e+02), forces1[65], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69652e+02, -5.26516e+02, -1.04064e+02), forces1[66], tol); -ASSERT_EQUAL_VEC(Vec3(-2.41602e+02, -9.41429e+01, 3.30147e+01), forces1[67], tol); -ASSERT_EQUAL_VEC(Vec3( 6.81069e+02, -5.79240e+02, -9.71642e-01), forces1[68], tol); -ASSERT_EQUAL_VEC(Vec3( 2.88769e+02, 2.41582e+02, -1.90685e+02), forces1[69], tol); -ASSERT_EQUAL_VEC(Vec3(-1.31603e+01, 1.14262e+01, 4.13776e+01), forces1[70], tol); -ASSERT_EQUAL_VEC(Vec3( 5.14411e+01, -9.72283e+01, 1.27245e+01), forces1[71], tol); -ASSERT_EQUAL_VEC(Vec3( 7.15737e+01, -1.94134e+02, -2.48980e+02), forces1[72], tol); -ASSERT_EQUAL_VEC(Vec3(-9.16921e+01, 1.23396e+02, -2.86180e+02), forces1[73], tol); -ASSERT_EQUAL_VEC(Vec3( 9.82499e+01, -7.07136e+01, -1.29192e+02), forces1[74], tol); -ASSERT_EQUAL_VEC(Vec3(-2.15576e+02, -1.43100e+02, -1.96438e+02), forces1[75], tol); -ASSERT_EQUAL_VEC(Vec3(-4.61162e+02, -4.03097e+02, -4.56028e+01), forces1[76], tol); -ASSERT_EQUAL_VEC(Vec3( 1.52885e+02, -9.37800e+02, 2.93600e+02), forces1[77], tol); -ASSERT_EQUAL_VEC(Vec3( 2.45711e+02, 1.99845e+01, 1.17917e+02), forces1[78], tol); -ASSERT_EQUAL_VEC(Vec3(-2.37050e+02, 2.49524e+02, 2.13426e+02), forces1[79], tol); -ASSERT_EQUAL_VEC(Vec3(-2.90554e+02, 1.91128e+02, -4.24254e+02), forces1[80], tol); -ASSERT_EQUAL_VEC(Vec3( 2.98841e+02, -5.76039e+00, 2.66632e+02), forces1[81], tol); -ASSERT_EQUAL_VEC(Vec3(-3.26781e+02, -2.54764e+02, -3.00077e+02), forces1[82], tol); -ASSERT_EQUAL_VEC(Vec3(-2.95144e+02, 1.21764e+02, -2.83475e+02), forces1[83], tol); -ASSERT_EQUAL_VEC(Vec3( 4.04598e+02, 1.66819e+02, -5.58132e+01), forces1[84], tol); -ASSERT_EQUAL_VEC(Vec3(-8.21664e+02, 5.19844e+02, 5.32043e+01), forces1[85], tol); -ASSERT_EQUAL_VEC(Vec3(-3.49444e+02, -1.47683e+02, -4.95512e+02), forces1[86], tol); -ASSERT_EQUAL_VEC(Vec3(-4.48878e+02, -7.41503e+01, -4.28596e+02), forces1[87], tol); -ASSERT_EQUAL_VEC(Vec3(-1.97044e+02, -3.40603e+02, 2.10204e+00), forces1[88], tol); -ASSERT_EQUAL_VEC(Vec3( 9.52481e+01, -4.20783e+02, 5.76746e+01), forces1[89], tol); -ASSERT_EQUAL_VEC(Vec3( 1.21807e+02, -1.40400e+02, -2.93285e+02), forces1[90], tol); -ASSERT_EQUAL_VEC(Vec3( 2.10629e+02, 5.88038e+01, 7.23663e+01), forces1[91], tol); -ASSERT_EQUAL_VEC(Vec3( 6.72915e+01, -1.46949e+02, -2.63710e+02), forces1[92], tol); -ASSERT_EQUAL_VEC(Vec3( 3.96779e+02, -4.38664e+02, -2.57916e+02), forces1[93], tol); -ASSERT_EQUAL_VEC(Vec3(-2.66189e+01, 1.59116e+01, 4.36637e+02), forces1[94], tol); -ASSERT_EQUAL_VEC(Vec3(-3.00015e+02, -6.20522e+01, -4.29146e+02), forces1[95], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77047e+02, 5.58882e+01, 1.05674e+02), forces1[96], tol); -ASSERT_EQUAL_VEC(Vec3(-6.92728e+01, -5.45431e+02, -2.10884e+01), forces1[97], tol); -ASSERT_EQUAL_VEC(Vec3(-3.90061e+01, -1.21126e+02, 1.68310e+01), forces1[98], tol); -ASSERT_EQUAL_VEC(Vec3(-2.19576e+01, 1.51712e+02, -3.39292e+01), forces1[99], tol); -ASSERT_EQUAL_VEC(Vec3( 9.20478e+01, -4.22547e+02, -1.81073e+01), forces1[100], tol); -ASSERT_EQUAL_VEC(Vec3( 5.80549e+01, 1.45413e+02, -4.53187e+01), forces1[101], tol); -ASSERT_EQUAL_VEC(Vec3( 6.12578e+02, -1.41330e+01, 2.13583e+02), forces1[102], tol); -ASSERT_EQUAL_VEC(Vec3(-1.02947e+02, -8.76472e+01, 2.20906e+02), forces1[103], tol); -ASSERT_EQUAL_VEC(Vec3( 1.44800e+02, -2.89016e+02, 1.68141e+02), forces1[104], tol); -ASSERT_EQUAL_VEC(Vec3( 9.68802e+01, -2.62265e+02, -3.07293e+02), forces1[105], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09044e+02, -2.43250e+02, -2.45232e+02), forces1[106], tol); -ASSERT_EQUAL_VEC(Vec3( 1.89553e+02, 1.49335e+02, -3.74288e+02), forces1[107], tol); -ASSERT_EQUAL_VEC(Vec3( 1.20770e+02, -1.66095e+02, -4.46390e+02), forces1[108], tol); -ASSERT_EQUAL_VEC(Vec3(-6.91040e+02, 6.62259e+02, 3.06075e+01), forces1[109], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61286e+02, 8.89662e+01, -3.35508e+01), forces1[110], tol); -ASSERT_EQUAL_VEC(Vec3(-4.17337e+02, 4.26282e+01, -7.77221e+01), forces1[111], tol); -ASSERT_EQUAL_VEC(Vec3(-4.01777e+01, 8.24730e+01, 4.51851e+02), forces1[112], tol); -ASSERT_EQUAL_VEC(Vec3(-1.40974e+01, -2.40650e+02, -1.27611e+02), forces1[113], tol); -ASSERT_EQUAL_VEC(Vec3( 2.83838e+02, 2.31052e+02, 1.33440e+01), forces1[114], tol); -ASSERT_EQUAL_VEC(Vec3( 5.10743e+01, -7.13353e+02, -4.07609e+02), forces1[115], tol); -ASSERT_EQUAL_VEC(Vec3(-1.56084e+02, -1.33127e+02, 2.25953e+02), forces1[116], tol); -ASSERT_EQUAL_VEC(Vec3( 3.69751e+01, -1.35050e+01, 1.10570e+02), forces1[117], tol); -ASSERT_EQUAL_VEC(Vec3( 3.37822e+02, 8.10444e+01, -5.39664e+01), forces1[118], tol); -ASSERT_EQUAL_VEC(Vec3( 5.49925e+01, 7.55077e+01, 1.80537e+02), forces1[119], tol); -ASSERT_EQUAL_VEC(Vec3( 1.10959e+02, -3.83960e+02, 2.78081e+01), forces1[120], tol); -ASSERT_EQUAL_VEC(Vec3(-2.63191e+02, -3.16263e+02, -3.95227e+02), forces1[121], tol); -ASSERT_EQUAL_VEC(Vec3( 3.42551e+02, -2.35755e+02, 4.60349e+02), forces1[122], tol); -ASSERT_EQUAL_VEC(Vec3( 2.47660e+02, 2.42873e+02, 1.52219e+02), forces1[123], tol); -ASSERT_EQUAL_VEC(Vec3(-2.70208e+02, 2.08577e+02, -1.86857e+02), forces1[124], tol); -ASSERT_EQUAL_VEC(Vec3( 3.24091e+02, 2.55006e+02, -1.10874e+02), forces1[125], tol); -ASSERT_EQUAL_VEC(Vec3( 5.16198e+02, -5.06223e+01, -2.80862e+02), forces1[126], tol); -ASSERT_EQUAL_VEC(Vec3(-3.30850e+02, -3.47287e+02, 1.45245e+02), forces1[127], tol); -ASSERT_EQUAL_VEC(Vec3(-1.28351e+02, 7.69111e+01, 2.14899e+02), forces1[128], tol); -ASSERT_EQUAL_VEC(Vec3(-1.91475e+02, -2.11487e+02, 1.35327e+02), forces1[129], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69888e+02, 1.11316e+02, -8.98475e+01), forces1[130], tol); -ASSERT_EQUAL_VEC(Vec3(-1.36356e+02, -2.14227e+02, -5.83946e+01), forces1[131], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38558e+02, 2.36118e+02, -2.08878e+01), forces1[132], tol); -ASSERT_EQUAL_VEC(Vec3(-2.47603e+02, 3.98194e+02, -1.64773e+02), forces1[133], tol); -ASSERT_EQUAL_VEC(Vec3(-8.37474e+01, 4.07950e+02, -1.24164e+02), forces1[134], tol); -ASSERT_EQUAL_VEC(Vec3(-1.60152e+02, -6.50199e+00, 3.55060e+02), forces1[135], tol); -ASSERT_EQUAL_VEC(Vec3( 3.58257e+02, -2.81406e+02, -1.28029e+02), forces1[136], tol); -ASSERT_EQUAL_VEC(Vec3( 3.33746e+02, -3.31207e+02, -2.41567e+01), forces1[137], tol); -ASSERT_EQUAL_VEC(Vec3(-3.00677e+02, -1.70094e+02, 8.30774e+01), forces1[138], tol); -ASSERT_EQUAL_VEC(Vec3(-1.94848e+01, 1.35839e+02, -3.65168e+02), forces1[139], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77179e+02, 4.44424e+01, 2.11476e+02), forces1[140], tol); -ASSERT_EQUAL_VEC(Vec3( 4.59288e+02, -3.23648e+02, 3.67802e+02), forces1[141], tol); -ASSERT_EQUAL_VEC(Vec3( 4.22135e+02, 2.22083e+02, 2.92481e+02), forces1[142], tol); -ASSERT_EQUAL_VEC(Vec3( 2.83734e+02, -2.92595e+02, 8.17914e+01), forces1[143], tol); -ASSERT_EQUAL_VEC(Vec3(-5.70476e+01, 2.40284e+02, -3.40876e+01), forces1[144], tol); -ASSERT_EQUAL_VEC(Vec3( 1.04088e+02, 1.58977e+02, 1.10182e+01), forces1[145], tol); -ASSERT_EQUAL_VEC(Vec3( 5.88504e+02, 2.07873e+02, -7.36857e+01), forces1[146], tol); -ASSERT_EQUAL_VEC(Vec3( 2.82644e+02, 2.25984e+02, 2.16741e+02), forces1[147], tol); -ASSERT_EQUAL_VEC(Vec3(-2.02425e+02, 1.65903e+02, -1.47473e+02), forces1[148], tol); -ASSERT_EQUAL_VEC(Vec3(-2.96634e+02, -4.87422e+02, 1.60837e+02), forces1[149], tol); -ASSERT_EQUAL_VEC(Vec3( 2.94716e+02, 1.30350e+02, 2.82786e+01), forces1[150], tol); -ASSERT_EQUAL_VEC(Vec3( 3.70883e+02, 3.22177e+01, 8.74457e+01), forces1[151], tol); -ASSERT_EQUAL_VEC(Vec3( 3.44000e+02, -2.07929e+02, 3.49059e+02), forces1[152], tol); -ASSERT_EQUAL_VEC(Vec3( 1.43030e+01, -2.80350e+02, 5.69624e+01), forces1[153], tol); -ASSERT_EQUAL_VEC(Vec3( 9.71900e+01, 1.42411e+01, 1.00140e+02), forces1[154], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56963e+02, -1.88089e+01, -1.07623e+02), forces1[155], tol); -ASSERT_EQUAL_VEC(Vec3( 4.20295e+02, 1.16954e+02, 4.29566e+02), forces1[156], tol); -ASSERT_EQUAL_VEC(Vec3(-2.05593e+02, -2.74959e+02, 1.32855e+02), forces1[157], tol); -ASSERT_EQUAL_VEC(Vec3( 2.89209e+01, 1.07778e+01, -2.09463e+02), forces1[158], tol); -ASSERT_EQUAL_VEC(Vec3(-4.54593e+02, -2.58228e+01, -2.66965e+02), forces1[159], tol); -ASSERT_EQUAL_VEC(Vec3( 5.91052e+02, -7.76642e+01, 9.29134e+01), forces1[160], tol); -ASSERT_EQUAL_VEC(Vec3(-8.26339e+00, 2.39612e+02, 1.04877e+02), forces1[161], tol); -ASSERT_EQUAL_VEC(Vec3( 4.79939e+01, -1.73697e+02, -5.98017e+01), forces1[162], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26010e+02, 1.64321e+02, -4.23292e+02), forces1[163], tol); -ASSERT_EQUAL_VEC(Vec3(-2.03195e+02, 1.46922e+02, 2.50713e+02), forces1[164], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38811e+02, 1.32928e+02, 2.75566e+02), forces1[165], tol); -ASSERT_EQUAL_VEC(Vec3( 9.19090e+01, -1.55644e+02, 1.24224e+02), forces1[166], tol); -ASSERT_EQUAL_VEC(Vec3( 2.09934e+02, 1.26972e+02, -3.32816e+02), forces1[167], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56192e+02, 6.10657e+00, 3.42782e+02), forces1[168], tol); -ASSERT_EQUAL_VEC(Vec3( 3.11423e+02, 9.42269e+01, -8.52675e+00), forces1[169], tol); -ASSERT_EQUAL_VEC(Vec3( 1.78684e+02, -1.37283e+01, -2.21919e+01), forces1[170], tol); -ASSERT_EQUAL_VEC(Vec3(-4.69160e+01, 5.77174e+02, 1.04228e+02), forces1[171], tol); -ASSERT_EQUAL_VEC(Vec3( 1.31260e+02, 7.57898e+01, -9.08328e+01), forces1[172], tol); -ASSERT_EQUAL_VEC(Vec3(-1.69432e+02, -3.62007e+02, 2.68885e+02), forces1[173], tol); -ASSERT_EQUAL_VEC(Vec3(-1.68470e+02, -2.62621e+02, 7.40996e+01), forces1[174], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53156e+02, 2.68902e+02, -3.92489e+02), forces1[175], tol); -ASSERT_EQUAL_VEC(Vec3( 1.95127e+02, -5.76545e+01, 3.91956e+02), forces1[176], tol); -ASSERT_EQUAL_VEC(Vec3( 2.43341e+02, -3.91473e+02, -8.63941e+01), forces1[177], tol); -ASSERT_EQUAL_VEC(Vec3(-1.34182e+02, 1.46584e+02, 1.19870e+02), forces1[178], tol); -ASSERT_EQUAL_VEC(Vec3( 1.63164e+02, -2.66967e+02, 1.65791e+02), forces1[179], tol); -ASSERT_EQUAL_VEC(Vec3( 5.46590e+01, 6.58743e+01, -4.94241e+02), forces1[180], tol); -ASSERT_EQUAL_VEC(Vec3(-1.62967e+02, 1.53812e+02, 2.72243e+01), forces1[181], tol); -ASSERT_EQUAL_VEC(Vec3(-1.97753e+02, -9.07862e+01, -5.59637e+02), forces1[182], tol); -ASSERT_EQUAL_VEC(Vec3(-9.59328e+01, -3.67223e+02, -1.37096e+02), forces1[183], tol); -ASSERT_EQUAL_VEC(Vec3(-3.13273e+02, -4.77523e+02, -2.82321e+02), forces1[184], tol); -ASSERT_EQUAL_VEC(Vec3( 3.47114e+01, -1.51858e+02, -2.71784e+02), forces1[185], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09989e+02, 7.60839e+01, -1.90745e+02), forces1[186], tol); -ASSERT_EQUAL_VEC(Vec3( 3.49591e+02, 1.52748e+02, 4.22478e+02), forces1[187], tol); -ASSERT_EQUAL_VEC(Vec3(-3.59778e+01, 3.55514e+01, -7.87122e+01), forces1[188], tol); -ASSERT_EQUAL_VEC(Vec3(-5.53788e+02, 1.58097e+02, -5.47413e+01), forces1[189], tol); -ASSERT_EQUAL_VEC(Vec3( 8.55383e+01, -2.88446e+02, 2.54335e+01), forces1[190], tol); -ASSERT_EQUAL_VEC(Vec3( 1.96776e+02, 1.69083e+02, 2.41079e+02), forces1[191], tol); -ASSERT_EQUAL_VEC(Vec3( 7.63954e+01, 3.05700e+02, 2.76177e+02), forces1[192], tol); -ASSERT_EQUAL_VEC(Vec3( 1.23270e+02, 8.57544e+01, 3.46732e+02), forces1[193], tol); -ASSERT_EQUAL_VEC(Vec3(-9.05524e+01, 5.50783e+01, -4.12477e+02), forces1[194], tol); -ASSERT_EQUAL_VEC(Vec3(-2.70275e+00, 1.30545e+02, -1.55114e+02), forces1[195], tol); -ASSERT_EQUAL_VEC(Vec3(-1.37391e+02, -2.94314e+02, -1.24617e+02), forces1[196], tol); -ASSERT_EQUAL_VEC(Vec3(-3.56081e+02, -9.03717e+01, 3.14903e+02), forces1[197], tol); -ASSERT_EQUAL_VEC(Vec3(-7.79201e+01, 1.12169e+02, 3.86360e+02), forces1[198], tol); -ASSERT_EQUAL_VEC(Vec3( 2.43084e+02, 5.36465e+02, -9.47472e+01), forces1[199], tol); -ASSERT_EQUAL_VEC(Vec3(-7.39515e+01, -3.53203e+02, 1.42906e+01), forces1[200], tol); -ASSERT_EQUAL_VEC(Vec3( 6.56525e+02, -2.80413e+02, 2.95738e+02), forces1[201], tol); -ASSERT_EQUAL_VEC(Vec3(-2.72295e+02, -1.44068e+02, 2.55682e+02), forces1[202], tol); -ASSERT_EQUAL_VEC(Vec3(-3.75581e+01, 2.99407e+02, -4.12452e+02), forces1[203], tol); -ASSERT_EQUAL_VEC(Vec3( 3.64683e+02, 3.39099e+02, -8.08627e+01), forces1[204], tol); -ASSERT_EQUAL_VEC(Vec3( 4.32794e+02, -1.78902e+02, 3.86635e+02), forces1[205], tol); -ASSERT_EQUAL_VEC(Vec3(-9.04431e+01, 3.89962e+02, -5.47942e+02), forces1[206], tol); -ASSERT_EQUAL_VEC(Vec3(-6.35047e+02, 1.85340e+01, 3.17100e+01), forces1[207], tol); -ASSERT_EQUAL_VEC(Vec3(-5.92927e+01, -2.85278e+02, -1.42336e+02), forces1[208], tol); -ASSERT_EQUAL_VEC(Vec3(-1.35200e+02, -3.56060e+02, 1.07958e+02), forces1[209], tol); -ASSERT_EQUAL_VEC(Vec3( 3.94881e+02, 9.99543e+01, -1.57851e+02), forces1[210], tol); -ASSERT_EQUAL_VEC(Vec3(-1.56550e+02, -1.66155e+02, -4.76763e+00), forces1[211], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77273e+02, -9.51984e+01, -3.42047e+02), forces1[212], tol); -ASSERT_EQUAL_VEC(Vec3( 2.97728e+02, 7.18136e+02, -4.94807e+02), forces1[213], tol); -ASSERT_EQUAL_VEC(Vec3(-5.12783e+02, 7.63620e+02, -5.44394e+01), forces1[214], tol); -ASSERT_EQUAL_VEC(Vec3(-2.55726e+02, -4.46420e+02, -1.72489e+02), forces1[215], tol); -ASSERT_EQUAL_VEC(Vec3( 3.15171e+02, 5.62389e+02, 2.42576e+02), forces1[216], tol); -ASSERT_EQUAL_VEC(Vec3(-2.90712e+01, 3.91014e+02, 1.36611e+02), forces1[217], tol); -ASSERT_EQUAL_VEC(Vec3(-4.26378e+02, 5.13932e+02, 8.37934e+01), forces1[218], tol); -ASSERT_EQUAL_VEC(Vec3(-2.88401e+02, 6.41261e+01, 3.02429e+02), forces1[219], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13219e+01, -3.20436e+02, 1.98720e+02), forces1[220], tol); -ASSERT_EQUAL_VEC(Vec3(-1.73195e+02, 2.09809e+02, 2.60748e+02), forces1[221], tol); -ASSERT_EQUAL_VEC(Vec3( 4.34172e+02, -1.25036e+02, 2.52922e+02), forces1[222], tol); -ASSERT_EQUAL_VEC(Vec3(-3.09527e+02, 2.63414e+02, -2.33511e+02), forces1[223], tol); -ASSERT_EQUAL_VEC(Vec3( 8.65417e+01, -5.32174e+02, -2.36445e+02), forces1[224], tol); -ASSERT_EQUAL_VEC(Vec3(-1.74956e+02, -2.30188e+02, -1.33696e+02), forces1[225], tol); -ASSERT_EQUAL_VEC(Vec3( 1.53827e+02, -1.24376e+02, -3.93704e+01), forces1[226], tol); -ASSERT_EQUAL_VEC(Vec3(-4.51770e+02, -7.75099e+01, -5.36164e+02), forces1[227], tol); -ASSERT_EQUAL_VEC(Vec3( 5.99182e+01, 2.97286e+02, 5.99064e+01), forces1[228], tol); -ASSERT_EQUAL_VEC(Vec3(-3.10611e+02, 2.95975e+00, -3.63666e+01), forces1[229], tol); -ASSERT_EQUAL_VEC(Vec3( 3.85866e+02, 1.41628e+02, 2.75110e+02), forces1[230], tol); -ASSERT_EQUAL_VEC(Vec3( 5.43212e+02, -3.20236e+02, -3.02040e+01), forces1[231], tol); -ASSERT_EQUAL_VEC(Vec3( 3.85594e+02, 6.64254e+01, -3.49438e+01), forces1[232], tol); -ASSERT_EQUAL_VEC(Vec3(-4.52870e+02, -3.40699e+02, 1.28895e+02), forces1[233], tol); -ASSERT_EQUAL_VEC(Vec3( 9.34274e+02, -1.39499e+02, 3.57860e+02), forces1[234], tol); -ASSERT_EQUAL_VEC(Vec3(-2.03059e+02, 7.44587e+01, 9.27241e+01), forces1[235], tol); -ASSERT_EQUAL_VEC(Vec3(-5.97529e+02, 1.26808e+02, 2.78892e+02), forces1[236], tol); -ASSERT_EQUAL_VEC(Vec3( 5.67859e+02, -5.34679e+02, -1.84220e+02), forces1[237], tol); -ASSERT_EQUAL_VEC(Vec3( 2.13200e+02, 2.99785e+02, -2.66449e+02), forces1[238], tol); -ASSERT_EQUAL_VEC(Vec3( 3.11287e+01, 4.54671e+02, 3.80933e+01), forces1[239], tol); -ASSERT_EQUAL_VEC(Vec3( 1.57505e+02, 3.19189e+01, -1.57725e+02), forces1[240], tol); -ASSERT_EQUAL_VEC(Vec3( 4.34917e+02, -4.69304e+02, -3.96804e+01), forces1[241], tol); -ASSERT_EQUAL_VEC(Vec3(-3.54012e+01, -1.00149e+02, 7.07594e+01), forces1[242], tol); -ASSERT_EQUAL_VEC(Vec3( 3.29664e+02, 3.63915e+02, -3.89187e+02), forces1[243], tol); -ASSERT_EQUAL_VEC(Vec3( 7.63973e+02, 2.97338e+02, -5.40126e+01), forces1[244], tol); -ASSERT_EQUAL_VEC(Vec3(-2.67921e+02, 2.23572e+02, -1.67260e+02), forces1[245], tol); -ASSERT_EQUAL_VEC(Vec3(-6.45303e+02, -9.38934e+00, -5.71083e+02), forces1[246], tol); -ASSERT_EQUAL_VEC(Vec3( 1.48206e+02, -1.78758e+02, 8.43606e+01), forces1[247], tol); -ASSERT_EQUAL_VEC(Vec3( 3.26733e+02, -3.84541e+02, 2.88339e+02), forces1[248], tol); -ASSERT_EQUAL_VEC(Vec3( 2.58355e+02, 5.43926e+01, 3.38657e+02), forces1[249], tol); -ASSERT_EQUAL_VEC(Vec3(-3.51580e+02, -3.06746e+02, -2.99583e+01), forces1[250], tol); -ASSERT_EQUAL_VEC(Vec3(-2.78564e+01, 2.36171e+02, 1.06051e+01), forces1[251], tol); -ASSERT_EQUAL_VEC(Vec3(-1.75884e+02, -9.36825e+00, 1.84217e+02), forces1[252], tol); -ASSERT_EQUAL_VEC(Vec3(-5.60414e+02, 1.90158e+02, -2.90241e+02), forces1[253], tol); -ASSERT_EQUAL_VEC(Vec3(-1.69419e+02, 2.23708e+02, -3.41993e+02), forces1[254], tol); -ASSERT_EQUAL_VEC(Vec3(-6.96442e+01, 1.66443e+02, -6.76290e+00), forces1[255], tol); -ASSERT_EQUAL_VEC(Vec3( 2.73634e+02, 1.47945e+00, 7.80674e+01), forces1[256], tol); -ASSERT_EQUAL_VEC(Vec3(-2.58360e+02, 8.46506e+01, -9.41941e+01), forces1[257], tol); -ASSERT_EQUAL_VEC(Vec3(-4.25856e+02, 9.84269e+00, 6.39688e+01), forces1[258], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12074e+02, 6.10175e+01, -1.38671e+02), forces1[259], tol); -ASSERT_EQUAL_VEC(Vec3( 3.21742e+01, 3.67503e+02, 6.86820e+01), forces1[260], tol); -ASSERT_EQUAL_VEC(Vec3(-3.72197e+02, 3.36299e+02, 3.15267e+02), forces1[261], tol); -ASSERT_EQUAL_VEC(Vec3( 4.28544e+01, 5.93439e+01, 4.86904e+02), forces1[262], tol); -ASSERT_EQUAL_VEC(Vec3( 3.03218e+01, 3.70289e+02, -5.83427e+02), forces1[263], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61746e+02, 3.70556e+02, -2.03554e+01), forces1[264], tol); -ASSERT_EQUAL_VEC(Vec3(-6.67228e+02, -1.24405e+01, -9.41848e+01), forces1[265], tol); -ASSERT_EQUAL_VEC(Vec3( 4.66963e+02, 3.49517e+02, 2.04653e+02), forces1[266], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52489e+02, -1.24054e+01, 2.24698e+01), forces1[267], tol); -ASSERT_EQUAL_VEC(Vec3( 4.58673e+01, -2.20882e+02, 7.64532e+01), forces1[268], tol); -ASSERT_EQUAL_VEC(Vec3(-4.43759e+01, -1.14901e+02, -2.87908e+02), forces1[269], tol); -ASSERT_EQUAL_VEC(Vec3(-9.22294e+01, 6.40897e+02, 3.17837e+02), forces1[270], tol); -ASSERT_EQUAL_VEC(Vec3(-2.15619e+02, -2.05476e+02, 6.85753e+01), forces1[271], tol); -ASSERT_EQUAL_VEC(Vec3( 2.24210e+02, -1.43086e+02, -4.17853e+01), forces1[272], tol); -ASSERT_EQUAL_VEC(Vec3( 1.79801e+02, -3.72431e+02, 2.12152e+02), forces1[273], tol); -ASSERT_EQUAL_VEC(Vec3( 9.74712e+01, 7.66879e+01, -5.04532e+02), forces1[274], tol); -ASSERT_EQUAL_VEC(Vec3( 2.17851e+01, -5.76193e+02, -3.23925e+02), forces1[275], tol); -ASSERT_EQUAL_VEC(Vec3(-2.97069e+02, -1.47147e+02, -1.56571e+02), forces1[276], tol); -ASSERT_EQUAL_VEC(Vec3( 4.21716e+01, -2.91447e+02, -1.50265e+02), forces1[277], tol); -ASSERT_EQUAL_VEC(Vec3( 1.75434e+02, -9.12760e+01, 6.45501e+01), forces1[278], tol); -ASSERT_EQUAL_VEC(Vec3( 1.50375e+02, -1.42450e+02, 2.67953e+02), forces1[279], tol); -ASSERT_EQUAL_VEC(Vec3(-4.86647e+02, -2.18743e+01, 1.45714e+02), forces1[280], tol); -ASSERT_EQUAL_VEC(Vec3( 9.28419e+01, -6.94980e+01, -8.90565e+00), forces1[281], tol); -ASSERT_EQUAL_VEC(Vec3(-5.85243e+01, 2.84897e+02, 4.82514e+02), forces1[282], tol); -ASSERT_EQUAL_VEC(Vec3(-2.83552e+01, -1.73734e+02, -3.77885e+02), forces1[283], tol); -ASSERT_EQUAL_VEC(Vec3(-4.34939e+02, -1.30344e+02, -3.31885e+02), forces1[284], tol); -ASSERT_EQUAL_VEC(Vec3( 3.85318e+01, -2.54993e+02, -5.18580e+02), forces1[285], tol); -ASSERT_EQUAL_VEC(Vec3(-7.78898e+01, 1.25376e+02, -3.80651e+02), forces1[286], tol); -ASSERT_EQUAL_VEC(Vec3(-1.27219e+02, 3.88677e+02, 9.40603e+01), forces1[287], tol); -ASSERT_EQUAL_VEC(Vec3( 1.39438e+02, 4.03527e+02, -4.33294e+02), forces1[288], tol); -ASSERT_EQUAL_VEC(Vec3(-2.88829e+00, -2.06320e+02, -7.48585e+02), forces1[289], tol); -ASSERT_EQUAL_VEC(Vec3( 1.07981e+01, 2.35861e+02, -1.38359e+02), forces1[290], tol); -ASSERT_EQUAL_VEC(Vec3( 8.60284e+01, 5.74943e+02, 1.95762e+02), forces1[291], tol); -ASSERT_EQUAL_VEC(Vec3(-2.45605e+02, 1.95528e+02, 1.22031e+02), forces1[292], tol); -ASSERT_EQUAL_VEC(Vec3(-3.33844e+02, -2.71363e+02, -3.43370e+02), forces1[293], tol); -ASSERT_EQUAL_VEC(Vec3(-4.28638e+02, 1.60891e+02, 2.18049e+02), forces1[294], tol); -ASSERT_EQUAL_VEC(Vec3(-5.40059e+02, -1.47441e+02, 4.35219e+02), forces1[295], tol); -ASSERT_EQUAL_VEC(Vec3( 1.48834e+02, 3.45734e+01, -1.25812e+02), forces1[296], tol); -ASSERT_EQUAL_VEC(Vec3( 3.39094e+02, 3.68778e+01, 2.99734e+01), forces1[297], tol); -ASSERT_EQUAL_VEC(Vec3(-1.67733e+02, -2.84609e+02, 3.88550e+01), forces1[298], tol); -ASSERT_EQUAL_VEC(Vec3(-3.21477e+02, -4.49303e+02, 1.41885e+02), forces1[299], tol); -ASSERT_EQUAL_VEC(Vec3( 1.16243e+02, 6.78513e+00, -1.08225e+02), forces1[300], tol); -ASSERT_EQUAL_VEC(Vec3(-1.85556e+02, -2.95254e+02, 5.01916e+02), forces1[301], tol); -ASSERT_EQUAL_VEC(Vec3( 9.27468e+01, -3.83936e+02, -2.77959e+02), forces1[302], tol); -ASSERT_EQUAL_VEC(Vec3(-3.97651e+01, 2.84541e+02, 2.33443e+02), forces1[303], tol); -ASSERT_EQUAL_VEC(Vec3( 1.40072e+00, 2.25399e+02, 9.48102e+01), forces1[304], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06096e+02, 2.06345e+02, -2.00217e+02), forces1[305], tol); -ASSERT_EQUAL_VEC(Vec3(-3.33985e+02, -3.09147e+01, -9.24046e+01), forces1[306], tol); -ASSERT_EQUAL_VEC(Vec3( 1.47346e+01, 1.47720e+02, 2.61218e+02), forces1[307], tol); -ASSERT_EQUAL_VEC(Vec3( 4.44221e+01, 1.15106e+02, 1.21336e+02), forces1[308], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53468e+02, 2.00343e+02, 3.39205e+01), forces1[309], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06608e+02, -1.16082e+02, 5.96468e+01), forces1[310], tol); -ASSERT_EQUAL_VEC(Vec3(-2.01600e+02, 4.15917e+01, 4.19308e+02), forces1[311], tol); -ASSERT_EQUAL_VEC(Vec3( 4.40503e+02, 1.34424e+02, 7.74282e+01), forces1[312], tol); -ASSERT_EQUAL_VEC(Vec3(-3.89154e+02, -2.83347e+02, -4.23560e+02), forces1[313], tol); -ASSERT_EQUAL_VEC(Vec3( 2.42086e+02, -6.45962e+02, 3.91500e+02), forces1[314], tol); -ASSERT_EQUAL_VEC(Vec3(-3.71539e+02, -4.53999e+01, 5.02838e+02), forces1[315], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52594e+02, 8.61216e+01, 2.63794e+02), forces1[316], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18403e+01, -1.24903e+02, -2.32014e+02), forces1[317], tol); -ASSERT_EQUAL_VEC(Vec3(-4.28776e+02, 2.69290e+02, -1.63292e+02), forces1[318], tol); -ASSERT_EQUAL_VEC(Vec3( 6.90376e+01, 2.01126e+02, -1.25394e+02), forces1[319], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43084e+01, -1.48482e+02, 9.25935e+01), forces1[320], tol); -ASSERT_EQUAL_VEC(Vec3(-3.53044e+01, 1.28686e+02, -3.63353e+02), forces1[321], tol); -ASSERT_EQUAL_VEC(Vec3(-5.24106e+02, -9.42773e+01, 1.18349e+01), forces1[322], tol); -ASSERT_EQUAL_VEC(Vec3( 2.26116e+02, 3.21645e+02, -3.90520e+02), forces1[323], tol); -ASSERT_EQUAL_VEC(Vec3( 3.59470e+01, -3.07422e+02, -5.38345e+01), forces1[324], tol); -ASSERT_EQUAL_VEC(Vec3(-1.17162e+02, 2.29578e+02, 1.57257e+02), forces1[325], tol); -ASSERT_EQUAL_VEC(Vec3(-9.86447e+01, -2.13510e+02, 9.34945e+01), forces1[326], tol); -ASSERT_EQUAL_VEC(Vec3( 2.32239e+02, 6.06792e+01, -3.57488e+02), forces1[327], tol); -ASSERT_EQUAL_VEC(Vec3(-4.16208e+01, 1.12534e+02, -2.00673e+02), forces1[328], tol); -ASSERT_EQUAL_VEC(Vec3(-5.14797e+01, 2.96279e+02, 3.68486e+02), forces1[329], tol); -ASSERT_EQUAL_VEC(Vec3( 1.02087e+02, -9.70760e+01, 3.02447e+01), forces1[330], tol); -ASSERT_EQUAL_VEC(Vec3(-1.03773e+02, -1.54768e+02, 2.10252e+02), forces1[331], tol); -ASSERT_EQUAL_VEC(Vec3( 1.90526e+02, 6.04195e+01, -9.59270e+01), forces1[332], tol); -ASSERT_EQUAL_VEC(Vec3(-1.16808e+02, -5.22817e+02, 5.66574e+02), forces1[333], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18109e+02, -1.37414e+02, 1.53024e+02), forces1[334], tol); -ASSERT_EQUAL_VEC(Vec3(-9.04344e+01, -1.47623e+02, 8.89515e+01), forces1[335], tol); -ASSERT_EQUAL_VEC(Vec3( 2.10214e+01, -2.05509e+02, 1.26834e+02), forces1[336], tol); -ASSERT_EQUAL_VEC(Vec3(-1.68046e+02, -2.97773e+02, -1.20748e+02), forces1[337], tol); -ASSERT_EQUAL_VEC(Vec3( 3.99130e+02, 2.95164e+02, 3.91133e+02), forces1[338], tol); -ASSERT_EQUAL_VEC(Vec3( 6.84897e+02, -2.36112e+02, 3.42241e+02), forces1[339], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26674e+02, 1.75741e+02, 1.84784e+02), forces1[340], tol); -ASSERT_EQUAL_VEC(Vec3(-1.32552e+01, 4.13616e+01, -7.24209e+01), forces1[341], tol); -ASSERT_EQUAL_VEC(Vec3(-2.77910e+02, 3.10252e+02, 1.84772e+01), forces1[342], tol); -ASSERT_EQUAL_VEC(Vec3( 1.17751e+02, 2.88285e+02, 2.83196e+02), forces1[343], tol); -ASSERT_EQUAL_VEC(Vec3(-2.14324e+01, 5.21203e+02, 1.00240e+02), forces1[344], tol); -ASSERT_EQUAL_VEC(Vec3( 1.24356e+02, -1.12357e+02, 2.11950e+02), forces1[345], tol); -ASSERT_EQUAL_VEC(Vec3( 6.49096e+00, 2.20316e+02, -3.03863e+02), forces1[346], tol); -ASSERT_EQUAL_VEC(Vec3( 3.27054e+02, 1.14349e+02, 4.53346e+02), forces1[347], tol); -ASSERT_EQUAL_VEC(Vec3( 3.89302e+01, 3.55284e+02, 2.25739e+01), forces1[348], tol); -ASSERT_EQUAL_VEC(Vec3(-2.25217e+02, -2.30560e+02, -2.32663e+02), forces1[349], tol); -ASSERT_EQUAL_VEC(Vec3(-4.40572e+02, -4.18868e+01, -8.73193e+01), forces1[350], tol); -ASSERT_EQUAL_VEC(Vec3( 2.03285e+02, -7.41876e+01, -3.11213e+02), forces1[351], tol); -ASSERT_EQUAL_VEC(Vec3( 3.14048e+02, -4.52169e+01, 1.15684e+02), forces1[352], tol); -ASSERT_EQUAL_VEC(Vec3(-3.05766e+02, -8.44138e+01, 2.77051e+02), forces1[353], tol); -ASSERT_EQUAL_VEC(Vec3( 6.03142e+02, 7.49854e+01, 1.08102e+02), forces1[354], tol); -ASSERT_EQUAL_VEC(Vec3( 1.19382e+02, 3.21995e+02, 1.19502e+01), forces1[355], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06924e+02, 2.87624e+01, 2.37383e+02), forces1[356], tol); -ASSERT_EQUAL_VEC(Vec3( 3.21440e+02, -7.92932e+02, 4.18479e+01), forces1[357], tol); -ASSERT_EQUAL_VEC(Vec3(-1.08675e+02, 2.36719e+02, -5.75404e+02), forces1[358], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53731e+02, -4.66587e+02, 3.71577e+02), forces1[359], tol); -ASSERT_EQUAL_VEC(Vec3(-1.56295e+02, -8.97020e+01, -3.26310e+02), forces1[360], tol); -ASSERT_EQUAL_VEC(Vec3( 3.42777e+02, -3.18031e+01, -4.08905e+02), forces1[361], tol); -ASSERT_EQUAL_VEC(Vec3( 1.47602e+02, 4.76918e+02, 4.19650e+01), forces1[362], tol); -ASSERT_EQUAL_VEC(Vec3( 6.19970e-01, -4.13644e+01, 4.39906e+02), forces1[363], tol); -ASSERT_EQUAL_VEC(Vec3(-2.56834e+02, -1.83029e+02, 5.99876e+01), forces1[364], tol); -ASSERT_EQUAL_VEC(Vec3( 2.48250e+02, 5.50128e+01, -1.55098e+01), forces1[365], tol); -ASSERT_EQUAL_VEC(Vec3(-1.93630e+02, -1.86414e+01, 6.10783e-01), forces1[366], tol); -ASSERT_EQUAL_VEC(Vec3(-1.63225e+02, 1.90017e+02, -4.93447e+02), forces1[367], tol); -ASSERT_EQUAL_VEC(Vec3(-2.85285e+01, -4.66015e+02, -2.10844e+02), forces1[368], tol); -ASSERT_EQUAL_VEC(Vec3( 2.27175e+02, 1.52519e+01, -1.64037e+02), forces1[369], tol); -ASSERT_EQUAL_VEC(Vec3(-1.07158e+02, 2.01372e+01, 6.04946e+01), forces1[370], tol); -ASSERT_EQUAL_VEC(Vec3( 2.41288e+02, 4.05688e+02, -8.71414e+01), forces1[371], tol); -ASSERT_EQUAL_VEC(Vec3( 1.33810e+02, 1.72165e+02, -1.15347e+02), forces1[372], tol); -ASSERT_EQUAL_VEC(Vec3( 4.19305e+02, -4.68244e+02, -3.30524e+02), forces1[373], tol); -ASSERT_EQUAL_VEC(Vec3(-1.88000e+02, -2.43516e+02, 8.87125e+01), forces1[374], tol); -ASSERT_EQUAL_VEC(Vec3( 1.54008e+02, 2.52337e+02, 1.76385e+02), forces1[375], tol); -ASSERT_EQUAL_VEC(Vec3(-1.10634e+02, 3.33134e+01, 1.23764e+02), forces1[376], tol); -ASSERT_EQUAL_VEC(Vec3( 1.64797e+02, 8.89785e-01, 1.56187e+02), forces1[377], tol); -ASSERT_EQUAL_VEC(Vec3(-1.65397e+02, -1.50246e+02, 2.41784e+02), forces1[378], tol); -ASSERT_EQUAL_VEC(Vec3( 4.78079e+02, -2.36417e+02, 4.04919e+02), forces1[379], tol); -ASSERT_EQUAL_VEC(Vec3(-2.33373e+02, -7.47052e+02, 1.09725e+02), forces1[380], tol); -ASSERT_EQUAL_VEC(Vec3( 1.09374e+02, -3.37524e+02, 1.99891e+02), forces1[381], tol); -ASSERT_EQUAL_VEC(Vec3( 1.45367e+02, 1.34685e+02, 3.46407e+02), forces1[382], tol); -ASSERT_EQUAL_VEC(Vec3(-8.86795e+01, 1.70743e+02, 1.86635e+02), forces1[383], tol); -ASSERT_EQUAL_VEC(Vec3( 1.03271e+02, -2.54982e+02, -2.04505e+01), forces1[384], tol); -ASSERT_EQUAL_VEC(Vec3(-5.06120e+02, -3.72063e+02, 9.10667e+01), forces1[385], tol); -ASSERT_EQUAL_VEC(Vec3( 4.33821e+02, 5.30907e+02, 1.18197e+02), forces1[386], tol); -ASSERT_EQUAL_VEC(Vec3(-3.34808e+02, 2.29883e+02, 1.73589e+02), forces1[387], tol); -ASSERT_EQUAL_VEC(Vec3(-3.27223e+00, 3.50940e+02, -5.66750e+00), forces1[388], tol); -ASSERT_EQUAL_VEC(Vec3(-3.18249e+02, -4.16016e+02, 3.93821e+00), forces1[389], tol); -ASSERT_EQUAL_VEC(Vec3(-9.01726e+01, -2.83141e+02, -1.78609e+02), forces1[390], tol); -ASSERT_EQUAL_VEC(Vec3(-1.86960e+02, 2.96534e+02, -1.29666e+02), forces1[391], tol); -ASSERT_EQUAL_VEC(Vec3(-7.78140e+02, 3.37747e+02, 2.46235e+02), forces1[392], tol); -ASSERT_EQUAL_VEC(Vec3(-4.88292e+02, -3.62809e+02, 1.09196e+02), forces1[393], tol); -ASSERT_EQUAL_VEC(Vec3( 1.68815e+02, -1.54070e+02, 2.44122e+02), forces1[394], tol); -ASSERT_EQUAL_VEC(Vec3( 8.59883e+01, -4.73417e+02, 1.81318e+02), forces1[395], tol); -ASSERT_EQUAL_VEC(Vec3(-5.15453e+01, 3.80575e+01, 1.48501e+02), forces1[396], tol); -ASSERT_EQUAL_VEC(Vec3( 4.40890e+02, -9.36667e+01, 2.19946e+02), forces1[397], tol); -ASSERT_EQUAL_VEC(Vec3( 4.55989e+01, 5.74616e+02, -5.74981e+01), forces1[398], tol); -ASSERT_EQUAL_VEC(Vec3( 1.07793e+02, -3.19752e+02, 1.16186e+01), forces1[399], tol); -ASSERT_EQUAL_VEC(Vec3(-1.73817e+02, -1.72672e+02, 3.26164e+02), forces1[400], tol); -ASSERT_EQUAL_VEC(Vec3(-4.48594e+02, -4.95425e+02, -1.37767e+02), forces1[401], tol); -ASSERT_EQUAL_VEC(Vec3( 1.43480e+02, -7.71741e+01, 1.27160e+02), forces1[402], tol); -ASSERT_EQUAL_VEC(Vec3( 1.26017e+02, -3.81397e+02, -2.85760e+02), forces1[403], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53035e+02, -2.67890e+02, 1.51840e+02), forces1[404], tol); -ASSERT_EQUAL_VEC(Vec3(-1.01060e+02, -1.79828e+02, -2.05754e+02), forces1[405], tol); -ASSERT_EQUAL_VEC(Vec3( 1.32075e+02, -2.56994e+02, -4.06095e+02), forces1[406], tol); -ASSERT_EQUAL_VEC(Vec3( 5.49913e+01, 5.21043e+01, -2.40692e+01), forces1[407], tol); -ASSERT_EQUAL_VEC(Vec3(-3.04198e+01, -3.45366e+02, 3.52724e+02), forces1[408], tol); -ASSERT_EQUAL_VEC(Vec3( 5.76204e+02, 2.51419e+02, -2.05669e+02), forces1[409], tol); -ASSERT_EQUAL_VEC(Vec3(-5.46249e+02, -3.81508e+01, 1.55947e+02), forces1[410], tol); -ASSERT_EQUAL_VEC(Vec3(-1.00739e+02, 2.13319e+02, 3.33076e+02), forces1[411], tol); -ASSERT_EQUAL_VEC(Vec3( 8.00363e+01, 1.85321e+02, -4.43381e+02), forces1[412], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53965e+02, 1.76341e+01, 5.07046e+01), forces1[413], tol); -ASSERT_EQUAL_VEC(Vec3(-2.54115e+01, -1.01737e+02, -1.47105e+02), forces1[414], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53030e+02, 2.89729e+02, -1.78282e+02), forces1[415], tol); -ASSERT_EQUAL_VEC(Vec3(-1.30262e+02, -4.66600e+02, -3.53368e+02), forces1[416], tol); -ASSERT_EQUAL_VEC(Vec3( 1.82473e+02, 3.77989e+02, 1.90480e+02), forces1[417], tol); -ASSERT_EQUAL_VEC(Vec3(-2.59797e+02, 3.29719e+02, 3.93445e+02), forces1[418], tol); -ASSERT_EQUAL_VEC(Vec3(-1.08424e+01, -5.30928e+02, -1.53190e+01), forces1[419], tol); -ASSERT_EQUAL_VEC(Vec3(-3.27758e+01, -3.45905e+02, -1.45609e+02), forces1[420], tol); -ASSERT_EQUAL_VEC(Vec3(-1.92427e+02, 3.70108e+00, -1.26539e+02), forces1[421], tol); -ASSERT_EQUAL_VEC(Vec3( 2.61433e+02, -1.63237e+02, -1.22721e+02), forces1[422], tol); -ASSERT_EQUAL_VEC(Vec3(-1.42907e+02, 4.15425e+02, 5.04223e+02), forces1[423], tol); -ASSERT_EQUAL_VEC(Vec3( 3.36579e+02, -1.06048e+02, 4.54179e+02), forces1[424], tol); -ASSERT_EQUAL_VEC(Vec3(-2.32219e+02, -1.84431e+00, 4.48455e+01), forces1[425], tol); -ASSERT_EQUAL_VEC(Vec3( 4.12408e+02, -5.04695e+02, 4.00897e+02), forces1[426], tol); -ASSERT_EQUAL_VEC(Vec3(-1.54644e+02, -2.68563e+02, -1.53010e+01), forces1[427], tol); -ASSERT_EQUAL_VEC(Vec3( 2.69725e+02, 2.18578e+02, -1.75382e+02), forces1[428], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77257e+01, -4.66563e+01, 6.24304e+01), forces1[429], tol); -ASSERT_EQUAL_VEC(Vec3(-1.29886e+02, 8.07543e+01, 1.84899e+01), forces1[430], tol); -ASSERT_EQUAL_VEC(Vec3( 1.76179e+02, -3.20023e+02, -2.47777e+02), forces1[431], tol); -ASSERT_EQUAL_VEC(Vec3(-1.68173e+02, 2.05763e+02, -1.17388e+02), forces1[432], tol); -ASSERT_EQUAL_VEC(Vec3(-1.93371e+02, 7.76884e+01, -1.60936e+02), forces1[433], tol); -ASSERT_EQUAL_VEC(Vec3(-8.97869e+01, 2.56574e+02, -3.94708e+02), forces1[434], tol); -ASSERT_EQUAL_VEC(Vec3(-2.33025e+02, 9.53235e+01, 3.02990e+02), forces1[435], tol); -ASSERT_EQUAL_VEC(Vec3( 4.34327e+01, -4.44348e+02, -5.00356e+00), forces1[436], tol); -ASSERT_EQUAL_VEC(Vec3( 3.32045e+02, -4.10887e+02, -6.13802e+01), forces1[437], tol); -ASSERT_EQUAL_VEC(Vec3(-1.45947e+02, -2.28307e+02, -2.99015e+02), forces1[438], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38554e+02, -1.27402e+02, -2.93859e+02), forces1[439], tol); -ASSERT_EQUAL_VEC(Vec3( 2.97418e+02, 3.38266e+02, -2.14828e+02), forces1[440], tol); -ASSERT_EQUAL_VEC(Vec3( 2.49417e+01, 1.88462e+02, -8.02993e+01), forces1[441], tol); -ASSERT_EQUAL_VEC(Vec3(-1.32440e+02, -3.86535e+02, -6.70018e+01), forces1[442], tol); -ASSERT_EQUAL_VEC(Vec3( 1.84581e+01, 2.24810e+02, -1.36951e+02), forces1[443], tol); -ASSERT_EQUAL_VEC(Vec3( 2.15314e+02, 1.06097e+02, -1.25729e+02), forces1[444], tol); -ASSERT_EQUAL_VEC(Vec3( 3.07808e+02, 4.34344e+02, 2.17287e+01), forces1[445], tol); -ASSERT_EQUAL_VEC(Vec3( 8.08473e+00, 4.99811e+01, -3.14217e+02), forces1[446], tol); -ASSERT_EQUAL_VEC(Vec3( 1.36944e+03, 6.44821e+02, -3.85099e+02), forces1[447], tol); -ASSERT_EQUAL_VEC(Vec3( 3.32220e+02, -1.04207e+02, -4.08594e+02), forces1[448], tol); -ASSERT_EQUAL_VEC(Vec3( 3.73256e+02, 2.70963e+02, 3.80703e+02), forces1[449], tol); -ASSERT_EQUAL_VEC(Vec3(-2.09802e+02, 4.29907e+02, 8.40858e+02), forces1[450], tol); -ASSERT_EQUAL_VEC(Vec3(-3.48550e+02, -3.63122e+02, 5.10367e+02), forces1[451], tol); -ASSERT_EQUAL_VEC(Vec3(-3.29139e+00, 4.63314e-01, -6.04797e+00), forces1[452], tol); -ASSERT_EQUAL_VEC(Vec3( 3.83320e+01, 3.59803e+02, 8.67059e+02), forces1[453], tol); -ASSERT_EQUAL_VEC(Vec3(-1.57402e+02, 5.68721e+02, -1.87722e+02), forces1[454], tol); -ASSERT_EQUAL_VEC(Vec3( 4.16157e+02, 5.83052e+01, -5.75714e+02), forces1[455], tol); -ASSERT_EQUAL_VEC(Vec3( 2.58777e+02, -1.00684e+02, -4.43414e+02), forces1[456], tol); -ASSERT_EQUAL_VEC(Vec3( 1.38944e+02, 4.93487e+02, 9.06788e+02), forces1[457], tol); -ASSERT_EQUAL_VEC(Vec3(-4.81206e+01, 9.53313e+02, -1.83923e+02), forces1[458], tol); -ASSERT_EQUAL_VEC(Vec3( 6.64525e+02, -3.77318e+02, 1.93095e+02), forces1[459], tol); -ASSERT_EQUAL_VEC(Vec3( 8.34571e+01, 1.77786e+02, 4.70682e+02), forces1[460], tol); -ASSERT_EQUAL_VEC(Vec3( 9.98937e+02, -3.98574e+02, 9.83608e+02), forces1[461], tol); -ASSERT_EQUAL_VEC(Vec3(-5.06594e+02, -4.10896e+01, 4.75194e+02), forces1[462], tol); -ASSERT_EQUAL_VEC(Vec3(-7.58517e+01, 1.45227e+02, 4.52920e+01), forces1[463], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13510e+02, 5.29893e+02, -3.00930e+02), forces1[464], tol); -ASSERT_EQUAL_VEC(Vec3(-1.46460e+02, -3.86625e+02, -6.42393e+02), forces1[465], tol); -ASSERT_EQUAL_VEC(Vec3(-2.70142e+02, 3.67184e+02, -1.78825e+02), forces1[466], tol); -ASSERT_EQUAL_VEC(Vec3(-1.23818e+02, -1.77327e+02, 2.37348e+02), forces1[467], tol); -ASSERT_EQUAL_VEC(Vec3(-4.94038e+02, 1.34882e+02, 6.98769e+02), forces1[468], tol); -ASSERT_EQUAL_VEC(Vec3( 7.08753e+02, 1.85253e+02, 5.51151e+02), forces1[469], tol); -ASSERT_EQUAL_VEC(Vec3( 2.01280e+02, -5.84706e+02, 5.82923e+02), forces1[470], tol); -ASSERT_EQUAL_VEC(Vec3( 5.29637e+02, 4.06934e+01, 9.99138e+01), forces1[471], tol); -ASSERT_EQUAL_VEC(Vec3(-1.19702e+02, 4.42978e+02, -2.70454e+02), forces1[472], tol); -ASSERT_EQUAL_VEC(Vec3(-6.87792e+02, -1.32245e+02, -7.35776e+01), forces1[473], tol); -ASSERT_EQUAL_VEC(Vec3(-2.99619e+02, 8.14627e+02, 2.72106e+01), forces1[474], tol); -ASSERT_EQUAL_VEC(Vec3(-2.26041e+02, -3.49841e+02, -2.73664e+02), forces1[475], tol); -ASSERT_EQUAL_VEC(Vec3(-3.38853e+02, 8.74214e+02, 2.98569e+02), forces1[476], tol); -ASSERT_EQUAL_VEC(Vec3( 5.63040e+02, 1.51174e+02, -1.10341e+02), forces1[477], tol); -ASSERT_EQUAL_VEC(Vec3( 3.44129e+02, 2.73283e+02, 5.44564e+02), forces1[478], tol); -ASSERT_EQUAL_VEC(Vec3( 3.29047e+01, 3.66771e+02, 3.30305e+02), forces1[479], tol); -ASSERT_EQUAL_VEC(Vec3(-4.97987e+01, -3.26340e+02, -6.47519e+02), forces1[480], tol); -ASSERT_EQUAL_VEC(Vec3( 6.05980e+01, -1.41021e+02, 4.05550e+02), forces1[481], tol); -ASSERT_EQUAL_VEC(Vec3(-1.35193e+03, 5.06460e+01, -1.40089e+02), forces1[482], tol); -ASSERT_EQUAL_VEC(Vec3( 7.69975e+01, -2.68983e+02, -1.75054e+02), forces1[483], tol); -ASSERT_EQUAL_VEC(Vec3(-1.89530e+02, -2.32958e+02, -2.54876e+02), forces1[484], tol); -ASSERT_EQUAL_VEC(Vec3( 2.37140e+02, 6.49184e+02, 1.01759e+02), forces1[485], tol); -ASSERT_EQUAL_VEC(Vec3(-3.38582e+02, 1.34683e+02, 7.89826e+02), forces1[486], tol); -ASSERT_EQUAL_VEC(Vec3(-5.59991e+02, -1.46821e+02, 3.62431e+01), forces1[487], tol); -ASSERT_EQUAL_VEC(Vec3(-3.52720e+02, 1.16574e+02, -4.55489e+02), forces1[488], tol); -ASSERT_EQUAL_VEC(Vec3( 6.56764e+01, 1.02552e+02, -9.81453e+01), forces1[489], tol); -ASSERT_EQUAL_VEC(Vec3(-4.22999e+02, 8.89176e+02, -9.19669e+01), forces1[490], tol); -ASSERT_EQUAL_VEC(Vec3( 5.13334e+02, 4.56108e+02, -6.86079e+01), forces1[491], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12135e+02, 6.84704e+02, 4.44625e+01), forces1[492], tol); -ASSERT_EQUAL_VEC(Vec3( 2.15971e+02, 3.33099e+02, -4.41275e+02), forces1[493], tol); -ASSERT_EQUAL_VEC(Vec3(-4.87370e-01, -2.16943e+02, -5.39078e+02), forces1[494], tol); -ASSERT_EQUAL_VEC(Vec3(-3.91577e+02, 2.80055e+02, 4.50317e+02), forces1[495], tol); -ASSERT_EQUAL_VEC(Vec3( 2.40450e+02, -1.24633e+02, -2.70115e+02), forces1[496], tol); -ASSERT_EQUAL_VEC(Vec3( 7.23732e+01, 1.59397e+01, -5.23970e+01), forces1[497], tol); -ASSERT_EQUAL_VEC(Vec3(-1.41172e+02, -3.23970e+02, -4.05105e+02), forces1[498], tol); -ASSERT_EQUAL_VEC(Vec3( 3.93746e+02, 3.77842e+02, -4.56281e+02), forces1[499], tol); -ASSERT_EQUAL_VEC(Vec3(-2.67998e+02, -2.12761e+02, -7.96439e+02), forces1[500], tol); -ASSERT_EQUAL_VEC(Vec3( 9.59492e+02, 1.74115e+02, 1.16152e+01), forces1[501], tol); -ASSERT_EQUAL_VEC(Vec3(-3.93501e+01, 1.29106e+01, -1.89347e+02), forces1[502], tol); -ASSERT_EQUAL_VEC(Vec3( 2.49458e+02, 7.83930e+01, -4.78250e+02), forces1[503], tol); -ASSERT_EQUAL_VEC(Vec3( 5.16044e+02, 6.52904e+02, -5.05255e+02), forces1[504], tol); -ASSERT_EQUAL_VEC(Vec3( 5.10790e+01, -5.19600e+02, 6.82941e+00), forces1[505], tol); -ASSERT_EQUAL_VEC(Vec3(-7.68988e+01, -1.13215e+03, -7.05215e+02), forces1[506], tol); -ASSERT_EQUAL_VEC(Vec3(-2.13083e+02, 1.68863e+00, 8.26377e+02), forces1[507], tol); -ASSERT_EQUAL_VEC(Vec3( 1.86606e+01, 1.91403e+02, 4.18423e+02), forces1[508], tol); -ASSERT_EQUAL_VEC(Vec3( 2.35358e+02, 3.79667e+02, -3.13829e+02), forces1[509], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26198e+02, -2.59719e+02, -6.76311e+02), forces1[510], tol); -ASSERT_EQUAL_VEC(Vec3(-1.38258e+02, -3.38620e+02, 2.20451e+02), forces1[511], tol); -ASSERT_EQUAL_VEC(Vec3(-2.25461e+02, -7.80816e+02, -2.43646e+02), forces1[512], tol); -ASSERT_EQUAL_VEC(Vec3(-3.10604e+01, 4.16051e+01, 6.15644e+01), forces1[513], tol); -ASSERT_EQUAL_VEC(Vec3( 6.75638e+01, 9.67799e+01, 6.03426e+02), forces1[514], tol); -ASSERT_EQUAL_VEC(Vec3(-1.27092e+02, -4.74786e+01, 4.67732e+02), forces1[515], tol); -ASSERT_EQUAL_VEC(Vec3(-2.72718e+02, 3.30904e+01, -2.81969e+02), forces1[516], tol); -ASSERT_EQUAL_VEC(Vec3( 4.78708e+02, 8.27630e+01, -3.32365e+02), forces1[517], tol); -ASSERT_EQUAL_VEC(Vec3( 1.48583e+02, 1.88623e+02, -5.92109e+02), forces1[518], tol); -ASSERT_EQUAL_VEC(Vec3(-9.24687e+01, 6.86960e+01, 5.16806e+02), forces1[519], tol); -ASSERT_EQUAL_VEC(Vec3( 4.32885e+02, -4.67487e+02, 1.09388e+02), forces1[520], tol); -ASSERT_EQUAL_VEC(Vec3(-2.19076e+02, 2.08356e+00, 1.05234e+03), forces1[521], tol); -ASSERT_EQUAL_VEC(Vec3(-3.95711e+02, -3.31334e+02, 6.33917e+02), forces1[522], tol); -ASSERT_EQUAL_VEC(Vec3( 2.29127e+01, 5.34140e+02, 3.48041e+01), forces1[523], tol); -ASSERT_EQUAL_VEC(Vec3( 4.58862e+02, -2.39332e+02, 5.46969e+01), forces1[524], tol); -ASSERT_EQUAL_VEC(Vec3( 9.97684e+01, 6.32200e+02, -2.38256e+02), forces1[525], tol); -ASSERT_EQUAL_VEC(Vec3(-5.41816e+02, 2.23588e+02, 3.43986e+02), forces1[526], tol); -ASSERT_EQUAL_VEC(Vec3( 6.66038e+02, 4.01166e+02, 3.95435e+02), forces1[527], tol); -ASSERT_EQUAL_VEC(Vec3(-3.06412e+02, 9.39713e+02, -8.27951e+01), forces1[528], tol); -ASSERT_EQUAL_VEC(Vec3(-6.74084e+02, 3.08236e+02, 3.73252e+02), forces1[529], tol); -ASSERT_EQUAL_VEC(Vec3( 2.12296e+02, -1.45360e+02, 2.64306e+02), forces1[530], tol); -ASSERT_EQUAL_VEC(Vec3( 5.45245e+01, -8.21096e+01, 1.51265e+01), forces1[531], tol); -ASSERT_EQUAL_VEC(Vec3( 1.18910e+03, 9.92315e+02, 1.56912e+02), forces1[532], tol); -ASSERT_EQUAL_VEC(Vec3( 4.27129e+02, 1.57559e+02, -3.44345e+02), forces1[533], tol); -ASSERT_EQUAL_VEC(Vec3( 4.25879e+02, -8.14513e+02, -2.37537e+02), forces1[534], tol); -ASSERT_EQUAL_VEC(Vec3( 1.28753e+02, 2.55759e+02, 4.07890e+02), forces1[535], tol); -ASSERT_EQUAL_VEC(Vec3(-4.27472e+02, 1.69782e+02, 1.81400e+02), forces1[536], tol); -ASSERT_EQUAL_VEC(Vec3(-1.35803e+01, 6.03708e+01, -2.72317e+02), forces1[537], tol); -ASSERT_EQUAL_VEC(Vec3( 3.33174e+02, 2.70226e+02, -1.39400e+02), forces1[538], tol); -ASSERT_EQUAL_VEC(Vec3( 4.27463e+02, 1.39185e+02, 1.50051e+02), forces1[539], tol); -ASSERT_EQUAL_VEC(Vec3(-8.29129e+01, -1.00155e+02, -6.82106e+01), forces1[540], tol); -ASSERT_EQUAL_VEC(Vec3( 4.42454e+02, -8.63490e+02, 5.13458e+02), forces1[541], tol); -ASSERT_EQUAL_VEC(Vec3( 2.60683e+02, -6.37510e+01, 1.70972e+02), forces1[542], tol); -ASSERT_EQUAL_VEC(Vec3(-3.90402e+02, -6.79668e+01, -2.36492e+02), forces1[543], tol); -ASSERT_EQUAL_VEC(Vec3( 2.47134e+02, -6.89590e+02, 2.32358e+02), forces1[544], tol); -ASSERT_EQUAL_VEC(Vec3(-5.36759e+02, 2.88860e+02, -6.13641e+02), forces1[545], tol); -ASSERT_EQUAL_VEC(Vec3(-7.93522e+02, 1.07651e+02, 1.05021e+03), forces1[546], tol); -ASSERT_EQUAL_VEC(Vec3( 5.82887e+02, 1.51816e+02, 4.23889e+02), forces1[547], tol); -ASSERT_EQUAL_VEC(Vec3( 1.88325e+02, 3.18348e+02, 2.45829e+02), forces1[548], tol); -ASSERT_EQUAL_VEC(Vec3( 2.61706e+02, 2.14114e+02, -1.84884e+02), forces1[549], tol); -ASSERT_EQUAL_VEC(Vec3(-6.23135e+01, -3.92081e+02, 3.63681e+02), forces1[550], tol); -ASSERT_EQUAL_VEC(Vec3( 2.19342e+02, -3.09069e+02, 2.60297e+02), forces1[551], tol); -ASSERT_EQUAL_VEC(Vec3( 5.02121e+02, -5.84013e+02, -2.55782e+02), forces1[552], tol); -ASSERT_EQUAL_VEC(Vec3( 3.03896e+02, 8.14784e+01, 3.89611e+02), forces1[553], tol); -ASSERT_EQUAL_VEC(Vec3(-1.63570e+01, -1.20665e+02, -1.80834e+02), forces1[554], tol); -ASSERT_EQUAL_VEC(Vec3( 5.41978e+02, 1.88566e+02, 1.13688e+02), forces1[555], tol); -ASSERT_EQUAL_VEC(Vec3( 1.22433e+01, -7.61806e+02, -5.24497e+02), forces1[556], tol); -ASSERT_EQUAL_VEC(Vec3(-4.66740e+02, 1.60557e+02, 1.60939e+02), forces1[557], tol); -ASSERT_EQUAL_VEC(Vec3( 1.52457e+02, -2.28607e+02, -5.94690e+01), forces1[558], tol); -ASSERT_EQUAL_VEC(Vec3( 1.80888e+02, 2.02585e+02, 2.57319e+02), forces1[559], tol); -ASSERT_EQUAL_VEC(Vec3( 6.16843e+02, -3.58498e+02, -5.69821e+02), forces1[560], tol); -ASSERT_EQUAL_VEC(Vec3(-1.57111e+02, -1.13569e+02, -1.64406e+02), forces1[561], tol); -ASSERT_EQUAL_VEC(Vec3(-5.95573e+02, 1.76708e+02, -1.20416e+02), forces1[562], tol); -ASSERT_EQUAL_VEC(Vec3(-6.71022e+01, 7.56220e+02, 5.71559e+02), forces1[563], tol); -ASSERT_EQUAL_VEC(Vec3(-2.03120e+02, -5.27280e+02, -8.87774e+01), forces1[564], tol); -ASSERT_EQUAL_VEC(Vec3(-1.55600e+02, 2.45850e+02, 3.01861e+01), forces1[565], tol); -ASSERT_EQUAL_VEC(Vec3( 1.30693e+02, -2.25616e+02, -3.22200e+02), forces1[566], tol); -ASSERT_EQUAL_VEC(Vec3( 8.50163e+00, -1.67330e+02, 1.64207e+02), forces1[567], tol); -ASSERT_EQUAL_VEC(Vec3(-2.31496e+02, -5.93524e+00, -4.92426e+02), forces1[568], tol); -ASSERT_EQUAL_VEC(Vec3(-1.99378e+02, -1.40003e+02, 2.20600e+01), forces1[569], tol); -ASSERT_EQUAL_VEC(Vec3(-2.65254e+02, 6.41911e+02, 2.96826e+01), forces1[570], tol); -ASSERT_EQUAL_VEC(Vec3(-6.43644e+02, -9.18721e+01, 4.59939e+02), forces1[571], tol); -ASSERT_EQUAL_VEC(Vec3( 3.08964e+02, 8.15563e+02, 4.66117e+02), forces1[572], tol); -ASSERT_EQUAL_VEC(Vec3( 3.27958e+02, -3.65732e+02, -7.14736e+02), forces1[573], tol); -ASSERT_EQUAL_VEC(Vec3(-2.27143e+01, 1.71616e+02, 5.53835e+02), forces1[574], tol); -ASSERT_EQUAL_VEC(Vec3(-3.66153e+02, -4.26970e+02, 4.19225e+02), forces1[575], tol); -ASSERT_EQUAL_VEC(Vec3( 3.35352e+02, 4.34253e+02, 3.88513e+02), forces1[576], tol); -ASSERT_EQUAL_VEC(Vec3( 1.92411e+02, 3.20021e+01, 2.85805e+02), forces1[577], tol); -ASSERT_EQUAL_VEC(Vec3(-1.98797e+02, -5.26323e+02, 3.78346e+02), forces1[578], tol); -ASSERT_EQUAL_VEC(Vec3( 1.45478e+01, -4.73229e+02, 1.99924e+02), forces1[579], tol); -ASSERT_EQUAL_VEC(Vec3(-4.54986e+02, -4.41692e+02, -1.24580e+01), forces1[580], tol); -ASSERT_EQUAL_VEC(Vec3(-4.14887e+02, 2.39737e+02, 1.50739e+02), forces1[581], tol); -ASSERT_EQUAL_VEC(Vec3(-3.05987e+02, -5.48474e+02, 1.68225e+02), forces1[582], tol); -ASSERT_EQUAL_VEC(Vec3(-4.75144e+02, -5.13947e+02, -3.05852e+02), forces1[583], tol); -ASSERT_EQUAL_VEC(Vec3(-1.94336e+02, 1.30198e+02, -3.61876e+02), forces1[584], tol); -ASSERT_EQUAL_VEC(Vec3(-3.90896e+02, 9.91483e+01, -5.15021e+02), forces1[585], tol); -ASSERT_EQUAL_VEC(Vec3(-6.84463e+01, 4.13153e+01, -2.50205e+02), forces1[586], tol); -ASSERT_EQUAL_VEC(Vec3(-1.33546e+02, 4.37436e+02, 3.93115e+02), forces1[587], tol); -ASSERT_EQUAL_VEC(Vec3( 2.17884e+02, -3.56946e+02, -2.18969e+01), forces1[588], tol); -ASSERT_EQUAL_VEC(Vec3(-6.71098e+01, -2.85177e+01, -4.77738e+02), forces1[589], tol); -ASSERT_EQUAL_VEC(Vec3(-1.52910e+02, 1.00734e+02, 7.10518e+01), forces1[590], tol); -ASSERT_EQUAL_VEC(Vec3(-4.51744e+02, 3.40012e+02, -4.62177e+02), forces1[591], tol); -ASSERT_EQUAL_VEC(Vec3(-3.10160e+02, 9.78204e+02, 6.76386e+02), forces1[592], tol); -ASSERT_EQUAL_VEC(Vec3(-3.27570e+02, -1.79611e+02, -2.92229e+02), forces1[593], tol); -ASSERT_EQUAL_VEC(Vec3(-1.59844e+02, 2.90908e+01, -2.88809e+02), forces1[594], tol); -ASSERT_EQUAL_VEC(Vec3( 2.51646e+02, -6.16089e+02, -2.74649e+02), forces1[595], tol); -ASSERT_EQUAL_VEC(Vec3(-4.29770e+02, 2.97845e+02, 2.42778e+02), forces1[596], tol); -ASSERT_EQUAL_VEC(Vec3(-6.54276e+01, -3.70145e+00, 1.09371e+02), forces1[597], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13649e+02, 1.22416e+02, -1.64174e+02), forces1[598], tol); -ASSERT_EQUAL_VEC(Vec3(-4.57994e+02, -5.24219e+02, -4.23537e+02), forces1[599], tol); -ASSERT_EQUAL_VEC(Vec3(-4.01122e+02, -3.10908e+02, -4.86433e+02), forces1[600], tol); -ASSERT_EQUAL_VEC(Vec3( 5.98525e+02, 2.14431e+02, -3.57310e+02), forces1[601], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56640e+02, 7.11992e+01, -6.74285e+02), forces1[602], tol); -ASSERT_EQUAL_VEC(Vec3(-4.29293e+02, 3.33266e+02, -9.12898e+02), forces1[603], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69637e+01, -1.31695e+02, -3.65262e+02), forces1[604], tol); -ASSERT_EQUAL_VEC(Vec3(-9.50771e+00, 3.29551e+02, 1.84445e+01), forces1[605], tol); -ASSERT_EQUAL_VEC(Vec3( 1.01475e+03, 8.03474e+01, -6.28561e+02), forces1[606], tol); -ASSERT_EQUAL_VEC(Vec3( 2.39376e+02, -4.08073e+02, -1.62858e+02), forces1[607], tol); -ASSERT_EQUAL_VEC(Vec3(-3.93618e+02, -5.17098e+02, 5.21853e+02), forces1[608], tol); -ASSERT_EQUAL_VEC(Vec3(-1.37173e+02, -3.86360e+01, 4.26832e+02), forces1[609], tol); -ASSERT_EQUAL_VEC(Vec3( 4.56735e+02, 1.63812e+02, 1.01401e+01), forces1[610], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53136e+02, 1.02274e+02, -7.27489e+02), forces1[611], tol); -ASSERT_EQUAL_VEC(Vec3(-1.82093e+02, 7.24771e+00, -5.10685e+02), forces1[612], tol); -ASSERT_EQUAL_VEC(Vec3( 3.54488e+02, -8.64195e+01, -4.10175e+02), forces1[613], tol); -ASSERT_EQUAL_VEC(Vec3(-6.67624e+01, -7.57961e+01, 7.77301e+01), forces1[614], tol); -ASSERT_EQUAL_VEC(Vec3( 5.34204e+01, -3.49058e+02, -4.41041e+02), forces1[615], tol); -ASSERT_EQUAL_VEC(Vec3(-2.55977e+02, -1.85092e+02, -1.67787e+01), forces1[616], tol); -ASSERT_EQUAL_VEC(Vec3(-2.60220e+02, 4.50663e+02, 6.87571e+02), forces1[617], tol); -ASSERT_EQUAL_VEC(Vec3(-4.84849e+01, -1.47661e+02, 1.30457e+02), forces1[618], tol); -ASSERT_EQUAL_VEC(Vec3(-5.03870e+02, 3.00380e+02, 2.91153e+01), forces1[619], tol); -ASSERT_EQUAL_VEC(Vec3(-3.26882e+02, -2.54121e+02, -1.97289e+02), forces1[620], tol); -ASSERT_EQUAL_VEC(Vec3( 2.23127e+02, 4.31849e+02, -3.45782e+02), forces1[621], tol); -ASSERT_EQUAL_VEC(Vec3(-2.69077e+00, -7.70485e+01, -4.23857e-01), forces1[622], tol); -ASSERT_EQUAL_VEC(Vec3( 8.20397e+02, 7.99593e+02, 4.14368e+02), forces1[623], tol); -ASSERT_EQUAL_VEC(Vec3(-6.20274e+01, -4.27151e+02, -3.70575e+02), forces1[624], tol); -ASSERT_EQUAL_VEC(Vec3(-2.49506e+01, -1.44622e+02, 7.41551e+02), forces1[625], tol); -ASSERT_EQUAL_VEC(Vec3(-6.41672e+02, 6.29867e+01, 1.58002e+02), forces1[626], tol); -ASSERT_EQUAL_VEC(Vec3(-5.89354e+02, -2.66715e+02, 7.40461e+01), forces1[627], tol); -ASSERT_EQUAL_VEC(Vec3( 5.26897e+02, -4.19406e+02, -2.37126e+02), forces1[628], tol); -ASSERT_EQUAL_VEC(Vec3( 4.42823e+02, -3.89602e+00, 5.35394e+02), forces1[629], tol); -ASSERT_EQUAL_VEC(Vec3( 2.38351e+02, -5.34626e+02, 2.63027e+02), forces1[630], tol); -ASSERT_EQUAL_VEC(Vec3(-2.48039e+02, -1.44724e+01, 7.55533e+02), forces1[631], tol); -ASSERT_EQUAL_VEC(Vec3(-8.06993e+01, -4.42707e+02, -4.11282e+02), forces1[632], tol); -ASSERT_EQUAL_VEC(Vec3( 4.64135e+02, -7.82572e+02, 7.48550e+02), forces1[633], tol); -ASSERT_EQUAL_VEC(Vec3( 3.75024e+02, 3.06926e+02, 2.76975e+02), forces1[634], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43670e+02, -1.70164e+02, -2.61356e+02), forces1[635], tol); -ASSERT_EQUAL_VEC(Vec3( 5.20769e+02, -7.66032e+00, -2.76126e+02), forces1[636], tol); -ASSERT_EQUAL_VEC(Vec3(-2.28461e+02, 5.33833e+02, -3.58038e+01), forces1[637], tol); -ASSERT_EQUAL_VEC(Vec3(-1.70108e+02, -7.30449e+01, -3.73102e+02), forces1[638], tol); -ASSERT_EQUAL_VEC(Vec3( 1.90864e+02, 1.53717e+02, -9.75681e+00), forces1[639], tol); -ASSERT_EQUAL_VEC(Vec3( 2.59596e+02, 2.75192e+01, -2.02348e+02), forces1[640], tol); -ASSERT_EQUAL_VEC(Vec3( 3.25228e+02, 2.78224e+01, 5.21697e+02), forces1[641], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12825e+02, -6.70108e+02, -7.86084e+01), forces1[642], tol); -ASSERT_EQUAL_VEC(Vec3(-1.10050e+01, -4.90683e+01, -2.91299e+02), forces1[643], tol); -ASSERT_EQUAL_VEC(Vec3( 2.77327e+02, 2.29323e+02, 5.59760e+02), forces1[644], tol); -ASSERT_EQUAL_VEC(Vec3( 4.59573e+02, 1.21299e+02, -4.79315e+02), forces1[645], tol); -ASSERT_EQUAL_VEC(Vec3(-5.30622e+02, -3.96117e+02, -4.37730e+01), forces1[646], tol); -ASSERT_EQUAL_VEC(Vec3( 5.87415e+01, 3.74983e+02, -4.59323e+00), forces1[647], tol); -ASSERT_EQUAL_VEC(Vec3(-5.72048e+02, -3.24796e+02, -5.11139e+01), forces1[648], tol); -ASSERT_EQUAL_VEC(Vec3(-1.51870e+03, 1.63888e+02, -7.67908e+01), forces1[649], tol); -ASSERT_EQUAL_VEC(Vec3( 4.86979e+02, 5.16872e+02, -7.62781e+01), forces1[650], tol); -ASSERT_EQUAL_VEC(Vec3( 2.48285e+02, -8.90776e+02, 6.71667e+01), forces1[651], tol); -ASSERT_EQUAL_VEC(Vec3(-1.54175e+00, 1.36939e+02, -1.04189e+02), forces1[652], tol); -ASSERT_EQUAL_VEC(Vec3(-1.20205e+02, 2.89638e+02, -6.63136e+02), forces1[653], tol); -ASSERT_EQUAL_VEC(Vec3(-1.59426e+02, -4.16181e+02, 2.79418e+02), forces1[654], tol); -ASSERT_EQUAL_VEC(Vec3(-2.98735e+02, -2.96276e+02, 3.36143e+02), forces1[655], tol); -ASSERT_EQUAL_VEC(Vec3(-4.91907e+02, -4.26747e+01, 1.25389e+01), forces1[656], tol); -ASSERT_EQUAL_VEC(Vec3(-2.47943e+02, -2.67473e+02, 2.21842e+02), forces1[657], tol); -ASSERT_EQUAL_VEC(Vec3(-2.42851e+01, 2.61470e+01, -6.65055e+01), forces1[658], tol); -ASSERT_EQUAL_VEC(Vec3( 3.64175e+02, 4.13063e+02, -5.51340e+02), forces1[659], tol); -ASSERT_EQUAL_VEC(Vec3( 3.74845e+02, -6.33619e+02, 5.37646e+00), forces1[660], tol); -ASSERT_EQUAL_VEC(Vec3( 6.51845e+01, 5.97073e+02, 2.54487e+01), forces1[661], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53437e+02, -7.70454e-02, -3.64178e+02), forces1[662], tol); -ASSERT_EQUAL_VEC(Vec3(-4.19786e+01, 5.32473e+02, 5.67523e+02), forces1[663], tol); -ASSERT_EQUAL_VEC(Vec3( 2.18380e+01, -2.88670e+02, 2.73917e+02), forces1[664], tol); -ASSERT_EQUAL_VEC(Vec3( 2.56668e+02, 1.75282e+02, 2.67811e+02), forces1[665], tol); -ASSERT_EQUAL_VEC(Vec3(-1.42006e+02, -1.93562e+02, -4.45933e+02), forces1[666], tol); -ASSERT_EQUAL_VEC(Vec3(-5.74483e+01, -4.30855e+02, -7.59684e+02), forces1[667], tol); -ASSERT_EQUAL_VEC(Vec3(-4.90370e+02, 2.12536e+02, 1.21399e+02), forces1[668], tol); -ASSERT_EQUAL_VEC(Vec3( 1.94634e+02, 1.32086e+02, 1.71425e+02), forces1[669], tol); -ASSERT_EQUAL_VEC(Vec3(-2.73623e+02, 7.78030e+02, 2.78021e+02), forces1[670], tol); -ASSERT_EQUAL_VEC(Vec3(-2.62074e+02, 3.53998e+02, 1.59712e+02), forces1[671], tol); -ASSERT_EQUAL_VEC(Vec3( 3.74175e+01, -6.21070e+02, -1.89712e+02), forces1[672], tol); -ASSERT_EQUAL_VEC(Vec3( 2.70256e+02, -1.98712e+02, -1.68453e+02), forces1[673], tol); -ASSERT_EQUAL_VEC(Vec3(-3.72180e+02, 2.16555e+02, -7.51654e+01), forces1[674], tol); -ASSERT_EQUAL_VEC(Vec3( 4.60646e+02, -2.41020e+02, 1.87544e+02), forces1[675], tol); -ASSERT_EQUAL_VEC(Vec3(-8.64562e+00, -4.96607e+01, 4.14111e+02), forces1[676], tol); -ASSERT_EQUAL_VEC(Vec3(-5.53550e+02, 2.02023e+02, 2.48778e+02), forces1[677], tol); -ASSERT_EQUAL_VEC(Vec3( 4.12902e+02, 3.97615e+02, -7.77105e+02), forces1[678], tol); -ASSERT_EQUAL_VEC(Vec3( 4.37864e+02, 3.87796e+02, -2.57117e+02), forces1[679], tol); -ASSERT_EQUAL_VEC(Vec3(-1.99545e+02, -5.31838e+02, -7.08357e+02), forces1[680], tol); -ASSERT_EQUAL_VEC(Vec3( 7.16820e+01, 2.15323e+02, -2.17986e+02), forces1[681], tol); -ASSERT_EQUAL_VEC(Vec3(-2.27238e+02, -3.33101e+02, -8.95801e+01), forces1[682], tol); -ASSERT_EQUAL_VEC(Vec3( 1.12342e+02, -2.81421e+02, 1.84405e+02), forces1[683], tol); -ASSERT_EQUAL_VEC(Vec3( 5.30416e+01, -1.73619e+02, 3.80448e+02), forces1[684], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53132e+02, -4.19546e+02, 3.62048e+02), forces1[685], tol); -ASSERT_EQUAL_VEC(Vec3(-8.26083e+01, 1.22020e+02, -2.05481e+01), forces1[686], tol); -ASSERT_EQUAL_VEC(Vec3(-4.09521e+02, 3.88078e+01, 7.34580e+02), forces1[687], tol); -ASSERT_EQUAL_VEC(Vec3( 2.30481e+02, 4.59140e+01, -3.44443e+02), forces1[688], tol); -ASSERT_EQUAL_VEC(Vec3(-2.99023e+02, 6.71185e+02, -1.01234e+03), forces1[689], tol); -ASSERT_EQUAL_VEC(Vec3( 2.93615e+02, -1.62637e+01, -5.52882e+02), forces1[690], tol); -ASSERT_EQUAL_VEC(Vec3(-1.41601e+02, -4.87777e+02, 2.73045e+02), forces1[691], tol); -ASSERT_EQUAL_VEC(Vec3(-1.26640e+02, -4.36399e+02, 7.19796e+01), forces1[692], tol); -ASSERT_EQUAL_VEC(Vec3( 1.33472e+02, 2.25647e+02, 5.65785e+02), forces1[693], tol); -ASSERT_EQUAL_VEC(Vec3( 7.34336e+02, 4.69224e+02, -5.53023e+02), forces1[694], tol); -ASSERT_EQUAL_VEC(Vec3(-6.36602e+01, -2.05110e+02, -4.73058e+02), forces1[695], tol); -ASSERT_EQUAL_VEC(Vec3(-3.35930e+02, -2.75966e+02, 4.10409e+02), forces1[696], tol); -ASSERT_EQUAL_VEC(Vec3(-1.98434e+02, -2.81395e+02, -1.48447e+02), forces1[697], tol); -ASSERT_EQUAL_VEC(Vec3( 6.97000e+02, -2.08385e+02, -1.22103e+02), forces1[698], tol); -ASSERT_EQUAL_VEC(Vec3( 6.16657e+02, -2.04959e+02, -2.28466e+02), forces1[699], tol); -ASSERT_EQUAL_VEC(Vec3( 1.59028e+02, 2.68339e+02, -1.13410e+02), forces1[700], tol); -ASSERT_EQUAL_VEC(Vec3( 2.52343e+02, 3.78670e+02, -1.30509e+03), forces1[701], tol); -ASSERT_EQUAL_VEC(Vec3( 7.30827e+02, -3.70990e+02, -6.60678e+02), forces1[702], tol); -ASSERT_EQUAL_VEC(Vec3(-4.64409e+01, 1.28066e+02, 8.75692e+01), forces1[703], tol); -ASSERT_EQUAL_VEC(Vec3( 3.26215e+02, -1.75860e+02, 7.03132e+01), forces1[704], tol); -ASSERT_EQUAL_VEC(Vec3( 9.80781e+01, -2.26689e+02, -2.00001e+02), forces1[705], tol); -ASSERT_EQUAL_VEC(Vec3( 5.01952e+01, 2.67236e+02, 5.24662e+02), forces1[706], tol); -ASSERT_EQUAL_VEC(Vec3(-2.52900e+02, -8.04961e+02, 4.03069e+02), forces1[707], tol); -ASSERT_EQUAL_VEC(Vec3(-2.40213e+02, -2.54318e+02, 5.06462e+02), forces1[708], tol); -ASSERT_EQUAL_VEC(Vec3( 4.48948e+02, 3.49506e+02, 2.88403e+02), forces1[709], tol); -ASSERT_EQUAL_VEC(Vec3( 3.10145e+02, 3.91032e+02, -9.77450e+02), forces1[710], tol); -ASSERT_EQUAL_VEC(Vec3( 7.63176e+02, 2.06934e+02, 1.03498e+02), forces1[711], tol); -ASSERT_EQUAL_VEC(Vec3( 4.64450e+02, 2.52676e+02, 7.37725e+01), forces1[712], tol); -ASSERT_EQUAL_VEC(Vec3( 9.14947e+02, 3.40040e+02, -2.99021e+02), forces1[713], tol); -ASSERT_EQUAL_VEC(Vec3( 5.05311e+02, 1.59558e+02, -9.12417e+00), forces1[714], tol); -ASSERT_EQUAL_VEC(Vec3(-3.46704e+02, 1.40018e+02, 1.54716e+02), forces1[715], tol); -ASSERT_EQUAL_VEC(Vec3(-1.66193e+01, -4.02081e+01, -1.23816e+02), forces1[716], tol); -ASSERT_EQUAL_VEC(Vec3(-7.57179e+01, -4.48049e+02, -4.21095e+02), forces1[717], tol); -ASSERT_EQUAL_VEC(Vec3( 1.04055e+03, -2.36062e+02, 1.43125e+01), forces1[718], tol); -ASSERT_EQUAL_VEC(Vec3(-2.65437e+01, 6.06573e+02, 4.91404e+01), forces1[719], tol); -ASSERT_EQUAL_VEC(Vec3(-1.33799e+02, -3.09741e+02, 2.79872e+01), forces1[720], tol); -ASSERT_EQUAL_VEC(Vec3(-9.76583e+01, -1.13792e+03, 4.60486e+02), forces1[721], tol); -ASSERT_EQUAL_VEC(Vec3(-2.56797e+02, 9.31614e+01, 3.24973e+02), forces1[722], tol); -ASSERT_EQUAL_VEC(Vec3(-8.66116e+01, 5.60535e+02, 2.96444e+02), forces1[723], tol); -ASSERT_EQUAL_VEC(Vec3( 1.26228e+02, 1.40946e+02, 3.97444e+02), forces1[724], tol); -ASSERT_EQUAL_VEC(Vec3( 1.03121e+02, -1.43347e+02, 1.91577e+02), forces1[725], tol); -ASSERT_EQUAL_VEC(Vec3(-9.29460e+01, 4.44591e+01, -9.69787e+01), forces1[726], tol); -ASSERT_EQUAL_VEC(Vec3(-1.07841e+02, 4.40146e+01, 2.20888e+02), forces1[727], tol); -ASSERT_EQUAL_VEC(Vec3( 2.92927e+02, 5.54167e+02, 3.56991e+02), forces1[728], tol); -ASSERT_EQUAL_VEC(Vec3(-6.11691e+02, 1.34361e+02, 4.75043e+01), forces1[729], tol); -ASSERT_EQUAL_VEC(Vec3(-8.07637e+02, 1.63874e+01, -2.56526e+02), forces1[730], tol); -ASSERT_EQUAL_VEC(Vec3( 5.08711e+01, 1.35146e+01, 4.82187e+02), forces1[731], tol); -ASSERT_EQUAL_VEC(Vec3(-5.01040e+02, -7.35292e+02, 6.67901e+02), forces1[732], tol); -ASSERT_EQUAL_VEC(Vec3(-1.74444e+00, 6.70711e+02, -1.03875e+03), forces1[733], tol); -ASSERT_EQUAL_VEC(Vec3(-1.95458e+02, 4.63751e+02, 7.41370e+01), forces1[734], tol); -ASSERT_EQUAL_VEC(Vec3(-2.73273e+02, -4.33968e+02, -5.86860e+02), forces1[735], tol); -ASSERT_EQUAL_VEC(Vec3( 3.87495e+02, -3.57412e+02, -1.22672e+02), forces1[736], tol); -ASSERT_EQUAL_VEC(Vec3( 2.10269e+02, -8.24362e+01, -3.92484e+02), forces1[737], tol); -ASSERT_EQUAL_VEC(Vec3( 8.30177e+02, -6.58237e+02, -4.70878e+02), forces1[738], tol); -ASSERT_EQUAL_VEC(Vec3( 1.32212e+02, 1.07237e+02, -2.42604e+02), forces1[739], tol); -ASSERT_EQUAL_VEC(Vec3(-4.36754e+02, 2.00495e+01, -3.45995e+02), forces1[740], tol); -ASSERT_EQUAL_VEC(Vec3(-5.77243e+02, 1.27456e+02, -4.58812e+02), forces1[741], tol); -ASSERT_EQUAL_VEC(Vec3( 1.97467e+02, -2.58380e+02, 1.34659e+02), forces1[742], tol); -ASSERT_EQUAL_VEC(Vec3( 3.87615e+01, -8.11440e+02, -2.37606e+02), forces1[743], tol); -ASSERT_EQUAL_VEC(Vec3(-5.43753e+02, 7.08855e+01, -1.18515e+02), forces1[744], tol); -ASSERT_EQUAL_VEC(Vec3(-4.18102e+02, 9.12534e+01, -3.26390e+02), forces1[745], tol); -ASSERT_EQUAL_VEC(Vec3(-1.04709e+02, 4.73095e+02, -5.52378e+02), forces1[746], tol); -ASSERT_EQUAL_VEC(Vec3( 1.50360e+02, 6.74565e+02, -8.65160e+01), forces1[747], tol); -ASSERT_EQUAL_VEC(Vec3(-4.91737e+01, 9.70173e+01, 4.14679e+01), forces1[748], tol); -ASSERT_EQUAL_VEC(Vec3(-1.53125e+02, -3.14702e+02, 1.64510e+02), forces1[749], tol); -ASSERT_EQUAL_VEC(Vec3( 5.30495e-01, -2.20851e+02, 2.62854e+02), forces1[750], tol); -ASSERT_EQUAL_VEC(Vec3(-6.92133e+02, 2.00411e+02, -2.65836e+02), forces1[751], tol); -ASSERT_EQUAL_VEC(Vec3( 3.79173e+01, -1.05185e+02, -3.82562e+01), forces1[752], tol); -ASSERT_EQUAL_VEC(Vec3(-2.53019e+02, 2.11965e+02, -3.81685e+02), forces1[753], tol); -ASSERT_EQUAL_VEC(Vec3(-2.51275e+02, -3.93318e+02, -1.33319e+01), forces1[754], tol); -ASSERT_EQUAL_VEC(Vec3(-3.01504e+01, 1.45593e+02, -6.30497e+01), forces1[755], tol); -ASSERT_EQUAL_VEC(Vec3(-2.76292e+02, -4.61698e+02, -2.69332e+02), forces1[756], tol); -ASSERT_EQUAL_VEC(Vec3( 6.48621e+01, 3.68736e+02, 2.32248e+02), forces1[757], tol); -ASSERT_EQUAL_VEC(Vec3(-4.48067e+02, 4.24009e+02, 2.00610e+02), forces1[758], tol); -ASSERT_EQUAL_VEC(Vec3( 1.50429e+01, -7.33695e+01, 4.00840e+02), forces1[759], tol); -ASSERT_EQUAL_VEC(Vec3( 4.06786e+02, 1.22307e+02, -3.26363e+02), forces1[760], tol); -ASSERT_EQUAL_VEC(Vec3(-3.55719e+02, -4.23669e+02, 1.92960e+02), forces1[761], tol); -ASSERT_EQUAL_VEC(Vec3(-4.78729e+01, 1.13402e+02, -4.55740e+02), forces1[762], tol); -ASSERT_EQUAL_VEC(Vec3( 5.50243e+02, 3.20969e+02, -2.04136e+02), forces1[763], tol); -ASSERT_EQUAL_VEC(Vec3(-3.98710e+01, 6.43079e+01, 2.62905e+02), forces1[764], tol); -ASSERT_EQUAL_VEC(Vec3(-7.85308e+01, -7.50634e+01, -7.62985e+02), forces1[765], tol); -ASSERT_EQUAL_VEC(Vec3( 9.57106e+00, -3.95503e+02, -8.95762e+01), forces1[766], tol); -ASSERT_EQUAL_VEC(Vec3( 4.83241e+02, -7.40429e+02, -5.32394e+02), forces1[767], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61812e+02, 8.15330e+01, 4.71839e+02), forces1[768], tol); -ASSERT_EQUAL_VEC(Vec3(-3.30804e+02, -4.22034e+01, -1.05047e+03), forces1[769], tol); -ASSERT_EQUAL_VEC(Vec3( 3.34235e+02, -1.34572e+02, 3.33949e+02), forces1[770], tol); -ASSERT_EQUAL_VEC(Vec3( 2.25419e+01, 6.94642e+02, 3.48219e+01), forces1[771], tol); -ASSERT_EQUAL_VEC(Vec3( 4.92303e+02, -3.56656e+02, 7.11609e+01), forces1[772], tol); -ASSERT_EQUAL_VEC(Vec3( 2.17147e+02, 4.05015e+01, 3.47170e+02), forces1[773], tol); -ASSERT_EQUAL_VEC(Vec3(-1.61124e+01, 1.47264e+03, 5.49828e+02), forces1[774], tol); -ASSERT_EQUAL_VEC(Vec3( 8.39474e+01, -4.18457e+02, 2.34855e+02), forces1[775], tol); -ASSERT_EQUAL_VEC(Vec3(-2.31366e+02, 2.37297e+02, 6.61710e+01), forces1[776], tol); -ASSERT_EQUAL_VEC(Vec3(-6.23896e+01, -7.00160e+02, 4.91298e+02), forces1[777], tol); -ASSERT_EQUAL_VEC(Vec3( 2.68205e+01, 2.46992e+02, 6.51925e-01), forces1[778], tol); -ASSERT_EQUAL_VEC(Vec3( 5.26229e+02, 1.10211e+02, 3.46425e+02), forces1[779], tol); -ASSERT_EQUAL_VEC(Vec3(-3.29259e+02, -3.87187e+02, 8.51738e+01), forces1[780], tol); -ASSERT_EQUAL_VEC(Vec3( 6.42840e+02, 2.34874e+02, 3.71367e+02), forces1[781], tol); -ASSERT_EQUAL_VEC(Vec3(-3.24670e+02, 5.64060e+02, -4.45941e+01), forces1[782], tol); -ASSERT_EQUAL_VEC(Vec3( 5.74639e+01, 1.20255e+02, -5.84555e+01), forces1[783], tol); -ASSERT_EQUAL_VEC(Vec3(-2.83818e+02, -2.10789e+02, 1.66016e+02), forces1[784], tol); -ASSERT_EQUAL_VEC(Vec3( 4.01586e+02, -2.85114e+02, 2.49462e+02), forces1[785], tol); -ASSERT_EQUAL_VEC(Vec3( 3.05493e+02, 7.04816e+02, -5.94585e+01), forces1[786], tol); -ASSERT_EQUAL_VEC(Vec3(-5.06832e+02, 3.13613e+02, -7.30025e+02), forces1[787], tol); -ASSERT_EQUAL_VEC(Vec3(-1.65633e+02, -1.02565e+02, -4.10514e+02), forces1[788], tol); -ASSERT_EQUAL_VEC(Vec3( 2.50011e+02, 9.82368e+02, 3.08282e+02), forces1[789], tol); -ASSERT_EQUAL_VEC(Vec3( 3.60209e+02, 3.06214e+02, 4.01448e+02), forces1[790], tol); -ASSERT_EQUAL_VEC(Vec3(-5.15566e+02, -3.80892e+02, -2.65987e+02), forces1[791], tol); -ASSERT_EQUAL_VEC(Vec3( 9.16906e+02, -2.70982e+02, 2.88897e+02), forces1[792], tol); -ASSERT_EQUAL_VEC(Vec3( 5.57959e+01, 1.28554e+02, 4.36834e+02), forces1[793], tol); -ASSERT_EQUAL_VEC(Vec3( 3.48851e+02, 3.63953e+02, 3.78555e+02), forces1[794], tol); -ASSERT_EQUAL_VEC(Vec3( 6.36621e+02, -1.91572e+02, 4.14270e+02), forces1[795], tol); -ASSERT_EQUAL_VEC(Vec3(-3.31253e+01, -1.47718e+02, 3.03786e+02), forces1[796], tol); -ASSERT_EQUAL_VEC(Vec3(-8.19713e+01, -5.66604e+02, -7.77410e+01), forces1[797], tol); -ASSERT_EQUAL_VEC(Vec3( 1.20358e+02, 3.66650e+02, -2.38055e+02), forces1[798], tol); -ASSERT_EQUAL_VEC(Vec3( 3.60706e+02, 4.45401e+02, -6.03554e+02), forces1[799], tol); -ASSERT_EQUAL_VEC(Vec3(-8.71329e+01, 1.63947e+02, -1.43935e+02), forces1[800], tol); -ASSERT_EQUAL_VEC(Vec3(-9.99017e+01, 1.95915e+01, -5.85374e+01), forces1[801], tol); -ASSERT_EQUAL_VEC(Vec3( 4.81470e+02, -7.03993e+01, -2.08008e+02), forces1[802], tol); -ASSERT_EQUAL_VEC(Vec3(-7.69394e+02, 5.40411e+01, 5.38431e+02), forces1[803], tol); -ASSERT_EQUAL_VEC(Vec3(-6.60820e+02, -1.87929e+02, 4.11990e+02), forces1[804], tol); -ASSERT_EQUAL_VEC(Vec3( 1.06278e+02, 3.55326e+02, -2.27795e+02), forces1[805], tol); -ASSERT_EQUAL_VEC(Vec3(-2.66101e+02, 2.41367e+02, -4.99250e+02), forces1[806], tol); -ASSERT_EQUAL_VEC(Vec3(-5.22955e+01, 9.33616e+01, 7.23845e+02), forces1[807], tol); -ASSERT_EQUAL_VEC(Vec3( 2.82637e+00, 6.04183e+01, 1.65509e+02), forces1[808], tol); -ASSERT_EQUAL_VEC(Vec3(-2.97247e+02, -5.53685e+01, 3.87138e+02), forces1[809], tol); -ASSERT_EQUAL_VEC(Vec3(-8.18648e+02, -2.66083e+02, 1.07281e+03), forces1[810], tol); -ASSERT_EQUAL_VEC(Vec3(-2.43734e+02, -2.51644e+02, 3.46336e+02), forces1[811], tol); -ASSERT_EQUAL_VEC(Vec3( 4.04771e+02, 1.12611e+02, -6.66755e+02), forces1[812], tol); -ASSERT_EQUAL_VEC(Vec3(-8.30809e+01, -9.75613e+01, -5.15283e+02), forces1[813], tol); -ASSERT_EQUAL_VEC(Vec3(-8.88969e+01, -2.43585e+02, -4.28237e+02), forces1[814], tol); -ASSERT_EQUAL_VEC(Vec3(-9.15331e+01, 4.50369e+02, -2.64187e+02), forces1[815], tol); -ASSERT_EQUAL_VEC(Vec3(-9.11685e+01, 4.24897e+02, -1.85102e+02), forces1[816], tol); -ASSERT_EQUAL_VEC(Vec3(-3.91181e+02, -6.86407e+02, 1.52727e+02), forces1[817], tol); -ASSERT_EQUAL_VEC(Vec3(-8.21105e+01, -2.49526e+02, 5.27526e+02), forces1[818], tol); -ASSERT_EQUAL_VEC(Vec3(-1.09397e+02, -6.29100e+02, 3.34949e+02), forces1[819], tol); -ASSERT_EQUAL_VEC(Vec3(-4.17364e+02, -9.10769e+01, -3.54884e+01), forces1[820], tol); -ASSERT_EQUAL_VEC(Vec3( 2.79520e+02, -5.39057e+02, 5.07383e+02), forces1[821], tol); -ASSERT_EQUAL_VEC(Vec3( 2.14808e+02, 1.92238e+01, -3.14844e+02), forces1[822], tol); -ASSERT_EQUAL_VEC(Vec3(-1.92606e+02, -4.26137e+02, -6.21690e+00), forces1[823], tol); -ASSERT_EQUAL_VEC(Vec3(-6.55144e+02, -4.86084e+02, -3.89405e+02), forces1[824], tol); -ASSERT_EQUAL_VEC(Vec3(-1.89858e+02, -3.77314e+02, -1.36225e+02), forces1[825], tol); -ASSERT_EQUAL_VEC(Vec3( 4.60006e+02, 1.99089e+02, 2.82592e+02), forces1[826], tol); -ASSERT_EQUAL_VEC(Vec3( 1.21553e+02, -1.21221e+02, 7.24045e+02), forces1[827], tol); -ASSERT_EQUAL_VEC(Vec3(-9.16961e+01, 7.09417e+01, 7.89088e+01), forces1[828], tol); -ASSERT_EQUAL_VEC(Vec3(-3.83816e+02, 8.44889e+01, 1.09603e+03), forces1[829], tol); -ASSERT_EQUAL_VEC(Vec3(-3.65376e+02, -1.88809e+02, 4.62338e+02), forces1[830], tol); -ASSERT_EQUAL_VEC(Vec3( 5.76327e+02, -9.42016e+01, -1.98144e+02), forces1[831], tol); -ASSERT_EQUAL_VEC(Vec3(-4.21543e+02, -5.96901e+01, -8.33520e+02), forces1[832], tol); -ASSERT_EQUAL_VEC(Vec3( 1.20308e+03, 4.53517e+02, 2.29384e+02), forces1[833], tol); -ASSERT_EQUAL_VEC(Vec3( 2.92105e+02, 4.13134e+01, -3.61124e+02), forces1[834], tol); -ASSERT_EQUAL_VEC(Vec3( 2.49880e+02, -1.26751e+02, 2.01746e+02), forces1[835], tol); -ASSERT_EQUAL_VEC(Vec3( 4.82079e+02, -4.36678e+02, 2.10916e+02), forces1[836], tol); -ASSERT_EQUAL_VEC(Vec3( 7.40340e+00, -3.07867e+02, -2.19268e+02), forces1[837], tol); -ASSERT_EQUAL_VEC(Vec3(-1.77931e+02, -1.78462e+02, 3.27369e+02), forces1[838], tol); -ASSERT_EQUAL_VEC(Vec3(-1.43493e+02, 2.36669e+02, 1.76242e+02), forces1[839], tol); -ASSERT_EQUAL_VEC(Vec3(-3.11001e+02, 3.30086e+01, 2.29454e+02), forces1[840], tol); -ASSERT_EQUAL_VEC(Vec3( 7.16440e+01, -1.42656e+00, -8.22932e+02), forces1[841], tol); -ASSERT_EQUAL_VEC(Vec3(-2.21653e+02, -4.50533e+01, -4.49967e+02), forces1[842], tol); -ASSERT_EQUAL_VEC(Vec3(-4.26325e+02, -2.93355e+02, 2.05051e+02), forces1[843], tol); -ASSERT_EQUAL_VEC(Vec3( 8.06715e+01, 3.83773e+02, 4.54367e+02), forces1[844], tol); -ASSERT_EQUAL_VEC(Vec3( 1.36370e+01, -1.12119e+02, -2.08559e+02), forces1[845], tol); -ASSERT_EQUAL_VEC(Vec3(-4.31375e+01, 1.28705e+02, 2.40993e+02), forces1[846], tol); -ASSERT_EQUAL_VEC(Vec3( 3.71930e+02, 3.66483e+02, -1.02572e+02), forces1[847], tol); -ASSERT_EQUAL_VEC(Vec3(-2.30298e+02, 7.54918e+02, 1.07591e+02), forces1[848], tol); -ASSERT_EQUAL_VEC(Vec3( 2.67868e+02, -1.52050e+01, -1.70085e+02), forces1[849], tol); -ASSERT_EQUAL_VEC(Vec3(-9.39293e+02, 5.64192e+01, -2.22390e+02), forces1[850], tol); -ASSERT_EQUAL_VEC(Vec3(-1.01320e+02, 3.31059e+02, 7.07374e+02), forces1[851], tol); -ASSERT_EQUAL_VEC(Vec3( 1.78173e+02, 8.50286e+01, -6.39943e+02), forces1[852], tol); -ASSERT_EQUAL_VEC(Vec3( 3.33072e+02, 9.10202e+01, 1.20449e+02), forces1[853], tol); -ASSERT_EQUAL_VEC(Vec3( 4.22307e+01, -7.37185e+02, 6.08442e+02), forces1[854], tol); -ASSERT_EQUAL_VEC(Vec3(-4.16912e+02, -4.82533e+02, 3.91904e+01), forces1[855], tol); -ASSERT_EQUAL_VEC(Vec3(-4.09092e+02, -1.95397e+02, -1.49049e+02), forces1[856], tol); -ASSERT_EQUAL_VEC(Vec3(-2.89402e+01, 3.78193e+02, 2.19684e+02), forces1[857], tol); -ASSERT_EQUAL_VEC(Vec3(-2.77581e+02, 7.90343e+01, 3.49462e+02), forces1[858], tol); -ASSERT_EQUAL_VEC(Vec3( 4.71062e+02, -1.88929e+02, -2.48123e+02), forces1[859], tol); -ASSERT_EQUAL_VEC(Vec3(-1.51510e+02, 4.96268e+01, -2.65476e+02), forces1[860], tol); -ASSERT_EQUAL_VEC(Vec3(-7.66386e+02, 8.46641e+01, -3.64816e+02), forces1[861], tol); -ASSERT_EQUAL_VEC(Vec3(-5.09778e+02, 2.10810e+01, 3.01816e+02), forces1[862], tol); -ASSERT_EQUAL_VEC(Vec3(-9.74895e+00, 7.12371e+01, 9.37892e+01), forces1[863], tol); -ASSERT_EQUAL_VEC(Vec3( 9.17307e+01, -4.41188e+02, -1.00390e+02), forces1[864], tol); -ASSERT_EQUAL_VEC(Vec3(-2.52934e+01, -1.90242e+02, 4.81585e+01), forces1[865], tol); -ASSERT_EQUAL_VEC(Vec3(-5.44265e+02, 2.54798e+02, -1.75185e+02), forces1[866], tol); -ASSERT_EQUAL_VEC(Vec3( 4.08129e+02, -1.23564e+02, -2.06955e+02), forces1[867], tol); -ASSERT_EQUAL_VEC(Vec3( 4.38403e+02, -1.73663e+02, 4.68123e+02), forces1[868], tol); -ASSERT_EQUAL_VEC(Vec3(-3.66073e+02, 3.32526e+02, 2.43522e+02), forces1[869], tol); -ASSERT_EQUAL_VEC(Vec3( 2.09695e+02, 2.98063e+02, -4.55262e+02), forces1[870], tol); -ASSERT_EQUAL_VEC(Vec3( 4.70466e+01, -8.03891e+01, 1.44535e+02), forces1[871], tol); -ASSERT_EQUAL_VEC(Vec3( 4.51402e+01, -3.68229e+02, 2.65397e+02), forces1[872], tol); -ASSERT_EQUAL_VEC(Vec3(-2.22430e+02, 4.99723e+02, 1.50953e+02), forces1[873], tol); -ASSERT_EQUAL_VEC(Vec3(-3.32916e+02, 7.08253e+02, -2.53294e+02), forces1[874], tol); -ASSERT_EQUAL_VEC(Vec3(-2.24293e+02, 3.61211e+02, 3.14058e+02), forces1[875], tol); -ASSERT_EQUAL_VEC(Vec3( 2.86069e+01, 3.62417e+02, -2.25939e+01), forces1[876], tol); -ASSERT_EQUAL_VEC(Vec3( 3.25305e+02, -8.59847e+01, 6.05371e+02), forces1[877], tol); -ASSERT_EQUAL_VEC(Vec3( 3.08168e+02, 2.08408e+02, -3.04918e+02), forces1[878], tol); -ASSERT_EQUAL_VEC(Vec3( 3.65569e+02, 1.38315e+02, 2.10354e+02), forces1[879], tol); -ASSERT_EQUAL_VEC(Vec3( 6.56765e+01, 4.57994e+02, -1.05220e+02), forces1[880], tol); -ASSERT_EQUAL_VEC(Vec3(-7.04583e+02, 1.95861e+02, 6.29259e+01), forces1[881], tol); -ASSERT_EQUAL_VEC(Vec3(-5.03165e+02, -4.91098e+02, 2.40840e+00), forces1[882], tol); -ASSERT_EQUAL_VEC(Vec3(-6.84653e+01, 8.09254e+01, 2.50208e+02), forces1[883], tol); -ASSERT_EQUAL_VEC(Vec3(-5.35069e+01, 1.91749e+02, -1.93660e+02), forces1[884], tol); -ASSERT_EQUAL_VEC(Vec3( 5.56345e+02, -6.69144e+02, -2.99821e+02), forces1[885], tol); -ASSERT_EQUAL_VEC(Vec3(-3.35809e+02, 5.18670e+01, -2.16408e+02), forces1[886], tol); -ASSERT_EQUAL_VEC(Vec3(-1.13154e+02, 6.23001e+02, -1.73934e+01), forces1[887], tol); -ASSERT_EQUAL_VEC(Vec3(-4.64234e+02, -2.03165e+02, 4.33719e+02), forces1[888], tol); -ASSERT_EQUAL_VEC(Vec3( 5.74659e+01, -4.61823e+02, -4.22519e+02), forces1[889], tol); -ASSERT_EQUAL_VEC(Vec3(-3.53687e+02, 1.03995e+02, 1.47418e+02), forces1[890], tol); -ASSERT_EQUAL_VEC(Vec3( 9.55591e+01, 4.15281e+02, 1.37721e+02), forces1[891], tol); -ASSERT_EQUAL_VEC(Vec3( 4.43132e+02, -3.70019e+01, -4.01946e+02), forces1[892], tol); -ASSERT_EQUAL_VEC(Vec3( 1.26695e+02, -2.55273e+02, 1.49235e+02), forces1[893], tol); diff --git a/platforms/reference/tests/nacl_crystal.forces_ewald b/platforms/reference/tests/nacl_crystal.forces_ewald deleted file mode 100644 index c7b2067a4..000000000 --- a/platforms/reference/tests/nacl_crystal.forces_ewald +++ /dev/null @@ -1,1000 +0,0 @@ -ASSERT_EQUAL_VEC(Vec3(-1.34723e-12, 1.34140e-13, -9.52623e-14), forcesEwald1[0], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.04187e-12, 2.68479e-13, -3.12203e-13), forcesEwald1[1], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.19033e-12, -2.72974e-13, -1.17325e-12), forcesEwald1[2], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.55500e-13, 3.03792e-13, -1.42362e-12), forcesEwald1[3], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.72329e-12, -1.44361e-13, -3.57021e-12), forcesEwald1[4], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.45922e-13, 1.29291e-12, 6.17080e-13), forcesEwald1[5], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.64509e-13, 9.44906e-13, 8.39154e-13), forcesEwald1[6], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.65557e-12, 8.83968e-13, 1.09292e-13), forcesEwald1[7], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.17223e-12, 1.34649e-12, 4.25484e-12), forcesEwald1[8], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.38017e-12, 3.13160e-13, -5.54905e-14), forcesEwald1[9], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.65712e-12, 1.97636e-13, -2.07437e-13), forcesEwald1[10], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.72962e-13, -1.92259e-13, -3.38762e-13), forcesEwald1[11], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.25799e-13, -3.83844e-13, -1.04405e-12), forcesEwald1[12], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.68674e-13, 8.89530e-14, -1.49909e-12), forcesEwald1[13], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.97125e-12, 6.85783e-14, -3.88406e-12), forcesEwald1[14], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.75429e-13, 1.39711e-12, 2.26411e-13), forcesEwald1[15], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.28125e-13, 8.52022e-13, 6.65930e-13), forcesEwald1[16], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.99108e-13, 7.44097e-13, 3.92401e-13), forcesEwald1[17], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.02361e-12, 1.49451e-12, 4.74191e-12), forcesEwald1[18], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.12980e-12, 1.38282e-12, 4.01078e-14), forcesEwald1[19], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.32736e-12, -1.05469e-12, -4.14514e-13), forcesEwald1[20], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.13226e-12, -8.07267e-13, -6.08231e-13), forcesEwald1[21], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.22023e-13, -9.49997e-13, -1.00993e-12), forcesEwald1[22], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.99632e-13, -7.41480e-13, -1.21048e-12), forcesEwald1[23], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.79014e-12, -9.71045e-13, -3.69459e-12), forcesEwald1[24], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.08707e-13, -2.45529e-13, -3.08884e-14), forcesEwald1[25], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.59015e-13, 7.16559e-14, 6.62334e-13), forcesEwald1[26], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.18263e-12, 1.22468e-13, 4.20933e-13), forcesEwald1[27], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.11959e-12, 8.49551e-13, 4.39294e-12), forcesEwald1[28], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.05160e-12, -2.96757e-14, 3.65713e-13), forcesEwald1[29], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.59724e-13, -1.60605e-12, -9.86531e-14), forcesEwald1[30], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.05984e-13, -1.11785e-12, -7.64274e-13), forcesEwald1[31], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.55805e-13, -1.50108e-12, -9.81712e-13), forcesEwald1[32], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.66341e-14, -1.00296e-12, -1.35849e-12), forcesEwald1[33], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.10287e-13, -1.24299e-12, -3.82802e-12), forcesEwald1[34], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.92278e-13, 4.41536e-12, 1.84342e-13), forcesEwald1[35], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.61828e-12, 4.78426e-12, 1.45710e-12), forcesEwald1[36], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.21839e-12, 4.47754e-12, 7.24406e-13), forcesEwald1[37], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.54978e-13, 4.95163e-12, 4.77626e-12), forcesEwald1[38], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.64235e-13, 4.54968e-12, 2.58644e-15), forcesEwald1[39], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.98308e-13, -3.99161e-12, -2.02835e-13), forcesEwald1[40], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.33096e-12, -3.97352e-12, -6.60652e-13), forcesEwald1[41], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.29278e-12, -3.39635e-12, -1.01322e-12), forcesEwald1[42], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.08283e-13, -3.82712e-12, -1.05139e-12), forcesEwald1[43], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.54470e-13, -3.96867e-12, -3.93860e-12), forcesEwald1[44], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.47320e-13, 2.47874e-13, 2.08057e-13), forcesEwald1[45], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.11910e-12, 6.46163e-13, 1.23157e-12), forcesEwald1[46], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.32007e-12, 4.61251e-13, 2.36073e-13), forcesEwald1[47], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.06413e-12, 2.19251e-13, 4.56446e-12), forcesEwald1[48], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.46004e-13, 1.69783e-13, -6.22071e-14), forcesEwald1[49], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.67018e-13, -3.71314e-14, 8.55534e-13), forcesEwald1[50], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.29704e-13, 1.37293e-13, 1.14150e-12), forcesEwald1[51], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.08639e-13, -3.67141e-14, 2.47374e-13), forcesEwald1[52], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.86071e-13, -3.44749e-14, 4.50460e-12), forcesEwald1[53], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.00385e-13, -2.05734e-13, 9.41300e-14), forcesEwald1[54], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.48031e-13, 6.40296e-13, -1.40348e-13), forcesEwald1[55], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.42020e-12, 8.67132e-13, 8.97016e-14), forcesEwald1[56], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.08867e-12, 8.46260e-13, -4.79358e-13), forcesEwald1[57], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.13990e-13, 6.94982e-13, -1.32009e-12), forcesEwald1[58], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.49356e-13, 1.00625e-12, -4.01459e-12), forcesEwald1[59], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.25064e-12, -8.36315e-13, 1.45543e-12), forcesEwald1[60], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.37190e-12, -8.54381e-13, 1.13288e-12), forcesEwald1[61], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.72423e-12, -8.64046e-13, 5.14782e-14), forcesEwald1[62], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.07622e-12, -3.00590e-13, 4.39532e-12), forcesEwald1[63], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.45700e-13, -3.34589e-13, -1.49226e-13), forcesEwald1[64], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.53461e-13, 1.52073e-12, -1.80047e-13), forcesEwald1[65], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.64532e-12, 2.46364e-13, -1.05348e-13), forcesEwald1[66], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.35154e-13, 2.98891e-13, -5.53406e-13), forcesEwald1[67], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.73793e-13, 1.26050e-12, -1.26111e-12), forcesEwald1[68], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.35320e-13, 1.44110e-12, -3.65450e-12), forcesEwald1[69], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.00840e-12, -1.03389e-12, 5.02917e-13), forcesEwald1[70], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.21551e-12, -1.13927e-12, 1.00202e-12), forcesEwald1[71], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.12268e-13, -9.65425e-13, 6.47425e-13), forcesEwald1[72], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.74999e-13, -8.24343e-13, 4.64881e-12), forcesEwald1[73], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.98446e-13, -5.67281e-13, 2.59942e-13), forcesEwald1[74], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.71788e-13, 2.59543e-13, -2.69816e-13), forcesEwald1[75], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.23881e-12, -3.48780e-13, -7.69104e-13), forcesEwald1[76], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.81792e-13, -1.98044e-13, -5.58744e-13), forcesEwald1[77], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.20574e-12, -1.68982e-13, -1.00188e-12), forcesEwald1[78], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.04826e-13, -1.66206e-13, -3.90233e-12), forcesEwald1[79], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.63465e-12, -1.43797e-12, 4.69215e-13), forcesEwald1[80], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.05861e-13, -1.82247e-12, 1.19679e-12), forcesEwald1[81], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.72438e-13, -1.99041e-12, 1.18511e-12), forcesEwald1[82], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.41910e-12, -8.24315e-13, 4.98937e-12), forcesEwald1[83], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.23625e-12, -1.02910e-12, 3.96699e-13), forcesEwald1[84], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.37137e-12, 4.24728e-12, -3.22115e-13), forcesEwald1[85], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.38814e-12, 4.16683e-12, -1.10826e-12), forcesEwald1[86], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.51735e-12, 4.30920e-12, -8.82845e-13), forcesEwald1[87], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.16235e-12, 4.74609e-12, -8.55254e-13), forcesEwald1[88], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.25398e-12, 4.39370e-12, -4.06978e-12), forcesEwald1[89], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.40566e-13, -3.91356e-12, 1.64866e-13), forcesEwald1[90], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.08776e-13, -3.17498e-12, 1.25186e-12), forcesEwald1[91], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.11432e-12, -3.65701e-12, 8.78652e-13), forcesEwald1[92], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.66637e-12, -3.84314e-12, 4.84266e-12), forcesEwald1[93], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.48737e-13, -4.26117e-12, 5.16300e-14), forcesEwald1[94], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.05342e-13, -9.60037e-14, -2.06479e-13), forcesEwald1[95], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.42397e-13, 7.37242e-13, -4.13033e-13), forcesEwald1[96], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.92404e-13, 1.25263e-12, -4.38857e-13), forcesEwald1[97], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.52195e-13, 7.79702e-14, -1.32223e-12), forcesEwald1[98], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.21133e-13, 3.04888e-13, -3.78376e-12), forcesEwald1[99], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.87744e-13, -3.39545e-13, -5.88670e-14), forcesEwald1[100], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.79312e-13, 2.95589e-13, -2.95655e-13), forcesEwald1[101], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.65128e-13, 1.85540e-13, -1.02954e-12), forcesEwald1[102], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.47731e-13, 9.38203e-15, -1.45146e-12), forcesEwald1[103], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01718e-12, -3.38342e-13, -3.98201e-12), forcesEwald1[104], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.53112e-13, 6.13570e-13, 9.35603e-13), forcesEwald1[105], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.86670e-13, 1.68614e-12, 9.73381e-13), forcesEwald1[106], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.21188e-12, 1.13782e-12, -2.34965e-13), forcesEwald1[107], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.23343e-12, 1.11433e-12, 4.25538e-12), forcesEwald1[108], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.64055e-14, 3.20193e-13, -1.54854e-13), forcesEwald1[109], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.30625e-13, 3.52084e-14, -1.60719e-14), forcesEwald1[110], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.45256e-12, -2.77331e-13, 3.53604e-13), forcesEwald1[111], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.32249e-12, -4.30796e-13, -1.46617e-12), forcesEwald1[112], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.08700e-12, -2.39699e-13, -1.49238e-12), forcesEwald1[113], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.97877e-12, -2.02435e-13, -4.01586e-12), forcesEwald1[114], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.01468e-13, 1.31987e-12, 7.08478e-13), forcesEwald1[115], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.48909e-12, 5.03319e-13, 9.81999e-13), forcesEwald1[116], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.38017e-12, 8.53971e-13, -2.13805e-13), forcesEwald1[117], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.03144e-12, 1.83846e-12, 4.67913e-12), forcesEwald1[118], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.57513e-13, 1.44418e-12, 1.70269e-13), forcesEwald1[119], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.08523e-13, -7.21272e-13, -1.48621e-13), forcesEwald1[120], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.35208e-12, -1.28995e-12, -4.29402e-13), forcesEwald1[121], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.78873e-13, -1.51657e-12, -1.08298e-12), forcesEwald1[122], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.08183e-12, -7.63585e-13, -1.23231e-12), forcesEwald1[123], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.66143e-12, -8.85720e-13, -3.70843e-12), forcesEwald1[124], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.33872e-13, 1.84272e-13, -5.32969e-14), forcesEwald1[125], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.24508e-12, -1.41872e-13, 8.75351e-13), forcesEwald1[126], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.10569e-12, 2.57318e-13, 4.42092e-13), forcesEwald1[127], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.56922e-13, 1.23694e-12, 4.21423e-12), forcesEwald1[128], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.64719e-13, 5.12088e-13, 3.00122e-13), forcesEwald1[129], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.25530e-13, -9.61348e-13, -3.47446e-13), forcesEwald1[130], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.75918e-13, -1.29030e-12, -1.26076e-12), forcesEwald1[131], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.29993e-12, -1.19773e-12, -9.09430e-13), forcesEwald1[132], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.67123e-13, -9.81521e-13, -8.59986e-13), forcesEwald1[133], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.25599e-12, -6.07748e-13, -3.82951e-12), forcesEwald1[134], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.29827e-12, 4.44727e-12, -3.51689e-13), forcesEwald1[135], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.43950e-12, 4.88229e-12, 1.50953e-12), forcesEwald1[136], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.29613e-12, 4.31143e-12, 9.02967e-13), forcesEwald1[137], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.21593e-12, 4.94933e-12, 5.17844e-12), forcesEwald1[138], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.59197e-13, 4.48261e-12, -7.63818e-14), forcesEwald1[139], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.51687e-13, -4.20566e-12, -3.60474e-13), forcesEwald1[140], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.44576e-13, -3.91129e-12, -1.11006e-12), forcesEwald1[141], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.42619e-13, -3.37055e-12, -6.49133e-13), forcesEwald1[142], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.57668e-13, -3.94920e-12, -8.76077e-13), forcesEwald1[143], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.11334e-12, -4.38953e-12, -3.95794e-12), forcesEwald1[144], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.68225e-13, 3.55186e-13, 1.42017e-13), forcesEwald1[145], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.92998e-13, 9.93883e-13, 9.89052e-13), forcesEwald1[146], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.63659e-13, 5.66164e-13, 1.81266e-13), forcesEwald1[147], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.60482e-13, -2.55350e-13, 4.69046e-12), forcesEwald1[148], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.12009e-14, -2.44592e-13, -1.65299e-13), forcesEwald1[149], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.99054e-12, -2.02586e-14, 5.13777e-13), forcesEwald1[150], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.96081e-12, 4.06895e-13, 1.09490e-12), forcesEwald1[151], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.78605e-12, -1.48781e-13, 3.36415e-13), forcesEwald1[152], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.05115e-12, -1.95755e-13, 4.57933e-12), forcesEwald1[153], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.00861e-12, -4.68458e-13, 1.79787e-13), forcesEwald1[154], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.59340e-12, 1.39742e-13, -2.82456e-14), forcesEwald1[155], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.13954e-12, 9.43183e-13, 3.15334e-14), forcesEwald1[156], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.08149e-12, 7.19872e-13, -5.22045e-13), forcesEwald1[157], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.09037e-12, 8.02430e-13, -1.40255e-12), forcesEwald1[158], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.79504e-12, 6.66674e-13, -3.53467e-12), forcesEwald1[159], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.43377e-12, -9.19952e-13, 1.48261e-12), forcesEwald1[160], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.66136e-12, -5.48878e-13, 1.06638e-12), forcesEwald1[161], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.51961e-12, -6.22899e-13, -1.19945e-13), forcesEwald1[162], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.51469e-12, -4.63195e-13, 4.42469e-12), forcesEwald1[163], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.18180e-12, -5.43742e-14, -9.81693e-14), forcesEwald1[164], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.82559e-12, 1.15608e-12, -4.25365e-14), forcesEwald1[165], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.65948e-12, 2.44837e-13, -1.08492e-14), forcesEwald1[166], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.87871e-12, 3.60252e-13, -5.89245e-13), forcesEwald1[167], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.27725e-12, 1.01730e-12, -1.49699e-12), forcesEwald1[168], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.01080e-12, 1.15329e-12, -3.32915e-12), forcesEwald1[169], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.31646e-12, -1.13224e-12, 5.00254e-13), forcesEwald1[170], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.78056e-12, -1.71077e-12, 1.02036e-12), forcesEwald1[171], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.73027e-12, -8.66267e-13, 3.38774e-13), forcesEwald1[172], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.91274e-12, -6.43928e-13, 4.67283e-12), forcesEwald1[173], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.12985e-12, -7.70316e-13, -2.13368e-13), forcesEwald1[174], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.28065e-12, 3.01512e-13, -2.13259e-13), forcesEwald1[175], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.97084e-12, -3.76802e-13, -4.15953e-13), forcesEwald1[176], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.89709e-12, -1.37451e-13, -3.24284e-13), forcesEwald1[177], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.10099e-12, 3.06023e-13, -1.37334e-12), forcesEwald1[178], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.74880e-12, 5.65990e-13, -3.39394e-12), forcesEwald1[179], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.12715e-12, -1.20883e-12, 3.38132e-13), forcesEwald1[180], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.13240e-12, -1.72427e-12, 1.25160e-12), forcesEwald1[181], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.51837e-12, -1.70640e-12, 7.85029e-13), forcesEwald1[182], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.79627e-12, -7.65096e-13, 5.09514e-12), forcesEwald1[183], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.74639e-12, -8.68546e-13, 1.83061e-13), forcesEwald1[184], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.87764e-12, 4.76009e-12, -4.16386e-13), forcesEwald1[185], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.35590e-12, 4.17502e-12, -8.57249e-13), forcesEwald1[186], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.43636e-12, 4.46920e-12, -4.82890e-13), forcesEwald1[187], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.47157e-12, 4.99078e-12, -9.29737e-13), forcesEwald1[188], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.04933e-12, 4.52240e-12, -3.91909e-12), forcesEwald1[189], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.63376e-12, -3.91691e-12, -3.64947e-14), forcesEwald1[190], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.39823e-12, -3.81266e-12, 1.30169e-12), forcesEwald1[191], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.11319e-12, -4.04151e-12, 7.67023e-13), forcesEwald1[192], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.32694e-12, -4.18732e-12, 5.03254e-12), forcesEwald1[193], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.90542e-12, -4.37374e-12, -4.66693e-13), forcesEwald1[194], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.16785e-12, -3.18934e-14, -5.55061e-13), forcesEwald1[195], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.26396e-12, 5.66035e-13, -3.10030e-13), forcesEwald1[196], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.25126e-12, 5.72467e-13, -2.11380e-13), forcesEwald1[197], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.23035e-12, 1.93661e-13, -1.24038e-12), forcesEwald1[198], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.42116e-12, 1.39899e-13, -3.41229e-12), forcesEwald1[199], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.19079e-13, -7.47481e-14, -1.46029e-13), forcesEwald1[200], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.86879e-13, -1.06659e-13, -2.72618e-13), forcesEwald1[201], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.49901e-13, -6.93153e-14, -8.48206e-13), forcesEwald1[202], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.97287e-13, -1.31949e-13, -1.61305e-12), forcesEwald1[203], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.06168e-13, -3.81116e-13, -3.82605e-12), forcesEwald1[204], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.12391e-13, 8.10031e-13, 4.51256e-13), forcesEwald1[205], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.75905e-13, 1.28007e-12, 1.14283e-12), forcesEwald1[206], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.51410e-13, 8.91191e-13, 3.73505e-13), forcesEwald1[207], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.78406e-13, 1.11482e-12, 4.32852e-12), forcesEwald1[208], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.58994e-13, 2.95226e-13, 2.95886e-13), forcesEwald1[209], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.99678e-13, 2.34543e-13, 2.09998e-13), forcesEwald1[210], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.39715e-13, -2.40247e-13, -4.19421e-13), forcesEwald1[211], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.08544e-13, -2.87523e-13, -1.09144e-12), forcesEwald1[212], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.56819e-13, -2.00587e-13, -1.28046e-12), forcesEwald1[213], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.51593e-13, -2.27359e-13, -3.73533e-12), forcesEwald1[214], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.77645e-13, 1.23118e-12, 2.97541e-13), forcesEwald1[215], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.65966e-13, 1.13102e-12, 1.02486e-12), forcesEwald1[216], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.22079e-13, 1.08314e-12, 2.82750e-14), forcesEwald1[217], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.99812e-13, 1.68630e-12, 4.70139e-12), forcesEwald1[218], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.02738e-13, 1.20519e-12, 1.86207e-13), forcesEwald1[219], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.90647e-13, -1.09663e-12, 1.61836e-13), forcesEwald1[220], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.60276e-13, -1.08980e-12, -4.87767e-13), forcesEwald1[221], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.62442e-13, -1.17836e-12, -1.01698e-12), forcesEwald1[222], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.36783e-13, -6.60445e-13, -1.51339e-12), forcesEwald1[223], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.56063e-13, -1.01233e-12, -3.52163e-12), forcesEwald1[224], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.52438e-13, -1.51756e-13, -2.63168e-14), forcesEwald1[225], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.87899e-13, 1.59366e-13, 1.04341e-12), forcesEwald1[226], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.47429e-14, 4.47965e-13, 5.08753e-13), forcesEwald1[227], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.34277e-13, 1.35221e-12, 4.14791e-12), forcesEwald1[228], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.04870e-13, 2.92575e-13, -8.82576e-15), forcesEwald1[229], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.97173e-13, -1.30388e-12, -1.79529e-13), forcesEwald1[230], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.36095e-13, -1.09845e-12, -3.28645e-13), forcesEwald1[231], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.75874e-13, -1.08062e-12, -8.73160e-13), forcesEwald1[232], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.97078e-13, -7.17217e-13, -1.46014e-12), forcesEwald1[233], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.81722e-13, -4.47482e-13, -3.95952e-12), forcesEwald1[234], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.70476e-15, 4.66396e-12, 1.69245e-13), forcesEwald1[235], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01457e-12, 4.65454e-12, 1.49946e-12), forcesEwald1[236], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.21129e-13, 4.24350e-12, 5.59764e-13), forcesEwald1[237], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.31672e-14, 5.21244e-12, 4.97468e-12), forcesEwald1[238], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.91151e-13, 4.59847e-12, -2.29153e-13), forcesEwald1[239], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.82770e-13, -3.66601e-12, -3.70501e-13), forcesEwald1[240], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.80744e-13, -4.09982e-12, -6.04401e-13), forcesEwald1[241], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.56104e-13, -3.65357e-12, -8.52869e-13), forcesEwald1[242], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.75827e-13, -3.71849e-12, -9.08450e-13), forcesEwald1[243], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.38089e-13, -3.86247e-12, -4.05425e-12), forcesEwald1[244], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.03437e-13, 2.86472e-13, -4.63077e-15), forcesEwald1[245], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.94655e-13, 6.21384e-13, 9.50734e-13), forcesEwald1[246], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.44386e-13, 3.26498e-13, 4.39297e-13), forcesEwald1[247], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.32830e-13, -1.29884e-13, 4.78000e-12), forcesEwald1[248], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.12624e-12, -1.44652e-13, -2.73799e-13), forcesEwald1[249], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.90783e-13, 5.98824e-14, 5.10842e-13), forcesEwald1[250], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.74093e-13, -1.44674e-13, 1.21045e-12), forcesEwald1[251], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.67533e-13, -3.07251e-13, 2.45042e-13), forcesEwald1[252], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.21731e-13, -2.55981e-13, 4.50258e-12), forcesEwald1[253], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.85277e-13, -6.34386e-14, 1.18780e-14), forcesEwald1[254], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.00988e-13, 7.16250e-13, -1.69531e-13), forcesEwald1[255], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.00928e-12, 1.02196e-12, -5.46624e-13), forcesEwald1[256], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.15772e-13, 6.51802e-13, -3.87783e-13), forcesEwald1[257], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.71671e-13, 9.58909e-13, -1.22453e-12), forcesEwald1[258], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.22625e-12, 8.26707e-13, -3.53506e-12), forcesEwald1[259], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.67353e-12, -8.12014e-13, 7.72711e-13), forcesEwald1[260], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.24209e-12, -2.88587e-13, 8.23384e-13), forcesEwald1[261], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.29224e-12, -5.23070e-13, 4.33861e-13), forcesEwald1[262], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.47184e-12, -4.56525e-13, 4.44351e-12), forcesEwald1[263], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.24368e-12, -1.09843e-13, 2.48341e-13), forcesEwald1[264], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.86105e-13, 1.19812e-12, -1.21010e-13), forcesEwald1[265], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.42276e-12, 6.39636e-13, -3.84757e-13), forcesEwald1[266], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.11347e-12, 9.49930e-13, -2.97598e-13), forcesEwald1[267], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.57654e-12, 1.57038e-12, -1.37500e-12), forcesEwald1[268], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.67580e-12, 1.43342e-12, -3.41406e-12), forcesEwald1[269], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.32300e-12, -1.45530e-12, 6.40174e-13), forcesEwald1[270], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.96142e-12, -1.25092e-12, 1.15285e-12), forcesEwald1[271], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.87442e-12, -1.40046e-12, 6.71139e-13), forcesEwald1[272], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.45188e-12, -7.57131e-13, 4.56078e-12), forcesEwald1[273], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.20987e-13, -1.49791e-12, 7.05872e-14), forcesEwald1[274], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.83057e-13, -2.42927e-13, -3.19048e-13), forcesEwald1[275], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.62590e-12, -6.43620e-13, -4.54024e-14), forcesEwald1[276], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.83244e-12, -1.46240e-13, -8.24035e-13), forcesEwald1[277], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.68258e-12, 1.20378e-13, -1.35907e-12), forcesEwald1[278], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.39769e-12, 7.62361e-14, -3.86531e-12), forcesEwald1[279], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.54695e-12, -1.35679e-12, 8.20788e-13), forcesEwald1[280], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.24682e-12, -1.61245e-12, 1.50056e-12), forcesEwald1[281], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.50133e-12, -1.87632e-12, 7.07787e-13), forcesEwald1[282], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.67689e-12, -1.14614e-12, 4.79907e-12), forcesEwald1[283], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.25221e-13, -1.26270e-12, 1.72793e-14), forcesEwald1[284], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.21087e-12, 4.13646e-12, -3.94798e-13), forcesEwald1[285], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.34870e-12, 3.81236e-12, -1.71897e-14), forcesEwald1[286], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.24325e-12, 3.78115e-12, -1.56549e-12), forcesEwald1[287], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.56128e-12, 4.46407e-12, -1.32017e-12), forcesEwald1[288], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.79896e-12, 4.04367e-12, -4.09519e-12), forcesEwald1[289], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.66324e-13, -3.34765e-12, 7.17441e-13), forcesEwald1[290], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.74519e-12, -3.78783e-12, 1.17048e-12), forcesEwald1[291], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.72279e-12, -3.91920e-12, 7.33048e-13), forcesEwald1[292], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01630e-12, -4.00711e-12, 4.57713e-12), forcesEwald1[293], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.60372e-14, -3.59645e-12, -4.60442e-13), forcesEwald1[294], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.44663e-14, 2.39279e-13, -2.19033e-13), forcesEwald1[295], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01488e-12, 3.88801e-13, -2.32534e-13), forcesEwald1[296], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.47365e-13, 4.20853e-13, -7.52461e-13), forcesEwald1[297], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.29121e-13, 2.91477e-13, -1.36139e-12), forcesEwald1[298], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.98133e-13, 3.74886e-13, -3.56859e-12), forcesEwald1[299], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.00857e-13, 3.20095e-13, -1.11971e-13), forcesEwald1[300], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.85192e-13, -4.68033e-13, -4.87599e-13), forcesEwald1[301], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.28527e-13, -5.14355e-13, -8.15904e-13), forcesEwald1[302], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.35176e-13, 1.69256e-13, -1.62788e-12), forcesEwald1[303], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.91781e-13, 7.01996e-14, -3.92916e-12), forcesEwald1[304], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.20457e-14, 7.08234e-13, 1.61323e-13), forcesEwald1[305], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.35176e-13, 4.75215e-13, 1.61760e-12), forcesEwald1[306], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.62016e-14, 6.61146e-13, 6.58689e-13), forcesEwald1[307], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.94497e-13, 1.29621e-12, 4.59120e-12), forcesEwald1[308], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.49907e-14, 8.58702e-13, 3.21233e-14), forcesEwald1[309], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.21891e-13, 1.46852e-13, -1.81299e-13), forcesEwald1[310], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.29127e-13, -2.69254e-15, -9.27365e-13), forcesEwald1[311], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.87542e-13, 1.26663e-13, -7.87571e-13), forcesEwald1[312], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.26122e-13, 2.35319e-13, -9.44791e-13), forcesEwald1[313], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.64879e-13, -1.90056e-13, -3.65717e-12), forcesEwald1[314], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.17090e-13, 1.13928e-12, -1.28503e-13), forcesEwald1[315], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.97044e-14, 1.56160e-12, 1.02318e-12), forcesEwald1[316], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.39322e-13, 1.63801e-12, 5.19624e-13), forcesEwald1[317], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.31462e-13, 1.72290e-12, 4.98948e-12), forcesEwald1[318], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.44567e-13, 1.10289e-12, -1.69122e-15), forcesEwald1[319], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.20119e-13, -1.65059e-12, -2.78951e-13), forcesEwald1[320], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.42969e-13, -1.38631e-12, -2.76229e-13), forcesEwald1[321], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.24604e-13, -5.70831e-13, -9.26237e-13), forcesEwald1[322], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.28409e-13, -5.07794e-13, -1.57492e-12), forcesEwald1[323], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.37376e-13, -1.11147e-12, -3.68615e-12), forcesEwald1[324], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.40485e-13, 3.21310e-13, 3.55920e-13), forcesEwald1[325], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.68729e-13, 6.90529e-13, 1.90420e-12), forcesEwald1[326], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.47181e-13, 7.11918e-13, 2.92080e-13), forcesEwald1[327], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.70607e-13, 9.54251e-13, 4.48571e-12), forcesEwald1[328], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.85270e-13, 3.40066e-14, -1.41445e-13), forcesEwald1[329], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.77581e-13, -1.76296e-12, -4.23836e-13), forcesEwald1[330], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.91709e-13, -9.94851e-13, 3.63096e-13), forcesEwald1[331], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.28810e-13, -6.95464e-13, -1.51097e-12), forcesEwald1[332], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.41719e-13, -1.14658e-12, -1.22575e-12), forcesEwald1[333], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.69732e-13, -1.02402e-12, -4.25272e-12), forcesEwald1[334], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.53461e-14, 4.53379e-12, 1.01142e-12), forcesEwald1[335], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.02976e-12, 4.62032e-12, 1.60437e-12), forcesEwald1[336], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.39522e-14, 4.44045e-12, -7.28874e-14), forcesEwald1[337], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.35041e-13, 4.85313e-12, 4.87142e-12), forcesEwald1[338], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.23303e-13, 4.70539e-12, -4.53487e-13), forcesEwald1[339], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.32502e-13, -3.64823e-12, -6.80330e-14), forcesEwald1[340], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.65790e-13, -4.21917e-12, 3.31857e-13), forcesEwald1[341], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.50741e-13, -4.27003e-12, -1.40061e-12), forcesEwald1[342], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.15468e-14, -3.68755e-12, -1.27676e-12), forcesEwald1[343], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.69949e-13, -3.87359e-12, -4.29792e-12), forcesEwald1[344], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.24275e-13, 3.47320e-13, 5.05833e-13), forcesEwald1[345], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.01122e-13, 1.04463e-13, 1.42052e-12), forcesEwald1[346], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.26810e-13, 4.88537e-13, 3.95001e-13), forcesEwald1[347], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.22873e-12, 3.52759e-13, 4.72833e-12), forcesEwald1[348], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.15358e-12, 2.32816e-13, -1.02579e-13), forcesEwald1[349], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.43452e-12, 2.03649e-13, 1.92953e-13), forcesEwald1[350], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.34242e-12, -4.72698e-13, 1.37796e-12), forcesEwald1[351], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.52685e-12, -2.65959e-13, 7.86049e-13), forcesEwald1[352], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.25756e-12, 2.08840e-13, 4.62071e-12), forcesEwald1[353], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.13361e-12, 3.05866e-13, 3.74681e-13), forcesEwald1[354], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.74341e-12, 1.00054e-12, -2.50829e-13), forcesEwald1[355], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.24985e-12, 3.17012e-13, -1.02278e-12), forcesEwald1[356], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.96519e-12, -1.41606e-13, -5.19542e-13), forcesEwald1[357], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.16875e-12, 4.42290e-13, -9.88932e-13), forcesEwald1[358], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.25925e-12, 9.64257e-13, -3.82212e-12), forcesEwald1[359], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.11908e-12, -4.90891e-13, -2.26599e-13), forcesEwald1[360], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.80761e-12, -4.22838e-13, 1.15280e-12), forcesEwald1[361], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.97495e-12, -5.04667e-13, 1.32124e-12), forcesEwald1[362], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.52715e-12, -2.08275e-13, 5.13581e-12), forcesEwald1[363], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.80614e-12, -1.30421e-13, 1.53021e-13), forcesEwald1[364], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.60409e-12, 9.03615e-13, -3.40853e-13), forcesEwald1[365], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.89575e-12, 1.31146e-12, -8.89475e-13), forcesEwald1[366], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.05818e-12, 1.36089e-12, -7.56428e-13), forcesEwald1[367], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.54418e-12, 1.26344e-12, -1.01118e-12), forcesEwald1[368], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.31174e-12, 1.62278e-12, -3.65979e-12), forcesEwald1[369], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.89494e-12, -1.77321e-12, 1.36320e-13), forcesEwald1[370], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.63328e-12, -1.32868e-12, 1.34734e-12), forcesEwald1[371], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.78477e-12, -1.51317e-12, 9.77555e-13), forcesEwald1[372], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.19511e-12, -1.11307e-12, 4.96457e-12), forcesEwald1[373], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.46440e-12, -1.61555e-12, -4.70400e-13), forcesEwald1[374], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.99848e-12, 1.26941e-13, -3.10656e-13), forcesEwald1[375], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.11033e-12, 9.41235e-13, -1.04775e-13), forcesEwald1[376], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.77744e-12, 8.23332e-13, -1.18781e-12), forcesEwald1[377], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.51040e-12, 2.62479e-13, -1.25999e-12), forcesEwald1[378], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.83978e-12, 1.22093e-13, -3.80627e-12), forcesEwald1[379], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.10120e-12, -1.36568e-12, 1.04403e-12), forcesEwald1[380], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.66331e-12, -6.85131e-13, 1.56795e-12), forcesEwald1[381], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.62585e-12, -1.26581e-12, 1.03111e-13), forcesEwald1[382], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.90204e-12, -1.57188e-12, 4.95891e-12), forcesEwald1[383], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.20884e-12, -1.73987e-12, -3.81965e-13), forcesEwald1[384], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.86471e-12, 4.46346e-12, -1.02610e-13), forcesEwald1[385], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.32753e-12, 4.29194e-12, 3.14574e-13), forcesEwald1[386], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.70383e-12, 4.32365e-12, -1.65005e-12), forcesEwald1[387], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.35030e-12, 4.26796e-12, -1.91362e-12), forcesEwald1[388], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.24700e-12, 4.39455e-12, -4.38560e-12), forcesEwald1[389], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.86908e-12, -3.67152e-12, 1.03768e-12), forcesEwald1[390], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.03574e-12, -4.91361e-12, 1.57582e-12), forcesEwald1[391], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.09355e-12, -4.36319e-12, 1.00918e-13), forcesEwald1[392], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.17427e-12, -3.84152e-12, 4.75949e-12), forcesEwald1[393], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.37850e-12, -3.84236e-12, -2.45604e-13), forcesEwald1[394], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.50024e-12, 7.15597e-14, -8.16641e-14), forcesEwald1[395], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.61987e-12, -3.99693e-13, -1.46895e-13), forcesEwald1[396], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.97558e-12, -3.68065e-13, -1.06069e-12), forcesEwald1[397], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.31263e-12, 6.61677e-14, -1.43698e-12), forcesEwald1[398], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.46959e-12, 4.43723e-13, -4.02541e-12), forcesEwald1[399], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.65355e-12, 3.95975e-13, 1.01311e-13), forcesEwald1[400], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.85016e-12, -6.20303e-15, -5.56212e-13), forcesEwald1[401], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.82249e-12, -4.88094e-13, -1.21382e-12), forcesEwald1[402], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.75182e-12, -7.44118e-14, -1.49277e-12), forcesEwald1[403], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.30683e-12, -1.51295e-14, -3.87995e-12), forcesEwald1[404], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.15898e-12, 6.67452e-13, 2.47480e-14), forcesEwald1[405], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.29782e-12, 1.17687e-13, 1.02848e-12), forcesEwald1[406], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.51883e-12, 3.68597e-13, 5.89730e-13), forcesEwald1[407], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.38671e-12, 8.95742e-13, 4.64907e-12), forcesEwald1[408], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.37259e-12, 7.35927e-13, 3.39048e-13), forcesEwald1[409], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.81453e-12, -3.39480e-13, -9.08799e-14), forcesEwald1[410], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.10647e-12, -4.37896e-13, -1.07780e-12), forcesEwald1[411], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.78850e-12, -2.21668e-13, -7.28946e-13), forcesEwald1[412], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.37520e-12, 2.83187e-13, -8.86007e-13), forcesEwald1[413], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.62303e-12, 3.28982e-15, -3.82018e-12), forcesEwald1[414], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.05607e-12, 1.10120e-12, -1.65016e-13), forcesEwald1[415], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.25810e-12, 1.57946e-12, 1.10439e-12), forcesEwald1[416], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.87668e-12, 1.54884e-12, 5.78782e-13), forcesEwald1[417], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.05995e-12, 1.54748e-12, 5.05423e-12), forcesEwald1[418], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.04811e-12, 1.19599e-12, -3.17768e-13), forcesEwald1[419], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.82387e-12, -1.36315e-12, -3.20366e-13), forcesEwald1[420], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.38295e-12, -5.15449e-13, -6.19557e-13), forcesEwald1[421], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.22671e-12, -9.17610e-13, -9.34959e-13), forcesEwald1[422], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.07999e-12, -1.04730e-12, -9.44297e-13), forcesEwald1[423], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.65432e-12, -1.25490e-12, -3.87190e-12), forcesEwald1[424], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.36573e-12, 4.83381e-14, 4.51036e-13), forcesEwald1[425], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.35918e-12, 6.48936e-13, 1.02437e-12), forcesEwald1[426], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.86258e-12, 4.54300e-13, 3.12748e-13), forcesEwald1[427], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.80574e-12, 4.65159e-13, 4.21251e-12), forcesEwald1[428], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.67587e-12, -2.53880e-13, -1.22370e-13), forcesEwald1[429], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.61996e-12, -1.80786e-12, 2.40749e-14), forcesEwald1[430], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.69686e-12, -1.09245e-12, 2.67605e-15), forcesEwald1[431], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.05927e-12, -9.42747e-13, -1.43402e-12), forcesEwald1[432], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.16269e-12, -1.15106e-12, -1.40968e-12), forcesEwald1[433], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.88272e-12, -1.40458e-12, -4.29182e-12), forcesEwald1[434], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.26496e-12, 4.54077e-12, 1.03067e-12), forcesEwald1[435], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.60941e-12, 4.79033e-12, 1.54185e-12), forcesEwald1[436], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.43574e-12, 4.24267e-12, -8.08309e-14), forcesEwald1[437], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.21274e-12, 5.06058e-12, 4.69779e-12), forcesEwald1[438], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.45577e-12, 4.62820e-12, -2.73750e-13), forcesEwald1[439], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.93296e-12, -3.67742e-12, 1.71131e-13), forcesEwald1[440], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.26715e-12, -4.07984e-12, -5.78532e-15), forcesEwald1[441], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.15850e-12, -3.87939e-12, -1.46592e-12), forcesEwald1[442], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.31305e-12, -3.61909e-12, -1.39736e-12), forcesEwald1[443], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.18604e-12, -3.66099e-12, -4.34015e-12), forcesEwald1[444], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.36147e-12, 4.47597e-13, 4.27429e-13), forcesEwald1[445], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.77912e-12, -7.74161e-15, 1.50805e-12), forcesEwald1[446], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.82810e-12, 2.23654e-13, 3.09573e-13), forcesEwald1[447], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.69096e-12, 2.09864e-13, 4.40560e-12), forcesEwald1[448], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.58386e-12, 5.90577e-13, 1.45066e-13), forcesEwald1[449], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.67545e-13, 2.66723e-13, 2.87936e-13), forcesEwald1[450], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.46363e-13, -4.71748e-14, 1.17036e-12), forcesEwald1[451], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.42887e-13, -2.92223e-13, -1.27504e-13), forcesEwald1[452], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.15256e-12, -4.32957e-15, 4.65917e-12), forcesEwald1[453], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.54462e-13, 1.68071e-13, -1.04775e-13), forcesEwald1[454], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.32446e-13, 1.55595e-13, -4.58073e-13), forcesEwald1[455], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.45105e-13, 4.00368e-13, -3.91231e-13), forcesEwald1[456], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.80761e-13, -1.04571e-13, -7.26342e-13), forcesEwald1[457], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.30509e-13, 6.00874e-13, -1.28037e-12), forcesEwald1[458], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.16667e-14, 9.90872e-13, -3.39197e-12), forcesEwald1[459], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.21531e-12, -1.04711e-12, 7.99287e-14), forcesEwald1[460], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.27196e-13, -6.44000e-13, 1.08024e-12), forcesEwald1[461], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.43697e-13, -5.03071e-13, 1.23109e-13), forcesEwald1[462], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.53819e-13, -1.74487e-13, 4.86822e-12), forcesEwald1[463], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.13828e-12, -9.74769e-14, -5.75249e-14), forcesEwald1[464], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.78626e-13, 1.14614e-12, -3.77621e-13), forcesEwald1[465], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.05770e-12, 9.97966e-13, -3.35126e-13), forcesEwald1[466], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.76943e-13, 8.60666e-13, -3.24260e-13), forcesEwald1[467], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.27279e-13, 1.32831e-12, -1.22436e-12), forcesEwald1[468], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.06508e-12, 1.23724e-12, -3.49680e-12), forcesEwald1[469], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.95398e-13, -1.18316e-12, 1.36978e-13), forcesEwald1[470], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.05020e-12, -1.17489e-12, 9.28207e-13), forcesEwald1[471], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.13069e-13, -1.21239e-12, 4.01385e-13), forcesEwald1[472], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.46125e-12, -6.82421e-13, 4.92440e-12), forcesEwald1[473], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.08477e-13, -1.33705e-12, -1.83981e-13), forcesEwald1[474], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.36550e-13, -4.65481e-13, -1.32918e-13), forcesEwald1[475], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.47764e-12, -6.12978e-13, -4.26802e-13), forcesEwald1[476], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.31212e-12, -2.57401e-13, -1.18715e-12), forcesEwald1[477], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.17126e-12, -3.86197e-13, -1.25896e-12), forcesEwald1[478], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.07961e-12, -7.58387e-13, -3.65056e-12), forcesEwald1[479], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.27873e-12, -1.48156e-12, 6.10790e-13), forcesEwald1[480], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.84363e-12, -1.60577e-12, 1.08286e-12), forcesEwald1[481], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.06594e-12, -1.64590e-12, 5.32135e-13), forcesEwald1[482], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.26084e-12, -1.33437e-12, 4.86637e-12), forcesEwald1[483], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.07273e-12, -1.73040e-12, 2.28958e-13), forcesEwald1[484], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.29495e-12, 4.43838e-12, -4.68431e-14), forcesEwald1[485], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.12006e-12, 4.23930e-12, -2.47453e-13), forcesEwald1[486], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.33605e-12, 4.77540e-12, -1.18793e-12), forcesEwald1[487], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.56001e-12, 5.10061e-12, -1.34966e-12), forcesEwald1[488], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.09717e-12, 4.62170e-12, -3.93053e-12), forcesEwald1[489], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.09615e-12, -3.69601e-12, 5.98408e-13), forcesEwald1[490], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.54383e-12, -3.69033e-12, 1.39409e-12), forcesEwald1[491], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.52142e-12, -3.46090e-12, -1.97019e-14), forcesEwald1[492], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.46491e-12, -3.39817e-12, 4.49683e-12), forcesEwald1[493], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.11613e-12, -3.69209e-12, -8.00944e-14), forcesEwald1[494], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.00709e-13, 4.15148e-13, -2.35865e-13), forcesEwald1[495], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.24062e-13, 2.49660e-13, 1.96352e-14), forcesEwald1[496], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.00236e-13, 2.14223e-13, -9.54781e-13), forcesEwald1[497], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.11210e-13, 1.84936e-13, -1.61151e-12), forcesEwald1[498], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.83425e-13, 3.37380e-13, -3.44943e-12), forcesEwald1[499], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.15326e-13, -4.10362e-13, -5.18694e-14), forcesEwald1[500], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.71909e-13, -6.46488e-13, 1.63327e-12), forcesEwald1[501], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.85771e-13, -3.47973e-13, 5.73959e-13), forcesEwald1[502], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.29804e-13, -2.05264e-13, 4.15464e-12), forcesEwald1[503], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.41330e-13, -5.49021e-13, 5.57230e-13), forcesEwald1[504], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.88040e-13, 5.88228e-13, 2.89777e-13), forcesEwald1[505], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.85382e-13, 1.13462e-12, -8.44640e-13), forcesEwald1[506], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.13532e-13, 8.30229e-13, -6.60917e-13), forcesEwald1[507], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.74371e-13, 8.91642e-13, -1.20786e-12), forcesEwald1[508], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.26763e-13, 1.03945e-12, -3.54870e-12), forcesEwald1[509], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.58896e-13, -6.92762e-13, 1.15589e-13), forcesEwald1[510], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.12923e-13, 3.52624e-13, 1.35174e-12), forcesEwald1[511], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.08815e-13, 5.52583e-13, 2.53025e-13), forcesEwald1[512], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.49207e-13, -6.04871e-13, 4.53848e-12), forcesEwald1[513], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.97182e-13, 4.61243e-14, 7.39156e-13), forcesEwald1[514], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.90191e-13, 2.18159e-12, 1.07119e-13), forcesEwald1[515], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.81154e-13, 2.17407e-12, -3.91994e-13), forcesEwald1[516], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.78502e-13, 2.49919e-12, -6.97596e-13), forcesEwald1[517], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.12444e-12, 2.40538e-12, -1.59152e-12), forcesEwald1[518], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.25460e-13, 2.17342e-12, -3.48025e-12), forcesEwald1[519], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.10464e-13, -8.57962e-13, 2.37749e-13), forcesEwald1[520], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.55243e-13, -5.33227e-13, 1.55917e-12), forcesEwald1[521], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.16703e-13, -6.62331e-13, 2.23631e-13), forcesEwald1[522], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.57888e-13, -7.58433e-13, 4.12597e-12), forcesEwald1[523], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.75691e-14, -1.59300e-12, 4.11472e-13), forcesEwald1[524], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.57283e-13, -1.15074e-13, 4.91614e-14), forcesEwald1[525], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.56585e-13, 8.54720e-14, -1.67408e-14), forcesEwald1[526], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.02257e-13, 2.93092e-13, -9.44249e-13), forcesEwald1[527], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.69984e-13, 6.08526e-13, -1.40570e-12), forcesEwald1[528], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.11227e-13, 5.50784e-14, -3.51872e-12), forcesEwald1[529], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.65968e-13, -1.04411e-12, 5.10309e-13), forcesEwald1[530], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.43040e-12, -1.30357e-12, 1.93159e-12), forcesEwald1[531], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.15093e-12, -1.20707e-12, 1.61796e-13), forcesEwald1[532], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.37297e-13, -1.54714e-12, 4.05093e-12), forcesEwald1[533], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.63904e-13, -6.15302e-13, 8.36408e-14), forcesEwald1[534], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.55000e-14, 4.73111e-12, -5.33667e-14), forcesEwald1[535], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.35564e-13, 4.47276e-12, -2.34307e-13), forcesEwald1[536], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.69944e-13, 4.57704e-12, -1.58902e-12), forcesEwald1[537], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.62892e-13, 5.18130e-12, -1.01161e-12), forcesEwald1[538], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.87993e-13, 4.55716e-12, -4.06829e-12), forcesEwald1[539], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.26259e-13, -3.78378e-12, 4.28902e-13), forcesEwald1[540], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.03974e-12, -3.97284e-12, 1.85539e-12), forcesEwald1[541], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.24815e-13, -3.57099e-12, 1.76014e-13), forcesEwald1[542], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.54249e-13, -4.17009e-12, 4.37443e-12), forcesEwald1[543], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.05573e-13, -3.53252e-12, 8.14256e-14), forcesEwald1[544], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.49244e-13, -9.62821e-14, 5.95868e-14), forcesEwald1[545], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.20071e-13, -4.14512e-13, -5.11231e-13), forcesEwald1[546], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.10365e-13, -2.27598e-13, -8.66046e-13), forcesEwald1[547], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.97930e-13, -2.38291e-13, -8.94229e-13), forcesEwald1[548], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.53819e-13, -7.35596e-14, -3.41119e-12), forcesEwald1[549], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.77184e-13, -1.39601e-13, -2.39067e-13), forcesEwald1[550], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.02714e-12, -7.50116e-13, -5.51786e-13), forcesEwald1[551], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.50251e-13, -7.31174e-13, 4.25463e-14), forcesEwald1[552], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.89161e-13, -5.33928e-13, -1.02116e-12), forcesEwald1[553], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.87953e-13, -4.91540e-13, -3.19305e-12), forcesEwald1[554], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.88286e-13, 1.05781e-12, 2.78563e-13), forcesEwald1[555], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.24472e-13, 6.52637e-13, 9.77886e-13), forcesEwald1[556], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.40196e-13, 1.09626e-12, 4.44337e-13), forcesEwald1[557], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.46385e-12, 1.06985e-12, 4.65127e-12), forcesEwald1[558], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.28252e-13, 1.24809e-12, 2.06887e-15), forcesEwald1[559], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.46850e-12, -8.69057e-13, -3.17962e-13), forcesEwald1[560], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.35386e-13, -5.30358e-13, -9.15348e-13), forcesEwald1[561], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.27480e-13, -3.77243e-13, 3.13270e-13), forcesEwald1[562], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.88148e-13, -7.02451e-13, -7.12132e-13), forcesEwald1[563], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.26270e-12, -1.07212e-12, -2.98300e-12), forcesEwald1[564], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05498e-12, 1.13637e-12, 7.29844e-13), forcesEwald1[565], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.69643e-13, 1.33770e-12, 1.16107e-12), forcesEwald1[566], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.58607e-13, 1.59680e-12, 6.53133e-13), forcesEwald1[567], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.58429e-12, 1.44529e-12, 4.58465e-12), forcesEwald1[568], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.11147e-12, 9.89426e-13, 1.14582e-13), forcesEwald1[569], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.37983e-13, -5.54000e-13, -2.53821e-13), forcesEwald1[570], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.13163e-12, 3.40204e-13, -2.52202e-13), forcesEwald1[571], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.75191e-13, 1.13570e-13, 8.89369e-14), forcesEwald1[572], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.28632e-12, -1.15907e-12, -1.04924e-12), forcesEwald1[573], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.04508e-13, -8.77131e-13, -3.40053e-12), forcesEwald1[574], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.03607e-12, 8.36633e-13, 1.54984e-12), forcesEwald1[575], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.37196e-12, 7.53887e-13, 1.21645e-12), forcesEwald1[576], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.26427e-12, 4.83462e-13, 7.23859e-13), forcesEwald1[577], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.78692e-12, 7.74712e-13, 4.07982e-12), forcesEwald1[578], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.54116e-13, -4.80006e-13, -1.98272e-14), forcesEwald1[579], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.10133e-12, -1.66717e-12, -1.14426e-13), forcesEwald1[580], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.30073e-12, -1.53192e-12, 1.39275e-13), forcesEwald1[581], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.52299e-13, -1.52353e-12, -1.40052e-12), forcesEwald1[582], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.23551e-12, -1.13236e-12, -1.45685e-12), forcesEwald1[583], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.80823e-13, -1.63398e-12, -3.77983e-12), forcesEwald1[584], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.14071e-12, 3.59267e-12, 1.69424e-12), forcesEwald1[585], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.14995e-12, 3.47232e-12, 1.52275e-12), forcesEwald1[586], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.81397e-12, 3.02183e-12, 4.52850e-13), forcesEwald1[587], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.90881e-12, 3.15143e-12, 4.52328e-12), forcesEwald1[588], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.27441e-13, 3.96892e-12, -2.01708e-13), forcesEwald1[589], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.04502e-13, -2.93216e-12, -1.48254e-13), forcesEwald1[590], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.63371e-13, -3.16537e-12, 9.01213e-14), forcesEwald1[591], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.20890e-12, -3.72154e-12, -4.48416e-13), forcesEwald1[592], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.67546e-13, -3.42712e-12, -9.96353e-13), forcesEwald1[593], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.36378e-13, -3.52450e-12, -3.75902e-12), forcesEwald1[594], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.69979e-13, 2.69468e-13, 9.02015e-13), forcesEwald1[595], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.50191e-13, -1.50705e-13, 9.93609e-13), forcesEwald1[596], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.24579e-13, 2.45708e-13, 1.22148e-12), forcesEwald1[597], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.24611e-12, -4.01093e-13, 4.46156e-12), forcesEwald1[598], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.37023e-13, 2.23382e-13, 1.61411e-13), forcesEwald1[599], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.16877e-12, -1.19330e-13, 7.17833e-15), forcesEwald1[600], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.79408e-12, -1.00005e-12, 9.26870e-13), forcesEwald1[601], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.40025e-12, -5.43948e-13, 3.59285e-13), forcesEwald1[602], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.20417e-12, -1.08203e-13, 4.25439e-12), forcesEwald1[603], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.54855e-12, -1.00338e-13, 5.85795e-13), forcesEwald1[604], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.60004e-12, 1.23873e-12, -7.24598e-13), forcesEwald1[605], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.04283e-12, 9.81329e-13, -1.32322e-12), forcesEwald1[606], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.24866e-12, 8.16294e-13, -5.32943e-13), forcesEwald1[607], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.73241e-12, 1.43938e-12, -1.36809e-12), forcesEwald1[608], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.52733e-12, 1.13993e-12, -3.46590e-12), forcesEwald1[609], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.50384e-12, -8.44338e-13, -5.13232e-13), forcesEwald1[610], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.39445e-13, -2.34712e-13, 1.09243e-12), forcesEwald1[611], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.29333e-12, 9.39583e-14, 5.37660e-13), forcesEwald1[612], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.69274e-12, -4.66082e-13, 4.62243e-12), forcesEwald1[613], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.22849e-12, -4.76614e-13, 3.41450e-13), forcesEwald1[614], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.30853e-12, 1.13531e-12, -5.69939e-13), forcesEwald1[615], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.41036e-12, 1.96797e-12, -1.15685e-12), forcesEwald1[616], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.67208e-13, 2.55682e-12, -4.21220e-13), forcesEwald1[617], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.00811e-13, 2.26954e-12, -1.19238e-12), forcesEwald1[618], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.04678e-13, 1.70828e-12, -3.73085e-12), forcesEwald1[619], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.21619e-12, -5.06841e-13, 2.35906e-13), forcesEwald1[620], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.47070e-13, 3.05597e-13, 9.97127e-13), forcesEwald1[621], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.24540e-12, -1.55123e-13, 1.78753e-13), forcesEwald1[622], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.91583e-13, -8.56494e-13, 4.31094e-12), forcesEwald1[623], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.98903e-12, -8.34869e-13, 5.93364e-13), forcesEwald1[624], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.16087e-12, 3.69878e-13, -2.42753e-13), forcesEwald1[625], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.41983e-12, 9.13047e-13, -3.25026e-13), forcesEwald1[626], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.36901e-12, 1.13466e-12, -9.50349e-13), forcesEwald1[627], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.66201e-12, 9.75356e-13, -1.67214e-12), forcesEwald1[628], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.10296e-12, 2.60991e-13, -3.87561e-12), forcesEwald1[629], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.73063e-12, -1.97689e-12, 1.14721e-12), forcesEwald1[630], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.37649e-12, -1.14908e-12, 2.14218e-12), forcesEwald1[631], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.84177e-12, -1.25938e-12, -1.28291e-13), forcesEwald1[632], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.59600e-13, -1.42058e-12, 3.81698e-12), forcesEwald1[633], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.20507e-12, -1.53311e-12, -2.55285e-13), forcesEwald1[634], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.03683e-12, 4.21440e-12, 4.48272e-13), forcesEwald1[635], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.96429e-13, 4.09535e-12, 5.07684e-13), forcesEwald1[636], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.45123e-12, 4.11093e-12, -1.86303e-12), forcesEwald1[637], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.77987e-13, 4.35202e-12, -1.27750e-12), forcesEwald1[638], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.49164e-12, 4.21979e-12, -4.23127e-12), forcesEwald1[639], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.84254e-12, -3.18500e-12, 8.87546e-13), forcesEwald1[640], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.29749e-12, -4.13304e-12, 1.11810e-12), forcesEwald1[641], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.47890e-12, -3.77252e-12, -2.75827e-13), forcesEwald1[642], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.63030e-12, -4.28922e-12, 4.11596e-12), forcesEwald1[643], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.44502e-12, -2.84679e-12, 1.17908e-13), forcesEwald1[644], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.83249e-12, 2.75510e-13, -8.46467e-13), forcesEwald1[645], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.36579e-12, -6.04640e-13, -5.31901e-13), forcesEwald1[646], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.17769e-12, -6.35629e-13, -9.28992e-13), forcesEwald1[647], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.46793e-12, -3.65604e-13, -1.22935e-12), forcesEwald1[648], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.50463e-12, 3.58130e-13, -3.45943e-12), forcesEwald1[649], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.61220e-13, -2.24412e-14, -2.31915e-13), forcesEwald1[650], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.20551e-12, -6.77313e-13, -2.60132e-13), forcesEwald1[651], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.34220e-13, -7.11094e-13, -9.19821e-14), forcesEwald1[652], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.70684e-13, -2.32426e-14, -1.24292e-12), forcesEwald1[653], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.58158e-13, -6.29306e-14, -2.75253e-12), forcesEwald1[654], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.99919e-13, 8.91749e-13, -6.59182e-14), forcesEwald1[655], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.69172e-13, 2.62299e-13, 1.06276e-12), forcesEwald1[656], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.19322e-13, 6.80320e-13, 1.44138e-13), forcesEwald1[657], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.74210e-13, 1.46831e-12, 4.83020e-12), forcesEwald1[658], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.32233e-12, 9.03102e-13, -1.61872e-13), forcesEwald1[659], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.08464e-13, -5.21848e-14, -4.60709e-13), forcesEwald1[660], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.39871e-13, 2.14289e-13, -8.12105e-13), forcesEwald1[661], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.08212e-13, 3.02357e-13, 6.00259e-13), forcesEwald1[662], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.73319e-13, -1.77963e-13, -7.08385e-13), forcesEwald1[663], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.01484e-13, -5.59168e-13, -3.12160e-12), forcesEwald1[664], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.77214e-13, 1.50651e-12, 7.95760e-14), forcesEwald1[665], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.77960e-13, 1.75394e-12, 1.14468e-12), forcesEwald1[666], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.84149e-14, 1.49965e-12, 4.79034e-13), forcesEwald1[667], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.18157e-13, 1.50170e-12, 4.86261e-12), forcesEwald1[668], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.18285e-12, 1.28388e-12, -1.59203e-13), forcesEwald1[669], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.98000e-13, -7.67754e-13, -3.31809e-13), forcesEwald1[670], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.61357e-13, -1.32331e-13, -2.82814e-13), forcesEwald1[671], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.33165e-13, -2.55710e-13, -1.23066e-13), forcesEwald1[672], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.13479e-14, -9.77117e-13, -1.25105e-12), forcesEwald1[673], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.97163e-14, -8.97740e-13, -3.31874e-12), forcesEwald1[674], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.45556e-14, 3.79505e-13, 1.10565e-12), forcesEwald1[675], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.61714e-13, 4.61643e-13, 1.03318e-12), forcesEwald1[676], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.85266e-13, 3.65257e-13, 6.46543e-13), forcesEwald1[677], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.66901e-13, 7.39665e-13, 4.43105e-12), forcesEwald1[678], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.93623e-14, -6.77408e-13, -3.38277e-13), forcesEwald1[679], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.28211e-13, -2.02874e-12, -6.54386e-14), forcesEwald1[680], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.12852e-13, -1.35991e-12, 1.80742e-13), forcesEwald1[681], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.35290e-13, -1.62242e-12, -1.41504e-12), forcesEwald1[682], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.52466e-13, -1.78244e-12, -1.60590e-12), forcesEwald1[683], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.14049e-14, -1.75919e-12, -4.03888e-12), forcesEwald1[684], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.13980e-12, 3.89501e-12, 1.31760e-12), forcesEwald1[685], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.57688e-13, 3.52948e-12, 1.27795e-12), forcesEwald1[686], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.62959e-13, 3.18197e-12, 3.20209e-13), forcesEwald1[687], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.31840e-12, 3.13009e-12, 4.53343e-12), forcesEwald1[688], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.21690e-13, 4.00967e-12, 3.99441e-14), forcesEwald1[689], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.93649e-13, -2.76013e-12, 4.70845e-14), forcesEwald1[690], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.07469e-13, -3.59375e-12, 2.53858e-13), forcesEwald1[691], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.56758e-13, -3.78256e-12, -8.45988e-13), forcesEwald1[692], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.96838e-13, -3.77901e-12, -1.26644e-12), forcesEwald1[693], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.42506e-13, -3.35738e-12, -3.16145e-12), forcesEwald1[694], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.58836e-13, 1.10776e-13, 4.03271e-13), forcesEwald1[695], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.02189e-12, -9.05573e-14, 9.38284e-13), forcesEwald1[696], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.68646e-13, 5.00148e-13, 8.04692e-14), forcesEwald1[697], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.86131e-13, 1.20264e-13, 4.57801e-12), forcesEwald1[698], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.89934e-13, 4.47638e-13, 1.28815e-13), forcesEwald1[699], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.99164e-12, -3.79801e-13, 7.08188e-14), forcesEwald1[700], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.67358e-12, -6.62765e-13, 9.76994e-13), forcesEwald1[701], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.22896e-12, -3.88874e-13, 3.79650e-13), forcesEwald1[702], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.45203e-12, -8.83640e-14, 4.01405e-12), forcesEwald1[703], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.48531e-12, -1.19126e-13, 8.00841e-13), forcesEwald1[704], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.27188e-12, 6.95733e-13, -3.08107e-13), forcesEwald1[705], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.66575e-12, 1.19824e-12, -7.37712e-13), forcesEwald1[706], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.46697e-12, 9.80234e-13, -7.82710e-13), forcesEwald1[707], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.21456e-12, 1.32814e-12, -1.47054e-12), forcesEwald1[708], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.30571e-12, 1.06933e-12, -3.53824e-12), forcesEwald1[709], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.57715e-12, -8.27343e-13, 1.56135e-13), forcesEwald1[710], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.46564e-12, 1.17962e-13, 1.17415e-12), forcesEwald1[711], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.82368e-12, 4.67834e-13, 3.21495e-13), forcesEwald1[712], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.06293e-12, -2.46755e-13, 4.45100e-12), forcesEwald1[713], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.67001e-12, 2.86935e-14, 7.87122e-13), forcesEwald1[714], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.23914e-12, 1.46224e-12, -3.17737e-13), forcesEwald1[715], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.86593e-12, 1.87918e-12, -4.33402e-13), forcesEwald1[716], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.68501e-12, 2.06257e-12, -6.47975e-13), forcesEwald1[717], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.79754e-12, 2.04100e-12, -1.46864e-12), forcesEwald1[718], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.01505e-12, 1.71233e-12, -3.76199e-12), forcesEwald1[719], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.39311e-12, -3.24498e-13, 2.59170e-13), forcesEwald1[720], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.32890e-12, -3.50703e-13, 1.17479e-12), forcesEwald1[721], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.44984e-12, -3.42912e-13, 3.53757e-13), forcesEwald1[722], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.04374e-12, -8.61438e-13, 4.36434e-12), forcesEwald1[723], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.77012e-12, -7.65629e-13, 4.09464e-13), forcesEwald1[724], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.16767e-12, 5.94846e-13, -3.55463e-13), forcesEwald1[725], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.44431e-12, 8.95413e-13, -1.51736e-13), forcesEwald1[726], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.54641e-12, 6.60862e-13, -8.50097e-13), forcesEwald1[727], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.01995e-12, 6.08924e-13, -1.54568e-12), forcesEwald1[728], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.37647e-12, 3.03322e-13, -3.67489e-12), forcesEwald1[729], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.97691e-12, -1.04404e-12, 4.52109e-13), forcesEwald1[730], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.08870e-12, -1.28284e-12, 1.24915e-12), forcesEwald1[731], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.51305e-12, -1.38712e-12, 2.71914e-13), forcesEwald1[732], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.39656e-12, -1.59925e-12, 4.04036e-12), forcesEwald1[733], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.39265e-12, -1.53199e-12, 7.25515e-13), forcesEwald1[734], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.61075e-12, 4.22360e-12, 4.15384e-13), forcesEwald1[735], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.60556e-12, 3.98845e-12, -1.22890e-13), forcesEwald1[736], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.59773e-12, 4.43862e-12, -1.49993e-12), forcesEwald1[737], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.28206e-12, 4.63297e-12, -1.31355e-12), forcesEwald1[738], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.05348e-12, 4.39685e-12, -4.05381e-12), forcesEwald1[739], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.19618e-12, -3.67667e-12, 3.58142e-13), forcesEwald1[740], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.60613e-12, -3.77232e-12, 1.11167e-12), forcesEwald1[741], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.23039e-12, -3.50149e-12, 8.31962e-14), forcesEwald1[742], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.12584e-12, -4.39861e-12, 4.22605e-12), forcesEwald1[743], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.86309e-12, -3.47322e-12, 6.89931e-13), forcesEwald1[744], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.49601e-12, 4.79404e-14, -3.68849e-13), forcesEwald1[745], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.96715e-12, -2.31016e-13, -3.72582e-13), forcesEwald1[746], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.72801e-12, -2.35498e-13, -9.40875e-13), forcesEwald1[747], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.45657e-12, -3.50455e-14, -1.51928e-12), forcesEwald1[748], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.98804e-12, 1.06987e-13, -3.28448e-12), forcesEwald1[749], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.78006e-12, -3.05975e-13, -1.69076e-13), forcesEwald1[750], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.24942e-12, -1.39514e-13, -2.21323e-14), forcesEwald1[751], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.09698e-12, -3.00901e-13, -9.81040e-13), forcesEwald1[752], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.40124e-12, 1.38400e-13, -1.16950e-12), forcesEwald1[753], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.54085e-12, -3.80494e-13, -3.58560e-12), forcesEwald1[754], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.52806e-12, 8.88043e-13, 7.62866e-13), forcesEwald1[755], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.74829e-12, 5.99878e-13, 1.08296e-12), forcesEwald1[756], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.58574e-12, 1.04324e-12, 9.44426e-13), forcesEwald1[757], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.23199e-13, 1.47760e-12, 4.31692e-12), forcesEwald1[758], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.44560e-12, 7.59829e-13, -2.13015e-13), forcesEwald1[759], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.27760e-12, -3.74712e-13, -3.10963e-13), forcesEwald1[760], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.76872e-12, -4.57223e-13, 6.78192e-14), forcesEwald1[761], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.00655e-12, -1.77260e-13, -5.69698e-14), forcesEwald1[762], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.80564e-12, -2.98252e-13, -8.91258e-13), forcesEwald1[763], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.61888e-12, -8.31520e-13, -3.98671e-12), forcesEwald1[764], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.86828e-12, 1.57006e-12, 7.78433e-13), forcesEwald1[765], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.04169e-12, 1.32056e-12, 1.06027e-12), forcesEwald1[766], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.23581e-12, 2.06783e-12, 9.42628e-13), forcesEwald1[767], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.63590e-13, 1.43300e-12, 4.42826e-12), forcesEwald1[768], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.03292e-12, 2.18324e-12, -1.32302e-13), forcesEwald1[769], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.93050e-12, -9.98873e-13, -3.80140e-13), forcesEwald1[770], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.43231e-12, -2.66114e-13, -6.47603e-14), forcesEwald1[771], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.80922e-12, -8.94062e-13, -4.34513e-13), forcesEwald1[772], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.48361e-12, -1.41956e-12, -1.28401e-12), forcesEwald1[773], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.56376e-12, -1.49045e-12, -3.46317e-12), forcesEwald1[774], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.20093e-12, 1.03541e-12, 1.09984e-12), forcesEwald1[775], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.51051e-12, 3.93106e-13, 8.97047e-13), forcesEwald1[776], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.45644e-12, 2.83464e-13, 1.10223e-12), forcesEwald1[777], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.70121e-13, 8.11689e-13, 4.53124e-12), forcesEwald1[778], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.84143e-12, -8.05080e-14, 2.58716e-13), forcesEwald1[779], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.91281e-12, -1.19677e-12, 8.39371e-14), forcesEwald1[780], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.58510e-12, -1.79861e-12, -6.82651e-13), forcesEwald1[781], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.08403e-12, -2.01537e-12, -1.35037e-12), forcesEwald1[782], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.83551e-12, -1.53020e-12, -1.47752e-12), forcesEwald1[783], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.13917e-13, -1.14776e-12, -3.90807e-12), forcesEwald1[784], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.07063e-13, 2.97949e-12, 7.47662e-13), forcesEwald1[785], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.93937e-13, 3.09302e-12, 1.18884e-12), forcesEwald1[786], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.72532e-14, 2.76001e-12, 8.83582e-13), forcesEwald1[787], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.78059e-13, 3.24139e-12, 4.65688e-12), forcesEwald1[788], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.35350e-12, 3.41457e-12, 3.04687e-13), forcesEwald1[789], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.25891e-12, -3.39089e-12, -1.02256e-13), forcesEwald1[790], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.60516e-12, -3.44752e-12, -3.41671e-13), forcesEwald1[791], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.01454e-12, -3.36314e-12, -1.10390e-12), forcesEwald1[792], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.10311e-12, -3.64771e-12, -1.03130e-12), forcesEwald1[793], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.59831e-13, -3.67126e-12, -3.72363e-12), forcesEwald1[794], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.15240e-12, 2.98493e-13, 3.41320e-13), forcesEwald1[795], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.79202e-12, 4.65352e-13, 1.17207e-12), forcesEwald1[796], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.23757e-12, 5.59690e-13, 8.76988e-13), forcesEwald1[797], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.08332e-13, 1.93956e-13, 4.53500e-12), forcesEwald1[798], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.77516e-12, 1.15400e-13, 9.66166e-14), forcesEwald1[799], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.97762e-12, -3.13043e-13, 4.21191e-13), forcesEwald1[800], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.10803e-12, 1.08840e-13, 1.11871e-12), forcesEwald1[801], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.21537e-12, -2.06222e-13, 3.35818e-13), forcesEwald1[802], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.99064e-12, -1.78776e-13, 4.58602e-12), forcesEwald1[803], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.31683e-12, -5.52396e-13, 6.70895e-14), forcesEwald1[804], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.05009e-12, 3.41599e-13, -1.18074e-13), forcesEwald1[805], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.15969e-12, 1.40748e-12, 2.74744e-13), forcesEwald1[806], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.72044e-12, 1.76364e-12, -1.45286e-12), forcesEwald1[807], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.56275e-12, 1.61295e-12, -1.85990e-12), forcesEwald1[808], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.14973e-12, 7.44501e-13, -4.00088e-12), forcesEwald1[809], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.87027e-12, -4.20129e-14, 1.01473e-12), forcesEwald1[810], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.19698e-12, -7.14528e-14, 1.51807e-12), forcesEwald1[811], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.47828e-12, 6.83728e-14, 1.68182e-14), forcesEwald1[812], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.01074e-12, -4.22768e-13, 3.68383e-12), forcesEwald1[813], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.96805e-12, -3.11798e-13, -2.00074e-14), forcesEwald1[814], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.36076e-12, 2.35370e-12, 1.28469e-13), forcesEwald1[815], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.01906e-12, 1.77519e-12, 2.68063e-13), forcesEwald1[816], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.81989e-12, 1.94985e-12, -1.14959e-12), forcesEwald1[817], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.62309e-12, 1.99180e-12, -1.69723e-12), forcesEwald1[818], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.97671e-12, 2.13491e-12, -3.83738e-12), forcesEwald1[819], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.60790e-12, -3.60831e-13, 3.44633e-13), forcesEwald1[820], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.02746e-12, -8.23369e-13, 1.10416e-12), forcesEwald1[821], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.52108e-12, -7.68428e-13, 3.73931e-13), forcesEwald1[822], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.29787e-12, -1.36217e-12, 4.02564e-12), forcesEwald1[823], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.69650e-12, -8.04831e-13, 3.07781e-13), forcesEwald1[824], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.18551e-12, 9.49850e-13, 1.68290e-13), forcesEwald1[825], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.48256e-12, 7.26685e-13, -4.91940e-13), forcesEwald1[826], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.60926e-12, 8.40553e-13, -1.25653e-12), forcesEwald1[827], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.51492e-12, 7.14279e-13, -2.34099e-12), forcesEwald1[828], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.76696e-12, 8.35776e-13, -3.52940e-12), forcesEwald1[829], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.15543e-12, -6.42366e-13, 1.20425e-13), forcesEwald1[830], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.98630e-12, -1.13229e-12, 1.75569e-12), forcesEwald1[831], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.10700e-12, -1.15477e-12, 4.85525e-13), forcesEwald1[832], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.51383e-12, -9.19726e-13, 4.37944e-12), forcesEwald1[833], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.29682e-12, -7.32544e-13, 4.15952e-13), forcesEwald1[834], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.06503e-12, 3.60963e-12, 8.21941e-13), forcesEwald1[835], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.06017e-12, 3.77784e-12, -8.71446e-13), forcesEwald1[836], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.62119e-12, 3.90976e-12, -1.20776e-12), forcesEwald1[837], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.05476e-12, 4.67046e-12, -1.24154e-12), forcesEwald1[838], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.30132e-12, 4.53052e-12, -3.88911e-12), forcesEwald1[839], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.88928e-12, -4.10594e-12, 5.87493e-14), forcesEwald1[840], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.46181e-12, -3.80510e-12, 1.30368e-12), forcesEwald1[841], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.30418e-12, -2.87270e-12, 4.50905e-13), forcesEwald1[842], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.43945e-12, -4.07441e-12, 4.46718e-12), forcesEwald1[843], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.06772e-12, -3.38868e-12, 1.69666e-13), forcesEwald1[844], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.51981e-12, -2.28177e-13, -3.73788e-13), forcesEwald1[845], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.71147e-12, 3.09297e-13, -4.79081e-13), forcesEwald1[846], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.57510e-12, 1.54788e-13, -1.22213e-12), forcesEwald1[847], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.04510e-12, -1.47895e-13, -1.21769e-12), forcesEwald1[848], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.75380e-12, -1.89848e-13, -3.65973e-12), forcesEwald1[849], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.12718e-12, -6.49768e-13, -2.22088e-13), forcesEwald1[850], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.60631e-12, -3.25730e-13, -1.62416e-13), forcesEwald1[851], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.63628e-12, 1.19571e-13, -2.15271e-12), forcesEwald1[852], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.38290e-12, -1.83085e-13, -1.04891e-12), forcesEwald1[853], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.73642e-12, -5.54124e-13, -4.39830e-12), forcesEwald1[854], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.01400e-12, 4.34840e-13, 1.63760e-12), forcesEwald1[855], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.82115e-12, 1.12153e-12, 1.53372e-12), forcesEwald1[856], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.90606e-12, 1.30024e-12, -4.90542e-14), forcesEwald1[857], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.26122e-12, 5.13594e-13, 4.57136e-12), forcesEwald1[858], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.25024e-12, 4.92318e-13, -5.30841e-13), forcesEwald1[859], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.72232e-12, -4.54323e-13, -1.66350e-13), forcesEwald1[860], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.21228e-12, -3.10291e-13, 2.63965e-13), forcesEwald1[861], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.25565e-12, -4.49363e-13, -2.17764e-12), forcesEwald1[862], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.19226e-12, -4.30461e-13, -1.35455e-12), forcesEwald1[863], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.13131e-12, -7.82619e-13, -4.08940e-12), forcesEwald1[864], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.17050e-12, 2.39025e-12, 1.44825e-12), forcesEwald1[865], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.16229e-12, 8.61684e-13, 1.37371e-12), forcesEwald1[866], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.41651e-12, 1.83747e-12, 3.96139e-13), forcesEwald1[867], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.26605e-12, 1.40300e-12, 4.50623e-12), forcesEwald1[868], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.08376e-12, 2.11406e-12, -3.03807e-13), forcesEwald1[869], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.29801e-12, -1.27263e-12, -8.64572e-14), forcesEwald1[870], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.41057e-12, -1.39162e-12, -2.19908e-13), forcesEwald1[871], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.61698e-12, -1.35972e-12, -1.41747e-12), forcesEwald1[872], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.92136e-12, -1.31388e-12, -1.31896e-12), forcesEwald1[873], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.39799e-12, -1.35906e-12, -4.15195e-12), forcesEwald1[874], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.19767e-12, 6.81165e-13, 9.47989e-13), forcesEwald1[875], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.54486e-12, 4.25057e-13, 1.31552e-12), forcesEwald1[876], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.65016e-12, 8.93677e-13, 7.24588e-13), forcesEwald1[877], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.04483e-12, 9.28630e-13, 4.61289e-12), forcesEwald1[878], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.17787e-12, 7.15496e-13, 1.87668e-13), forcesEwald1[879], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.42473e-12, 3.18821e-14, -2.20037e-13), forcesEwald1[880], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.12981e-12, -9.12011e-13, -1.29895e-12), forcesEwald1[881], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.13664e-12, -1.80296e-12, -1.34190e-12), forcesEwald1[882], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.68086e-12, -1.28184e-12, -1.40307e-12), forcesEwald1[883], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.27523e-12, -4.53455e-13, -4.10601e-12), forcesEwald1[884], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.66621e-12, 3.55921e-12, -1.10519e-13), forcesEwald1[885], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.91980e-12, 3.37654e-12, 1.10698e-12), forcesEwald1[886], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.98515e-12, 3.12756e-12, 1.18676e-12), forcesEwald1[887], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.60379e-12, 4.22956e-12, 5.44837e-12), forcesEwald1[888], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.16117e-12, 3.79768e-12, 3.97747e-13), forcesEwald1[889], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.48189e-12, -4.25659e-12, -4.12137e-13), forcesEwald1[890], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.81451e-12, -3.93846e-12, -1.20785e-12), forcesEwald1[891], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.85877e-12, -3.67959e-12, -1.83263e-12), forcesEwald1[892], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.42036e-12, -3.95277e-12, -7.86036e-13), forcesEwald1[893], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.07289e-12, -4.23734e-12, -4.31077e-12), forcesEwald1[894], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.59465e-12, -3.21195e-13, 1.01826e-12), forcesEwald1[895], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.47669e-12, 1.10367e-13, 1.32832e-12), forcesEwald1[896], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.52223e-12, 1.80856e-14, 4.55301e-13), forcesEwald1[897], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.04399e-12, -4.57747e-13, 5.09564e-12), forcesEwald1[898], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.31017e-12, -7.31731e-13, -2.90418e-13), forcesEwald1[899], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.76754e-12, -4.07114e-13, 3.41817e-13), forcesEwald1[900], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.83688e-12, -7.23359e-15, 1.74565e-12), forcesEwald1[901], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.55439e-12, -1.80717e-13, 2.35915e-13), forcesEwald1[902], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.43185e-12, -3.46006e-13, 4.33030e-12), forcesEwald1[903], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.50682e-12, -5.88048e-13, -2.15048e-14), forcesEwald1[904], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.98756e-12, 3.89752e-13, 3.16431e-13), forcesEwald1[905], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.86895e-12, 1.49593e-12, -2.68612e-13), forcesEwald1[906], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.94453e-12, 1.30709e-12, -9.77387e-13), forcesEwald1[907], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.44713e-12, 1.21453e-12, -1.19492e-12), forcesEwald1[908], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.56160e-12, 8.99520e-13, -3.95932e-12), forcesEwald1[909], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.86438e-12, -6.48841e-13, 8.34489e-13), forcesEwald1[910], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.10551e-12, 1.53551e-14, 1.18689e-12), forcesEwald1[911], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.30708e-12, 4.92912e-14, -1.56632e-13), forcesEwald1[912], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.94442e-12, -5.77976e-13, 4.29005e-12), forcesEwald1[913], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.21516e-12, -2.47510e-13, 2.41431e-13), forcesEwald1[914], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.38711e-12, 2.58072e-12, 2.56502e-13), forcesEwald1[915], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.61427e-12, 1.60994e-12, 1.54900e-14), forcesEwald1[916], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.16086e-12, 1.70297e-12, -1.30621e-12), forcesEwald1[917], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.44753e-12, 2.35506e-12, -1.40969e-12), forcesEwald1[918], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.31142e-12, 2.24400e-12, -3.91029e-12), forcesEwald1[919], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.87711e-12, -9.80542e-13, 3.66135e-13), forcesEwald1[920], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.76118e-12, -1.11699e-12, 1.19261e-12), forcesEwald1[921], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.18419e-12, -7.42346e-13, 9.43832e-14), forcesEwald1[922], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.65570e-12, -8.32393e-13, 4.36830e-12), forcesEwald1[923], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.19159e-12, -1.00721e-12, 3.20027e-13), forcesEwald1[924], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.56819e-12, 7.73765e-13, 8.55383e-14), forcesEwald1[925], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.92888e-12, 4.11147e-13, -4.18027e-13), forcesEwald1[926], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.07977e-12, 3.55335e-13, -9.65623e-13), forcesEwald1[927], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.10019e-12, 6.95000e-13, -1.25049e-12), forcesEwald1[928], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.16041e-12, 7.40991e-13, -3.78109e-12), forcesEwald1[929], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.14604e-12, -9.73021e-13, 6.16754e-14), forcesEwald1[930], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.89739e-12, -1.39138e-12, 1.89967e-12), forcesEwald1[931], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.51146e-12, -1.04776e-12, 4.67684e-13), forcesEwald1[932], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.09900e-12, -1.06053e-12, 4.43149e-12), forcesEwald1[933], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.34563e-12, -3.85967e-13, -4.48952e-14), forcesEwald1[934], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.92230e-12, 4.41989e-12, -2.69639e-14), forcesEwald1[935], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.75444e-12, 4.26760e-12, -9.87491e-13), forcesEwald1[936], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.64323e-12, 4.41862e-12, -1.23581e-12), forcesEwald1[937], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.66794e-12, 4.95172e-12, -6.55200e-13), forcesEwald1[938], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.17874e-12, 4.88199e-12, -4.12277e-12), forcesEwald1[939], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.88732e-12, -3.69420e-12, 1.73780e-14), forcesEwald1[940], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.90298e-12, -3.44049e-12, 1.64743e-12), forcesEwald1[941], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.54119e-12, -3.46547e-12, 4.40448e-13), forcesEwald1[942], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.71037e-12, -4.03659e-12, 5.07883e-12), forcesEwald1[943], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.95321e-12, -3.73699e-12, 1.85053e-13), forcesEwald1[944], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.25689e-12, -3.47606e-13, -1.05847e-13), forcesEwald1[945], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.93705e-12, -4.42777e-14, -6.74335e-13), forcesEwald1[946], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.88650e-12, 1.22786e-13, -1.10910e-12), forcesEwald1[947], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.72501e-12, -3.93934e-13, -6.82509e-13), forcesEwald1[948], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.31199e-12, -1.54413e-13, -3.60040e-12), forcesEwald1[949], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.21059e-12, -5.01182e-13, -1.91674e-13), forcesEwald1[950], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.59324e-13, -3.98877e-13, -2.90642e-13), forcesEwald1[951], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.90052e-13, -1.45100e-13, -1.62371e-13), forcesEwald1[952], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.83107e-13, 4.22655e-14, -1.20668e-12), forcesEwald1[953], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.99133e-13, -4.63470e-13, -2.80937e-12), forcesEwald1[954], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.37279e-12, 7.15609e-13, 5.95548e-13), forcesEwald1[955], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.14260e-12, 5.32804e-13, 1.08352e-12), forcesEwald1[956], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.83324e-12, 4.23621e-13, 4.73270e-13), forcesEwald1[957], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.34251e-12, 6.28765e-13, 4.37042e-12), forcesEwald1[958], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.20425e-12, 3.25001e-13, -1.81933e-13), forcesEwald1[959], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.31953e-12, -3.21711e-13, -1.77854e-13), forcesEwald1[960], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.99395e-13, 1.49808e-13, -9.37201e-14), forcesEwald1[961], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.69985e-13, 4.41726e-14, -8.57487e-14), forcesEwald1[962], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.25729e-13, -6.55073e-13, -1.19896e-12), forcesEwald1[963], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.07973e-12, -7.09025e-13, -2.51077e-12), forcesEwald1[964], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.50558e-13, 1.29743e-12, 8.50588e-13), forcesEwald1[965], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.05950e-14, 1.28917e-12, 1.00069e-12), forcesEwald1[966], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.24437e-13, 2.05730e-12, 3.23430e-13), forcesEwald1[967], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01535e-12, 1.54958e-12, 4.50290e-12), forcesEwald1[968], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05996e-12, 1.74830e-12, 3.52671e-13), forcesEwald1[969], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.87354e-13, -9.16698e-13, -1.83253e-13), forcesEwald1[970], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.97440e-13, -3.98600e-13, 6.77768e-14), forcesEwald1[971], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.65999e-13, -4.55305e-13, -2.55094e-13), forcesEwald1[972], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.60673e-13, -1.26264e-12, -1.65663e-12), forcesEwald1[973], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.86058e-13, -1.06370e-12, -2.73017e-12), forcesEwald1[974], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.36819e-13, 3.92256e-13, 8.47419e-13), forcesEwald1[975], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.80301e-13, 4.63407e-14, 1.38628e-12), forcesEwald1[976], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.98222e-13, -1.01275e-13, 8.45154e-13), forcesEwald1[977], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.14666e-12, 1.04640e-12, 4.42555e-12), forcesEwald1[978], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.50915e-13, -3.28736e-14, -6.31594e-15), forcesEwald1[979], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.30892e-13, -1.30838e-12, -3.99828e-13), forcesEwald1[980], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.08581e-13, -1.14216e-12, -2.07203e-13), forcesEwald1[981], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.08417e-12, -1.87974e-12, -1.55037e-12), forcesEwald1[982], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.28334e-13, -1.08033e-12, -1.37696e-12), forcesEwald1[983], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.63116e-13, -7.45132e-13, -3.38410e-12), forcesEwald1[984], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.96293e-13, 3.95043e-12, 5.44156e-13), forcesEwald1[985], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05572e-12, 3.54936e-12, 1.37220e-12), forcesEwald1[986], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.70267e-13, 3.04640e-12, 7.22949e-13), forcesEwald1[987], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.20212e-13, 4.09741e-12, 5.06374e-12), forcesEwald1[988], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.40740e-13, 3.67405e-12, -5.66798e-13), forcesEwald1[989], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.39430e-13, -2.75377e-12, -2.21028e-13), forcesEwald1[990], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.35793e-13, -2.73832e-12, -4.01296e-13), forcesEwald1[991], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.74333e-13, -2.99037e-12, -6.36548e-13), forcesEwald1[992], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.05541e-15, -3.61026e-12, -8.40540e-13), forcesEwald1[993], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.42106e-13, -4.10188e-12, -3.36982e-12), forcesEwald1[994], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.15796e-13, -7.69314e-14, 3.39012e-13), forcesEwald1[995], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.18692e-12, -2.25483e-13, 9.63790e-13), forcesEwald1[996], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.19276e-12, 4.82919e-14, 1.02449e-12), forcesEwald1[997], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.09072e-12, -2.56049e-13, 4.71664e-12), forcesEwald1[998], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.29054e-13, -3.26182e-13, 1.84928e-14), forcesEwald1[999], 10*TOL); diff --git a/platforms/reference/tests/water.dat b/platforms/reference/tests/water.dat deleted file mode 100644 index c6e2f5695..000000000 --- a/platforms/reference/tests/water.dat +++ /dev/null @@ -1,648 +0,0 @@ -positions[0] = Vec3(0.230000,0.628000,0.113000); -positions[1] = Vec3(0.137000,0.626000,0.150000); -positions[2] = Vec3(0.231000,0.589000,0.021000); -positions[3] = Vec3(0.225000,0.275000,-0.866000); -positions[4] = Vec3(0.260000,0.258000,-0.774000); -positions[5] = Vec3(0.137000,0.230000,-0.878000); -positions[6] = Vec3(0.019000,0.368000,0.647000); -positions[7] = Vec3(-0.063000,0.411000,0.686000); -positions[8] = Vec3(-0.009000,0.295000,0.584000); -positions[9] = Vec3(0.569000,-0.587000,-0.697000); -positions[10] = Vec3(0.476000,-0.594000,-0.734000); -positions[11] = Vec3(0.580000,-0.498000,-0.653000); -positions[12] = Vec3(-0.307000,-0.351000,0.703000); -positions[13] = Vec3(-0.364000,-0.367000,0.784000); -positions[14] = Vec3(-0.366000,-0.341000,0.623000); -positions[15] = Vec3(-0.119000,0.618000,0.856000); -positions[16] = Vec3(-0.086000,0.712000,0.856000); -positions[17] = Vec3(-0.068000,0.564000,0.922000); -positions[18] = Vec3(-0.727000,0.703000,0.717000); -positions[19] = Vec3(-0.670000,0.781000,0.692000); -positions[20] = Vec3(-0.787000,0.729000,0.793000); -positions[21] = Vec3(-0.107000,0.607000,0.231000); -positions[22] = Vec3(-0.119000,0.594000,0.132000); -positions[23] = Vec3(-0.137000,0.526000,0.280000); -positions[24] = Vec3(0.768000,-0.718000,-0.839000); -positions[25] = Vec3(0.690000,-0.701000,-0.779000); -positions[26] = Vec3(0.802000,-0.631000,-0.875000); -positions[27] = Vec3(0.850000,0.798000,-0.039000); -positions[28] = Vec3(0.846000,0.874000,0.026000); -positions[29] = Vec3(0.872000,0.834000,-0.130000); -positions[30] = Vec3(0.685000,-0.850000,0.665000); -positions[31] = Vec3(0.754000,-0.866000,0.735000); -positions[32] = Vec3(0.612000,-0.793000,0.703000); -positions[33] = Vec3(0.686000,-0.701000,-0.059000); -positions[34] = Vec3(0.746000,-0.622000,-0.045000); -positions[35] = Vec3(0.600000,-0.670000,-0.100000); -positions[36] = Vec3(0.335000,-0.427000,-0.801000); -positions[37] = Vec3(0.257000,-0.458000,-0.854000); -positions[38] = Vec3(0.393000,-0.369000,-0.858000); -positions[39] = Vec3(-0.402000,-0.357000,-0.523000); -positions[40] = Vec3(-0.378000,-0.263000,-0.497000); -positions[41] = Vec3(-0.418000,-0.411000,-0.441000); -positions[42] = Vec3(0.438000,0.392000,-0.363000); -positions[43] = Vec3(0.520000,0.336000,-0.354000); -positions[44] = Vec3(0.357000,0.334000,-0.359000); -positions[45] = Vec3(-0.259000,0.447000,0.737000); -positions[46] = Vec3(-0.333000,0.493000,0.687000); -positions[47] = Vec3(-0.208000,0.515000,0.790000); -positions[48] = Vec3(0.231000,-0.149000,0.483000); -positions[49] = Vec3(0.265000,-0.072000,0.537000); -positions[50] = Vec3(0.275000,-0.149000,0.393000); -positions[51] = Vec3(-0.735000,-0.521000,-0.172000); -positions[52] = Vec3(-0.688000,-0.521000,-0.084000); -positions[53] = Vec3(-0.783000,-0.608000,-0.183000); -positions[54] = Vec3(0.230000,-0.428000,0.538000); -positions[55] = Vec3(0.204000,-0.332000,0.538000); -positions[56] = Vec3(0.159000,-0.482000,0.583000); -positions[57] = Vec3(0.240000,-0.771000,0.886000); -positions[58] = Vec3(0.254000,-0.855000,0.938000); -positions[59] = Vec3(0.185000,-0.707000,0.941000); -positions[60] = Vec3(0.620000,-0.076000,-0.423000); -positions[61] = Vec3(0.528000,-0.093000,-0.388000); -positions[62] = Vec3(0.648000,0.016000,-0.397000); -positions[63] = Vec3(0.606000,-0.898000,0.123000); -positions[64] = Vec3(0.613000,-0.814000,0.069000); -positions[65] = Vec3(0.652000,-0.885000,0.211000); -positions[66] = Vec3(-0.268000,0.114000,-0.382000); -positions[67] = Vec3(-0.286000,0.181000,-0.454000); -positions[68] = Vec3(-0.271000,0.160000,-0.293000); -positions[69] = Vec3(0.122000,0.643000,0.563000); -positions[70] = Vec3(0.077000,0.555000,0.580000); -positions[71] = Vec3(0.121000,0.697000,0.647000); -positions[72] = Vec3(-0.020000,-0.095000,0.359000); -positions[73] = Vec3(0.034000,-0.124000,0.439000); -positions[74] = Vec3(0.010000,-0.005000,0.330000); -positions[75] = Vec3(0.027000,-0.266000,0.117000); -positions[76] = Vec3(0.008000,-0.362000,0.138000); -positions[77] = Vec3(-0.006000,-0.208000,0.192000); -positions[78] = Vec3(-0.173000,0.922000,0.612000); -positions[79] = Vec3(-0.078000,0.893000,0.620000); -positions[80] = Vec3(-0.181000,0.987000,0.537000); -positions[81] = Vec3(-0.221000,-0.754000,0.432000); -positions[82] = Vec3(-0.135000,-0.752000,0.380000); -positions[83] = Vec3(-0.207000,-0.707000,0.520000); -positions[84] = Vec3(0.113000,0.737000,-0.265000); -positions[85] = Vec3(0.201000,0.724000,-0.220000); -positions[86] = Vec3(0.100000,0.834000,-0.287000); -positions[87] = Vec3(0.613000,-0.497000,0.726000); -positions[88] = Vec3(0.564000,-0.584000,0.735000); -positions[89] = Vec3(0.590000,-0.454000,0.639000); -positions[90] = Vec3(-0.569000,-0.634000,-0.439000); -positions[91] = Vec3(-0.532000,-0.707000,-0.497000); -positions[92] = Vec3(-0.517000,-0.629000,-0.354000); -positions[93] = Vec3(0.809000,0.004000,0.502000); -positions[94] = Vec3(0.849000,0.095000,0.493000); -positions[95] = Vec3(0.709000,0.012000,0.508000); -positions[96] = Vec3(0.197000,-0.886000,-0.598000); -positions[97] = Vec3(0.286000,-0.931000,-0.612000); -positions[98] = Vec3(0.124000,-0.951000,-0.617000); -positions[99] = Vec3(-0.337000,-0.863000,0.190000); -positions[100] = Vec3(-0.400000,-0.939000,0.203000); -positions[101] = Vec3(-0.289000,-0.845000,0.276000); -positions[102] = Vec3(-0.675000,-0.070000,-0.246000); -positions[103] = Vec3(-0.651000,-0.010000,-0.322000); -positions[104] = Vec3(-0.668000,-0.165000,-0.276000); -positions[105] = Vec3(0.317000,0.251000,-0.061000); -positions[106] = Vec3(0.388000,0.322000,-0.055000); -positions[107] = Vec3(0.229000,0.290000,-0.033000); -positions[108] = Vec3(-0.396000,-0.445000,-0.909000); -positions[109] = Vec3(-0.455000,-0.439000,-0.829000); -positions[110] = Vec3(-0.411000,-0.533000,-0.955000); -positions[111] = Vec3(-0.195000,-0.148000,0.572000); -positions[112] = Vec3(-0.236000,-0.171000,0.484000); -positions[113] = Vec3(-0.213000,-0.222000,0.637000); -positions[114] = Vec3(0.598000,0.729000,0.270000); -positions[115] = Vec3(0.622000,0.798000,0.202000); -positions[116] = Vec3(0.520000,0.762000,0.324000); -positions[117] = Vec3(-0.581000,0.345000,-0.918000); -positions[118] = Vec3(-0.667000,0.295000,-0.931000); -positions[119] = Vec3(-0.519000,0.291000,-0.862000); -positions[120] = Vec3(-0.286000,-0.200000,0.307000); -positions[121] = Vec3(-0.197000,-0.154000,0.310000); -positions[122] = Vec3(-0.307000,-0.224000,0.212000); -positions[123] = Vec3(0.807000,0.605000,-0.397000); -positions[124] = Vec3(0.760000,0.602000,-0.308000); -positions[125] = Vec3(0.756000,0.550000,-0.463000); -positions[126] = Vec3(-0.468000,0.469000,-0.188000); -positions[127] = Vec3(-0.488000,0.512000,-0.100000); -positions[128] = Vec3(-0.390000,0.407000,-0.179000); -positions[129] = Vec3(-0.889000,0.890000,-0.290000); -positions[130] = Vec3(-0.843000,0.806000,-0.319000); -positions[131] = Vec3(-0.945000,0.924000,-0.365000); -positions[132] = Vec3(-0.871000,0.410000,-0.620000); -positions[133] = Vec3(-0.948000,0.444000,-0.566000); -positions[134] = Vec3(-0.905000,0.359000,-0.699000); -positions[135] = Vec3(-0.821000,0.701000,0.429000); -positions[136] = Vec3(-0.795000,0.697000,0.525000); -positions[137] = Vec3(-0.906000,0.650000,0.415000); -positions[138] = Vec3(0.076000,0.811000,0.789000); -positions[139] = Vec3(0.175000,0.799000,0.798000); -positions[140] = Vec3(0.052000,0.906000,0.810000); -positions[141] = Vec3(0.130000,-0.041000,-0.291000); -positions[142] = Vec3(0.120000,-0.056000,-0.192000); -positions[143] = Vec3(0.044000,-0.005000,-0.327000); -positions[144] = Vec3(0.865000,0.348000,0.195000); -positions[145] = Vec3(0.924000,0.411000,0.146000); -positions[146] = Vec3(0.884000,0.254000,0.166000); -positions[147] = Vec3(-0.143000,0.585000,-0.031000); -positions[148] = Vec3(-0.169000,0.674000,-0.067000); -positions[149] = Vec3(-0.145000,0.517000,-0.104000); -positions[150] = Vec3(-0.500000,-0.718000,0.545000); -positions[151] = Vec3(-0.417000,-0.747000,0.497000); -positions[152] = Vec3(-0.549000,-0.651000,0.489000); -positions[153] = Vec3(0.550000,0.196000,0.885000); -positions[154] = Vec3(0.545000,0.191000,0.985000); -positions[155] = Vec3(0.552000,0.292000,0.856000); -positions[156] = Vec3(-0.854000,-0.406000,0.477000); -positions[157] = Vec3(-0.900000,-0.334000,0.425000); -positions[158] = Vec3(-0.858000,-0.386000,0.575000); -positions[159] = Vec3(0.351000,-0.061000,0.853000); -positions[160] = Vec3(0.401000,-0.147000,0.859000); -positions[161] = Vec3(0.416000,0.016000,0.850000); -positions[162] = Vec3(-0.067000,-0.796000,0.873000); -positions[163] = Vec3(-0.129000,-0.811000,0.797000); -positions[164] = Vec3(-0.119000,-0.785000,0.958000); -positions[165] = Vec3(-0.635000,-0.312000,-0.356000); -positions[166] = Vec3(-0.629000,-0.389000,-0.292000); -positions[167] = Vec3(-0.687000,-0.338000,-0.436000); -positions[168] = Vec3(0.321000,-0.919000,0.242000); -positions[169] = Vec3(0.403000,-0.880000,0.200000); -positions[170] = Vec3(0.294000,-1.001000,0.193000); -positions[171] = Vec3(-0.404000,0.735000,0.728000); -positions[172] = Vec3(-0.409000,0.670000,0.803000); -positions[173] = Vec3(-0.324000,0.794000,0.741000); -positions[174] = Vec3(0.461000,-0.596000,-0.135000); -positions[175] = Vec3(0.411000,-0.595000,-0.221000); -positions[176] = Vec3(0.398000,-0.614000,-0.059000); -positions[177] = Vec3(-0.751000,-0.086000,0.237000); -positions[178] = Vec3(-0.811000,-0.148000,0.287000); -positions[179] = Vec3(-0.720000,-0.130000,0.152000); -positions[180] = Vec3(0.202000,0.285000,-0.364000); -positions[181] = Vec3(0.122000,0.345000,-0.377000); -positions[182] = Vec3(0.192000,0.236000,-0.278000); -positions[183] = Vec3(-0.230000,-0.485000,0.081000); -positions[184] = Vec3(-0.262000,-0.391000,0.071000); -positions[185] = Vec3(-0.306000,-0.548000,0.069000); -positions[186] = Vec3(0.464000,-0.119000,0.323000); -positions[187] = Vec3(0.497000,-0.080000,0.409000); -positions[188] = Vec3(0.540000,-0.126000,0.258000); -positions[189] = Vec3(-0.462000,0.107000,0.426000); -positions[190] = Vec3(-0.486000,0.070000,0.336000); -positions[191] = Vec3(-0.363000,0.123000,0.430000); -positions[192] = Vec3(0.249000,-0.077000,-0.621000); -positions[193] = Vec3(0.306000,-0.142000,-0.571000); -positions[194] = Vec3(0.233000,-0.110000,-0.714000); -positions[195] = Vec3(-0.922000,-0.164000,0.904000); -positions[196] = Vec3(-0.842000,-0.221000,0.925000); -positions[197] = Vec3(-0.971000,-0.204000,0.827000); -positions[198] = Vec3(0.382000,0.700000,0.480000); -positions[199] = Vec3(0.427000,0.610000,0.477000); -positions[200] = Vec3(0.288000,0.689000,0.513000); -positions[201] = Vec3(-0.315000,0.222000,-0.133000); -positions[202] = Vec3(-0.320000,0.259000,-0.041000); -positions[203] = Vec3(-0.387000,0.153000,-0.145000); -positions[204] = Vec3(0.614000,0.122000,0.117000); -positions[205] = Vec3(0.712000,0.100000,0.124000); -positions[206] = Vec3(0.583000,0.105000,0.024000); -positions[207] = Vec3(0.781000,0.264000,-0.113000); -positions[208] = Vec3(0.848000,0.203000,-0.070000); -positions[209] = Vec3(0.708000,0.283000,-0.048000); -positions[210] = Vec3(0.888000,-0.348000,-0.667000); -positions[211] = Vec3(0.865000,-0.373000,-0.761000); -positions[212] = Vec3(0.949000,-0.417000,-0.628000); -positions[213] = Vec3(-0.511000,0.590000,-0.429000); -positions[214] = Vec3(-0.483000,0.547000,-0.344000); -positions[215] = Vec3(-0.486000,0.686000,-0.428000); -positions[216] = Vec3(0.803000,-0.460000,0.924000); -positions[217] = Vec3(0.893000,-0.446000,0.882000); -positions[218] = Vec3(0.732000,-0.458000,0.853000); -positions[219] = Vec3(0.922000,0.503000,0.899000); -positions[220] = Vec3(0.897000,0.494000,0.803000); -positions[221] = Vec3(0.970000,0.421000,0.930000); -positions[222] = Vec3(0.539000,0.064000,0.512000); -positions[223] = Vec3(0.458000,0.065000,0.570000); -positions[224] = Vec3(0.542000,0.147000,0.457000); -positions[225] = Vec3(-0.428000,-0.674000,0.041000); -positions[226] = Vec3(-0.396000,-0.750000,0.098000); -positions[227] = Vec3(-0.520000,-0.647000,0.071000); -positions[228] = Vec3(0.297000,0.035000,0.171000); -positions[229] = Vec3(0.346000,0.119000,0.150000); -positions[230] = Vec3(0.359000,-0.030000,0.216000); -positions[231] = Vec3(-0.927000,0.236000,0.480000); -positions[232] = Vec3(-0.975000,0.277000,0.402000); -positions[233] = Vec3(-0.828000,0.234000,0.461000); -positions[234] = Vec3(-0.786000,0.683000,-0.398000); -positions[235] = Vec3(-0.866000,0.622000,-0.395000); -positions[236] = Vec3(-0.705000,0.630000,-0.422000); -positions[237] = Vec3(-0.635000,-0.292000,0.793000); -positions[238] = Vec3(-0.614000,-0.218000,0.728000); -positions[239] = Vec3(-0.567000,-0.292000,0.866000); -positions[240] = Vec3(0.459000,-0.710000,0.741000); -positions[241] = Vec3(0.388000,-0.737000,0.806000); -positions[242] = Vec3(0.433000,-0.738000,0.648000); -positions[243] = Vec3(-0.591000,-0.065000,0.591000); -positions[244] = Vec3(-0.547000,-0.001000,0.527000); -positions[245] = Vec3(-0.641000,-0.013000,0.661000); -positions[246] = Vec3(-0.830000,0.549000,0.016000); -positions[247] = Vec3(-0.871000,0.631000,-0.023000); -positions[248] = Vec3(-0.766000,0.575000,0.089000); -positions[249] = Vec3(0.078000,0.556000,-0.476000); -positions[250] = Vec3(0.170000,0.555000,-0.517000); -positions[251] = Vec3(0.072000,0.630000,-0.409000); -positions[252] = Vec3(0.561000,0.222000,-0.715000); -positions[253] = Vec3(0.599000,0.138000,-0.678000); -positions[254] = Vec3(0.473000,0.241000,-0.671000); -positions[255] = Vec3(0.866000,0.454000,0.642000); -positions[256] = Vec3(0.834000,0.526000,0.580000); -positions[257] = Vec3(0.890000,0.373000,0.589000); -positions[258] = Vec3(-0.845000,0.039000,0.753000); -positions[259] = Vec3(-0.917000,0.044000,0.684000); -positions[260] = Vec3(-0.869000,-0.030000,0.822000); -positions[261] = Vec3(-0.433000,-0.689000,0.867000); -positions[262] = Vec3(-0.488000,-0.773000,0.860000); -positions[263] = Vec3(-0.407000,-0.660000,0.775000); -positions[264] = Vec3(-0.396000,0.590000,-0.870000); -positions[265] = Vec3(-0.426000,0.495000,-0.863000); -positions[266] = Vec3(-0.323000,0.606000,-0.804000); -positions[267] = Vec3(-0.005000,0.833000,0.377000); -positions[268] = Vec3(0.037000,0.769000,0.441000); -positions[269] = Vec3(-0.043000,0.782000,0.299000); -positions[270] = Vec3(0.488000,-0.477000,0.174000); -positions[271] = Vec3(0.401000,-0.492000,0.221000); -positions[272] = Vec3(0.471000,-0.451000,0.079000); -positions[273] = Vec3(-0.198000,-0.582000,0.657000); -positions[274] = Vec3(-0.099000,-0.574000,0.671000); -positions[275] = Vec3(-0.243000,-0.498000,0.688000); -positions[276] = Vec3(-0.472000,0.575000,0.078000); -positions[277] = Vec3(-0.526000,0.554000,0.159000); -positions[278] = Vec3(-0.381000,0.534000,0.087000); -positions[279] = Vec3(0.527000,0.256000,0.328000); -positions[280] = Vec3(0.554000,0.197000,0.253000); -positions[281] = Vec3(0.527000,0.351000,0.297000); -positions[282] = Vec3(-0.108000,-0.639000,-0.274000); -positions[283] = Vec3(-0.017000,-0.678000,-0.287000); -positions[284] = Vec3(-0.100000,-0.543000,-0.250000); -positions[285] = Vec3(-0.798000,-0.515000,-0.522000); -positions[286] = Vec3(-0.878000,-0.538000,-0.467000); -positions[287] = Vec3(-0.715000,-0.541000,-0.473000); -positions[288] = Vec3(-0.270000,-0.233000,-0.237000); -positions[289] = Vec3(-0.243000,-0.199000,-0.327000); -positions[290] = Vec3(-0.191000,-0.271000,-0.191000); -positions[291] = Vec3(-0.751000,-0.667000,-0.762000); -positions[292] = Vec3(-0.791000,-0.623000,-0.681000); -positions[293] = Vec3(-0.792000,-0.630000,-0.845000); -positions[294] = Vec3(-0.224000,-0.763000,-0.783000); -positions[295] = Vec3(-0.219000,-0.682000,-0.724000); -positions[296] = Vec3(-0.310000,-0.761000,-0.834000); -positions[297] = Vec3(0.915000,0.089000,-0.460000); -positions[298] = Vec3(0.940000,0.069000,-0.555000); -positions[299] = Vec3(0.987000,0.145000,-0.418000); -positions[300] = Vec3(-0.882000,-0.746000,-0.143000); -positions[301] = Vec3(-0.981000,-0.740000,-0.133000); -positions[302] = Vec3(-0.859000,-0.826000,-0.199000); -positions[303] = Vec3(0.705000,-0.812000,0.368000); -positions[304] = Vec3(0.691000,-0.805000,0.467000); -positions[305] = Vec3(0.789000,-0.863000,0.350000); -positions[306] = Vec3(0.410000,0.813000,-0.611000); -positions[307] = Vec3(0.496000,0.825000,-0.561000); -positions[308] = Vec3(0.368000,0.726000,-0.584000); -positions[309] = Vec3(-0.588000,0.386000,-0.600000); -positions[310] = Vec3(-0.567000,0.460000,-0.536000); -positions[311] = Vec3(-0.677000,0.403000,-0.643000); -positions[312] = Vec3(0.064000,-0.298000,-0.531000); -positions[313] = Vec3(0.018000,-0.216000,-0.565000); -positions[314] = Vec3(0.162000,-0.279000,-0.522000); -positions[315] = Vec3(0.367000,-0.762000,0.501000); -positions[316] = Vec3(0.360000,-0.679000,0.445000); -positions[317] = Vec3(0.371000,-0.842000,0.441000); -positions[318] = Vec3(0.566000,0.537000,0.865000); -positions[319] = Vec3(0.578000,0.603000,0.791000); -positions[320] = Vec3(0.612000,0.571000,0.948000); -positions[321] = Vec3(-0.610000,-0.514000,0.388000); -positions[322] = Vec3(-0.560000,-0.437000,0.428000); -positions[323] = Vec3(-0.705000,-0.512000,0.420000); -positions[324] = Vec3(-0.590000,-0.417000,-0.720000); -positions[325] = Vec3(-0.543000,-0.404000,-0.633000); -positions[326] = Vec3(-0.656000,-0.491000,-0.711000); -positions[327] = Vec3(-0.280000,0.639000,0.472000); -positions[328] = Vec3(-0.311000,0.700000,0.545000); -positions[329] = Vec3(-0.230000,0.691000,0.403000); -positions[330] = Vec3(0.354000,-0.352000,-0.533000); -positions[331] = Vec3(0.333000,-0.396000,-0.620000); -positions[332] = Vec3(0.451000,-0.326000,-0.530000); -positions[333] = Vec3(0.402000,0.751000,-0.264000); -positions[334] = Vec3(0.470000,0.806000,-0.311000); -positions[335] = Vec3(0.442000,0.663000,-0.237000); -positions[336] = Vec3(-0.275000,0.779000,-0.192000); -positions[337] = Vec3(-0.367000,0.817000,-0.197000); -positions[338] = Vec3(-0.215000,0.826000,-0.257000); -positions[339] = Vec3(-0.849000,0.105000,-0.092000); -positions[340] = Vec3(-0.843000,0.190000,-0.144000); -positions[341] = Vec3(-0.817000,0.029000,-0.149000); -positions[342] = Vec3(0.504000,0.050000,-0.122000); -positions[343] = Vec3(0.462000,-0.007000,-0.192000); -positions[344] = Vec3(0.438000,0.119000,-0.090000); -positions[345] = Vec3(0.573000,0.870000,-0.833000); -positions[346] = Vec3(0.617000,0.959000,-0.842000); -positions[347] = Vec3(0.510000,0.870000,-0.756000); -positions[348] = Vec3(-0.502000,0.862000,-0.817000); -positions[349] = Vec3(-0.577000,0.862000,-0.883000); -positions[350] = Vec3(-0.465000,0.770000,-0.808000); -positions[351] = Vec3(-0.653000,0.525000,0.275000); -positions[352] = Vec3(-0.640000,0.441000,0.329000); -positions[353] = Vec3(-0.682000,0.599000,0.335000); -positions[354] = Vec3(0.307000,0.213000,-0.631000); -positions[355] = Vec3(0.284000,0.250000,-0.541000); -positions[356] = Vec3(0.277000,0.118000,-0.637000); -positions[357] = Vec3(0.037000,-0.552000,-0.580000); -positions[358] = Vec3(0.090000,-0.601000,-0.512000); -positions[359] = Vec3(0.059000,-0.454000,-0.575000); -positions[360] = Vec3(0.732000,0.634000,-0.798000); -positions[361] = Vec3(0.791000,0.608000,-0.874000); -positions[362] = Vec3(0.704000,0.730000,-0.809000); -positions[363] = Vec3(-0.134000,-0.927000,-0.008000); -positions[364] = Vec3(-0.180000,-0.934000,-0.097000); -positions[365] = Vec3(-0.196000,-0.883000,0.058000); -positions[366] = Vec3(0.307000,0.063000,0.618000); -positions[367] = Vec3(0.296000,0.157000,0.651000); -positions[368] = Vec3(0.302000,-0.000000,0.695000); -positions[369] = Vec3(-0.240000,0.367000,0.374000); -positions[370] = Vec3(-0.238000,0.291000,0.438000); -positions[371] = Vec3(-0.288000,0.444000,0.414000); -positions[372] = Vec3(-0.839000,0.766000,-0.896000); -positions[373] = Vec3(-0.824000,0.787000,-0.800000); -positions[374] = Vec3(-0.869000,0.671000,-0.905000); -positions[375] = Vec3(-0.882000,-0.289000,-0.162000); -positions[376] = Vec3(-0.902000,-0.245000,-0.250000); -positions[377] = Vec3(-0.843000,-0.380000,-0.178000); -positions[378] = Vec3(-0.003000,-0.344000,-0.257000); -positions[379] = Vec3(0.011000,-0.317000,-0.352000); -positions[380] = Vec3(0.080000,-0.322000,-0.204000); -positions[381] = Vec3(0.350000,0.898000,-0.058000); -positions[382] = Vec3(0.426000,0.942000,-0.010000); -positions[383] = Vec3(0.385000,0.851000,-0.140000); -positions[384] = Vec3(-0.322000,0.274000,0.125000); -positions[385] = Vec3(-0.383000,0.199000,0.148000); -positions[386] = Vec3(-0.300000,0.326000,0.208000); -positions[387] = Vec3(-0.559000,0.838000,0.042000); -positions[388] = Vec3(-0.525000,0.745000,0.057000); -positions[389] = Vec3(-0.541000,0.865000,-0.053000); -positions[390] = Vec3(-0.794000,-0.529000,0.849000); -positions[391] = Vec3(-0.787000,-0.613000,0.794000); -positions[392] = Vec3(-0.732000,-0.460000,0.813000); -positions[393] = Vec3(0.319000,0.810000,-0.913000); -positions[394] = Vec3(0.412000,0.846000,-0.908000); -positions[395] = Vec3(0.313000,0.725000,-0.861000); -positions[396] = Vec3(0.339000,0.509000,-0.856000); -positions[397] = Vec3(0.287000,0.426000,-0.873000); -positions[398] = Vec3(0.416000,0.514000,-0.920000); -positions[399] = Vec3(0.511000,0.415000,-0.054000); -positions[400] = Vec3(0.493000,0.460000,0.034000); -positions[401] = Vec3(0.553000,0.480000,-0.117000); -positions[402] = Vec3(-0.724000,0.380000,-0.184000); -positions[403] = Vec3(-0.769000,0.443000,-0.120000); -positions[404] = Vec3(-0.631000,0.411000,-0.201000); -positions[405] = Vec3(-0.702000,0.207000,-0.385000); -positions[406] = Vec3(-0.702000,0.271000,-0.308000); -positions[407] = Vec3(-0.674000,0.255000,-0.468000); -positions[408] = Vec3(0.008000,-0.536000,0.200000); -positions[409] = Vec3(-0.085000,-0.515000,0.169000); -positions[410] = Vec3(0.018000,-0.635000,0.213000); -positions[411] = Vec3(0.088000,-0.061000,0.927000); -positions[412] = Vec3(0.046000,-0.147000,0.900000); -positions[413] = Vec3(0.182000,-0.058000,0.893000); -positions[414] = Vec3(0.504000,-0.294000,0.910000); -positions[415] = Vec3(0.570000,-0.220000,0.919000); -positions[416] = Vec3(0.548000,-0.373000,0.868000); -positions[417] = Vec3(-0.860000,0.796000,-0.624000); -positions[418] = Vec3(-0.819000,0.764000,-0.538000); -positions[419] = Vec3(-0.956000,0.769000,-0.627000); -positions[420] = Vec3(0.040000,0.544000,-0.748000); -positions[421] = Vec3(0.125000,0.511000,-0.789000); -positions[422] = Vec3(0.053000,0.559000,-0.650000); -positions[423] = Vec3(0.189000,0.520000,-0.140000); -positions[424] = Vec3(0.248000,0.480000,-0.210000); -positions[425] = Vec3(0.131000,0.591000,-0.181000); -positions[426] = Vec3(-0.493000,-0.912000,-0.202000); -positions[427] = Vec3(-0.454000,-0.823000,-0.182000); -positions[428] = Vec3(-0.483000,-0.932000,-0.299000); -positions[429] = Vec3(0.815000,0.572000,0.325000); -positions[430] = Vec3(0.822000,0.483000,0.279000); -positions[431] = Vec3(0.721000,0.606000,0.317000); -positions[432] = Vec3(-0.205000,0.604000,-0.656000); -positions[433] = Vec3(-0.243000,0.535000,-0.594000); -positions[434] = Vec3(-0.123000,0.568000,-0.700000); -positions[435] = Vec3(0.252000,-0.298000,-0.118000); -positions[436] = Vec3(0.222000,-0.241000,-0.042000); -positions[437] = Vec3(0.245000,-0.395000,-0.092000); -positions[438] = Vec3(0.671000,0.464000,-0.593000); -positions[439] = Vec3(0.637000,0.375000,-0.623000); -positions[440] = Vec3(0.697000,0.518000,-0.673000); -positions[441] = Vec3(0.930000,-0.184000,-0.397000); -positions[442] = Vec3(0.906000,-0.202000,-0.492000); -positions[443] = Vec3(0.960000,-0.090000,-0.387000); -positions[444] = Vec3(0.473000,0.500000,0.191000); -positions[445] = Vec3(0.534000,0.580000,0.195000); -positions[446] = Vec3(0.378000,0.531000,0.198000); -positions[447] = Vec3(0.159000,-0.725000,-0.396000); -positions[448] = Vec3(0.181000,-0.786000,-0.320000); -positions[449] = Vec3(0.169000,-0.774000,-0.482000); -positions[450] = Vec3(-0.515000,-0.803000,-0.628000); -positions[451] = Vec3(-0.491000,-0.866000,-0.702000); -positions[452] = Vec3(-0.605000,-0.763000,-0.646000); -positions[453] = Vec3(-0.560000,0.855000,0.309000); -positions[454] = Vec3(-0.646000,0.824000,0.351000); -positions[455] = Vec3(-0.564000,0.841000,0.210000); -positions[456] = Vec3(-0.103000,-0.115000,-0.708000); -positions[457] = Vec3(-0.042000,-0.085000,-0.781000); -positions[458] = Vec3(-0.141000,-0.204000,-0.730000); -positions[459] = Vec3(-0.610000,-0.131000,-0.734000); -positions[460] = Vec3(-0.526000,-0.126000,-0.788000); -positions[461] = Vec3(-0.633000,-0.227000,-0.716000); -positions[462] = Vec3(0.083000,-0.604000,-0.840000); -positions[463] = Vec3(0.078000,-0.605000,-0.740000); -positions[464] = Vec3(0.000000,-0.645000,-0.878000); -positions[465] = Vec3(0.688000,-0.200000,-0.146000); -positions[466] = Vec3(0.632000,-0.119000,-0.137000); -positions[467] = Vec3(0.740000,-0.196000,-0.232000); -positions[468] = Vec3(0.903000,0.086000,0.133000); -positions[469] = Vec3(0.954000,0.087000,0.047000); -positions[470] = Vec3(0.959000,0.044000,0.204000); -positions[471] = Vec3(-0.136000,0.135000,0.523000); -positions[472] = Vec3(-0.063000,0.118000,0.456000); -positions[473] = Vec3(-0.167000,0.048000,0.561000); -positions[474] = Vec3(-0.474000,-0.289000,0.477000); -positions[475] = Vec3(-0.407000,-0.277000,0.403000); -positions[476] = Vec3(-0.514000,-0.200000,0.500000); -positions[477] = Vec3(0.130000,-0.068000,-0.011000); -positions[478] = Vec3(0.089000,-0.142000,0.042000); -positions[479] = Vec3(0.194000,-0.017000,0.047000); -positions[480] = Vec3(-0.582000,0.927000,0.672000); -positions[481] = Vec3(-0.522000,0.846000,0.674000); -positions[482] = Vec3(-0.542000,0.996000,0.612000); -positions[483] = Vec3(0.830000,-0.589000,-0.440000); -positions[484] = Vec3(0.825000,-0.556000,-0.345000); -positions[485] = Vec3(0.744000,-0.570000,-0.486000); -positions[486] = Vec3(0.672000,-0.246000,0.154000); -positions[487] = Vec3(0.681000,-0.236000,0.055000); -positions[488] = Vec3(0.632000,-0.335000,0.175000); -positions[489] = Vec3(-0.212000,-0.142000,-0.468000); -positions[490] = Vec3(-0.159000,-0.132000,-0.552000); -positions[491] = Vec3(-0.239000,-0.052000,-0.434000); -positions[492] = Vec3(-0.021000,0.175000,-0.899000); -positions[493] = Vec3(0.018000,0.090000,-0.935000); -positions[494] = Vec3(-0.119000,0.177000,-0.918000); -positions[495] = Vec3(0.263000,0.326000,0.720000); -positions[496] = Vec3(0.184000,0.377000,0.686000); -positions[497] = Vec3(0.254000,0.311000,0.818000); -positions[498] = Vec3(-0.668000,-0.250000,0.031000); -positions[499] = Vec3(-0.662000,-0.343000,0.068000); -positions[500] = Vec3(-0.727000,-0.250000,-0.049000); -positions[501] = Vec3(0.822000,-0.860000,-0.490000); -positions[502] = Vec3(0.862000,-0.861000,-0.582000); -positions[503] = Vec3(0.832000,-0.768000,-0.450000); -positions[504] = Vec3(0.916000,0.910000,0.291000); -positions[505] = Vec3(0.979000,0.948000,0.223000); -positions[506] = Vec3(0.956000,0.827000,0.330000); -positions[507] = Vec3(-0.358000,-0.255000,0.044000); -positions[508] = Vec3(-0.450000,-0.218000,0.051000); -positions[509] = Vec3(-0.320000,-0.235000,-0.046000); -positions[510] = Vec3(0.372000,-0.574000,-0.372000); -positions[511] = Vec3(0.359000,-0.481000,-0.406000); -positions[512] = Vec3(0.288000,-0.626000,-0.385000); -positions[513] = Vec3(-0.248000,-0.570000,-0.573000); -positions[514] = Vec3(-0.188000,-0.567000,-0.493000); -positions[515] = Vec3(-0.323000,-0.506000,-0.560000); -positions[516] = Vec3(-0.823000,-0.764000,0.696000); -positions[517] = Vec3(-0.893000,-0.811000,0.750000); -positions[518] = Vec3(-0.764000,-0.832000,0.653000); -positions[519] = Vec3(-0.848000,0.236000,-0.891000); -positions[520] = Vec3(-0.856000,0.200000,-0.984000); -positions[521] = Vec3(-0.850000,0.160000,-0.826000); -positions[522] = Vec3(0.590000,-0.375000,0.491000); -positions[523] = Vec3(0.632000,-0.433000,0.421000); -positions[524] = Vec3(0.546000,-0.296000,0.447000); -positions[525] = Vec3(-0.153000,0.385000,-0.481000); -positions[526] = Vec3(-0.080000,0.454000,-0.477000); -positions[527] = Vec3(-0.125000,0.310000,-0.540000); -positions[528] = Vec3(0.255000,-0.514000,0.290000); -positions[529] = Vec3(0.159000,-0.513000,0.263000); -positions[530] = Vec3(0.267000,-0.461000,0.374000); -positions[531] = Vec3(0.105000,-0.849000,-0.136000); -positions[532] = Vec3(0.028000,-0.882000,-0.082000); -positions[533] = Vec3(0.190000,-0.879000,-0.094000); -positions[534] = Vec3(0.672000,0.203000,-0.373000); -positions[535] = Vec3(0.762000,0.187000,-0.413000); -positions[536] = Vec3(0.680000,0.208000,-0.274000); -positions[537] = Vec3(0.075000,0.345000,0.033000); -positions[538] = Vec3(-0.017000,0.317000,0.004000); -positions[539] = Vec3(0.106000,0.422000,-0.023000); -positions[540] = Vec3(-0.422000,0.856000,-0.464000); -positions[541] = Vec3(-0.479000,0.908000,-0.527000); -positions[542] = Vec3(-0.326000,0.868000,-0.488000); -positions[543] = Vec3(0.072000,0.166000,0.318000); -positions[544] = Vec3(0.055000,0.249000,0.264000); -positions[545] = Vec3(0.162000,0.129000,0.296000); -positions[546] = Vec3(-0.679000,-0.527000,0.119000); -positions[547] = Vec3(-0.778000,-0.538000,0.121000); -positions[548] = Vec3(-0.645000,-0.512000,0.212000); -positions[549] = Vec3(0.613000,0.842000,-0.431000); -positions[550] = Vec3(0.669000,0.923000,-0.448000); -positions[551] = Vec3(0.672000,0.762000,-0.428000); -positions[552] = Vec3(-0.369000,-0.095000,-0.903000); -positions[553] = Vec3(-0.336000,-0.031000,-0.972000); -positions[554] = Vec3(-0.303000,-0.101000,-0.828000); -positions[555] = Vec3(0.716000,0.565000,-0.154000); -positions[556] = Vec3(0.735000,0.630000,-0.080000); -positions[557] = Vec3(0.776000,0.485000,-0.145000); -positions[558] = Vec3(-0.412000,-0.642000,-0.229000); -positions[559] = Vec3(-0.421000,-0.652000,-0.130000); -positions[560] = Vec3(-0.316000,-0.649000,-0.255000); -positions[561] = Vec3(0.390000,-0.121000,-0.302000); -positions[562] = Vec3(0.299000,-0.080000,-0.304000); -positions[563] = Vec3(0.383000,-0.215000,-0.270000); -positions[564] = Vec3(-0.188000,0.883000,-0.608000); -positions[565] = Vec3(-0.215000,0.794000,-0.645000); -positions[566] = Vec3(-0.187000,0.951000,-0.681000); -positions[567] = Vec3(-0.637000,0.325000,0.449000); -positions[568] = Vec3(-0.572000,0.251000,0.438000); -positions[569] = Vec3(-0.617000,0.375000,0.533000); -positions[570] = Vec3(0.594000,0.745000,0.652000); -positions[571] = Vec3(0.644000,0.830000,0.633000); -positions[572] = Vec3(0.506000,0.747000,0.604000); -positions[573] = Vec3(-0.085000,0.342000,-0.220000); -positions[574] = Vec3(-0.102000,0.373000,-0.314000); -positions[575] = Vec3(-0.169000,0.305000,-0.182000); -positions[576] = Vec3(-0.132000,-0.928000,-0.345000); -positions[577] = Vec3(-0.094000,-0.837000,-0.330000); -positions[578] = Vec3(-0.140000,-0.945000,-0.444000); -positions[579] = Vec3(0.859000,-0.488000,0.016000); -positions[580] = Vec3(0.813000,-0.473000,0.104000); -positions[581] = Vec3(0.903000,-0.403000,-0.014000); -positions[582] = Vec3(0.661000,-0.072000,-0.909000); -positions[583] = Vec3(0.615000,0.016000,-0.922000); -positions[584] = Vec3(0.760000,-0.060000,-0.916000); -positions[585] = Vec3(-0.454000,-0.011000,-0.142000); -positions[586] = Vec3(-0.550000,-0.022000,-0.169000); -positions[587] = Vec3(-0.398000,-0.078000,-0.190000); -positions[588] = Vec3(0.859000,-0.906000,0.861000); -positions[589] = Vec3(0.913000,-0.975000,0.909000); -positions[590] = Vec3(0.827000,-0.837000,0.927000); -positions[591] = Vec3(-0.779000,-0.878000,0.087000); -positions[592] = Vec3(-0.802000,-0.825000,0.005000); -positions[593] = Vec3(-0.698000,-0.934000,0.068000); -positions[594] = Vec3(-0.001000,-0.293000,0.851000); -positions[595] = Vec3(-0.072000,-0.305000,0.781000); -positions[596] = Vec3(0.000000,-0.372000,0.911000); -positions[597] = Vec3(0.221000,-0.548000,-0.018000); -positions[598] = Vec3(0.156000,-0.621000,-0.039000); -positions[599] = Vec3(0.225000,-0.534000,0.080000); -positions[600] = Vec3(0.079000,-0.622000,0.653000); -positions[601] = Vec3(0.078000,-0.669000,0.741000); -positions[602] = Vec3(0.161000,-0.650000,0.602000); -positions[603] = Vec3(0.672000,-0.471000,-0.238000); -positions[604] = Vec3(0.594000,-0.521000,-0.200000); -positions[605] = Vec3(0.669000,-0.376000,-0.207000); -positions[606] = Vec3(-0.038000,0.192000,-0.635000); -positions[607] = Vec3(-0.042000,0.102000,-0.591000); -positions[608] = Vec3(-0.035000,0.181000,-0.734000); -positions[609] = Vec3(0.428000,0.424000,0.520000); -positions[610] = Vec3(0.458000,0.352000,0.458000); -positions[611] = Vec3(0.389000,0.384000,0.603000); -positions[612] = Vec3(-0.157000,-0.375000,-0.758000); -positions[613] = Vec3(-0.250000,-0.400000,-0.785000); -positions[614] = Vec3(-0.131000,-0.425000,-0.676000); -positions[615] = Vec3(0.317000,0.547000,-0.582000); -positions[616] = Vec3(0.355000,0.488000,-0.510000); -positions[617] = Vec3(0.357000,0.521000,-0.670000); -positions[618] = Vec3(0.812000,-0.276000,0.687000); -positions[619] = Vec3(0.844000,-0.266000,0.593000); -positions[620] = Vec3(0.733000,-0.338000,0.689000); -positions[621] = Vec3(-0.438000,0.214000,-0.750000); -positions[622] = Vec3(-0.386000,0.149000,-0.695000); -positions[623] = Vec3(-0.487000,0.277000,-0.689000); -positions[624] = Vec3(-0.861000,0.034000,-0.708000); -positions[625] = Vec3(-0.924000,-0.038000,-0.739000); -positions[626] = Vec3(-0.768000,-0.002000,-0.708000); -positions[627] = Vec3(0.770000,-0.532000,0.301000); -positions[628] = Vec3(0.724000,-0.619000,0.318000); -positions[629] = Vec3(0.861000,-0.535000,0.342000); -positions[630] = Vec3(0.618000,-0.295000,-0.578000); -positions[631] = Vec3(0.613000,-0.213000,-0.521000); -positions[632] = Vec3(0.707000,-0.298000,-0.623000); -positions[633] = Vec3(-0.510000,0.052000,0.168000); -positions[634] = Vec3(-0.475000,0.011000,0.084000); -positions[635] = Vec3(-0.600000,0.014000,0.188000); -positions[636] = Vec3(-0.562000,0.453000,0.691000); -positions[637] = Vec3(-0.621000,0.533000,0.695000); -positions[638] = Vec3(-0.547000,0.418000,0.784000); -positions[639] = Vec3(-0.269000,0.221000,0.882000); -positions[640] = Vec3(-0.353000,0.220000,0.936000); -positions[641] = Vec3(-0.267000,0.304000,0.826000); -positions[642] = Vec3(0.039000,-0.785000,0.300000); -positions[643] = Vec3(0.138000,-0.796000,0.291000); -positions[644] = Vec3(-0.001000,-0.871000,0.332000); -positions[645] = Vec3(0.875000,-0.216000,0.337000); -positions[646] = Vec3(0.798000,-0.251000,0.283000); -positions[647] = Vec3(0.843000,-0.145000,0.399000); diff --git a/platforms/reference/tests/water_GromacsForces.dat b/platforms/reference/tests/water_GromacsForces.dat deleted file mode 100644 index 34db43d00..000000000 --- a/platforms/reference/tests/water_GromacsForces.dat +++ /dev/null @@ -1,648 +0,0 @@ -ASSERT_EQUAL_VEC(Vec3( 1.53862e+01, -9.40085e+01, 8.09974e+01), forces1[0], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.16025e+01, 3.42647e+01, 7.90920e+01), forces1[1], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.96273e+01, 7.80017e+01, 7.38545e+00), forces1[2], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.28843e+01, -1.89277e+01, -2.54913e+02), forces1[3], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.22785e+01, -3.88301e+01, -2.81351e+02), forces1[4], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.09090e+02, 1.75451e+02, -1.29874e+02), forces1[5], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.95616e+02, 5.36132e+02, -4.55554e+02), forces1[6], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.85944e+02, -1.19523e+02, 7.88721e+01), forces1[7], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.13615e+02, -6.17221e+01, 1.57270e+02), forces1[8], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.66977e+01, -6.36326e+01, 1.65651e+02), forces1[9], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.62216e+00, 1.13905e+02, -5.46500e+01), forces1[10], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.21610e+01, 2.96483e+01, -6.34852e+01), forces1[11], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.01658e+01, 1.07406e+02, 2.69335e+01), forces1[12], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.14730e+01, 9.63730e+01, 1.37884e+02), forces1[13], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.45980e+02, 2.47183e+01, 1.30466e+02), forces1[14], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.15321e+01, 2.08457e+02, 4.15324e+02), forces1[15], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.53856e+02, 6.74890e+01, -7.69439e+01), forces1[16], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.56804e+02, 1.82869e+02, 2.35455e+02), forces1[17], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.78646e+02, 4.16416e+01, -2.55139e+02), forces1[18], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.51530e+01, 3.24295e+01, 1.87664e+01), forces1[19], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.04660e+02, -2.25016e+02, 5.95159e+01), forces1[20], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.93048e+01, 3.22523e+01, 1.06075e+02), forces1[21], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.84792e+01, 1.15745e+02, 9.08190e+01), forces1[22], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.22807e+01, -3.30640e+01, 2.38179e+01), forces1[23], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.10281e+01, 5.37699e+01, 1.70935e+02), forces1[24], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.55507e+01, 2.52756e+02, 1.34829e+02), forces1[25], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.62832e+01, -6.20729e+01, -9.53832e+01), forces1[26], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.93262e+01, -8.64360e+01, -9.20284e+01), forces1[27], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.72500e+00, -1.78213e+02, 1.54062e+01), forces1[28], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.46320e+02, 1.93997e+01, -1.06660e+01), forces1[29], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.02138e+01, 1.84585e+02, -1.96791e+02), forces1[30], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.44392e+01, -1.63547e+02, -1.34078e+02), forces1[31], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.64487e+01, -1.01917e+02, -2.94291e+01), forces1[32], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.62979e+02, -8.44104e+01, 4.45776e+00), forces1[33], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.37054e+02, -1.64893e+01, 1.62445e+02), forces1[34], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.79879e+02, -1.28158e+02, 1.46225e+02), forces1[35], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.18701e+02, 1.96825e+01, 1.78171e+02), forces1[36], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.05936e+01, -1.32890e+02, 3.44742e+01), forces1[37], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.00952e+01, -2.04575e+02, 1.62082e+02), forces1[38], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.48119e+02, -5.51581e+01, 7.61226e+01), forces1[39], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.54706e+02, -7.79318e+01, -1.19613e+02), forces1[40], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.99297e+02, 1.36546e+02, 1.92910e+02), forces1[41], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.30607e+02, 9.45022e+01, -1.15484e+02), forces1[42], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.87492e+01, 3.38234e+01, -1.13593e+02), forces1[43], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.13434e+01, 1.75865e+02, 7.10201e+01), forces1[44], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.98165e+02, -1.81350e+02, -1.38226e+02), forces1[45], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.58294e+02, -1.74709e+02, -1.91109e+02), forces1[46], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.09248e+02, -1.57551e+02, -2.54299e+02), forces1[47], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.75881e+01, -1.06801e+02, -8.62635e+01), forces1[48], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.96592e+02, -1.56687e+01, -9.07580e+01), forces1[49], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.07471e+02, -1.59465e+02, 1.41495e+01), forces1[50], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.97824e+02, -1.58296e+01, -3.62499e+01), forces1[51], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.93794e+01, 2.56345e+01, 5.39562e+01), forces1[52], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.00946e+02, 1.34042e+02, 8.37801e+01), forces1[53], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.44101e+01, 1.04507e+02, -7.20338e+00), forces1[54], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.36940e+02, 1.45544e+02, 7.49711e+01), forces1[55], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.50152e+00, 2.02504e+02, 1.20796e+02), forces1[56], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.94096e+02, -4.04458e+01, 5.69722e+01), forces1[57], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.39977e+01, -1.51534e+02, -4.73434e+01), forces1[58], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.19892e+01, -9.31361e+01, -3.38910e+01), forces1[59], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.17884e+01, 1.00547e+02, -1.33243e+02), forces1[60], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.71112e+01, 6.21495e+01, 1.61566e+02), forces1[61], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.56825e+01, 6.35038e+01, -1.08713e+02), forces1[62], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.42227e+02, 2.10144e+02, 1.68761e+02), forces1[63], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.92938e+02, -1.15636e+02, -2.42672e+02), forces1[64], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.46946e+01, 1.75845e+02, 2.87636e+01), forces1[65], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.35161e+01, -3.00661e+01, -1.51624e+02), forces1[66], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.77087e+01, 1.55190e+02, 2.57432e+01), forces1[67], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.98358e+00, -2.76639e+02, -2.72293e+01), forces1[68], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.05003e+02, 1.07560e+02, 3.34506e+01), forces1[69], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.18245e+01, -1.75537e+01, -9.57309e+01), forces1[70], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.67253e+02, 5.59922e-01, 1.01207e+02), forces1[71], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.62670e+02, -6.88248e+01, -4.21201e+02), forces1[72], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.18113e+02, -5.78800e+01, -2.27353e+02), forces1[73], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.64922e+00, 9.21166e+01, -8.93683e+01), forces1[74], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.12201e+02, -3.27194e+01, 1.34264e+02), forces1[75], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.44131e+01, -7.40189e+01, 1.05403e+02), forces1[76], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.25775e+01, -1.36797e+02, 2.73836e+02), forces1[77], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.10304e+01, 7.16395e+01, 4.68672e+02), forces1[78], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.93444e+01, -2.15029e+02, -6.63119e+01), forces1[79], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.55389e+02, -3.73611e+02, 1.19751e+02), forces1[80], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.45909e+02, -1.24787e+02, 3.49148e+01), forces1[81], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.32739e+01, 2.95694e+02, -5.37526e+01), forces1[82], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.54390e+02, 4.53455e+02, -2.26764e+02), forces1[83], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.41532e+02, 4.99625e+01, -2.51478e+02), forces1[84], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.44295e+02, 3.25984e+02, -1.78338e+02), forces1[85], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.41100e+02, 7.63283e+01, 1.44488e+02), forces1[86], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.38640e+00, 2.32776e+02, 7.67636e+01), forces1[87], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.02516e+01, 2.34037e+02, 1.90372e+02), forces1[88], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.91986e+01, 6.06007e+01, -2.82869e+01), forces1[89], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.17690e+01, 2.95809e+02, 8.76127e+01), forces1[90], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.68695e+02, 3.01744e+02, -4.89279e+01), forces1[91], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.69699e+01, -8.28133e+01, 1.45608e+02), forces1[92], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.06525e+02, -1.67708e+02, -8.84405e+01), forces1[93], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.24225e+02, -2.54622e+02, 6.45408e+01), forces1[94], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.17139e+01, 8.98704e+01, 1.46449e+02), forces1[95], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.77809e+01, -7.22944e+00, -1.54716e+02), forces1[96], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.09684e+01, -7.69721e+01, 4.92171e+01), forces1[97], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.39983e+01, -1.04019e+01, -1.19765e+02), forces1[98], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.69240e+02, -4.03667e+02, -1.80224e+01), forces1[99], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.94854e+01, 1.06162e+02, 2.06747e+02), forces1[100], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.37669e+02, 1.53252e+02, 2.04131e+02), forces1[101], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.32814e+02, 6.44910e+01, -3.37777e+02), forces1[102], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.66103e+02, 8.69357e+01, -1.09283e+02), forces1[103], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.18540e+01, 6.11078e+01, -1.30500e+02), forces1[104], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.89128e+02, -2.65106e+02, -1.28996e+02), forces1[105], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.45378e+01, -3.81579e+02, -1.11586e+02), forces1[106], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.79366e+01, -2.27092e+02, 2.32158e+02), forces1[107], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.14303e+02, 1.21953e+02, 3.08605e+01), forces1[108], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.95355e+02, 2.38433e+02, -3.78260e+01), forces1[109], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.25306e+02, -5.62806e+01, 2.93849e+02), forces1[110], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.32541e+02, 1.53253e+02, 1.18339e+02), forces1[111], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.26061e+02, 1.22366e+02, 6.31712e+00), forces1[112], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.68565e+02, 9.40491e+01, 4.12643e+01), forces1[113], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.19917e+02, -1.43527e+02, -2.21682e+02), forces1[114], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.93757e+01, 9.98556e+01, 7.38225e+01), forces1[115], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.87240e+01, -7.40610e+01, 1.37672e+02), forces1[116], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.90455e+01, -9.52131e+01, -4.21601e+02), forces1[117], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.97078e+02, 2.45509e+02, 9.26765e+01), forces1[118], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.98206e+02, 1.14032e+02, 8.71204e+01), forces1[119], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.19803e+02, 1.82722e+01, -3.52888e+00), forces1[120], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.30623e+02, 7.51475e-01, -4.84435e+01), forces1[121], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.02126e+01, 5.55326e+01, 2.67927e+00), forces1[122], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.87364e+02, 1.76214e+02, -3.09445e+02), forces1[123], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.85190e+02, -1.63720e+02, -7.15048e+01), forces1[124], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.65174e+02, -1.33924e+02, -6.94217e+01), forces1[125], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.39913e+00, 2.52232e+01, 5.05709e+01), forces1[126], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.63349e+02, 9.56277e+01, 5.30812e+01), forces1[127], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.92027e+01, -9.44704e+01, -7.51200e+00), forces1[128], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.24094e+02, 7.38856e+01, 1.76005e+02), forces1[129], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.92944e+01, 3.02317e+02, 1.39375e+02), forces1[130], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.66291e+01, 1.41333e+02, 6.15473e+00), forces1[131], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.36178e+01, -1.58532e+01, -8.84526e+00), forces1[132], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.48146e+01, -3.41461e+01, -5.24216e+01), forces1[133], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.99809e+01, 1.02879e+01, -5.01739e+01), forces1[134], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.62285e+02, -4.90274e+01, 3.03601e+01), forces1[135], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.06458e+02, -3.96124e+01, 1.03454e+02), forces1[136], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.29243e+02, 6.18585e+01, -1.77272e+02), forces1[137], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.15853e+02, 2.19635e+02, -4.11751e+02), forces1[138], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.16425e+01, 8.23178e+01, 4.42405e+02), forces1[139], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.21858e+01, 4.82821e+01, 1.93947e+02), forces1[140], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.03450e+00, 2.30768e+01, 4.96796e+01), forces1[141], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.67572e+01, 7.23375e+01, 6.32957e+01), forces1[142], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.67345e+01, 1.26459e+01, 8.78382e+01), forces1[143], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.43687e+02, 1.76648e+01, 3.89767e+01), forces1[144], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.77056e+01, -9.46510e+01, -1.60263e+02), forces1[145], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.49800e+01, -2.68488e+01, 4.35106e+01), forces1[146], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.46710e+02, -5.25895e+01, -5.40524e+01), forces1[147], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.33729e+01, -4.69399e+01, -7.85015e+01), forces1[148], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.78265e+02, 3.19667e+00, -1.14997e+02), forces1[149], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.93773e+02, 7.50014e+01, -6.05331e+01), forces1[150], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.41372e+02, 1.04392e+02, -1.69148e+02), forces1[151], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.16023e+01, -7.84331e+00, -3.50072e+01), forces1[152], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.91752e+02, -8.75055e+01, 2.06764e+01), forces1[153], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.24104e+01, 2.55823e+02, 5.03937e+01), forces1[154], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.44493e+01, -1.88359e+02, -2.96664e+02), forces1[155], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.95569e+01, -1.48556e+02, -3.25981e+01), forces1[156], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.87067e+01, -3.24463e+01, -4.72036e+01), forces1[157], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.57426e+01, -4.76206e+01, -4.60343e+01), forces1[158], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.72900e+01, 5.41697e-01, -1.00543e+02), forces1[159], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.18469e+01, -6.73531e+00, 1.21198e+02), forces1[160], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.22925e+01, -1.12784e+01, 1.43764e+02), forces1[161], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.83447e+00, -1.45820e+01, -1.70105e+02), forces1[162], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.76068e+01, -7.28345e+00, -1.56973e+02), forces1[163], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.79090e+01, -1.92976e+02, -1.29871e+02), forces1[164], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.93110e+01, -1.12724e+02, 2.45046e+01), forces1[165], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.69833e+02, -9.82967e+01, 5.93923e+01), forces1[166], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.02085e+02, 9.27636e+00, 6.98988e+01), forces1[167], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.84338e+01, 1.41909e+02, -4.11691e+01), forces1[168], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.23626e+02, -1.04296e+02, 4.77490e+01), forces1[169], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.37003e+01, 4.13719e+01, 1.29790e+02), forces1[170], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.42874e+02, -8.32344e+01, -3.05737e+01), forces1[171], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.41293e+01, 7.66533e+01, 1.00918e+02), forces1[172], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.02752e+02, -3.11320e+01, -2.04248e+01), forces1[173], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.71192e+01, -3.13758e+02, 2.83511e+02), forces1[174], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.43170e+02, 1.60859e+02, 6.31587e+01), forces1[175], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.26734e+02, 1.91452e+02, -1.93402e+00), forces1[176], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.10931e+02, -1.64391e+01, -6.86948e+01), forces1[177], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.38600e+01, 2.32825e+02, -5.25593e+00), forces1[178], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.54520e+01, -1.88445e+02, -4.29131e+01), forces1[179], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.24785e+02, -1.05275e+02, -2.98944e+01), forces1[180], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.05063e+02, -6.53701e+01, 3.24520e+01), forces1[181], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.53521e+01, -9.04667e+01, -1.59980e+01), forces1[182], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.53764e+01, -3.04915e+01, 1.37888e+02), forces1[183], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.08932e+02, -9.35386e+01, -1.80955e+01), forces1[184], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.64566e+02, -1.70413e+02, -1.27317e+01), forces1[185], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.22672e+02, -3.22897e+02, 3.76674e+00), forces1[186], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.09547e+01, 3.37045e+02, -2.28878e+02), forces1[187], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.33946e+01, -1.01157e+02, -5.42970e+01), forces1[188], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.88672e+01, 2.85116e+01, -8.06985e-01), forces1[189], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.46034e+01, 1.78114e+02, -8.00020e+01), forces1[190], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.94640e+01, -7.09864e+01, 1.32544e+02), forces1[191], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.87772e+01, 8.20162e+01, -9.03433e+01), forces1[192], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.88680e+00, 8.72448e+01, -2.61573e+01), forces1[193], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.28593e+01, 2.51197e+00, -5.73722e+01), forces1[194], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.80417e+01, -7.37577e+01, 1.00134e+02), forces1[195], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.56974e+01, 6.72072e+00, -3.81539e+01), forces1[196], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.19232e+01, -3.54500e+01, 8.29318e+01), forces1[197], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.04113e+01, -4.41970e+01, 1.03326e+02), forces1[198], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.90881e+01, -1.12057e+02, 4.49403e+01), forces1[199], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.92007e+01, 3.55272e+01, -2.40127e+02), forces1[200], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.43562e+02, 6.23027e+02, -2.49264e+02), forces1[201], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.76198e+02, -3.02372e+02, 1.62332e+02), forces1[202], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.20299e+02, -2.27586e+02, 5.80333e+01), forces1[203], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.39488e+01, -1.07027e+00, -2.95203e+01), forces1[204], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.73263e+01, -1.08485e+02, 5.71183e+00), forces1[205], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.00039e+01, -2.49895e+02, 3.39192e+01), forces1[206], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.29623e+01, 1.32732e+02, 2.08741e+01), forces1[207], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.25554e+02, -1.56772e+01, -1.08164e+02), forces1[208], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.38717e+01, 1.52424e+01, 4.36131e+01), forces1[209], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.76367e+01, 1.13676e+02, -8.52759e+01), forces1[210], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.96298e+01, -9.30520e+01, -2.23851e+01), forces1[211], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.75027e+01, 1.64821e+02, 6.78676e+01), forces1[212], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.64028e+02, 3.12107e+01, 8.76753e+01), forces1[213], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.72632e+01, 5.28099e+01, 1.69700e+01), forces1[214], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.40135e+02, -7.08379e+01, -1.93293e+02), forces1[215], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.76562e+01, 2.29918e+02, 1.30609e+02), forces1[216], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.81640e+01, -2.90103e+02, 1.36757e+00), forces1[217], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.79291e+01, -2.93974e+02, 1.15436e+02), forces1[218], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.17338e+02, 1.11581e+02, 3.46029e+01), forces1[219], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.13346e+01, 3.15582e+01, 8.34550e+01), forces1[220], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.57677e+01, 1.77750e+01, 1.01067e+02), forces1[221], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.49827e+02, 8.44938e+01, 1.82793e+02), forces1[222], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.35999e+02, -1.89848e+02, -2.50760e+02), forces1[223], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.41970e+02, -1.87691e+02, -2.44756e+02), forces1[224], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.37302e+02, 8.71479e+01, -2.13793e+02), forces1[225], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.45010e+01, 2.44686e+02, -1.46416e+02), forces1[226], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.31020e+02, 1.28244e+02, 7.71140e+01), forces1[227], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.53744e+01, 1.29065e+02, 2.11056e+02), forces1[228], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.21924e+01, 9.95419e+00, -1.07719e+02), forces1[229], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.85756e+01, 9.52314e+01, 8.76358e+01), forces1[230], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.93957e+00, 1.53656e+02, -1.13339e+02), forces1[231], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.02172e+02, 8.87905e+01, -2.13701e+02), forces1[232], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.68099e+01, 1.91141e+02, 4.82221e+01), forces1[233], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.92679e+02, -2.47187e+02, 6.66851e+01), forces1[234], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.09980e+02, -1.43568e+02, -3.01739e+01), forces1[235], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.33167e+02, -3.32798e+02, 5.34600e+01), forces1[236], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.24223e+01, 9.76875e+00, 4.47725e+01), forces1[237], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.69405e+01, -8.41132e+01, -5.38952e+01), forces1[238], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.12010e+01, 1.44242e+01, -1.42070e+01), forces1[239], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.96477e+02, -4.50656e+02, 1.11329e+02), forces1[240], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.39163e+02, 1.76905e+02, 5.32392e+00), forces1[241], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.19746e+02, 1.76406e+02, 1.08727e+01), forces1[242], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.59625e+01, 1.08166e+01, 1.58314e+02), forces1[243], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.06176e+00, 1.91897e+01, 1.04092e+02), forces1[244], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.25838e+02, -4.67771e+00, -5.29138e+01), forces1[245], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.85855e+01, 1.78805e+01, -1.25884e+02), forces1[246], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.10798e+02, 9.15074e+01, 1.95780e+02), forces1[247], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.10572e+01, -1.48442e+02, 4.74169e+01), forces1[248], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.25479e+02, 2.55010e+01, 8.47576e+01), forces1[249], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.10701e+02, -6.73355e+01, 1.19913e+02), forces1[250], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.70376e+01, -6.37904e+00, 1.26145e+02), forces1[251], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.37588e+02, 1.02142e+02, 3.67769e+02), forces1[252], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.52584e+01, -7.07147e+01, 1.73165e+02), forces1[253], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.33450e+01, -2.18105e+02, -1.55636e+02), forces1[254], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.29365e+02, 7.78338e+01, -3.82730e+01), forces1[255], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.57375e+02, -6.66875e+01, -5.81031e+01), forces1[256], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.78245e+01, -1.40991e+01, 3.12933e+01), forces1[257], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.87648e+01, 2.74231e+02, 7.27232e+01), forces1[258], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.14936e+02, 1.20339e+01, -1.48413e+02), forces1[259], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.06217e+02, -3.13647e+01, -1.68616e+02), forces1[260], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.25106e+02, -2.60277e+02, -1.61136e+02), forces1[261], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.70346e+02, -9.32224e+00, -5.51717e+01), forces1[262], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.83465e+01, -2.28314e+02, -2.29566e+02), forces1[263], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.96075e+01, 1.48719e+02, 9.34688e+01), forces1[264], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.71370e+02, 1.70586e+02, -9.94963e+01), forces1[265], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.40521e+01, -1.08310e+02, 3.14259e+01), forces1[266], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.40452e+02, -2.41911e+02, 1.64059e+02), forces1[267], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.58929e+02, -1.31148e+02, -5.32733e+01), forces1[268], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.63751e+01, -2.73274e+02, -8.70685e+00), forces1[269], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.31634e+02, 2.19012e+02, -9.03802e+01), forces1[270], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.18020e+02, -1.92997e+01, -5.66165e+00), forces1[271], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.73518e+01, -3.11848e+01, -1.30020e+02), forces1[272], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.17466e+01, -3.68264e+02, 2.52209e+02), forces1[273], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05037e+02, -1.84548e+02, -2.29593e+02), forces1[274], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.33053e+02, -1.07748e+02, -3.35660e+02), forces1[275], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.26641e+00, -2.78635e+00, -6.24895e+01), forces1[276], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.89712e+01, -4.30328e+01, -1.35221e+02), forces1[277], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.08792e+01, 8.56090e+01, 7.01326e+01), forces1[278], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.41320e+01, 1.50690e+02, -3.83537e+01), forces1[279], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.77423e+01, 7.38950e+01, 4.53469e+01), forces1[280], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.26780e+02, 1.02539e+02, -1.85815e+02), forces1[281], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.00799e+01, 1.14102e+02, -1.69102e+02), forces1[282], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.76513e+01, 8.40729e+01, 4.44592e+01), forces1[283], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.26467e+01, 5.77168e+01, 6.22600e+01), forces1[284], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.50347e+02, 3.61081e+02, -9.77920e+00), forces1[285], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.74580e+01, -5.17134e+01, -4.47767e+02), forces1[286], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.34437e+01, -3.97370e+02, -1.13442e+02), forces1[287], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.99880e+01, 2.09852e+02, 5.14899e+02), forces1[288], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.66190e+02, -2.26561e+02, 2.12404e+02), forces1[289], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.70999e+02, -2.62349e+02, -1.29205e+01), forces1[290], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.14337e+01, 5.49849e+01, 1.43268e+02), forces1[291], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.68620e+02, 3.93466e+00, 5.58857e+01), forces1[292], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.80270e+02, -1.13992e+01, 5.41069e+01), forces1[293], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.97739e+00, 1.29408e+02, -5.46560e+01), forces1[294], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.63236e+02, -1.28719e+02, 3.12749e+02), forces1[295], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.22808e+01, 1.12193e+02, 7.28319e+01), forces1[296], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.99596e+01, 2.53709e+02, 4.53500e+01), forces1[297], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.27720e+01, 8.59763e+01, 6.45557e+01), forces1[298], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.27058e+02, 1.22472e+01, 1.29561e+01), forces1[299], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.06664e+01, -9.58809e+01, -3.53582e+01), forces1[300], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.53970e+01, 5.12101e+01, 1.16686e+02), forces1[301], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.73120e+02, -1.27943e+02, -7.31003e+01), forces1[302], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.71294e+01, 2.17024e+02, 9.31014e+01), forces1[303], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.68161e+01, -1.85137e+02, 1.09745e+02), forces1[304], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.01521e+02, 5.92488e+00, -4.76997e+01), forces1[305], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.65074e+02, -7.65780e+01, -1.09596e+02), forces1[306], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.97306e+01, 3.84936e+01, 3.18940e+02), forces1[307], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.03733e+01, -3.14806e+01, -1.59317e+02), forces1[308], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.43092e+01, -1.29125e+02, 1.63512e+02), forces1[309], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.96060e+02, 5.77380e+01, -1.44479e+02), forces1[310], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.06352e+01, 5.46684e+00, 1.26620e+02), forces1[311], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.68377e+01, 1.94905e+02, 2.46429e+02), forces1[312], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.30349e+02, 9.49772e+01, -1.35362e+02), forces1[313], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.38512e+01, 6.40803e+01, 8.45394e+00), forces1[314], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.42175e+01, -1.59403e+00, -1.30405e+02), forces1[315], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.35848e+01, -4.54779e+00, -1.44903e+02), forces1[316], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.11989e+02, -1.18639e+01, -1.17828e+02), forces1[317], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.49970e+02, 6.35046e+01, -2.88805e+01), forces1[318], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.44126e+01, -6.56825e+01, -1.14100e+02), forces1[319], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.77255e+01, -3.66261e+01, -1.19649e+02), forces1[320], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.97007e+01, 1.88165e+01, 4.66627e+01), forces1[321], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.11016e+01, 1.60276e+01, -8.72109e+01), forces1[322], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.62297e+01, 1.86600e+02, 7.68552e+01), forces1[323], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.39138e+02, 2.21671e+02, 8.47440e+01), forces1[324], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.74277e+02, -6.06765e+01, -4.23965e+01), forces1[325], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.63159e+02, -6.13787e+01, -2.54964e+01), forces1[326], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.00529e+01, -6.56450e+01, -3.53408e+01), forces1[327], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.27153e+01, -9.16080e+01, -6.10037e+00), forces1[328], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.07795e+01, -6.31786e+01, 3.97424e+01), forces1[329], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.69043e+01, 2.05417e+02, -1.55673e+02), forces1[330], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.55098e+01, 6.25556e+01, -9.57571e+01), forces1[331], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.75174e+00, -7.00953e+01, -1.65779e+01), forces1[332], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.48906e+02, -9.37035e+01, -1.37237e+02), forces1[333], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05834e+02, -1.77865e+02, -2.97998e+02), forces1[334], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.28005e+02, -1.09597e+02, -1.57769e+02), forces1[335], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.72019e+01, -2.11978e+02, -5.75568e+01), forces1[336], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.47436e+00, -2.09055e+01, 9.54998e+01), forces1[337], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.00282e+01, -1.18118e+02, 7.20331e+01), forces1[338], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.27051e+01, 3.88512e+01, -3.37338e+02), forces1[339], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.92361e+02, 4.97166e+01, -2.72135e+02), forces1[340], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.01809e+02, 3.12384e+01, -1.44869e+02), forces1[341], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.70524e+01, 6.01604e+01, -1.29958e+01), forces1[342], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.75977e+01, -6.85964e+01, 5.29205e+01), forces1[343], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.82625e+01, 5.36498e+01, -1.27179e+02), forces1[344], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.48158e+02, 1.18954e+01, 1.03589e+02), forces1[345], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.76540e+01, 8.31945e+01, 6.88425e-01), forces1[346], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.36393e+01, 5.97150e+00, 5.92665e+01), forces1[347], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.35596e+01, -3.45187e+01, -8.71186e+01), forces1[348], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.14736e+01, 1.99758e+01, 3.17942e+01), forces1[349], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.15299e+01, -6.78140e+01, -1.20761e+02), forces1[350], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.48161e+02, 1.61995e+02, -2.00364e+01), forces1[351], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.91715e+02, 4.15257e+01, -1.01480e+02), forces1[352], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.53537e+02, 2.47464e+01, -9.32184e+01), forces1[353], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.26331e+02, -1.50752e+02, 3.87836e+02), forces1[354], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.80549e+02, -1.04529e+02, 2.64609e+02), forces1[355], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.33299e+00, -1.04191e+02, 2.43081e+02), forces1[356], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.49417e+02, -2.10331e+02, -2.12391e+02), forces1[357], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.64496e+01, -8.65224e+01, 2.09075e+02), forces1[358], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.26786e+02, -1.04116e+02, 2.42460e+02), forces1[359], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.67930e+01, 5.02589e+01, 7.66782e+01), forces1[360], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.64137e+01, -5.87259e+01, 1.21975e+02), forces1[361], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.49708e+02, -5.25609e+01, -2.18329e+02), forces1[362], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.57850e+02, 5.04311e+02, -5.05894e+01), forces1[363], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.62212e+01, -2.94583e+02, 1.54045e+02), forces1[364], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.61638e+01, -1.84431e+02, 1.13710e+02), forces1[365], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.06173e+02, 9.36425e+01, 2.20592e+02), forces1[366], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.52623e+02, 1.46025e+02, 8.97291e+01), forces1[367], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.54323e+01, 2.26018e+02, 3.46087e+02), forces1[368], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.27183e+02, -2.09440e+01, -1.89634e+02), forces1[369], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.73506e+02, 2.01241e+02, 5.03574e+01), forces1[370], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.14771e+02, 1.73517e+02, 2.04777e+02), forces1[371], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.08803e+02, -4.69136e+01, 3.13410e+01), forces1[372], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.70333e+01, -9.14230e+01, 2.67645e+01), forces1[373], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.42054e+01, -1.04732e+02, -1.88134e+00), forces1[374], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.41157e+02, -1.07118e+02, 1.67297e+02), forces1[375], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.48356e+01, -8.47055e+01, 2.43285e+02), forces1[376], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.80449e+01, -1.46446e+02, 1.85386e+01), forces1[377], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.80687e+00, -6.96210e+01, 1.25177e+01), forces1[378], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.23687e+01, -9.93136e+01, 1.45164e+00), forces1[379], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.95215e+00, 1.37747e+01, 4.23959e+00), forces1[380], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.62211e+01, 5.78277e+02, 3.68049e+01), forces1[381], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.65270e+02, -1.15374e+02, 1.18132e+02), forces1[382], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.66667e+02, -8.49100e+01, 2.96994e+02), forces1[383], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.99785e+02, 2.24069e+02, 2.30458e+01), forces1[384], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.83662e+01, 2.02857e+01, 5.16795e+01), forces1[385], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.30910e+02, -2.01579e+02, 1.48973e+02), forces1[386], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.48803e+01, -2.39996e+02, -6.71369e+01), forces1[387], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.45565e+02, -2.03246e+02, -2.90114e+02), forces1[388], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.28809e+01, 1.07210e+02, 5.79218e+01), forces1[389], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.33045e+01, 4.29217e+01, -2.51884e+01), forces1[390], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.01216e+02, 7.87171e+01, -8.84528e+01), forces1[391], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.94984e+01, -1.82575e+00, 6.60948e+01), forces1[392], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.01760e+01, 1.13645e+02, 1.03720e+02), forces1[393], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.02227e+01, -1.82477e+02, -1.93295e+02), forces1[394], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.88739e+01, -7.04682e+01, -1.97902e+02), forces1[395], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.08208e+02, 2.04314e+02, -9.77061e+01), forces1[396], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.97001e+02, -3.37469e+01, 1.30428e+02), forces1[397], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.39859e+01, 1.55789e+02, 9.33634e+01), forces1[398], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.71075e+01, 1.01907e+02, -1.62363e+02), forces1[399], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.51477e+02, -1.49509e+02, 2.38020e+01), forces1[400], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.62232e+02, 1.06486e+02, 1.02031e+02), forces1[401], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.24938e+01, 1.19921e+02, -9.62759e+01), forces1[402], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.56992e+01, -1.10020e+02, 1.49108e+02), forces1[403], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.10656e+01, 2.79604e+01, 1.91755e+02), forces1[404], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.74338e+00, -7.08051e+01, -1.05929e+02), forces1[405], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.64700e+02, -1.27130e+02, -5.91595e+01), forces1[406], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.30385e+01, 2.08802e+01, -3.57840e+01), forces1[407], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.08287e+02, 2.29771e+01, -2.26233e+02), forces1[408], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.58650e+02, -1.14832e+02, -1.67121e+02), forces1[409], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.19177e+02, 9.05557e+01, 3.00496e+02), forces1[410], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.59854e+01, -1.24855e+02, 1.73507e+02), forces1[411], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01537e+02, -3.21500e+01, -1.62947e+02), forces1[412], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.68513e+01, 7.25403e+01, 1.10509e+02), forces1[413], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.74676e+01, 1.99661e+02, -3.30448e+02), forces1[414], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.89877e+02, -5.06918e+01, 2.07261e+02), forces1[415], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.05311e+01, 7.99589e+01, -9.81659e+01), forces1[416], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.19039e+02, 7.86478e+01, -1.36094e+02), forces1[417], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.39276e+01, 1.04302e+02, -1.99319e+02), forces1[418], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.07836e+01, -7.02154e+01, -3.20077e+01), forces1[419], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.04021e+01, -2.95668e+01, -9.62964e+01), forces1[420], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.13789e+01, 2.11057e+01, -7.24998e+01), forces1[421], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.89102e+01, -6.59244e+01, -8.40365e+01), forces1[422], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.19672e+02, -4.01191e+01, 6.57098e+01), forces1[423], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.87553e+01, -8.69171e+01, 2.43178e+01), forces1[424], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.67881e+01, -1.94017e+02, 4.85473e+01), forces1[425], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.07150e+02, -1.99734e+02, -2.09862e+01), forces1[426], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.36179e+02, 1.95193e+01, -1.32315e+02), forces1[427], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.23323e+02, -6.31094e+01, -8.32846e+01), forces1[428], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.02495e+00, -1.45980e+02, 5.02494e+02), forces1[429], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.25222e+01, 1.02561e+02, 1.77325e+01), forces1[430], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.12695e+02, 3.15051e+02, -4.46404e+01), forces1[431], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.92031e+02, -9.89024e+01, -3.74688e+02), forces1[432], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.43199e+01, 7.50213e+01, 1.10375e+02), forces1[433], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.10558e+01, 2.43859e+02, 5.47498e+01), forces1[434], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.97703e+01, -1.48364e+02, -1.17638e+02), forces1[435], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.62397e+01, 4.88941e+01, -2.71595e+02), forces1[436], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.31340e+01, -8.20624e+01, 1.16191e+02), forces1[437], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.38517e+02, -7.62394e+01, -5.88168e+00), forces1[438], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.62851e+01, 6.72427e+01, -1.80434e+01), forces1[439], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.58861e+02, 1.15957e+02, -3.78160e+01), forces1[440], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.51803e+02, -4.12446e+01, -8.91525e+01), forces1[441], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.61287e+01, -1.36689e+02, -9.23537e+00), forces1[442], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.82943e+02, 1.05844e+02, -1.72148e+02), forces1[443], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.55236e+01, 9.18378e+01, 1.24360e+01), forces1[444], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.01227e+01, 8.39026e+01, 3.96741e+02), forces1[445], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.87558e+01, 5.47395e+01, -5.73402e+00), forces1[446], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.60796e+02, -5.52985e+01, 3.17802e+01), forces1[447], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.11619e+02, 1.11090e+02, 1.51495e+02), forces1[448], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.78213e+01, -1.33902e+02, 1.13590e+02), forces1[449], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.74607e+02, -2.79326e+02, -1.00171e+02), forces1[450], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.47808e+01, -1.29366e+02, -1.92232e+02), forces1[451], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.75509e+00, 1.63688e+01, -3.24829e+02), forces1[452], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.93082e+01, -2.44679e+02, 7.91941e+01), forces1[453], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.41263e+01, 9.35389e+01, 9.69223e+01), forces1[454], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.76713e+02, 1.98982e+02, 2.68113e+01), forces1[455], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.79544e+01, 6.96513e+01, -1.90320e+02), forces1[456], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.34104e+02, 2.74828e+01, -3.93803e+01), forces1[457], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.28254e+02, -1.35572e+02, -4.32733e+01), forces1[458], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.28600e+01, 3.07094e+00, -3.78996e+01), forces1[459], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.03587e+02, 1.77989e+02, -6.99490e+01), forces1[460], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.08656e+02, -4.54770e+01, -6.76500e+01), forces1[461], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.71838e+01, 5.19782e+01, -2.94923e+01), forces1[462], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.40301e+02, 2.74572e+02, -3.56579e+01), forces1[463], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.03587e+01, -3.16257e+01, -7.72873e+01), forces1[464], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.67138e+02, -7.24846e+01, -6.24143e+01), forces1[465], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.03813e+00, 9.49458e+01, 3.72519e+01), forces1[466], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.14010e+01, 6.47582e+01, 1.42218e+02), forces1[467], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.20325e+01, 1.99039e+02, 3.65580e+02), forces1[468], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.42970e+02, -8.88587e+01, 1.72171e+02), forces1[469], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.90803e+01, -2.60758e+02, 1.15577e+02), forces1[470], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.52557e+02, -8.51485e+00, -1.82612e+02), forces1[471], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 5.19978e+00, 1.82368e+02, 4.96817e+01), forces1[472], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.60405e+02, -5.75249e+01, 4.30526e+01), forces1[473], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.05782e+01, -1.01381e+02, 5.21152e+01), forces1[474], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.98251e-01, 1.60005e+02, 2.94808e+01), forces1[475], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.38812e+02, -2.31535e+02, 1.88049e+02), forces1[476], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.81939e+01, 1.28753e+02, -1.67824e+02), forces1[477], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.23875e+02, 1.55757e+02, -2.79290e+02), forces1[478], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.68146e+01, 8.00636e+01, 1.82356e+00), forces1[479], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.81555e+02, -2.44338e+02, -1.67866e+02), forces1[480], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.60882e+02, 1.64545e+02, 1.24397e+02), forces1[481], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.43347e+02, 1.22527e+02, 2.15375e+02), forces1[482], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.75592e+02, -3.02264e+02, 3.12921e+02), forces1[483], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.42347e+02, 1.64524e+02, 1.46878e+02), forces1[484], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.44791e+00, 6.90323e+01, -3.86573e+01), forces1[485], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.00184e+02, -1.07891e+02, 3.14068e+01), forces1[486], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.40711e+01, 1.27511e+01, 5.66277e+01), forces1[487], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.74580e+02, -1.14306e+02, -1.37535e+02), forces1[488], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.98657e+01, 2.19658e+02, -7.96343e+01), forces1[489], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.90069e+02, 1.36943e+02, -1.78217e+02), forces1[490], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.64334e+01, 2.56388e+02, -8.52711e+01), forces1[491], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.38510e+01, -1.61329e+02, 2.59550e+02), forces1[492], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-8.11033e+01, -7.18533e+01, 7.75259e+00), forces1[493], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05854e+02, 3.14397e+02, -4.61488e+02), forces1[494], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.69218e+02, 1.76533e+02, 2.08605e+02), forces1[495], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.06655e+01, -6.09886e+02, -6.99069e+01), forces1[496], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.19305e+02, -1.88157e+02, 1.20294e+02), forces1[497], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.74817e+01, -1.67738e+01, -7.85411e+00), forces1[498], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.56252e+00, -4.35681e+01, -6.24241e+01), forces1[499], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.73399e+01, 1.15493e+02, 9.92190e+01), forces1[500], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.58626e+01, 9.15080e+01, 3.20924e+00), forces1[501], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.09582e+01, -1.76054e+01, 6.71996e+00), forces1[502], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.59525e+01, 1.83369e+02, -1.70381e+02), forces1[503], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.32243e+01, 3.37044e+01, -6.27663e+01), forces1[504], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.91590e+01, -5.93696e+01, -7.26003e+01), forces1[505], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.74042e+00, 7.24544e+01, 5.83752e+01), forces1[506], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.35769e+01, 4.35961e+02, 7.54309e+01), forces1[507], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.81578e+02, -1.82955e+02, -1.36110e+02), forces1[508], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.53200e+02, -2.25646e+01, -1.26235e+02), forces1[509], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.02017e+01, 7.54878e+01, -9.98370e+01), forces1[510], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.56935e+01, 7.19882e+00, -3.07487e+02), forces1[511], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.60290e+01, 4.63810e+01, -1.39429e+02), forces1[512], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.36883e+02, -2.71943e+02, 1.90138e+01), forces1[513], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.95573e+01, -1.31976e+02, -1.48737e+02), forces1[514], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.61876e+02, 1.02997e+02, -1.00309e+02), forces1[515], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.73595e+00, 3.79678e+01, 9.45418e+01), forces1[516], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.60218e+00, -7.40917e+01, -2.21371e+01), forces1[517], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.27199e+02, 1.31094e+02, 1.12529e+02), forces1[518], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.04103e+02, 4.69682e+01, -1.18068e+02), forces1[519], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.12794e+01, -1.26833e+02, -4.04741e+01), forces1[520], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.09384e+01, 1.86161e+02, 3.95213e+01), forces1[521], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.91470e+02, 8.17955e+01, -9.25509e+01), forces1[522], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.33121e+01, 7.77548e-01, -1.48384e+02), forces1[523], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.52149e+02, -1.00219e+02, -7.57906e+01), forces1[524], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.46003e+02, -1.03331e+01, 1.17347e+01), forces1[525], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.09634e+00, 1.43847e+02, -1.42581e+02), forces1[526], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.68641e+02, 6.25042e+01, -7.01507e+01), forces1[527], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.49802e+01, 2.37203e+02, -2.40370e+02), forces1[528], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.85669e+01, -1.41784e+02, 4.28138e+01), forces1[529], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.75729e+01, -3.33632e+02, 1.31688e+02), forces1[530], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.04035e+02, 1.12452e+02, 7.19995e+01), forces1[531], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.61972e+00, 5.32166e+01, -9.89477e+01), forces1[532], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.19982e+01, -2.20164e+02, 9.06987e-01), forces1[533], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.71185e+01, -7.67379e+01, 8.12237e+01), forces1[534], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.80057e+01, -1.09793e+02, -2.04253e+01), forces1[535], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.16821e+02, 1.20240e+02, 5.96457e+01), forces1[536], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.64018e+01, 6.17819e+01, 9.91575e+01), forces1[537], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.55515e+01, -9.66187e+01, -8.19956e+00), forces1[538], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.17947e+01, -1.53378e+01, 1.27485e+00), forces1[539], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.02055e+02, 7.70776e+01, 1.14883e+02), forces1[540], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.43124e+01, 9.43473e+01, 8.60578e+01), forces1[541], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.81264e+01, -1.32125e+02, 2.56224e+01), forces1[542], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.25842e+01, -1.26725e+02, -8.30650e+01), forces1[543], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.50125e+01, -6.20165e+01, 2.58080e+01), forces1[544], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.55319e+01, -1.59769e+01, -7.15921e+01), forces1[545], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.34804e+01, 4.08590e+02, -8.70023e+01), forces1[546], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.53654e+01, -2.03185e+02, -4.39618e+01), forces1[547], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.62931e+01, -2.78936e+02, 5.62579e+00), forces1[548], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.92745e+01, -9.69829e+01, -3.54599e+01), forces1[549], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.58047e+01, -8.17034e+01, 5.89773e+01), forces1[550], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.75002e+01, -7.94191e+01, 7.55542e+01), forces1[551], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-9.53611e+01, 1.20621e+02, 1.49809e+02), forces1[552], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.63438e+01, -6.24402e+01, -1.12122e+01), forces1[553], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.11429e+02, -4.56045e+01, -4.59567e+01), forces1[554], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.28516e+02, -4.47595e+00, 1.81453e+02), forces1[555], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.33297e+02, 1.44805e+02, -4.27640e+01), forces1[556], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.16740e+02, -7.65847e+00, 7.66024e+01), forces1[557], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.77942e+02, -1.45939e+02, 8.07326e+01), forces1[558], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.68632e+02, 2.69537e+02, 1.22007e+02), forces1[559], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.12709e+02, 6.01408e+01, 1.54041e+02), forces1[560], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.27652e+02, -5.25610e+01, -9.60596e+01), forces1[561], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.14047e+02, -2.01466e+01, -4.96293e+01), forces1[562], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.09791e+02, 4.12161e+01, 1.83442e+02), forces1[563], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.49134e+02, -4.62596e+00, 2.20999e+01), forces1[564], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.30637e+02, -3.75250e+01, 4.14259e+01), forces1[565], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.75025e+02, 3.85962e+01, 5.80226e+01), forces1[566], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.98389e+00, -1.23933e+02, 1.30628e+02), forces1[567], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.05449e+01, -1.14065e+02, 9.70791e+01), forces1[568], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.60462e+01, -9.53328e+01, 9.89856e+01), forces1[569], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.13288e+01, -1.44056e+01, 1.39952e+02), forces1[570], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.42917e+01, 1.66166e+01, 1.91947e+02), forces1[571], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.13590e+02, -1.55874e+02, -1.13269e+02), forces1[572], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.42809e+02, 3.88945e+02, 1.47303e+02), forces1[573], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.29792e+02, -1.91594e+02, -4.64513e+01), forces1[574], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.06517e+02, -3.17549e+02, 9.06953e+00), forces1[575], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.35062e+02, -3.38933e+01, -9.66009e+01), forces1[576], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.67609e+02, 1.26402e+02, -4.97788e+01), forces1[577], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.05138e+00, 1.07362e+02, -1.02375e+02), forces1[578], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.22771e+02, -7.72250e+01, 1.66501e+02), forces1[579], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.95650e+01, 8.12102e+00, 1.03117e+02), forces1[580], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.75584e+02, 2.88991e+01, -1.17320e+02), forces1[581], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-6.91275e+01, 8.38319e+01, 4.97708e+01), forces1[582], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.51951e+02, 1.60368e+02, -2.06266e+02), forces1[583], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.31889e+01, -2.02781e+02, -8.72161e+01), forces1[584], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.92408e+02, -1.87100e+01, 2.05541e+02), forces1[585], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.73554e+02, -5.01580e+00, 2.66621e+02), forces1[586], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.59561e+02, 9.15584e+00, 1.28235e+02), forces1[587], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.11016e+01, 7.42097e+01, -4.28122e+01), forces1[588], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.03537e+02, 2.10837e+01, -1.33908e+02), forces1[589], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.16906e+01, -1.58535e+01, 4.67992e+01), forces1[590], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.44325e+02, -2.46328e+00, -1.81854e+01), forces1[591], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-5.30320e+01, 9.72891e+01, 2.06240e+01), forces1[592], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.36896e+01, 1.33852e+02, 5.19553e+01), forces1[593], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 9.50875e+00, -1.63962e+02, -7.41674e+01), forces1[594], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.07601e+02, -8.54691e+01, 3.11595e+01), forces1[595], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.65770e+02, -4.64405e+01, 8.34911e+01), forces1[596], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.44367e+01, -1.84108e+02, 1.39835e+02), forces1[597], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.24114e+02, 2.50886e+01, 2.54009e+01), forces1[598], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.16187e+02, -4.85179e+01, 1.32305e+02), forces1[599], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.37446e+01, -3.29674e+01, 1.16326e+02), forces1[600], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.68011e+01, -1.00073e+02, 8.04682e+01), forces1[601], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-4.83294e+01, -1.73859e+02, 1.36328e+01), forces1[602], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.83292e+01, 1.39303e+02, -1.01045e+02), forces1[603], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.07133e+01, 1.29633e+02, -1.90943e+02), forces1[604], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.55543e+02, 7.87557e+01, 9.29806e+01), forces1[605], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.64013e+02, -2.60759e+01, 1.75076e+02), forces1[606], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.33794e+02, -1.63774e+02, -6.37393e+01), forces1[607], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.54235e+02, 2.41512e+02, 1.60676e+02), forces1[608], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.17775e+02, 6.48107e+01, 3.84545e+01), forces1[609], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.04735e+01, 2.01260e+01, 2.39831e+01), forces1[610], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.38884e+02, 1.20777e+02, -5.46490e+01), forces1[611], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.07723e+02, 2.58444e+02, 1.48247e+02), forces1[612], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.01470e+02, -6.94941e+01, -2.70882e+02), forces1[613], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.21667e+01, -1.98769e+02, -1.54892e+02), forces1[614], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.80724e+02, 4.52486e+01, 1.40398e+02), forces1[615], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 3.86820e+02, -7.75719e+00, -1.08164e+01), forces1[616], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.42790e+02, 4.80985e+01, -6.18837e+00), forces1[617], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.76946e+02, -1.97796e+02, 2.44731e+01), forces1[618], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.47411e+02, 2.23512e+02, -4.11150e+01), forces1[619], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.04834e+01, 5.22527e+01, -2.27808e+01), forces1[620], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.52307e+02, 7.40937e+01, 1.12984e+02), forces1[621], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.32953e+01, -1.29608e+02, 1.32966e+02), forces1[622], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.23861e+01, -1.19511e+02, 1.00268e+02), forces1[623], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.50610e+01, -1.46388e+02, -7.77507e+01), forces1[624], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 8.62300e+01, -1.37666e+02, -1.20764e+02), forces1[625], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.47310e+01, -1.47118e+02, -5.18370e+01), forces1[626], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.62932e+01, 7.13690e+01, 1.43985e+02), forces1[627], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.96823e+01, -3.58054e+01, -1.45690e+02), forces1[628], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.18087e+00, 1.85480e+01, 9.50527e+01), forces1[629], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.74362e+00, 1.43052e+01, -4.25871e+01), forces1[630], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.97525e+02, -1.59562e+01, 1.90143e+01), forces1[631], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 2.57292e+01, -2.08667e+02, 2.11507e+01), forces1[632], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.01669e+01, -1.07214e+02, -2.53008e+01), forces1[633], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.18560e+02, 4.41674e+01, -1.78058e+02), forces1[634], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.93301e+00, 5.90508e+01, -3.94824e+01), forces1[635], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-7.81815e+01, 8.73784e+01, -6.35956e+01), forces1[636], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.52356e+01, 1.30136e+02, 1.52025e+01), forces1[637], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.66178e+02, -5.94385e+01, -1.04578e+02), forces1[638], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-1.19123e+02, -1.75069e+02, -2.04114e+00), forces1[639], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-3.92283e+01, 5.61702e+01, 1.27395e+02), forces1[640], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 4.74836e-01, -2.04058e+02, -4.01525e+01), forces1[641], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 6.92669e+01, 6.04519e+00, 4.03163e+01), forces1[642], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.08236e+01, 1.26554e+02, -8.63729e+01), forces1[643], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.88180e+02, -1.08833e+02, -1.18964e+02), forces1[644], 10*TOL); -ASSERT_EQUAL_VEC(Vec3(-2.76077e+01, -2.97113e+02, 5.08198e+02), forces1[645], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 1.84023e+02, 3.56521e+02, -2.17616e+02), forces1[646], 10*TOL); -ASSERT_EQUAL_VEC(Vec3( 7.81607e+01, 3.17356e+02, -1.40920e+02), forces1[647], 10*TOL); diff --git a/tests/TestCheckpoints.h b/tests/TestCheckpoints.h new file mode 100644 index 000000000..c5dbd08b5 --- /dev/null +++ b/tests/TestCheckpoints.h @@ -0,0 +1,133 @@ +/* -------------------------------------------------------------------------- * + * 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) 2012-2015 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/internal/AssertionUtilities.h" +#include "openmm/AndersenThermostat.h" +#include "openmm/Context.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void compareStates(State& s1, State& s2) { + ASSERT_EQUAL_TOL(s1.getTime(), s2.getTime(), TOL); + int numParticles = s1.getPositions().size(); + for (int i = 0; i < numParticles; i++) { + ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], TOL); + ASSERT_EQUAL_VEC(s1.getVelocities()[i], s2.getVelocities()[i], TOL); + Vec3 a1, b1, c1, a2, b2, c2; + s1.getPeriodicBoxVectors(a1, b1, c1); + s2.getPeriodicBoxVectors(a2, b2, c2); + ASSERT_EQUAL_VEC(a1, a2, TOL); + ASSERT_EQUAL_VEC(b1, b2, TOL); + ASSERT_EQUAL_VEC(c1, c2, TOL); + for (map::const_iterator iter = s1.getParameters().begin(); iter != s1.getParameters().end(); ++iter) + ASSERT_EQUAL(iter->second, (*s2.getParameters().find(iter->first)).second); + } +} + +void testSetState() { + const int numParticles = 10; + const double boxSize = 3.0; + const double temperature = 200.0; + System system; + system.addForce(new AndersenThermostat(0.0, 100.0)); + NonbondedForce* nonbonded = new NonbondedForce(); + system.addForce(nonbonded); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.0); + nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1); + positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + } + VerletIntegrator integrator(0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + context.setParameter(AndersenThermostat::Temperature(), temperature); + + // Run for a little while. + + integrator.step(100); + + // Record the current state. + + State s1 = context.getState(State::Positions | State::Velocities | State::Parameters); + + // Continue the simulation for a few more steps and record a partial state. + + integrator.step(10); + State s2 = context.getState(State::Positions); + + // Restore the original state and see if everything gets restored correctly. + + context.setPeriodicBoxVectors(Vec3(2*boxSize, 0, 0), Vec3(0, 2*boxSize, 0), Vec3(0, 0, 2*boxSize)); + context.setParameter(AndersenThermostat::Temperature(), temperature+10); + context.setState(s1); + State s3 = context.getState(State::Positions | State::Velocities | State::Parameters); + compareStates(s1, s3); + + // Set the partial state and see if the correct things were set. + + context.setState(s2); + State s4 = context.getState(State::Positions | State::Velocities | State::Parameters); + for (int i = 0; i < numParticles; i++) { + ASSERT_EQUAL_VEC(s2.getPositions()[i], s4.getPositions()[i], TOL); + ASSERT_EQUAL_VEC(s1.getVelocities()[i], s4.getVelocities()[i], TOL); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSetState(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestEwald.h b/tests/TestEwald.h new file mode 100644 index 000000000..2ee8a425d --- /dev/null +++ b/tests/TestEwald.h @@ -0,0 +1,405 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.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 "openmm/internal/NonbondedForceImpl.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +void testEwaldExact() { + +// Use a NaCl crystal to compare the calculated and Madelung energies + + const int numParticles = 1000; + const double cutoff = 1.0; + const double boxSize = 2.82; + const double ewaldTol = 1e-5; + + System system; + for (int i = 0; i < numParticles/2; i++) + system.addParticle(22.99); + for (int i = 0; i < numParticles/2; i++) + system.addParticle(35.45); + VerletIntegrator integrator(0.01); + NonbondedForce* nonbonded = new NonbondedForce(); + 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); + nonbonded->setNonbondedMethod(NonbondedForce::Ewald); + nonbonded->setCutoffDistance(cutoff); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + nonbonded->setEwaldErrorTolerance(ewaldTol); + system.addForce(nonbonded); + Context context(system, integrator, platform); + vector positions(numParticles); + #include "nacl_crystal.dat" + context.setPositions(positions); + + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + +// The potential energy of an ion in a crystal is +// E = - (M*e^2/ 4*pi*epsilon0*a0), +// where +// M : Madelung constant (dimensionless, for FCC cells such as NaCl it is 1.7476) +// e : 1.6022 × 10−19 C +// 4*pi*epsilon0: 1.112 × 10−10 C²/(J m) +// a0 : 0.282 x 10-9 m (perfect cell) +// +// E is then the energy per pair of ions, so for our case +// E has to be divided by 2 (per ion), multiplied by N(avogadro), multiplied by number of particles, and divided by 1000 for kJ + double exactEnergy = - (1.7476 * 1.6022e-19 * 1.6022e-19 * 6.02214e+23 * numParticles) / (1.112e-10 * 0.282e-9 * 2 * 1000); + //cout << "exact\t\t: " << exactEnergy << endl; + //cout << "calc\t\t: " << state.getPotentialEnergy() << endl; + ASSERT_EQUAL_TOL(exactEnergy, state.getPotentialEnergy(), 100*ewaldTol); +} + +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; + + 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 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 this matches the Reference platform when using Ewald Method + + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context context(system, integrator1, platform); + Context referenceContext(system, integrator2, reference); + context.setPositions(positions); + referenceContext.setPositions(positions); + State state = context.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], state.getForces()[i], tol); + } + tol = 1e-5; + ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), state.getPotentialEnergy(), tol); + if (!includeExceptions) + ASSERT_EQUAL_TOL(-3.82047e+05, state.getPotentialEnergy(), 1e-5); // Value from Gromacs + +// (2) Check whether Ewald method is self-consistent + + double norm = 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]; + } + + 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 = state.getForces()[i]; + positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + } + VerletIntegrator integrator3(0.01); + Context context2(system, integrator3, platform); + context2.setPositions(positions); + + tol = 1e-2; + State state2 = context2.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/delta, tol) + +// (3) Check whether this matches the Reference platform when using PME + + nonbonded->setNonbondedMethod(NonbondedForce::PME); + context.reinitialize(); + referenceContext.reinitialize(); + context.setPositions(positions); + referenceContext.setPositions(positions); + state = context.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], state.getForces()[i], tol); + } + tol = 1e-5; + ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), state.getPotentialEnergy(), tol); + if (!includeExceptions) + ASSERT_EQUAL_TOL(-3.82047e+05, state.getPotentialEnergy(), 1e-3); // Value from Gromacs + +// (4) Check whether PME method is self-consistent + + norm = 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]; + } + + norm = std::sqrt(norm); + 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); + } + VerletIntegrator integrator4(0.01); + Context context3(system, integrator4, platform); + context3.setPositions(positions); + + tol = 1e-2; + State state3 = context3.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state3.getPotentialEnergy()-state.getPotentialEnergy())/delta, tol) +} + +void testTriclinic() { + // Create a triclinic box containing eight particles. + + System system; + system.setDefaultPeriodicBoxVectors(Vec3(2.5, 0, 0), Vec3(0.5, 3.0, 0), Vec3(0.7, 0.9, 3.5)); + for (int i = 0; i < 8; i++) + system.addParticle(1.0); + NonbondedForce* force = new NonbondedForce(); + system.addForce(force); + force->setNonbondedMethod(NonbondedForce::PME); + force->setCutoffDistance(1.0); + force->setPMEParameters(3.45891, 32, 40, 48); + for (int i = 0; i < 4; i++) + force->addParticle(-1, 0.440104, 0.4184); // Cl parameters + for (int i = 0; i < 4; i++) + force->addParticle(1, 0.332840, 0.0115897); // Na parameters + vector positions(8); + positions[0] = Vec3(1.744, 2.788, 3.162); + positions[1] = Vec3(1.048, 0.762, 2.340); + positions[2] = Vec3(2.489, 1.570, 2.817); + positions[3] = Vec3(1.027, 1.893, 3.271); + positions[4] = Vec3(0.937, 0.825, 0.009); + positions[5] = Vec3(2.290, 1.887, 3.352); + positions[6] = Vec3(1.266, 1.111, 2.894); + positions[7] = Vec3(0.933, 1.862, 3.490); + + // Compute the forces and energy. + + VerletIntegrator integ(0.001); + Context context(system, integ, platform); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + + // Compare them to values computed by Gromacs. + + double expectedEnergy = -963.370; + vector expectedForce(8); + expectedForce[0] = Vec3(4.25253e+01, -1.23503e+02, 1.22139e+02); + expectedForce[1] = Vec3(9.74752e+01, 1.68213e+02, 1.93169e+02); + expectedForce[2] = Vec3(-1.50348e+02, 1.29165e+02, 3.70435e+02); + expectedForce[3] = Vec3(9.18644e+02, -3.52571e+00, -1.34772e+03); + expectedForce[4] = Vec3(-1.61193e+02, 9.01528e+01, -7.12904e+01); + expectedForce[5] = Vec3(2.82630e+02, 2.78029e+01, -3.72864e+02); + expectedForce[6] = Vec3(-1.47454e+02, -2.14448e+02, -3.55789e+02); + expectedForce[7] = Vec3(-8.82195e+02, -7.39132e+01, 1.46202e+03); + for (int i = 0; i < 8; i++) { + ASSERT_EQUAL_VEC(expectedForce[i], state.getForces()[i], 1e-4); + } + ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-4); +} + +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 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); + + // 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 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); + } + if (method == NonbondedForce::PME) { + // See if the PME parameters were calculated correctly. + + double expectedAlpha, actualAlpha; + int expectedSize[3], actualSize[3]; + NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); + force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); + ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); + for (int i = 0; i < 3; i++) { + ASSERT(actualSize[i] >= expectedSize[i]); + ASSERT(actualSize[i] < expectedSize[i]+10); + } + } + } + } +} + +void testPMEParameters() { + // Create a cloud of random point charges. + + const int numParticles = 51; + const double boxWidth = 4.7; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth)); + NonbondedForce* force = new NonbondedForce(); + system.addForce(force); + vector 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(NonbondedForce::PME); + + // Compute the energy with an error tolerance of 1e-3. + + force->setEwaldErrorTolerance(1e-3); + VerletIntegrator integrator1(0.01); + Context context1(system, integrator1, platform); + context1.setPositions(positions); + double energy1 = context1.getState(State::Energy).getPotentialEnergy(); + + // Try again with an error tolerance of 1e-4. + + force->setEwaldErrorTolerance(1e-4); + VerletIntegrator integrator2(0.01); + Context context2(system, integrator2, platform); + context2.setPositions(positions); + double energy2 = context2.getState(State::Energy).getPotentialEnergy(); + + // Now explicitly set the parameters. These should match the values that were + // used for tolerance 1e-3. + + force->setPMEParameters(2.49291157051793, 32, 32, 32); + VerletIntegrator integrator3(0.01); + Context context3(system, integrator3, platform); + context3.setPositions(positions); + double energy3 = context3.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL(energy1, energy3, 1e-6); + ASSERT(fabs((energy1-energy2)/energy1) > 1e-5); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testEwaldExact(); + testEwaldPME(false); + testEwaldPME(true); + testTriclinic(); + testErrorTolerance(NonbondedForce::Ewald); + testErrorTolerance(NonbondedForce::PME); + testPMEParameters(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestGBSAOBCForce.h b/tests/TestGBSAOBCForce.h new file mode 100644 index 000000000..ba5b323d7 --- /dev/null +++ b/tests/TestGBSAOBCForce.h @@ -0,0 +1,283 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "ReferencePlatform.h" +#include "openmm/GBSAOBCForce.h" +#include "openmm/System.h" +#include "openmm/LangevinIntegrator.h" +#include "openmm/NonbondedForce.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSingleParticle() { + 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); + ASSERT(!gbsa->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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 = 0.15+0.14; // probe radius + double nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); + ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); + + // Change the parameters and see if it is still correct. + + gbsa->setParticleParameters(0, 0.4, 0.25, 1); + gbsa->updateParametersInContext(context); + state = context.getState(State::Energy); + bornRadius = 0.25-0.009; // dielectric offset + bornEnergy = (-0.4*0.4/(8*PI_M*eps0))*(1.0/gbsa->getSoluteDielectric()-1.0/gbsa->getSolventDielectric())/bornRadius; + extendedRadius = 0.25+0.14; + nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.25/bornRadius, 6.0); + ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); +} + +void testGlobalSettings() { + System system; + system.addParticle(2.0); + LangevinIntegrator integrator(0, 0.1, 0.01); + GBSAOBCForce* gbsa = new GBSAOBCForce(); + gbsa->addParticle(0.5, 0.15, 1); + const double soluteDielectric = 2.1; + const double solventDielectric = 35.0; + const double surfaceAreaEnergy = 0.75; + gbsa->setSoluteDielectric(soluteDielectric); + gbsa->setSolventDielectric(solventDielectric); + gbsa->setSurfaceAreaEnergy(surfaceAreaEnergy); + system.addForce(gbsa); + ASSERT(!gbsa->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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/soluteDielectric-1.0/solventDielectric)/bornRadius; + double extendedRadius = 0.15+0.14; // probe radius + double nonpolarEnergy = 4*PI_M*surfaceAreaEnergy*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0); + ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01); +} + +void testCutoffAndPeriodic() { + 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 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); + ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); + ASSERT(!gbsa->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + context.setPositions(positions); + State state1 = context.getState(State::Forces); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic); + ASSERT(nonbonded->usesPeriodicBoundaryConditions()); + ASSERT(gbsa->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + context.reinitialize(); + context.setPositions(positions); + State state2 = context.getState(State::Forces); + positions[1][0]+= boxSize; + nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); + gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic); + ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); + ASSERT(!gbsa->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + context.reinitialize(); + context.setPositions(positions); + State state3 = context.getState(State::Forces); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic); + ASSERT(nonbonded->usesPeriodicBoundaryConditions()); + ASSERT(gbsa->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + 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) { + 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, platform); + Context refContext(system, integrator2, reference); + + // Set random (but uniformly distributed) positions for all the particles. + + vector 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 this agrees with the Reference platform. + + 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 and see whether the potential energy changes by the expected amount. + // (This doesn't work with cutoffs, since the energy changes discontinuously at the cutoff distance.) + + if (method == NonbondedForce::NoCutoff) + { + const double delta = 0.3; + double step = 0.5*delta/norm; + vector positions2(numParticles), positions3(numParticles); + for (int i = 0; i < numParticles; ++i) { + Vec3 p = positions[i]; + Vec3 f = state.getForces()[i]; + positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); + } + context.setPositions(positions2); + State state2 = context.getState(State::Energy); + context.setPositions(positions3); + State state3 = context.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-2) + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleParticle(); + testGlobalSettings(); + 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); + } + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestLangevinIntegrator.h b/tests/TestLangevinIntegrator.h new file mode 100644 index 000000000..2f22f334c --- /dev/null +++ b/tests/TestLangevinIntegrator.h @@ -0,0 +1,279 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/LangevinIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSingleBond() { + 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 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; + 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 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; + 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 positions(numParticles); + vector 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 testConstrainedMasslessParticles() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + system.addConstraint(0, 1, 1.5); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + LangevinIntegrator integrator(300.0, 2.0, 0.01); + bool failed = false; + try { + // This should throw an exception. + + Context context(system, integrator, platform); + } + catch (exception& ex) { + failed = true; + } + ASSERT(failed); + + // Now make both particles massless, which should work. + + system.setParticleMass(1, 0.0); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(300.0); + integrator.step(1); + State state = context.getState(State::Velocities); + ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +} + +void testRandomSeed() { + const int numParticles = 8; + const double temp = 100.0; + 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 positions(numParticles); + vector 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]); + } + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleBond(); + testTemperature(); + testConstraints(); + testConstrainedMasslessParticles(); + testRandomSeed(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestLocalEnergyMinimizer.h b/tests/TestLocalEnergyMinimizer.h new file mode 100644 index 000000000..6f7899bb1 --- /dev/null +++ b/tests/TestLocalEnergyMinimizer.h @@ -0,0 +1,215 @@ + +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/LocalEnergyMinimizer.h" +#include "openmm/NonbondedForce.h" +#include "openmm/VerletIntegrator.h" +#include "openmm/VirtualSite.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +void testHarmonicBonds() { + const int numParticles = 10; + System system; + HarmonicBondForce* bonds = new HarmonicBondForce(); + system.addForce(bonds); + + // Create a chain of particles connected by harmonic bonds. + + vector positions(numParticles); + for (int i = 0; i < numParticles; i++) { + system.addParticle(1.0); + positions[i] = Vec3(i, 0, 0); + if (i > 0) + bonds->addBond(i-1, i, 1+0.1*i, 1); + } + + // Minimize it and check that all bonds are at their equilibrium distances. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + LocalEnergyMinimizer::minimize(context, 1e-5); + State state = context.getState(State::Positions); + for (int i = 1; i < numParticles; i++) { + Vec3 delta = state.getPositions()[i]-state.getPositions()[i-1]; + ASSERT_EQUAL_TOL(1+0.1*i, sqrt(delta.dot(delta)), 1e-4); + } +} + +void testLargeSystem() { + const int numMolecules = 25; + const int numParticles = numMolecules*2; + const double cutoff = 2.0; + const double boxSize = 4.0; + const double tolerance = 10; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + NonbondedForce* nonbonded = new NonbondedForce(); + nonbonded->setCutoffDistance(cutoff); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + system.addForce(nonbonded); + + // Create a cloud of molecules. + + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + vector positions(numParticles); + for (int i = 0; i < numMolecules; i++) { + system.addParticle(1.0); + system.addParticle(1.0); + nonbonded->addParticle(-1.0, 0.2, 0.2); + nonbonded->addParticle(1.0, 0.2, 0.2); + 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]); + system.addConstraint(2*i, 2*i+1, 1.0); + } + + // Minimize it and verify that the energy has decreased. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + State initialState = context.getState(State::Forces | State::Energy); + LocalEnergyMinimizer::minimize(context, tolerance); + State finalState = context.getState(State::Forces | State::Energy | State::Positions); + ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); + + // Compute the force magnitude, subtracting off any component parallel to a constraint, and + // check that it satisfies the requested tolerance. + + double forceNorm = 0.0; + for (int i = 0; i < numParticles; i += 2) { + Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; + double distance = sqrt(dir.dot(dir)); + dir *= 1.0/distance; + Vec3 f = finalState.getForces()[i]; + f -= dir*dir.dot(f); + forceNorm += f.dot(f); + f = finalState.getForces()[i+1]; + f -= dir*dir.dot(f); + forceNorm += f.dot(f); + } + forceNorm = sqrt(forceNorm/(5*numMolecules)); + ASSERT(forceNorm < 2*tolerance); +} + +void testVirtualSites() { + const int numMolecules = 25; + const int numParticles = numMolecules*3; + const double cutoff = 2.0; + const double boxSize = 4.0; + const double tolerance = 10; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + NonbondedForce* nonbonded = new NonbondedForce(); + nonbonded->setCutoffDistance(cutoff); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + system.addForce(nonbonded); + + // Create a cloud of molecules. + + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + vector positions(numParticles); + for (int i = 0; i < numMolecules; i++) { + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + nonbonded->addParticle(-1.0, 0.2, 0.2); + nonbonded->addParticle(0.5, 0.2, 0.2); + nonbonded->addParticle(0.5, 0.2, 0.2); + positions[3*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); + positions[3*i+1] = Vec3(positions[3*i][0]+1.0, positions[3*i][1], positions[3*i][2]); + positions[3*i+2] = Vec3(); + system.addConstraint(3*i, 3*i+1, 1.0); + system.setVirtualSite(3*i+2, new TwoParticleAverageSite(3*i, 3*i+1, 0.5, 0.5)); + } + + // Minimize it and verify that the energy has decreased. + + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + context.applyConstraints(1e-5); + State initialState = context.getState(State::Forces | State::Energy); + LocalEnergyMinimizer::minimize(context, tolerance); + State finalState = context.getState(State::Forces | State::Energy | State::Positions); + ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy()); + + // Compute the force magnitude, subtracting off any component parallel to a constraint, and + // check that it satisfies the requested tolerance. + + double forceNorm = 0.0; + for (int i = 0; i < numParticles; i += 3) { + Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i]; + double distance = sqrt(dir.dot(dir)); + dir *= 1.0/distance; + Vec3 f = finalState.getForces()[i]; + f -= dir*dir.dot(f); + forceNorm += f.dot(f); + f = finalState.getForces()[i+1]; + f -= dir*dir.dot(f); + forceNorm += f.dot(f); + + // Check the virtual site location. + + ASSERT_EQUAL_VEC((finalState.getPositions()[i+1]+finalState.getPositions()[i])*0.5, finalState.getPositions()[i+2], 1e-5); + } + forceNorm = sqrt(forceNorm/(5*numMolecules)); + ASSERT(forceNorm < 2*tolerance); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testHarmonicBonds(); + testLargeSystem(); + testVirtualSites(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestMonteCarloAnisotropicBarostat.h b/tests/TestMonteCarloAnisotropicBarostat.h new file mode 100644 index 000000000..149ff63e9 --- /dev/null +++ b/tests/TestMonteCarloAnisotropicBarostat.h @@ -0,0 +1,479 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 Stanford University and the Authors. * + * Authors: Peter Eastman, Lee-Ping Wang * + * 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/internal/AssertionUtilities.h" +#include "openmm/CustomExternalForce.h" +#include "openmm/MonteCarloBarostat.h" +#include "openmm/MonteCarloAnisotropicBarostat.h" +#include "openmm/Context.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/LangevinIntegrator.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +void testIdealGas() { + const int numParticles = 64; + const int frequency = 10; + const int steps = 1000; + const double pressure = 1.5; + const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 + const double temp[] = {300.0, 600.0, 1000.0}; + const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; + const double initialLength = std::pow(initialVolume, 1.0/3.0); + + // Create a gas of noninteracting particles. + + System system; + system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(1.0); + positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); + } + MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], true, true, true, frequency); + system.addForce(barostat); + ASSERT(barostat->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + + // Test it for three different temperatures. + + for (int i = 0; i < 3; i++) { + barostat->setTemperature(temp[i]); + LangevinIntegrator integrator(temp[i], 0.1, 0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + + // Let it equilibrate. + + integrator.step(10000); + + // Now run it for a while and see if the volume is correct. + + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + volume += box[0][0]*box[1][1]*box[2][2]; + integrator.step(frequency); + } + volume /= steps; + double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; + ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); + } +} + +void testIdealGasAxis(int axis) { + // Test scaling just one axis. + const int numParticles = 64; + const int frequency = 10; + const int steps = 1000; + const double pressure = 1.5; + const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 + const double temp[] = {300.0, 600.0, 1000.0}; + const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; + const double initialLength = std::pow(initialVolume, 1.0/3.0); + const bool scaleX = (axis == 0); + const bool scaleY = (axis == 1); + const bool scaleZ = (axis == 2); + double boxX; + double boxY; + double boxZ; + + // Create a gas of noninteracting particles. + + System system; + system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(1.0); + positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); + } + MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], scaleX, scaleY, scaleZ, frequency); + system.addForce(barostat); + ASSERT(barostat->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + + // Test it for three different temperatures. + + for (int i = 0; i < 3; i++) { + barostat->setTemperature(temp[i]); + LangevinIntegrator integrator(temp[i], 0.1, 0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + + // Let it equilibrate. + + integrator.step(10000); + + // Now run it for a while and see if the volume is correct. + + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + boxX = box[0][0]; + boxY = box[1][1]; + boxZ = box[2][2]; + volume += box[0][0]*box[1][1]*box[2][2]; + integrator.step(frequency); + } + volume /= steps; + double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; + ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); + if (!scaleX) { + ASSERT(boxX == initialLength); + } + if (!scaleY) { + ASSERT(boxY == 0.5*initialLength); + } + if (!scaleZ) { + ASSERT(boxZ == 2*initialLength); + } + } +} + +void testRandomSeed() { + const int numParticles = 8; + const double temp = 100.0; + const double pressure = 1.5; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); + VerletIntegrator integrator(0.01); + NonbondedForce* forceField = new NonbondedForce(); + forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + 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); + MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp, true, true, true, 1); + system.addForce(barostat); + ASSERT(barostat->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + vector positions(numParticles); + vector 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. + + barostat->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. + + barostat->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]); + } + } +} + +void testTriclinic() { + const int numParticles = 64; + const int frequency = 10; + const int steps = 1000; + const double pressure = 1.5; + const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 + const double temperature = 300.0; + const double initialVolume = numParticles*BOLTZ*temperature/pressureInMD; + const double initialLength = std::pow(initialVolume, 1.0/3.0); + + // Create a gas of noninteracting particles. + + System system; + Vec3 initialBox[3]; + initialBox[0] = Vec3(initialLength, 0, 0); + initialBox[1] = Vec3(0.2*initialLength, initialLength, 0); + initialBox[2] = Vec3(0.1*initialLength, 0.3*initialLength, initialLength); + system.setDefaultPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(1.0); + positions[i] = Vec3(initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt)); + } + MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temperature, true, true, true, frequency); + system.addForce(barostat); + + // Run a simulation + + LangevinIntegrator integrator(temperature, 0.1, 0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + + // Let it equilibrate. + + integrator.step(10000); + + // Now run it for a while and see if the volume is correct. + + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + volume += box[0][0]*box[1][1]*box[2][2]; + integrator.step(frequency); + } + volume /= steps; + double expected = (numParticles+1)*BOLTZ*temperature/pressureInMD; + ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); + + // Make sure the box vectors have been scaled consistently. + + State state = context.getState(State::Positions); + Vec3 box[3]; + state.getPeriodicBoxVectors(box[0], box[1], box[2]); + double xscale = box[2][0]/(0.1*initialLength); + double yscale = box[2][1]/(0.3*initialLength); + double zscale = box[2][2]/(1.0*initialLength); + for (int i = 0; i < 3; i++) { + ASSERT_EQUAL_VEC(Vec3(xscale*initialBox[i][0], yscale*initialBox[i][1], zscale*initialBox[i][2]), box[i], 1e-5); + } + + // The barostat should have put all particles inside the first periodic box. One integration step + // has happened since then, so they may have moved slightly outside it. + + for (int i = 0; i < numParticles; i++) { + Vec3 pos = state.getPositions()[i]; + ASSERT(pos[2]/box[2][2] > -1 && pos[2]/box[2][2] < 2); + pos -= box[2]*floor(pos[2]/box[2][2]); + ASSERT(pos[1]/box[1][1] > -1 && pos[1]/box[1][1] < 2); + pos -= box[1]*floor(pos[1]/box[1][1]); + ASSERT(pos[0]/box[0][0] > -1 && pos[0]/box[0][0] < 2); + } +} + +/** + * Run a constant pressure simulation on an anisotropic Einstein crystal + * using isotropic and anisotropic barostats. There are a total of 15 simulations: + * + * 1) 3 pressures: 9.0, 10.0, 11.0 bar, for each of the following groups: + * 2) 3 groups of simulations that scale just one axis: x, y, z + * 3) 1 group of simulations that scales all three axes in the anisotropic barostat + * 4) 1 group of simulations that scales all three axes in the isotropic barostat + * + * Results that we will check: + * + * a) In each group of simulations, the volume should decrease with increasing pressure + * b) In the three simulation groups that scale just one axis, the compressibility (i.e. incremental volume change + * with increasing pressure) should go like kx > ky > kz (because the spring constant is largest in the z-direction) + * c) The anisotropic barostat should produce the same result as the isotropic barostat when all three axes are scaled + */ +void testEinsteinCrystal() { + const int numParticles = 64; + const int frequency = 2; + const int equil = 10000; + const int steps = 5000; + const double pressure = 10.0; + const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 + const double temp = 300.0; // Only test one temperature since we're looking at three pressures. + const double pres3[] = {2.0, 8.0, 15.0}; + const double initialVolume = numParticles*BOLTZ*temp/pressureInMD; + const double initialLength = std::pow(initialVolume, 1.0/3.0); + vector initialPositions(3); + vector results; + // Run four groups of anisotropic simulations; scaling just x, y, z, then all three. + for (int a = 0; a < 4; a++) { + // Test barostat for three different pressures. + for (int p = 0; p < 3; p++) { + // Create a system of noninteracting particles attached by harmonic springs to their initial positions. + System system; + system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + // Anisotropic force constants. + CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); + force->addPerParticleParameter("x0"); + force->addPerParticleParameter("y0"); + force->addPerParticleParameter("z0"); + NonbondedForce* nb = new NonbondedForce(); + nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(1.0); + positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); + initialPositions[0] = positions[i][0]; + initialPositions[1] = positions[i][1]; + initialPositions[2] = positions[i][2]; + force->addParticle(i, initialPositions); + nb->addParticle(0, initialLength/6, 0.1); + } + system.addForce(force); + system.addForce(nb); + // Create the barostat. + MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pres3[p], pres3[p], pres3[p]), temp, (a==0||a==3), (a==1||a==3), (a==2||a==3), frequency); + system.addForce(barostat); + barostat->setTemperature(temp); + LangevinIntegrator integrator(temp, 0.1, 0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + // Let it equilibrate. + integrator.step(equil); + // Now run it for a while and see if the volume is correct. + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + volume += box[0][0]*box[1][1]*box[2][2]; + integrator.step(frequency); + } + volume /= steps; + results.push_back(volume); + } + } + for (int p = 0; p < 3; p++) { + // Create a system of noninteracting particles attached by harmonic springs to their initial positions. + System system; + system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength)); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + // Anisotropic force constants. + CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2"); + force->addPerParticleParameter("x0"); + force->addPerParticleParameter("y0"); + force->addPerParticleParameter("z0"); + NonbondedForce* nb = new NonbondedForce(); + nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(1.0); + positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4); + initialPositions[0] = positions[i][0]; + initialPositions[1] = positions[i][1]; + initialPositions[2] = positions[i][2]; + force->addParticle(i, initialPositions); + nb->addParticle(0, initialLength/6, 0.1); + } + system.addForce(force); + system.addForce(nb); + // Create the barostat. + MonteCarloBarostat* barostat = new MonteCarloBarostat(pres3[p], temp, frequency); + system.addForce(barostat); + barostat->setTemperature(temp); + LangevinIntegrator integrator(temp, 0.1, 0.001); + Context context(system, integrator, platform); + context.setPositions(positions); + // Let it equilibrate. + integrator.step(equil); + // Now run it for a while and see if the volume is correct. + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + volume += box[0][0]*box[1][1]*box[2][2]; + integrator.step(frequency); + } + volume /= steps; + results.push_back(volume); + } + + // Check to see if volumes decrease with increasing pressure. + ASSERT_USUALLY_TRUE(results[0] > results[1]); + ASSERT_USUALLY_TRUE(results[1] > results[2]); + ASSERT_USUALLY_TRUE(results[3] > results[4]); + ASSERT_USUALLY_TRUE(results[4] > results[5]); + ASSERT_USUALLY_TRUE(results[6] > results[7]); + ASSERT_USUALLY_TRUE(results[7] > results[8]); + + // Check to see if incremental volume changes with increasing pressure go like kx > ky > kz. + ASSERT_USUALLY_TRUE((results[0] - results[1]) > (results[3] - results[4])); + ASSERT_USUALLY_TRUE((results[1] - results[2]) > (results[4] - results[5])); + ASSERT_USUALLY_TRUE((results[3] - results[4]) > (results[6] - results[7])); + ASSERT_USUALLY_TRUE((results[4] - results[5]) > (results[7] - results[8])); + + // Check to see if the volumes are equal for isotropic and anisotropic (all axis). + ASSERT_USUALLY_EQUAL_TOL(results[9], results[12], 3/std::sqrt((double) steps)); + ASSERT_USUALLY_EQUAL_TOL(results[10], results[13], 3/std::sqrt((double) steps)); + ASSERT_USUALLY_EQUAL_TOL(results[11], results[14], 3/std::sqrt((double) steps)); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testIdealGas(); + testIdealGasAxis(0); + testIdealGasAxis(1); + testIdealGasAxis(2); + testRandomSeed(); + testTriclinic(); + //testEinsteinCrystal(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + diff --git a/tests/TestMonteCarloBarostat.h b/tests/TestMonteCarloBarostat.h new file mode 100644 index 000000000..e02209ed7 --- /dev/null +++ b/tests/TestMonteCarloBarostat.h @@ -0,0 +1,289 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/MonteCarloBarostat.h" +#include "openmm/Context.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/LangevinIntegrator.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include "SimTKOpenMMRealType.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +void testChangingBoxSize() { + System system; + system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 5, 0), Vec3(0, 0, 6)); + system.addParticle(1.0); + NonbondedForce* nb = new NonbondedForce(); + nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + nb->setCutoffDistance(2.0); + nb->addParticle(1, 0.5, 0.5); + system.addForce(nb); + LangevinIntegrator integrator(300.0, 1.0, 0.01); + Context context(system, integrator, platform); + vector positions; + positions.push_back(Vec3()); + context.setPositions(positions); + Vec3 x, y, z; + context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); + ASSERT_EQUAL_VEC(Vec3(4, 0, 0), x, 0); + ASSERT_EQUAL_VEC(Vec3(0, 5, 0), y, 0); + ASSERT_EQUAL_VEC(Vec3(0, 0, 6), z, 0); + context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 9)); + context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); + ASSERT_EQUAL_VEC(Vec3(7, 0, 0), x, 0); + ASSERT_EQUAL_VEC(Vec3(0, 8, 0), y, 0); + ASSERT_EQUAL_VEC(Vec3(0, 0, 9), z, 0); + + // Shrinking the box too small should produce an exception. + + context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 3.9, 0), Vec3(0, 0, 9)); + bool ok = true; + try { + context.getState(State::Forces).getPeriodicBoxVectors(x, y, z); + ok = false; + } + catch (exception& ex) { + } + ASSERT(ok); +} + +void testIdealGas() { + const int numParticles = 64; + const int frequency = 10; + const int steps = 1000; + const double pressure = 1.5; + const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 + const double temp[] = {300.0, 600.0, 1000.0}; + const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD; + const double initialLength = std::pow(initialVolume, 1.0/3.0); + + // Create a gas of noninteracting particles. + + System system; + system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength)); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(1.0); + positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); + } + MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp[0], frequency); + system.addForce(barostat); + ASSERT(barostat->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + + // Test it for three different temperatures. + + for (int i = 0; i < 3; i++) { + barostat->setTemperature(temp[i]); + LangevinIntegrator integrator(temp[i], 0.1, 0.01); + Context context(system, integrator, platform); + context.setPositions(positions); + + // Let it equilibrate. + + integrator.step(10000); + + // Now run it for a while and see if the volume is correct. + + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + volume += box[0][0]*box[1][1]*box[2][2]; + ASSERT_EQUAL_TOL(0.5*box[0][0], box[1][1], 1e-5); + ASSERT_EQUAL_TOL(2*box[0][0], box[2][2], 1e-5); + integrator.step(frequency); + } + volume /= steps; + double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD; + ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps)); + } +} + +void testRandomSeed() { + const int numParticles = 8; + const double temp = 100.0; + const double pressure = 1.5; + System system; + system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8)); + VerletIntegrator integrator(0.01); + NonbondedForce* forceField = new NonbondedForce(); + forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + 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); + MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, 1); + system.addForce(barostat); + ASSERT(barostat->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + vector positions(numParticles); + vector 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. + + barostat->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. + + barostat->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]); + } + } +} + +void testWater() { + const int gridSize = 8; + const int numMolecules = gridSize*gridSize*gridSize; + const int frequency = 10; + const int steps = 400; + const double temp = 273.15; + const double pressure = 3; + const double spacing = 0.32; + const double angle = 109.47*M_PI/180; + const double dOH = 0.1; + const double dHH = dOH*2*std::sin(0.5*angle); + + // Create a box of SPC water molecules. + + System system; + system.setDefaultPeriodicBoxVectors(Vec3(gridSize*spacing, 0, 0), Vec3(0, gridSize*spacing, 0), Vec3(0, 0, gridSize*spacing)); + NonbondedForce* nonbonded = new NonbondedForce(); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + nonbonded->setUseDispersionCorrection(true); + vector positions; + Vec3 offset1(dOH, 0, 0); + Vec3 offset2(dOH*std::cos(angle), dOH*std::sin(angle), 0); + for (int i = 0; i < gridSize; ++i) { + for (int j = 0; j < gridSize; ++j) { + for (int k = 0; k < gridSize; ++k) { + int firstParticle = system.getNumParticles(); + system.addParticle(16.0); + system.addParticle(1.0); + system.addParticle(1.0); + nonbonded->addParticle(-0.82, 0.316557, 0.650194); + nonbonded->addParticle(0.41, 1, 0); + nonbonded->addParticle(0.41, 1, 0); + Vec3 pos = Vec3(spacing*i, spacing*j, spacing*k); + positions.push_back(pos); + positions.push_back(pos+offset1); + positions.push_back(pos+offset2); + system.addConstraint(firstParticle, firstParticle+1, dOH); + system.addConstraint(firstParticle, firstParticle+2, dOH); + system.addConstraint(firstParticle+1, firstParticle+2, dHH); + nonbonded->addException(firstParticle, firstParticle+1, 0, 1, 0); + nonbonded->addException(firstParticle, firstParticle+2, 0, 1, 0); + nonbonded->addException(firstParticle+1, firstParticle+2, 0, 1, 0); + } + } + } + system.addForce(nonbonded); + MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, frequency); + system.addForce(barostat); + + // Simulate it and see if the density matches the expected value (1 g/mL). + + LangevinIntegrator integrator(temp, 1.0, 0.002); + Context context(system, integrator, platform); + context.setPositions(positions); + integrator.step(2000); + double volume = 0.0; + for (int j = 0; j < steps; ++j) { + Vec3 box[3]; + context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]); + volume += box[0][0]*box[1][1]*box[2][2]; + integrator.step(frequency); + } + volume /= steps; + double density = numMolecules*18/(AVOGADRO*volume*1e-21); + ASSERT_USUALLY_EQUAL_TOL(1.0, density, 0.02); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testChangingBoxSize(); + testIdealGas(); + testRandomSeed(); + // Don't run testWater() here, because it's very slow on Reference platform. + // Individual platforms can run it from runPlatformTests(). + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestNonbondedForce.h b/tests/TestNonbondedForce.h new file mode 100644 index 000000000..560318184 --- /dev/null +++ b/tests/TestNonbondedForce.h @@ -0,0 +1,712 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "ReferencePlatform.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testCoulomb() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + NonbondedForce* forceField = new NonbondedForce(); + forceField->addParticle(0.5, 1, 0); + forceField->addParticle(-1.5, 1, 0); + system.addForce(forceField); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& forces = state.getForces(); + double force = ONE_4PI_EPS0*(-0.75)/4.0; + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); + ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(-0.75)/2.0, state.getPotentialEnergy(), TOL); +} + +void testLJ() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + NonbondedForce* forceField = new NonbondedForce(); + forceField->addParticle(0, 1.2, 1); + forceField->addParticle(0, 1.4, 2); + system.addForce(forceField); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& forces = state.getForces(); + double x = 1.3/2.0; + double eps = SQRT_TWO; + double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0; + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL); + ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL); +} + +void testExclusionsAnd14() { + System system; + NonbondedForce* nonbonded = new NonbondedForce(); + for (int i = 0; i < 5; ++i) { + system.addParticle(1.0); + nonbonded->addParticle(0, 1.5, 0); + } + vector > bonds; + bonds.push_back(pair(0, 1)); + bonds.push_back(pair(1, 2)); + bonds.push_back(pair(2, 3)); + bonds.push_back(pair(3, 4)); + nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); + int first14, second14; + for (int i = 0; i < nonbonded->getNumExceptions(); i++) { + int particle1, particle2; + double chargeProd, sigma, epsilon; + nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); + if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) + first14 = i; + if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) + second14 = i; + } + system.addForce(nonbonded); + VerletIntegrator integrator(0.01); + Context context(system, integrator, platform); + for (int i = 1; i < 5; ++i) { + + // Test LJ forces + + vector positions(5); + const double r = 1.0; + for (int j = 0; j < 5; ++j) { + nonbonded->setParticleParameters(j, 0, 1.5, 0); + positions[j] = Vec3(0, j, 0); + } + nonbonded->setParticleParameters(0, 0, 1.5, 1); + nonbonded->setParticleParameters(i, 0, 1.5, 1); + nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); + nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); + positions[i] = Vec3(r, 0, 0); + context.reinitialize(); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double x = 1.5/r; + double eps = 1.0; + double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; + double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); + if (i == 3) { + force *= 0.5; + energy *= 0.5; + } + if (i < 3) { + force = 0; + energy = 0; + } + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); + + // Test Coulomb forces + + nonbonded->setParticleParameters(0, 2, 1.5, 0); + nonbonded->setParticleParameters(i, 2, 1.5, 0); + nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0); + nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); + context.reinitialize(); + context.setPositions(positions); + state = context.getState(State::Forces | State::Energy); + const vector& forces2 = state.getForces(); + force = ONE_4PI_EPS0*4/(r*r); + energy = ONE_4PI_EPS0*4/r; + if (i == 3) { + force /= 1.2; + energy /= 1.2; + } + if (i < 3) { + force = 0; + energy = 0; + } + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); + } +} + +void testCutoff() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + NonbondedForce* forceField = new NonbondedForce(); + forceField->addParticle(1.0, 1, 0); + forceField->addParticle(1.0, 1, 0); + forceField->addParticle(1.0, 1, 0); + forceField->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); + const double cutoff = 2.9; + forceField->setCutoffDistance(cutoff); + const double eps = 50.0; + forceField->setReactionFieldDielectric(eps); + system.addForce(forceField); + ASSERT(!forceField->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector 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& forces = state.getForces(); + const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); + const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); + const double force1 = ONE_4PI_EPS0*(1.0)*(0.25-2.0*krf*2.0); + const double force2 = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); + ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL); + ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL); + const double energy1 = ONE_4PI_EPS0*(1.0)*(0.5+krf*4.0-crf); + const double energy2 = ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf); + ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL); +} + +void testCutoff14() { + System system; + VerletIntegrator integrator(0.01); + NonbondedForce* nonbonded = new NonbondedForce(); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); + for (int i = 0; i < 5; i++) { + system.addParticle(1.0); + nonbonded->addParticle(0, 1.5, 0); + } + const double cutoff = 3.5; + nonbonded->setCutoffDistance(cutoff); + const double eps = 30.0; + nonbonded->setReactionFieldDielectric(eps); + vector > bonds; + bonds.push_back(pair(0, 1)); + bonds.push_back(pair(1, 2)); + bonds.push_back(pair(2, 3)); + bonds.push_back(pair(3, 4)); + nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); + int first14, second14; + for (int i = 0; i < nonbonded->getNumExceptions(); i++) { + int particle1, particle2; + double chargeProd, sigma, epsilon; + nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); + if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) + first14 = i; + if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) + second14 = i; + } + system.addForce(nonbonded); + ASSERT(!nonbonded->usesPeriodicBoundaryConditions()); + ASSERT(!system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector positions(5); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + positions[2] = Vec3(2, 0, 0); + positions[3] = Vec3(3, 0, 0); + positions[4] = Vec3(4, 0, 0); + for (int i = 1; i < 5; ++i) { + + // Test LJ forces + + nonbonded->setParticleParameters(0, 0, 1.5, 1); + for (int j = 1; j < 5; ++j) + nonbonded->setParticleParameters(j, 0, 1.5, 0); + nonbonded->setParticleParameters(i, 0, 1.5, 1); + nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); + nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); + context.reinitialize(); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + double r = positions[i][0]; + double x = 1.5/r; + double e = 1.0; + double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; + double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0)); + if (i == 3) { + force *= 0.5; + energy *= 0.5; + } + if (i < 3 || r > cutoff) { + force = 0; + energy = 0; + } + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); + + // Test Coulomb forces + + const double q = 0.7; + nonbonded->setParticleParameters(0, q, 1.5, 0); + nonbonded->setParticleParameters(i, q, 1.5, 0); + nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0); + nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); + context.reinitialize(); + context.setPositions(positions); + state = context.getState(State::Forces | State::Energy); + const vector& forces2 = state.getForces(); + force = ONE_4PI_EPS0*q*q/(r*r); + energy = ONE_4PI_EPS0*q*q/r; + if (i == 3) { + force /= 1.2; + energy /= 1.2; + } + if (i < 3 || r > cutoff) { + force = 0; + energy = 0; + } + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); + ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); + } +} + +void testPeriodic() { + System system; + system.addParticle(1.0); + 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->addParticle(1.0, 1, 0); + nonbonded->addException(0, 1, 0.0, 1.0, 0.0); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + const double cutoff = 2.0; + nonbonded->setCutoffDistance(cutoff); + system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); + system.addForce(nonbonded); + ASSERT(nonbonded->usesPeriodicBoundaryConditions()); + ASSERT(system.usesPeriodicBoundaryConditions()); + Context context(system, integrator, platform); + vector positions(3); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(2, 0, 0); + positions[2] = Vec3(3, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + const vector& forces = state.getForces(); + const double eps = 78.3; + const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); + const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); + const double force = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0); + ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL); + ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL); + ASSERT_EQUAL_TOL(2*ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL); +} + +void testTriclinic() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + Vec3 a(3.1, 0, 0); + Vec3 b(0.4, 3.5, 0); + Vec3 c(-0.1, -0.5, 4.0); + system.setDefaultPeriodicBoxVectors(a, b, c); + VerletIntegrator integrator(0.01); + NonbondedForce* nonbonded = new NonbondedForce(); + nonbonded->addParticle(1.0, 1, 0); + nonbonded->addParticle(1.0, 1, 0); + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + const double cutoff = 1.5; + nonbonded->setCutoffDistance(cutoff); + system.addForce(nonbonded); + Context context(system, integrator, platform); + vector positions(2); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + const double eps = 78.3; + const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0); + const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0); + for (int iteration = 0; iteration < 50; iteration++) { + // Generate random positions for the two particles. + + positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); + positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt); + context.setPositions(positions); + + // Loop over all possible periodic copies and find the nearest one. + + Vec3 delta; + double distance2 = 100.0; + for (int i = -1; i < 2; i++) + for (int j = -1; j < 2; j++) + for (int k = -1; k < 2; k++) { + Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k; + if (d.dot(d) < distance2) { + delta = d; + distance2 = d.dot(d); + } + } + double distance = sqrt(distance2); + + // See if the force and energy are correct. + + State state = context.getState(State::Forces | State::Energy); + if (distance >= cutoff) { + ASSERT_EQUAL(0.0, state.getPotentialEnergy()); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0); + } + else { + const Vec3 force = delta*ONE_4PI_EPS0*(-1.0/(distance*distance*distance)+2.0*krf); + ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(1.0/distance+krf*distance*distance-crf), state.getPotentialEnergy(), 1e-4); + ASSERT_EQUAL_VEC(force, state.getForces()[0], 1e-4); + ASSERT_EQUAL_VEC(-force, state.getForces()[1], 1e-4); + } + } +} + +void testLargeSystem() { + const int numMolecules = 600; + const int numParticles = numMolecules*2; + const double cutoff = 2.0; + const double boxSize = 20.0; + const double tol = 2e-3; + ReferencePlatform reference; + System system; + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + NonbondedForce* nonbonded = new NonbondedForce(); + HarmonicBondForce* bonds = new HarmonicBondForce(); + vector positions(numParticles); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + for (int i = 0; i < numMolecules; i++) { + if (i < numMolecules/2) { + nonbonded->addParticle(-1.0, 0.2, 0.1); + nonbonded->addParticle(1.0, 0.1, 0.1); + } + else { + nonbonded->addParticle(-1.0, 0.2, 0.2); + nonbonded->addParticle(1.0, 0.1, 0.2); + } + 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)); + bonds->addBond(2*i, 2*i+1, 1.0, 0.1); + nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); + } + + // Try with cutoffs but not periodic boundary conditions, and make sure it agrees with the Reference platform. + + nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); + nonbonded->setCutoffDistance(cutoff); + system.addForce(nonbonded); + system.addForce(bonds); + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context context(system, integrator1, platform); + Context referenceContext(system, integrator2, reference); + context.setPositions(positions); + context.setVelocities(velocities); + referenceContext.setPositions(positions); + referenceContext.setVelocities(velocities); + State state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy); + State referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); + for (int i = 0; i < numParticles; i++) { + ASSERT_EQUAL_VEC(state.getPositions()[i], referenceState.getPositions()[i], tol); + ASSERT_EQUAL_VEC(state.getVelocities()[i], referenceState.getVelocities()[i], tol); + ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol); + } + ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); + + // Now do the same thing with periodic boundary conditions. + + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + context.reinitialize(); + referenceContext.reinitialize(); + context.setPositions(positions); + context.setVelocities(velocities); + referenceContext.setPositions(positions); + referenceContext.setVelocities(velocities); + state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy); + referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); + for (int i = 0; i < numParticles; i++) { + double dx = state.getPositions()[i][0]-referenceState.getPositions()[i][0]; + double dy = state.getPositions()[i][1]-referenceState.getPositions()[i][1]; + double dz = state.getPositions()[i][2]-referenceState.getPositions()[i][2]; + ASSERT_EQUAL_TOL(dx-floor(dx/boxSize+0.5)*boxSize, 0, tol); + ASSERT_EQUAL_TOL(dy-floor(dy/boxSize+0.5)*boxSize, 0, tol); + ASSERT_EQUAL_TOL(dz-floor(dz/boxSize+0.5)*boxSize, 0, tol); + ASSERT_EQUAL_VEC(state.getVelocities()[i], referenceState.getVelocities()[i], tol); + ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol); + } + ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); +} + +void testDispersionCorrection() { + // Create a box full of identical particles. + + int gridSize = 5; + int numParticles = gridSize*gridSize*gridSize; + double boxSize = gridSize*0.7; + double cutoff = boxSize/3; + System system; + VerletIntegrator integrator(0.01); + NonbondedForce* nonbonded = new NonbondedForce(); + vector positions(numParticles); + int index = 0; + for (int i = 0; i < gridSize; i++) + for (int j = 0; j < gridSize; j++) + for (int k = 0; k < gridSize; k++) { + system.addParticle(1.0); + nonbonded->addParticle(0, 1.1, 0.5); + positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); + index++; + } + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + nonbonded->setCutoffDistance(cutoff); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + system.addForce(nonbonded); + + // See if the correction has the correct value. + + Context context(system, integrator, platform); + context.setPositions(positions); + double energy1 = context.getState(State::Energy).getPotentialEnergy(); + nonbonded->setUseDispersionCorrection(false); + context.reinitialize(); + context.setPositions(positions); + double energy2 = context.getState(State::Energy).getPotentialEnergy(); + double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9; + double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3; + double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); + ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); + + // Now modify half the particles to be different, and see if it is still correct. + + int numType2 = 0; + for (int i = 0; i < numParticles; i += 2) { + nonbonded->setParticleParameters(i, 0, 1, 1); + numType2++; + } + int numType1 = numParticles-numType2; + nonbonded->updateParametersInContext(context); + energy2 = context.getState(State::Energy).getPotentialEnergy(); + nonbonded->setUseDispersionCorrection(true); + context.reinitialize(); + context.setPositions(positions); + energy1 = context.getState(State::Energy).getPotentialEnergy(); + term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9; + term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3; + term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9; + term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3; + double combinedSigma = 0.5*(1+1.1); + double combinedEpsilon = sqrt(1*0.5); + term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9; + term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3; + term1 /= (numParticles*(numParticles+1))/2; + term2 /= (numParticles*(numParticles+1))/2; + expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); + ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); +} + +void testChangingParameters() { + const int numMolecules = 600; + const int numParticles = numMolecules*2; + const double cutoff = 2.0; + const double boxSize = 20.0; + const double tol = 2e-3; + ReferencePlatform reference; + System system; + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + NonbondedForce* nonbonded = new NonbondedForce(); + vector positions(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + for (int i = 0; i < numMolecules; i++) { + if (i < numMolecules/2) { + nonbonded->addParticle(-1.0, 0.2, 0.1); + nonbonded->addParticle(1.0, 0.1, 0.1); + } + else { + nonbonded->addParticle(-1.0, 0.2, 0.2); + nonbonded->addParticle(1.0, 0.1, 0.2); + } + 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]); + system.addConstraint(2*i, 2*i+1, 1.0); + nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); + } + nonbonded->setNonbondedMethod(NonbondedForce::PME); + nonbonded->setCutoffDistance(cutoff); + system.addForce(nonbonded); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + + // See if the forces and energies match the Reference platform. + + VerletIntegrator integrator1(0.01); + VerletIntegrator integrator2(0.01); + Context context(system, integrator1, platform); + Context referenceContext(system, integrator2, reference); + context.setPositions(positions); + referenceContext.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + State referenceState = referenceContext.getState(State::Forces | State::Energy); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol); + ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); + + // Now modify parameters and see if they still agree. + + for (int i = 0; i < numParticles; i += 5) { + double charge, sigma, epsilon; + nonbonded->getParticleParameters(i, charge, sigma, epsilon); + nonbonded->setParticleParameters(i, 1.5*charge, 1.1*sigma, 1.7*epsilon); + } + nonbonded->updateParametersInContext(context); + nonbonded->updateParametersInContext(referenceContext); + state = context.getState(State::Forces | State::Energy); + referenceState = referenceContext.getState(State::Forces | State::Energy); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol); + ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); +} + +void testSwitchingFunction(NonbondedForce::NonbondedMethod method) { + System system; + system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6)); + system.addParticle(1.0); + system.addParticle(1.0); + VerletIntegrator integrator(0.01); + NonbondedForce* nonbonded = new NonbondedForce(); + nonbonded->addParticle(0, 1.2, 1); + nonbonded->addParticle(0, 1.4, 2); + nonbonded->setNonbondedMethod(method); + nonbonded->setCutoffDistance(2.0); + nonbonded->setUseSwitchingFunction(true); + nonbonded->setSwitchingDistance(1.5); + nonbonded->setUseDispersionCorrection(false); + system.addForce(nonbonded); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + double eps = SQRT_TWO; + + // Compute the interaction at various distances. + + for (double r = 1.0; r < 2.5; r += 0.1) { + positions[1] = Vec3(r, 0, 0); + context.setPositions(positions); + State state = context.getState(State::Forces | State::Energy); + + // See if the energy is correct. + + double x = 1.3/r; + double expectedEnergy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); + double switchValue; + if (r <= 1.5) + switchValue = 1; + else if (r >= 2.0) + switchValue = 0; + else { + double t = (r-1.5)/0.5; + switchValue = 1+t*t*t*(-10+t*(15-t*6)); + } + ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL); + + // See if the force is the gradient of the energy. + + double delta = 1e-3; + positions[1] = Vec3(r-delta, 0, 0); + context.setPositions(positions); + double e1 = context.getState(State::Energy).getPotentialEnergy(); + positions[1] = Vec3(r+delta, 0, 0); + context.setPositions(positions); + double e2 = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testCoulomb(); + testLJ(); + testExclusionsAnd14(); + testCutoff(); + testCutoff14(); + testPeriodic(); + testTriclinic(); + testLargeSystem(); + testDispersionCorrection(); + testChangingParameters(); + testSwitchingFunction(NonbondedForce::CutoffNonPeriodic); + testSwitchingFunction(NonbondedForce::PME); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestSettle.h b/tests/TestSettle.h new file mode 100644 index 000000000..3e1818ff1 --- /dev/null +++ b/tests/TestSettle.h @@ -0,0 +1,114 @@ + +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/LangevinIntegrator.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +void testConstraints() { + const int numMolecules = 10; + const int numParticles = numMolecules*3; + const int numConstraints = numMolecules*3; + const double temp = 100.0; + System system; + LangevinIntegrator integrator(temp, 2.0, 0.001); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numMolecules; ++i) { + system.addParticle(16.0); + system.addParticle(1.0); + system.addParticle(1.0); + forceField->addParticle(-0.82, 0.317, 0.65); + forceField->addParticle(0.41, 1.0, 0.0); + forceField->addParticle(0.41, 1.0, 0.0); + system.addConstraint(i*3, i*3+1, 0.1); + system.addConstraint(i*3, i*3+2, 0.1); + system.addConstraint(i*3+1, i*3+2, 0.163); + } + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(numParticles); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + for (int i = 0; i < numMolecules; ++i) { + positions[i*3] = Vec3((i%4)*0.4, (i/4)*0.4, 0); + positions[i*3+1] = positions[i*3]+Vec3(0.1, 0, 0); + positions[i*3+2] = positions[i*3]+Vec3(-0.03333, 0.09428, 0); + velocities[i*3] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); + velocities[i*3+1] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); + velocities[i*3+2] = 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) { + integrator.step(1); + State state = context.getState(State::Positions | State::Forces); + 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-5); + } + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testConstraints(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/platforms/cpu/tests/nacl_amorph.dat b/tests/nacl_amorph.dat similarity index 100% rename from platforms/cpu/tests/nacl_amorph.dat rename to tests/nacl_amorph.dat diff --git a/platforms/reference/tests/nacl_crystal.dat b/tests/nacl_crystal.dat similarity index 100% rename from platforms/reference/tests/nacl_crystal.dat rename to tests/nacl_crystal.dat -- GitLab From 8b5d3dc013509e1b3a2b870a9c594f759afe5dfe Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Wed, 23 Sep 2015 13:28:56 -0700 Subject: [PATCH 13/49] Finished refactoring test cases --- .../TestCudaVariableLangevinIntegrator.cpp | 311 +----------- .../TestCudaVariableVerletIntegrator.cpp | 289 +---------- .../cuda/tests/TestCudaVerletIntegrator.cpp | 225 +-------- platforms/cuda/tests/TestCudaVirtualSites.cpp | 454 +---------------- .../TestOpenCLVariableLangevinIntegrator.cpp | 311 +----------- .../TestOpenCLVariableVerletIntegrator.cpp | 289 +---------- .../tests/TestOpenCLVerletIntegrator.cpp | 223 +------- .../opencl/tests/TestOpenCLVirtualSites.cpp | 454 +---------------- ...estReferenceVariableLangevinIntegrator.cpp | 309 +----------- .../TestReferenceVariableVerletIntegrator.cpp | 286 +---------- .../tests/TestReferenceVerletIntegrator.cpp | 218 +------- .../tests/TestReferenceVirtualSites.cpp | 408 +-------------- tests/TestVariableLangevinIntegrator.h | 334 ++++++++++++ tests/TestVariableVerletIntegrator.h | 313 ++++++++++++ tests/TestVerletIntegrator.h | 246 +++++++++ tests/TestVirtualSites.h | 475 ++++++++++++++++++ 16 files changed, 1418 insertions(+), 3727 deletions(-) create mode 100644 tests/TestVariableLangevinIntegrator.h create mode 100644 tests/TestVariableVerletIntegrator.h create mode 100644 tests/TestVerletIntegrator.h create mode 100644 tests/TestVirtualSites.h diff --git a/platforms/cuda/tests/TestCudaVariableLangevinIntegrator.cpp b/platforms/cuda/tests/TestCudaVariableLangevinIntegrator.cpp index 7abb555a5..349e6142f 100644 --- a/platforms/cuda/tests/TestCudaVariableLangevinIntegrator.cpp +++ b/platforms/cuda/tests/TestCudaVariableLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,311 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of VariableLangevinIntegrator. - */ +#include "CudaTests.h" +#include "TestVariableLangevinIntegrator.h" -#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/VariableLangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VariableLangevinIntegrator integrator(0, 0.1, 1e-6); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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); - } - - // Now 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.05); - integrator.step(1); - } -} - -void testTemperature() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 5.0, 5e-5); - 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 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); - context.setVelocitiesToTemperature(temp); - - // Let it equilibrate. - - integrator.step(5000); - - // Now run it for a while and see if the temperature is correct. - - double ke = 0.0; - for (int i = 0; i < 5000; ++i) { - State state = context.getState(State::Energy); - ke += state.getKineticEnergy(); - integrator.step(5); - } - ke /= 5000; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); - integrator.setConstraintTolerance(1e-5); - integrator.setRandomNumberSeed(0); - 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); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 < numParticles-1; ++j) { - Vec3 p1 = state.getPositions()[j]; - Vec3 p2 = state.getPositions()[j+1]; - 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(1.0, dist, 2e-5); - } - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VariableLangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); - 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 positions(numParticles); - vector 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]); - } - } -} - -void testArgonBox() { - const int gridSize = 8; - const double mass = 40.0; // Ar atomic mass - const double temp = 120.0; // K - const double epsilon = BOLTZ * temp; // L-J well depth for Ar - const double sigma = 0.34; // L-J size for Ar in nm - const double density = 0.8; // atoms / sigma^3 - double cellSize = sigma / pow(density, 0.333); - double boxSize = gridSize * cellSize; - double cutoff = 2.0 * sigma; - - // Create a box of argon atoms. - - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const Vec3 half(0.5, 0.5, 0.5); - int numParticles = 0; - for (int i = 0; i < gridSize; i++) { - for (int j = 0; j < gridSize; j++) { - for (int k = 0; k < gridSize; k++) { - system.addParticle(mass); - nonbonded->addParticle(0, sigma, epsilon); - positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); - ++numParticles; - } - } - } - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - VariableLangevinIntegrator integrator(temp, 6.0, 1e-4); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(temp); - - // Equilibrate. - - integrator.stepTo(2.0); - - // Make sure the temperature is correct. - - double ke = 0.0; - for (int i = 0; i < 1000; ++i) { - double t = 2.0 + 0.02 * (i + 1); - integrator.stepTo(t); - State state = context.getState(State::Energy); - ke += state.getKineticEnergy(); - } - ke /= 1000; - double expected = 1.5 * numParticles * BOLTZ * temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.01); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - testArgonBox(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaVariableVerletIntegrator.cpp b/platforms/cuda/tests/TestCudaVariableVerletIntegrator.cpp index 1be1b4861..5385e26d7 100644 --- a/platforms/cuda/tests/TestCudaVariableVerletIntegrator.cpp +++ b/platforms/cuda/tests/TestCudaVariableVerletIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,289 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of VariableVerletIntegrator. - */ +#include "CudaTests.h" +#include "TestVariableVerletIntegrator.h" -#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/VariableVerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VariableVerletIntegrator integrator(1e-6); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - State state = context.getState(State::Energy); - const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); - for (int i = 0; i < 1000; ++i) { - state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*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*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); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); - integrator.step(1); - } -} - -void testConstraints() { - const int numParticles = 8; - const int numConstraints = 5; - const double temp = 100.0; - System system; - VariableVerletIntegrator integrator(1e-5); - 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 positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - 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); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - double finalTime = context.getState(State::Positions).getTime(); - ASSERT(finalTime > 0.1); - - // Now try the stepTo() method. - - finalTime += 0.5; - integrator.stepTo(finalTime); - ASSERT_EQUAL(finalTime, context.getState(State::Positions).getTime()); -} - -void testConstrainedClusters() { - const int numParticles = 7; - System system; - VariableVerletIntegrator integrator(1e-5); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i > 1 ? 1.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - system.addConstraint(0, 1, 1.0); - system.addConstraint(0, 2, 1.0); - system.addConstraint(0, 3, 1.0); - system.addConstraint(0, 4, 1.0); - system.addConstraint(1, 5, 1.0); - system.addConstraint(1, 6, 1.0); - system.addConstraint(2, 3, sqrt(2.0)); - system.addConstraint(2, 4, sqrt(2.0)); - system.addConstraint(3, 4, sqrt(2.0)); - system.addConstraint(5, 6, sqrt(2.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(-1, 0, 0); - positions[3] = Vec3(0, 1, 0); - positions[4] = Vec3(0, 0, 1); - positions[5] = Vec3(2, 0, 0); - positions[6] = Vec3(1, 1, 0); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - ASSERT(context.getState(State::Positions).getTime() > 0.1); -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VariableVerletIntegrator integrator(0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testArgonBox() { - const int gridSize = 8; - const double mass = 40.0; // Ar atomic mass - const double temp = 120.0; // K - const double epsilon = BOLTZ * temp; // L-J well depth for Ar - const double sigma = 0.34; // L-J size for Ar in nm - const double density = 0.8; // atoms / sigma^3 - double cellSize = sigma / pow(density, 0.333); - double boxSize = gridSize * cellSize; - double cutoff = 2.0 * sigma; - - // Create a box of argon atoms. - - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const Vec3 half(0.5, 0.5, 0.5); - for (int i = 0; i < gridSize; i++) { - for (int j = 0; j < gridSize; j++) { - for (int k = 0; k < gridSize; k++) { - system.addParticle(mass); - nonbonded->addParticle(0, sigma, epsilon); - positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); - } - } - } - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - VariableVerletIntegrator integrator(1e-5); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(temp); - - // Equilibrate. - - integrator.stepTo(1.0); - - // Simulate it and see whether energy remains constant. - - State state0 = context.getState(State::Energy); - double initialEnergy = state0.getKineticEnergy() + state0.getPotentialEnergy(); - for (int i = 0; i < 20; i++) { - double t = 1.0 + 0.05*(i+1); - integrator.stepTo(t); - State state = context.getState(State::Energy); - double energy = state.getKineticEnergy() + state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleBond(); - testConstraints(); - testConstrainedClusters(); - testConstrainedMasslessParticles(); - testArgonBox(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/cuda/tests/TestCudaVerletIntegrator.cpp b/platforms/cuda/tests/TestCudaVerletIntegrator.cpp index 811094587..30f8c5d3c 100644 --- a/platforms/cuda/tests/TestCudaVerletIntegrator.cpp +++ b/platforms/cuda/tests/TestCudaVerletIntegrator.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,225 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of VerletIntegrator. - */ +#include "CudaTests.h" +#include "TestVerletIntegrator.h" -#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/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VerletIntegrator integrator(0.01); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - State state = context.getState(State::Energy); - const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); - for (int i = 0; i < 1000; ++i) { - state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*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*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); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - ASSERT_EQUAL_TOL(10.0, context.getState(0).getTime(), 1e-5); -} - -void testConstraints() { - const int numParticles = 8; - const int numConstraints = 5; - const double temp = 100.0; - System system; - VerletIntegrator integrator(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 positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - 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); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } +void runPlatformTests() { } - -void testConstrainedClusters() { - const int numParticles = 7; - System system; - VerletIntegrator integrator(0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i > 1 ? 1.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - system.addConstraint(0, 1, 1.0); - system.addConstraint(0, 2, 1.0); - system.addConstraint(0, 3, 1.0); - system.addConstraint(0, 4, 1.0); - system.addConstraint(1, 5, 1.0); - system.addConstraint(1, 6, 1.0); - system.addConstraint(2, 3, sqrt(2.0)); - system.addConstraint(2, 4, sqrt(2.0)); - system.addConstraint(3, 4, sqrt(2.0)); - system.addConstraint(5, 6, sqrt(2.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(-1, 0, 0); - positions[3] = Vec3(0, 1, 0); - positions[4] = Vec3(0, 0, 1); - positions[5] = Vec3(2, 0, 0); - positions[6] = Vec3(1, 1, 0); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VerletIntegrator integrator(0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testSingleBond(); - testConstraints(); - testConstrainedClusters(); - testConstrainedMasslessParticles(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/cuda/tests/TestCudaVirtualSites.cpp b/platforms/cuda/tests/TestCudaVirtualSites.cpp index be9149b82..bc70454e5 100644 --- a/platforms/cuda/tests/TestCudaVirtualSites.cpp +++ b/platforms/cuda/tests/TestCudaVirtualSites.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2014 Stanford University and the Authors. * + * Portions copyright (c) 2012-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,394 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the CUDA implementation of virtual sites. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "CudaPlatform.h" -#include "openmm/CustomBondForce.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/VirtualSite.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -CudaPlatform platform; - -/** - * Check that massless particles are handled correctly. - */ -void testMasslessParticle() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - CustomBondForce* bonds = new CustomBondForce("-1/r"); - system.addForce(bonds); - vector params; - bonds->addBond(0, 1, params); - VerletIntegrator integrator(0.002); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - vector velocities(2); - velocities[0] = Vec3(0, 0, 0); - velocities[1] = Vec3(0, 1, 0); - context.setVelocities(velocities); - - // The second particle should move in a circular orbit around the first one. - // Compare it to the analytical solution. - - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Velocities | State::Forces); - double time = state.getTime(); - ASSERT_EQUAL_VEC(Vec3(0,0,0), state.getPositions()[0], 0.0); - ASSERT_EQUAL_VEC(Vec3(0,0,0), state.getVelocities()[0], 0.0); - ASSERT_EQUAL_VEC(Vec3(cos(time), sin(time), 0), state.getPositions()[1], 0.01); - ASSERT_EQUAL_VEC(Vec3(-sin(time), cos(time), 0), state.getVelocities()[1], 0.01); - integrator.step(1); - } -} - -/** - * Test a TwoParticleAverageSite virtual site. - */ -void testTwoParticleAverage() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.8, 0.2)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - ASSERT_EQUAL_VEC(pos[0]*0.8+pos[1]*0.2, pos[2], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.1+0.3*0.8, 0, 0), state.getForces()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.2+0.3*0.2, 0, 0), state.getForces()[1], 1e-4); - integrator.step(1); - } -} - -/** - * Test a ThreeParticleAverageSite virtual site. - */ -void testThreeParticleAverage() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new ThreeParticleAverageSite(0, 1, 2, 0.2, 0.3, 0.5)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - params[0] = 0.4; - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(0, 1, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - ASSERT_EQUAL_VEC(pos[0]*0.2+pos[1]*0.3+pos[2]*0.5, pos[3], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.1+0.4*0.2, 0, 0), state.getForces()[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.2+0.4*0.3, 0, 0), state.getForces()[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3+0.4*0.5, 0, 0), state.getForces()[2], 1e-5); - integrator.step(1); - } -} - -/** - * Test an OutOfPlaneSite virtual site. - */ -void testOutOfPlane() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new OutOfPlaneSite(0, 1, 2, 0.3, 0.4, 0.5)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - params[0] = 0.4; - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(0, 1, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - Vec3 v12 = pos[1]-pos[0]; - Vec3 v13 = pos[2]-pos[0]; - Vec3 cross = v12.cross(v13); - ASSERT_EQUAL_VEC(pos[0]+v12*0.3+v13*0.4+cross*0.5, pos[3], 1e-5); - const vector& f = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0.1+0.2+0.3+0.4, 0, 0), f[0]+f[1]+f[2], 1e-5); - Vec3 f2(0.4*0.3, 0.4*0.5*v13[2], -0.4*0.5*v13[1]); - Vec3 f3(0.4*0.4, -0.4*0.5*v12[2], 0.4*0.5*v12[1]); - ASSERT_EQUAL_VEC(Vec3(0.1+0.4, 0, 0)-f2-f3, f[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.2, 0, 0)+f2, f[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3, 0, 0)+f3, f[2], 1e-5); - integrator.step(1); - } -} - -/** - * Test a LocalCoordinatesSite virtual site. - */ -void testLocalCoordinates() { - const Vec3 originWeights(0.2, 0.3, 0.5); - const Vec3 xWeights(-1.0, 0.5, 0.5); - const Vec3 yWeights(0.0, -1.0, 1.0); - const Vec3 localPosition(0.4, 0.3, 0.2); - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new LocalCoordinatesSite(0, 1, 2, originWeights, xWeights, yWeights, localPosition)); - CustomExternalForce* forceField = new CustomExternalForce("2*x^2+3*y^2+4*z^2"); - system.addForce(forceField); - vector params; - forceField->addParticle(0, params); - forceField->addParticle(1, params); - forceField->addParticle(2, params); - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4), positions2(4), positions3(4); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < 100; i++) { - // Set the particles at random positions. - - Vec3 xdir, ydir, zdir; - do { - for (int j = 0; j < 3; j++) - positions[j] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - xdir = positions[0]*xWeights[0] + positions[1]*xWeights[1] + positions[2]*xWeights[2]; - ydir = positions[0]*yWeights[0] + positions[1]*yWeights[1] + positions[2]*yWeights[2]; - zdir = xdir.cross(ydir); - if (sqrt(xdir.dot(xdir)) > 0.1 && sqrt(ydir.dot(ydir)) > 0.1 && sqrt(zdir.dot(zdir)) > 0.1) - break; // These positions give a reasonable coordinate system. - } while (true); - context.setPositions(positions); - context.applyConstraints(0.0001); - - // See if the virtual site is positioned correctly. - - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - Vec3 origin = pos[0]*originWeights[0] + pos[1]*originWeights[1] + pos[2]*originWeights[2]; - xdir /= sqrt(xdir.dot(xdir)); - zdir /= sqrt(zdir.dot(zdir)); - ydir = zdir.cross(xdir); - ASSERT_EQUAL_VEC(origin+xdir*localPosition[0]+ydir*localPosition[1]+zdir*localPosition[2], pos[3], 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < 3; ++i) { - Vec3 f = state.getForces()[i]; - norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; - } - norm = std::sqrt(norm); - const double delta = 1e-2; - double step = 0.5*delta/norm; - for (int i = 0; i < 3; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - context.applyConstraints(0.0001); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - context.applyConstraints(0.0001); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-3) - } -} - -/** - * Make sure that energy, linear momentum, and angular momentum are all conserved - * when using virtual sites. - */ -void testConservationLaws() { - System system; - NonbondedForce* forceField = new NonbondedForce(); - system.addForce(forceField); - vector positions; - - // Create a linear molecule with a TwoParticleAverage virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.4, 0.6)); - system.addConstraint(0, 1, 2.0); - for (int i = 0; i < 3; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i, j, 0, 1, 0); - } - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(2, 0, 0)); - positions.push_back(Vec3()); - - // Create a planar molecule with a ThreeParticleAverage virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(6, new ThreeParticleAverageSite(3, 4, 5, 0.3, 0.5, 0.2)); - system.addConstraint(3, 4, 1.0); - system.addConstraint(3, 5, 1.0); - system.addConstraint(4, 5, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+3, j+3, 0, 1, 0); - } - positions.push_back(Vec3(0, 0, 1)); - positions.push_back(Vec3(1, 0, 1)); - positions.push_back(Vec3(0, 1, 1)); - positions.push_back(Vec3()); - - // Create a tetrahedral molecule with an OutOfPlane virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(10, new OutOfPlaneSite(7, 8, 9, 0.3, 0.5, 0.2)); - system.addConstraint(7, 8, 1.0); - system.addConstraint(7, 9, 1.0); - system.addConstraint(8, 9, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+7, j+7, 0, 1, 0); - } - positions.push_back(Vec3(1, 0, -1)); - positions.push_back(Vec3(2, 0, -1)); - positions.push_back(Vec3(1, 1, -1)); - positions.push_back(Vec3()); - - // Create a molecule with a LocalCoordinatesSite virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(14, new LocalCoordinatesSite(11, 12, 13, Vec3(0.3, 0.3, 0.4), Vec3(1.0, -0.5, -0.5), Vec3(0, -1.0, 1.0), Vec3(0.2, 0.2, 1.0))); - system.addConstraint(11, 12, 1.0); - system.addConstraint(11, 13, 1.0); - system.addConstraint(12, 13, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+11, j+11, 0, 1, 0); - } - positions.push_back(Vec3(1, 2, 0)); - positions.push_back(Vec3(2, 2, 0)); - positions.push_back(Vec3(1, 3, 0)); - positions.push_back(Vec3()); - - // Simulate it and check conservation laws. - - VerletIntegrator integrator(0.002); - Context context(system, integrator, platform); - context.setPositions(positions); - context.applyConstraints(0.0001); - int numParticles = system.getNumParticles(); - double initialEnergy; - Vec3 initialMomentum, initialAngularMomentum; - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - const vector& pos = state.getPositions(); - const vector& vel = state.getVelocities(); - const vector& f = state.getForces(); - double energy = state.getPotentialEnergy(); - for (int j = 0; j < numParticles; j++) { - Vec3 v = vel[j] + f[j]*0.5*integrator.getStepSize(); - energy += 0.5*system.getParticleMass(j)*v.dot(v); - } - if (i == 0) - initialEnergy = energy; - else - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - Vec3 momentum; - for (int j = 0; j < numParticles; j++) - momentum += vel[j]*system.getParticleMass(j); - if (i == 0) - initialMomentum = momentum; - else - ASSERT_EQUAL_VEC(initialMomentum, momentum, 0.02); - Vec3 angularMomentum; - for (int j = 0; j < numParticles; j++) - angularMomentum += pos[j].cross(vel[j])*system.getParticleMass(j); - if (i == 0) - initialAngularMomentum = angularMomentum; - else - ASSERT_EQUAL_VEC(initialAngularMomentum, angularMomentum, 0.03); - integrator.step(1); - } -} +#include "CudaTests.h" +#include "TestVirtualSites.h" /** * Make sure that atom reordering respects virtual sites. @@ -524,64 +138,6 @@ void testReordering() { } } -/** - * Test a System where multiple virtual sites are all calculated from the same particles. - */ -void testOverlappingSites() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - system.addForce(nonbonded); - nonbonded->addParticle(1.0, 0.0, 0.0); - nonbonded->addParticle(-0.5, 0.0, 0.0); - nonbonded->addParticle(-0.5, 0.0, 0.0); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(10, 0, 0)); - positions.push_back(Vec3(0, 10, 0)); - for (int i = 0; i < 20; i++) { - system.addParticle(0.0); - double u = 0.1*((i+1)%4); - double v = 0.05*i; - system.setVirtualSite(3+i, new ThreeParticleAverageSite(0, 1, 2, u, v, 1-u-v)); - nonbonded->addParticle(i%2 == 0 ? -1.0 : 1.0, 0.0, 0.0); - positions.push_back(Vec3()); - } - VerletIntegrator i1(0.002); - VerletIntegrator i2(0.002); - Context c1(system, i1, Platform::getPlatformByName("Reference")); - Context c2(system, i2, platform); - c1.setPositions(positions); - c2.setPositions(positions); - c1.applyConstraints(0.0001); - c2.applyConstraints(0.0001); - State s1 = c1.getState(State::Positions | State::Forces); - State s2 = c2.getState(State::Positions | State::Forces); - for (int i = 0; i < system.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], 1e-5); - for (int i = 0; i < 3; i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 1e-5); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("CudaPrecision", string(argv[1])); - testMasslessParticle(); - testTwoParticleAverage(); - testThreeParticleAverage(); - testOutOfPlane(); - testLocalCoordinates(); - testConservationLaws(); - testReordering(); - testOverlappingSites(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testReordering(); } diff --git a/platforms/opencl/tests/TestOpenCLVariableLangevinIntegrator.cpp b/platforms/opencl/tests/TestOpenCLVariableLangevinIntegrator.cpp index 613e4acf0..dd424404f 100644 --- a/platforms/opencl/tests/TestOpenCLVariableLangevinIntegrator.cpp +++ b/platforms/opencl/tests/TestOpenCLVariableLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,311 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of VariableLangevinIntegrator. - */ +#include "OpenCLTests.h" +#include "TestVariableLangevinIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VariableLangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VariableLangevinIntegrator integrator(0, 0.1, 1e-6); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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); - } - - // Now 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.05); - integrator.step(1); - } -} - -void testTemperature() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 5.0, 5e-5); - 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 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); - context.setVelocitiesToTemperature(temp); - - // Let it equilibrate. - - integrator.step(5000); - - // Now run it for a while and see if the temperature is correct. - - double ke = 0.0; - for (int i = 0; i < 5000; ++i) { - State state = context.getState(State::Energy); - ke += state.getKineticEnergy(); - integrator.step(5); - } - ke /= 5000; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); - integrator.setConstraintTolerance(1e-5); - integrator.setRandomNumberSeed(0); - 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); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 < numParticles-1; ++j) { - Vec3 p1 = state.getPositions()[j]; - Vec3 p2 = state.getPositions()[j+1]; - 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(1.0, dist, 2e-5); - } - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VariableLangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); - 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 positions(numParticles); - vector 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]); - } - } -} - -void testArgonBox() { - const int gridSize = 8; - const double mass = 40.0; // Ar atomic mass - const double temp = 120.0; // K - const double epsilon = BOLTZ * temp; // L-J well depth for Ar - const double sigma = 0.34; // L-J size for Ar in nm - const double density = 0.8; // atoms / sigma^3 - double cellSize = sigma / pow(density, 0.333); - double boxSize = gridSize * cellSize; - double cutoff = 2.0 * sigma; - - // Create a box of argon atoms. - - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const Vec3 half(0.5, 0.5, 0.5); - int numParticles = 0; - for (int i = 0; i < gridSize; i++) { - for (int j = 0; j < gridSize; j++) { - for (int k = 0; k < gridSize; k++) { - system.addParticle(mass); - nonbonded->addParticle(0, sigma, epsilon); - positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); - ++numParticles; - } - } - } - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - VariableLangevinIntegrator integrator(temp, 6.0, 1e-4); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(temp); - - // Equilibrate. - - integrator.stepTo(2.0); - - // Make sure the temperature is correct. - - double ke = 0.0; - for (int i = 0; i < 1000; ++i) { - double t = 2.0 + 0.02 * (i + 1); - integrator.stepTo(t); - State state = context.getState(State::Energy); - ke += state.getKineticEnergy(); - } - ke /= 1000; - double expected = 1.5 * numParticles * BOLTZ * temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.01); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - testArgonBox(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLVariableVerletIntegrator.cpp b/platforms/opencl/tests/TestOpenCLVariableVerletIntegrator.cpp index 523462e6a..c8ca9155e 100644 --- a/platforms/opencl/tests/TestOpenCLVariableVerletIntegrator.cpp +++ b/platforms/opencl/tests/TestOpenCLVariableVerletIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,289 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of VariableVerletIntegrator. - */ +#include "OpenCLTests.h" +#include "TestVariableVerletIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VariableVerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VariableVerletIntegrator integrator(1e-6); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - State state = context.getState(State::Energy); - const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); - for (int i = 0; i < 1000; ++i) { - state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*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*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); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); - integrator.step(1); - } -} - -void testConstraints() { - const int numParticles = 8; - const int numConstraints = 5; - System system; - VariableVerletIntegrator integrator(1e-5); - 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 positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - 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); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - double finalTime = context.getState(State::Positions).getTime(); - ASSERT(finalTime > 0.1); - - // Now try the stepTo() method. - - finalTime += 0.5; - integrator.stepTo(finalTime); - ASSERT_EQUAL(finalTime, context.getState(State::Positions).getTime()); -} - -void testConstrainedClusters() { - const int numParticles = 7; - System system; - VariableVerletIntegrator integrator(1e-5); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i > 1 ? 1.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - system.addConstraint(0, 1, 1.0); - system.addConstraint(0, 2, 1.0); - system.addConstraint(0, 3, 1.0); - system.addConstraint(0, 4, 1.0); - system.addConstraint(1, 5, 1.0); - system.addConstraint(1, 6, 1.0); - system.addConstraint(2, 3, sqrt(2.0)); - system.addConstraint(2, 4, sqrt(2.0)); - system.addConstraint(3, 4, sqrt(2.0)); - system.addConstraint(5, 6, sqrt(2.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(-1, 0, 0); - positions[3] = Vec3(0, 1, 0); - positions[4] = Vec3(0, 0, 1); - positions[5] = Vec3(2, 0, 0); - positions[6] = Vec3(1, 1, 0); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - ASSERT(context.getState(State::Positions).getTime() > 0.1); -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VariableVerletIntegrator integrator(0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - - -void testArgonBox() { - const int gridSize = 8; - const double mass = 40.0; // Ar atomic mass - const double temp = 120.0; // K - const double epsilon = BOLTZ * temp; // L-J well depth for Ar - const double sigma = 0.34; // L-J size for Ar in nm - const double density = 0.8; // atoms / sigma^3 - double cellSize = sigma / pow(density, 0.333); - double boxSize = gridSize * cellSize; - double cutoff = 2.0 * sigma; - - // Create a box of argon atoms. - - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const Vec3 half(0.5, 0.5, 0.5); - for (int i = 0; i < gridSize; i++) { - for (int j = 0; j < gridSize; j++) { - for (int k = 0; k < gridSize; k++) { - system.addParticle(mass); - nonbonded->addParticle(0, sigma, epsilon); - positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); - } - } - } - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - VariableVerletIntegrator integrator(1e-5); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(temp); - - // Equilibrate. - - integrator.stepTo(1.0); - - // Simulate it and see whether energy remains constant. - - State state0 = context.getState(State::Energy); - double initialEnergy = state0.getKineticEnergy() + state0.getPotentialEnergy(); - for (int i = 0; i < 20; i++) { - double t = 1.0 + 0.05*(i+1); - integrator.stepTo(t); - State state = context.getState(State::Energy); - double energy = state.getKineticEnergy() + state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - } -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSingleBond(); - testConstraints(); - testConstrainedClusters(); - testConstrainedMasslessParticles(); - testArgonBox(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/opencl/tests/TestOpenCLVerletIntegrator.cpp b/platforms/opencl/tests/TestOpenCLVerletIntegrator.cpp index ae1a7f588..681b74842 100644 --- a/platforms/opencl/tests/TestOpenCLVerletIntegrator.cpp +++ b/platforms/opencl/tests/TestOpenCLVerletIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,223 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of VerletIntegrator. - */ +#include "OpenCLTests.h" +#include "TestVerletIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VerletIntegrator integrator(0.01); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - State state = context.getState(State::Energy); - const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); - for (int i = 0; i < 1000; ++i) { - state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*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*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); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -void testConstraints() { - const int numParticles = 8; - const int numConstraints = 5; - System system; - VerletIntegrator integrator(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 positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - 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); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } +void runPlatformTests() { } - -void testConstrainedClusters() { - const int numParticles = 7; - System system; - VerletIntegrator integrator(0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i > 1 ? 1.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - system.addConstraint(0, 1, 1.0); - system.addConstraint(0, 2, 1.0); - system.addConstraint(0, 3, 1.0); - system.addConstraint(0, 4, 1.0); - system.addConstraint(1, 5, 1.0); - system.addConstraint(1, 6, 1.0); - system.addConstraint(2, 3, sqrt(2.0)); - system.addConstraint(2, 4, sqrt(2.0)); - system.addConstraint(3, 4, sqrt(2.0)); - system.addConstraint(5, 6, sqrt(2.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(-1, 0, 0); - positions[3] = Vec3(0, 1, 0); - positions[4] = Vec3(0, 0, 1); - positions[5] = Vec3(2, 0, 0); - positions[6] = Vec3(1, 1, 0); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VerletIntegrator integrator(0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testSingleBond(); - testConstraints(); - testConstrainedClusters(); - testConstrainedMasslessParticles(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/opencl/tests/TestOpenCLVirtualSites.cpp b/platforms/opencl/tests/TestOpenCLVirtualSites.cpp index 09e690fe1..1cc5cdca5 100644 --- a/platforms/opencl/tests/TestOpenCLVirtualSites.cpp +++ b/platforms/opencl/tests/TestOpenCLVirtualSites.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2014 Stanford University and the Authors. * + * Portions copyright (c) 2012-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,394 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the OpenCL implementation of virtual sites. - */ - -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "OpenCLPlatform.h" -#include "openmm/CustomBondForce.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/VirtualSite.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -static OpenCLPlatform platform; - -/** - * Check that massless particles are handled correctly. - */ -void testMasslessParticle() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - CustomBondForce* bonds = new CustomBondForce("-1/r"); - system.addForce(bonds); - vector params; - bonds->addBond(0, 1, params); - VerletIntegrator integrator(0.002); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - vector velocities(2); - velocities[0] = Vec3(0, 0, 0); - velocities[1] = Vec3(0, 1, 0); - context.setVelocities(velocities); - - // The second particle should move in a circular orbit around the first one. - // Compare it to the analytical solution. - - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Velocities | State::Forces); - double time = state.getTime(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getPositions()[0], 0.0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getVelocities()[0], 0.0); - ASSERT_EQUAL_VEC(Vec3(cos(time), sin(time), 0), state.getPositions()[1], 0.01); - ASSERT_EQUAL_VEC(Vec3(-sin(time), cos(time), 0), state.getVelocities()[1], 0.01); - integrator.step(1); - } -} - -/** - * Test a TwoParticleAverageSite virtual site. - */ -void testTwoParticleAverage() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.8, 0.2)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - ASSERT_EQUAL_VEC(pos[0]*0.8+pos[1]*0.2, pos[2], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.1+0.3*0.8, 0, 0), state.getForces()[0], 1e-4); - ASSERT_EQUAL_VEC(Vec3(0.2+0.3*0.2, 0, 0), state.getForces()[1], 1e-4); - integrator.step(1); - } -} - -/** - * Test a ThreeParticleAverageSite virtual site. - */ -void testThreeParticleAverage() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new ThreeParticleAverageSite(0, 1, 2, 0.2, 0.3, 0.5)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - params[0] = 0.4; - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(0, 1, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - ASSERT_EQUAL_VEC(pos[0]*0.2+pos[1]*0.3+pos[2]*0.5, pos[3], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.1+0.4*0.2, 0, 0), state.getForces()[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.2+0.4*0.3, 0, 0), state.getForces()[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3+0.4*0.5, 0, 0), state.getForces()[2], 1e-5); - integrator.step(1); - } -} - -/** - * Test an OutOfPlaneSite virtual site. - */ -void testOutOfPlane() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new OutOfPlaneSite(0, 1, 2, 0.3, 0.4, 0.5)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - params[0] = 0.4; - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(0, 1, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - Vec3 v12 = pos[1]-pos[0]; - Vec3 v13 = pos[2]-pos[0]; - Vec3 cross = v12.cross(v13); - ASSERT_EQUAL_VEC(pos[0]+v12*0.3+v13*0.4+cross*0.5, pos[3], 1e-5); - const vector& f = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0.1+0.2+0.3+0.4, 0, 0), f[0]+f[1]+f[2], 1e-5); - Vec3 f2(0.4*0.3, 0.4*0.5*v13[2], -0.4*0.5*v13[1]); - Vec3 f3(0.4*0.4, -0.4*0.5*v12[2], 0.4*0.5*v12[1]); - ASSERT_EQUAL_VEC(Vec3(0.1+0.4, 0, 0)-f2-f3, f[0], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.2, 0, 0)+f2, f[1], 1e-5); - ASSERT_EQUAL_VEC(Vec3(0.3, 0, 0)+f3, f[2], 1e-5); - integrator.step(1); - } -} - -/** - * Test a LocalCoordinatesSite virtual site. - */ -void testLocalCoordinates() { - const Vec3 originWeights(0.2, 0.3, 0.5); - const Vec3 xWeights(-1.0, 0.5, 0.5); - const Vec3 yWeights(0.0, -1.0, 1.0); - const Vec3 localPosition(0.4, 0.3, 0.2); - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new LocalCoordinatesSite(0, 1, 2, originWeights, xWeights, yWeights, localPosition)); - CustomExternalForce* forceField = new CustomExternalForce("2*x^2+3*y^2+4*z^2"); - system.addForce(forceField); - vector params; - forceField->addParticle(0, params); - forceField->addParticle(1, params); - forceField->addParticle(2, params); - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4), positions2(4), positions3(4); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < 100; i++) { - // Set the particles at random positions. - - Vec3 xdir, ydir, zdir; - do { - for (int j = 0; j < 3; j++) - positions[j] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - xdir = positions[0]*xWeights[0] + positions[1]*xWeights[1] + positions[2]*xWeights[2]; - ydir = positions[0]*yWeights[0] + positions[1]*yWeights[1] + positions[2]*yWeights[2]; - zdir = xdir.cross(ydir); - if (sqrt(xdir.dot(xdir)) > 0.1 && sqrt(ydir.dot(ydir)) > 0.1 && sqrt(zdir.dot(zdir)) > 0.1) - break; // These positions give a reasonable coordinate system. - } while (true); - context.setPositions(positions); - context.applyConstraints(0.0001); - - // See if the virtual site is positioned correctly. - - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - Vec3 origin = pos[0]*originWeights[0] + pos[1]*originWeights[1] + pos[2]*originWeights[2]; - xdir /= sqrt(xdir.dot(xdir)); - zdir /= sqrt(zdir.dot(zdir)); - ydir = zdir.cross(xdir); - ASSERT_EQUAL_VEC(origin+xdir*localPosition[0]+ydir*localPosition[1]+zdir*localPosition[2], pos[3], 1e-5); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < 3; ++i) { - Vec3 f = state.getForces()[i]; - norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; - } - norm = std::sqrt(norm); - const double delta = 1e-2; - double step = 0.5*delta/norm; - for (int i = 0; i < 3; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - context.applyConstraints(0.0001); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - context.applyConstraints(0.0001); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-3) - } -} - -/** - * Make sure that energy, linear momentum, and angular momentum are all conserved - * when using virtual sites. - */ -void testConservationLaws() { - System system; - NonbondedForce* forceField = new NonbondedForce(); - system.addForce(forceField); - vector positions; - - // Create a linear molecule with a TwoParticleAverage virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.4, 0.6)); - system.addConstraint(0, 1, 2.0); - for (int i = 0; i < 3; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i, j, 0, 1, 0); - } - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(2, 0, 0)); - positions.push_back(Vec3()); - - // Create a planar molecule with a ThreeParticleAverage virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(6, new ThreeParticleAverageSite(3, 4, 5, 0.3, 0.5, 0.2)); - system.addConstraint(3, 4, 1.0); - system.addConstraint(3, 5, 1.0); - system.addConstraint(4, 5, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+3, j+3, 0, 1, 0); - } - positions.push_back(Vec3(0, 0, 1)); - positions.push_back(Vec3(1, 0, 1)); - positions.push_back(Vec3(0, 1, 1)); - positions.push_back(Vec3()); - - // Create a tetrahedral molecule with an OutOfPlane virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(10, new OutOfPlaneSite(7, 8, 9, 0.3, 0.5, 0.2)); - system.addConstraint(7, 8, 1.0); - system.addConstraint(7, 9, 1.0); - system.addConstraint(8, 9, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+7, j+7, 0, 1, 0); - } - positions.push_back(Vec3(1, 0, -1)); - positions.push_back(Vec3(2, 0, -1)); - positions.push_back(Vec3(1, 1, -1)); - positions.push_back(Vec3()); - - // Create a molecule with a LocalCoordinatesSite virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(14, new LocalCoordinatesSite(11, 12, 13, Vec3(0.3, 0.3, 0.4), Vec3(1.0, -0.5, -0.5), Vec3(0, -1.0, 1.0), Vec3(0.2, 0.2, 1.0))); - system.addConstraint(11, 12, 1.0); - system.addConstraint(11, 13, 1.0); - system.addConstraint(12, 13, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+11, j+11, 0, 1, 0); - } - positions.push_back(Vec3(1, 2, 0)); - positions.push_back(Vec3(2, 2, 0)); - positions.push_back(Vec3(1, 3, 0)); - positions.push_back(Vec3()); - - // Simulate it and check conservation laws. - - VerletIntegrator integrator(0.002); - Context context(system, integrator, platform); - context.setPositions(positions); - context.applyConstraints(0.0001); - int numParticles = system.getNumParticles(); - double initialEnergy; - Vec3 initialMomentum, initialAngularMomentum; - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - const vector& pos = state.getPositions(); - const vector& vel = state.getVelocities(); - const vector& f = state.getForces(); - double energy = state.getPotentialEnergy(); - for (int j = 0; j < numParticles; j++) { - Vec3 v = vel[j] + f[j]*0.5*integrator.getStepSize(); - energy += 0.5*system.getParticleMass(j)*v.dot(v); - } - if (i == 0) - initialEnergy = energy; - else - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - Vec3 momentum; - for (int j = 0; j < numParticles; j++) - momentum += vel[j]*system.getParticleMass(j); - if (i == 0) - initialMomentum = momentum; - else - ASSERT_EQUAL_VEC(initialMomentum, momentum, 0.02); - Vec3 angularMomentum; - for (int j = 0; j < numParticles; j++) - angularMomentum += pos[j].cross(vel[j])*system.getParticleMass(j); - if (i == 0) - initialAngularMomentum = angularMomentum; - else - ASSERT_EQUAL_VEC(initialAngularMomentum, angularMomentum, 0.05); - integrator.step(1); - } -} +#include "OpenCLTests.h" +#include "TestVirtualSites.h" /** * Make sure that atom reordering respects virtual sites. @@ -524,64 +138,6 @@ void testReordering() { } } -/** - * Test a System where multiple virtual sites are all calculated from the same particles. - */ -void testOverlappingSites() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - NonbondedForce* nonbonded = new NonbondedForce(); - system.addForce(nonbonded); - nonbonded->addParticle(1.0, 0.0, 0.0); - nonbonded->addParticle(-0.5, 0.0, 0.0); - nonbonded->addParticle(-0.5, 0.0, 0.0); - vector positions; - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(10, 0, 0)); - positions.push_back(Vec3(0, 10, 0)); - for (int i = 0; i < 20; i++) { - system.addParticle(0.0); - double u = 0.1*((i+1)%4); - double v = 0.05*i; - system.setVirtualSite(3+i, new ThreeParticleAverageSite(0, 1, 2, u, v, 1-u-v)); - nonbonded->addParticle(i%2 == 0 ? -1.0 : 1.0, 0.0, 0.0); - positions.push_back(Vec3()); - } - VerletIntegrator i1(0.002); - VerletIntegrator i2(0.002); - Context c1(system, i1, Platform::getPlatformByName("Reference")); - Context c2(system, i2, platform); - c1.setPositions(positions); - c2.setPositions(positions); - c1.applyConstraints(0.0001); - c2.applyConstraints(0.0001); - State s1 = c1.getState(State::Positions | State::Forces); - State s2 = c2.getState(State::Positions | State::Forces); - for (int i = 0; i < system.getNumParticles(); i++) - ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], 1e-5); - for (int i = 0; i < 3; i++) - ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 1e-5); -} - -int main(int argc, char* argv[]) { - try { - if (argc > 1) - platform.setPropertyDefaultValue("OpenCLPrecision", string(argv[1])); - testMasslessParticle(); - testTwoParticleAverage(); - testThreeParticleAverage(); - testOutOfPlane(); - testLocalCoordinates(); - testConservationLaws(); - testReordering(); - testOverlappingSites(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { + testReordering(); } diff --git a/platforms/reference/tests/TestReferenceVariableLangevinIntegrator.cpp b/platforms/reference/tests/TestReferenceVariableLangevinIntegrator.cpp index d6fa874fc..e201686a2 100644 --- a/platforms/reference/tests/TestReferenceVariableLangevinIntegrator.cpp +++ b/platforms/reference/tests/TestReferenceVariableLangevinIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,309 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of VariableLangevinIntegrator. - */ +#include "ReferenceTests.h" +#include "TestVariableLangevinIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VariableLangevinIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VariableLangevinIntegrator integrator(0, 0.1, 1e-6); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector 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); - } - - // Now 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.05); - integrator.step(1); - } -} - -void testTemperature() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 5.0, 5e-5); - 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 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); - context.setVelocitiesToTemperature(temp); - - // Let it equilibrate. - - integrator.step(5000); - - // Now run it for a while and see if the temperature is correct. - - double ke = 0.0; - for (int i = 0; i < 5000; ++i) { - State state = context.getState(State::Energy); - ke += state.getKineticEnergy(); - integrator.step(5); - } - ke /= 5000; - double expected = 0.5*numParticles*3*BOLTZ*temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); - integrator.setConstraintTolerance(1e-5); - integrator.setRandomNumberSeed(0); - 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); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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 < numParticles-1; ++j) { - Vec3 p1 = state.getPositions()[j]; - Vec3 p2 = state.getPositions()[j+1]; - 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(1.0, dist, 2e-5); - } - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VariableLangevinIntegrator integrator(300.0, 2.0, 0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -void testRandomSeed() { - const int numParticles = 8; - const double temp = 100.0; - System system; - VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); - 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 positions(numParticles); - vector 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]); - } - } -} - -void testArgonBox() { - const int gridSize = 8; - const double mass = 40.0; // Ar atomic mass - const double temp = 120.0; // K - const double epsilon = BOLTZ * temp; // L-J well depth for Ar - const double sigma = 0.34; // L-J size for Ar in nm - const double density = 0.8; // atoms / sigma^3 - double cellSize = sigma / pow(density, 0.333); - double boxSize = gridSize * cellSize; - double cutoff = 2.0 * sigma; - - // Create a box of argon atoms. - - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const Vec3 half(0.5, 0.5, 0.5); - int numParticles = 0; - for (int i = 0; i < gridSize; i++) { - for (int j = 0; j < gridSize; j++) { - for (int k = 0; k < gridSize; k++) { - system.addParticle(mass); - nonbonded->addParticle(0, sigma, epsilon); - positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); - ++numParticles; - } - } - } - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - VariableLangevinIntegrator integrator(temp, 6.0, 1e-4); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(temp); - - // Equilibrate. - - integrator.stepTo(2.0); - - // Make sure the temperature is correct. - - double ke = 0.0; - for (int i = 0; i < 1000; ++i) { - double t = 2.0 + 0.02 * (i + 1); - integrator.stepTo(t); - State state = context.getState(State::Energy); - ke += state.getKineticEnergy(); - } - ke /= 1000; - double expected = 1.5 * numParticles * BOLTZ * temp; - ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.01); -} - -int main() { - try { - testSingleBond(); - testTemperature(); - testConstraints(); - testConstrainedMasslessParticles(); - testRandomSeed(); - testArgonBox(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceVariableVerletIntegrator.cpp b/platforms/reference/tests/TestReferenceVariableVerletIntegrator.cpp index 120400486..dc0abd34c 100644 --- a/platforms/reference/tests/TestReferenceVariableVerletIntegrator.cpp +++ b/platforms/reference/tests/TestReferenceVariableVerletIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,286 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of VariableVerletIntegrator. - */ +#include "ReferenceTests.h" +#include "TestVariableVerletIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VariableVerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VariableVerletIntegrator integrator(1e-6); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0; - State state = context.getState(State::Energy); - const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); - for (int i = 0; i < 1000; ++i) { - state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*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*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); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); - integrator.step(1); - } - ASSERT(state.getTime() > 1.0); -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 500.0; - System system; - VariableVerletIntegrator integrator(1e-5); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - double finalTime = context.getState(State::Positions).getTime(); - ASSERT(finalTime > 0.1); - - // Now try the stepTo() method. - - finalTime += 0.5; - integrator.stepTo(finalTime); - ASSERT_EQUAL(finalTime, context.getState(State::Positions).getTime()); -} - -void testConstrainedClusters() { - const int numParticles = 7; - const double temp = 500.0; - System system; - VariableVerletIntegrator integrator(1e-5); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i > 1 ? 1.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - system.addConstraint(0, 1, 1.0); - system.addConstraint(0, 2, 1.0); - system.addConstraint(0, 3, 1.0); - system.addConstraint(0, 4, 1.0); - system.addConstraint(1, 5, 1.0); - system.addConstraint(1, 6, 1.0); - system.addConstraint(2, 3, sqrt(2.0)); - system.addConstraint(2, 4, sqrt(2.0)); - system.addConstraint(3, 4, sqrt(2.0)); - system.addConstraint(5, 6, sqrt(2.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(-1, 0, 0); - positions[3] = Vec3(0, 1, 0); - positions[4] = Vec3(0, 0, 1); - positions[5] = Vec3(2, 0, 0); - positions[6] = Vec3(1, 1, 0); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } - ASSERT(context.getState(State::Positions).getTime() > 0.1); -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VariableVerletIntegrator integrator(0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +void runPlatformTests() { } - -void testArgonBox() { - const int gridSize = 8; - const double mass = 40.0; // Ar atomic mass - const double temp = 120.0; // K - const double epsilon = BOLTZ * temp; // L-J well depth for Ar - const double sigma = 0.34; // L-J size for Ar in nm - const double density = 0.8; // atoms / sigma^3 - double cellSize = sigma / pow(density, 0.333); - double boxSize = gridSize * cellSize; - double cutoff = 2.0 * sigma; - - // Create a box of argon atoms. - - System system; - NonbondedForce* nonbonded = new NonbondedForce(); - vector positions; - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - const Vec3 half(0.5, 0.5, 0.5); - for (int i = 0; i < gridSize; i++) { - for (int j = 0; j < gridSize; j++) { - for (int k = 0; k < gridSize; k++) { - system.addParticle(mass); - nonbonded->addParticle(0, sigma, epsilon); - positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); - } - } - } - - nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); - nonbonded->setCutoffDistance(cutoff); - system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); - system.addForce(nonbonded); - - VariableVerletIntegrator integrator(1e-5); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(temp); - - // Equilibrate. - - integrator.stepTo(1.0); - - // Simulate it and see whether energy remains constant. - - State state0 = context.getState(State::Energy); - double initialEnergy = state0.getKineticEnergy() + state0.getPotentialEnergy(); - for (int i = 0; i < 20; i++) { - double t = 1.0 + 0.05*(i+1); - integrator.stepTo(t); - State state = context.getState(State::Energy); - double energy = state.getKineticEnergy() + state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - } -} - -int main() { - try { - testSingleBond(); - testConstraints(); - testConstrainedClusters(); - testConstrainedMasslessParticles(); - testArgonBox(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; -} - diff --git a/platforms/reference/tests/TestReferenceVerletIntegrator.cpp b/platforms/reference/tests/TestReferenceVerletIntegrator.cpp index c3eb060e8..48c1a11d8 100644 --- a/platforms/reference/tests/TestReferenceVerletIntegrator.cpp +++ b/platforms/reference/tests/TestReferenceVerletIntegrator.cpp @@ -6,7 +6,7 @@ * 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. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,218 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of VerletIntegrator. - */ +#include "ReferenceTests.h" +#include "TestVerletIntegrator.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/HarmonicBondForce.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "SimTKOpenMMRealType.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -const double TOL = 1e-5; - -void testSingleBond() { - System system; - system.addParticle(2.0); - system.addParticle(2.0); - VerletIntegrator integrator(0.01); - HarmonicBondForce* forceField = new HarmonicBondForce(); - forceField->addBond(0, 1, 1.5, 1); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - - // This is simply a harmonic oscillator, so compare it to the analytical solution. - - const double freq = 1.0;; - State state = context.getState(State::Energy); - const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); - for (int i = 0; i < 1000; ++i) { - state = context.getState(State::Positions | State::Velocities | State::Energy); - double time = state.getTime(); - double expectedDist = 1.5+0.5*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*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); - double energy = state.getKineticEnergy()+state.getPotentialEnergy(); - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -void testConstraints() { - const int numParticles = 8; - const double temp = 500.0; - System system; - VerletIntegrator integrator(0.002); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i%2 == 0 ? 5.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - for (int i = 0; i < numParticles-1; ++i) - system.addConstraint(i, i+1, 1.0); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - vector 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getPotentialEnergy()+state.getKineticEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -void testConstrainedClusters() { - const int numParticles = 7; - const double temp = 500.0; - System system; - VerletIntegrator integrator(0.001); - integrator.setConstraintTolerance(1e-5); - NonbondedForce* forceField = new NonbondedForce(); - for (int i = 0; i < numParticles; ++i) { - system.addParticle(i > 1 ? 1.0 : 10.0); - forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); - } - system.addConstraint(0, 1, 1.0); - system.addConstraint(0, 2, 1.0); - system.addConstraint(0, 3, 1.0); - system.addConstraint(0, 4, 1.0); - system.addConstraint(1, 5, 1.0); - system.addConstraint(1, 6, 1.0); - system.addConstraint(2, 3, sqrt(2.0)); - system.addConstraint(2, 4, sqrt(2.0)); - system.addConstraint(3, 4, sqrt(2.0)); - system.addConstraint(5, 6, sqrt(2.0)); - system.addForce(forceField); - Context context(system, integrator, platform); - vector positions(numParticles); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(-1, 0, 0); - positions[3] = Vec3(0, 1, 0); - positions[4] = Vec3(0, 0, 1); - positions[5] = Vec3(2, 0, 0); - positions[6] = Vec3(1, 1, 0); - vector velocities(numParticles); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - - for (int i = 0; i < numParticles; ++i) - 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. - - double initialEnergy = 0.0; - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); - for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); - } - double energy = state.getPotentialEnergy()+state.getKineticEnergy(); - if (i == 1) - initialEnergy = energy; - else if (i > 1) - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - integrator.step(1); - } -} - -void testConstrainedMasslessParticles() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - system.addConstraint(0, 1, 1.5); - vector positions(2); - positions[0] = Vec3(-1, 0, 0); - positions[1] = Vec3(1, 0, 0); - VerletIntegrator integrator(0.01); - bool failed = false; - try { - // This should throw an exception. - - Context context(system, integrator, platform); - } - catch (exception& ex) { - failed = true; - } - ASSERT(failed); - - // Now make both particles massless, which should work. - - system.setParticleMass(1, 0.0); - Context context(system, integrator, platform); - context.setPositions(positions); - context.setVelocitiesToTemperature(300.0); - integrator.step(1); - State state = context.getState(State::Velocities | State::Positions); - ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); -} - -int main() { - try { - testSingleBond(); - testConstraints(); - testConstrainedClusters(); - testConstrainedMasslessParticles(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/platforms/reference/tests/TestReferenceVirtualSites.cpp b/platforms/reference/tests/TestReferenceVirtualSites.cpp index ff4afab9e..57be3478d 100644 --- a/platforms/reference/tests/TestReferenceVirtualSites.cpp +++ b/platforms/reference/tests/TestReferenceVirtualSites.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2012-2014 Stanford University and the Authors. * + * Portions copyright (c) 2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -29,408 +29,8 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -/** - * This tests the reference implementation of virtual sites. - */ +#include "ReferenceTests.h" +#include "TestVirtualSites.h" -#include "openmm/internal/AssertionUtilities.h" -#include "openmm/Context.h" -#include "ReferencePlatform.h" -#include "openmm/CustomBondForce.h" -#include "openmm/CustomExternalForce.h" -#include "openmm/LangevinIntegrator.h" -#include "openmm/NonbondedForce.h" -#include "openmm/System.h" -#include "openmm/VerletIntegrator.h" -#include "openmm/VirtualSite.h" -#include "sfmt/SFMT.h" -#include -#include - -using namespace OpenMM; -using namespace std; - -ReferencePlatform platform; - -/** - * Check that massless particles are handled correctly. - */ -void testMasslessParticle() { - System system; - system.addParticle(0.0); - system.addParticle(1.0); - CustomBondForce* bonds = new CustomBondForce("-1/r"); - system.addForce(bonds); - vector params; - bonds->addBond(0, 1, params); - VerletIntegrator integrator(0.002); - Context context(system, integrator, platform); - vector positions(2); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - vector velocities(2); - velocities[0] = Vec3(0, 0, 0); - velocities[1] = Vec3(0, 1, 0); - context.setVelocities(velocities); - - // The second particle should move in a circular orbit around the first one. - // Compare it to the analytical solution. - - for (int i = 0; i < 1000; ++i) { - State state = context.getState(State::Positions | State::Velocities | State::Forces); - double time = state.getTime(); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getPositions()[0], 0.0); - ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getVelocities()[0], 0.0); - ASSERT_EQUAL_VEC(Vec3(cos(time), sin(time), 0), state.getPositions()[1], 0.01); - ASSERT_EQUAL_VEC(Vec3(-sin(time), cos(time), 0), state.getVelocities()[1], 0.01); - integrator.step(1); - } -} - -/** - * Test a TwoParticleAverageSite virtual site. - */ -void testTwoParticleAverage() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.8, 0.2)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(3); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - ASSERT_EQUAL_VEC(pos[0]*0.8+pos[1]*0.2, pos[2], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.1+0.3*0.8, 0, 0), state.getForces()[0], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.2+0.3*0.2, 0, 0), state.getForces()[1], 1e-10); - integrator.step(1); - } -} - -/** - * Test a ThreeParticleAverageSite virtual site. - */ -void testThreeParticleAverage() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new ThreeParticleAverageSite(0, 1, 2, 0.2, 0.3, 0.5)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - params[0] = 0.4; - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(0, 1, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - ASSERT_EQUAL_VEC(pos[0]*0.2+pos[1]*0.3+pos[2]*0.5, pos[3], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.1+0.4*0.2, 0, 0), state.getForces()[0], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.2+0.4*0.3, 0, 0), state.getForces()[1], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.3+0.4*0.5, 0, 0), state.getForces()[2], 1e-10); - integrator.step(1); - } -} - -/** - * Test an OutOfPlaneSite virtual site. - */ -void testOutOfPlane() { - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new OutOfPlaneSite(0, 1, 2, 0.3, 0.4, 0.5)); - CustomExternalForce* forceField = new CustomExternalForce("-a*x"); - system.addForce(forceField); - forceField->addPerParticleParameter("a"); - vector params(1); - params[0] = 0.1; - forceField->addParticle(0, params); - params[0] = 0.2; - forceField->addParticle(1, params); - params[0] = 0.3; - forceField->addParticle(2, params); - params[0] = 0.4; - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4); - positions[0] = Vec3(0, 0, 0); - positions[1] = Vec3(1, 0, 0); - positions[2] = Vec3(0, 1, 0); - context.setPositions(positions); - context.applyConstraints(0.0001); - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - Vec3 v12 = pos[1]-pos[0]; - Vec3 v13 = pos[2]-pos[0]; - Vec3 cross = v12.cross(v13); - ASSERT_EQUAL_VEC(pos[0]+v12*0.3+v13*0.4+cross*0.5, pos[3], 1e-10); - const vector& f = state.getForces(); - ASSERT_EQUAL_VEC(Vec3(0.1+0.2+0.3+0.4, 0, 0), f[0]+f[1]+f[2], 1e-10); - Vec3 f2(0.4*0.3, 0.4*0.5*v13[2], -0.4*0.5*v13[1]); - Vec3 f3(0.4*0.4, -0.4*0.5*v12[2], 0.4*0.5*v12[1]); - ASSERT_EQUAL_VEC(Vec3(0.1+0.4, 0, 0)-f2-f3, f[0], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.2, 0, 0)+f2, f[1], 1e-10); - ASSERT_EQUAL_VEC(Vec3(0.3, 0, 0)+f3, f[2], 1e-10); - integrator.step(1); - } -} - -/** - * Test a LocalCoordinatesSite virtual site. - */ -void testLocalCoordinates() { - const Vec3 originWeights(0.2, 0.3, 0.5); - const Vec3 xWeights(-1.0, 0.5, 0.5); - const Vec3 yWeights(0.0, -1.0, 1.0); - const Vec3 localPosition(0.4, 0.3, 0.2); - System system; - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(3, new LocalCoordinatesSite(0, 1, 2, originWeights, xWeights, yWeights, localPosition)); - CustomExternalForce* forceField = new CustomExternalForce("2*x^2+3*y^2+4*z^2"); - system.addForce(forceField); - vector params; - forceField->addParticle(0, params); - forceField->addParticle(1, params); - forceField->addParticle(2, params); - forceField->addParticle(3, params); - LangevinIntegrator integrator(300.0, 0.1, 0.002); - Context context(system, integrator, platform); - vector positions(4), positions2(4), positions3(4); - OpenMM_SFMT::SFMT sfmt; - init_gen_rand(0, sfmt); - for (int i = 0; i < 100; i++) { - // Set the particles at random positions. - - Vec3 xdir, ydir, zdir; - do { - for (int j = 0; j < 3; j++) - positions[j] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); - xdir = positions[0]*xWeights[0] + positions[1]*xWeights[1] + positions[2]*xWeights[2]; - ydir = positions[0]*yWeights[0] + positions[1]*yWeights[1] + positions[2]*yWeights[2]; - zdir = xdir.cross(ydir); - if (sqrt(xdir.dot(xdir)) > 0.1 && sqrt(ydir.dot(ydir)) > 0.1 && sqrt(zdir.dot(zdir)) > 0.1) - break; // These positions give a reasonable coordinate system. - } while (true); - context.setPositions(positions); - context.applyConstraints(0.0001); - - // See if the virtual site is positioned correctly. - - State state = context.getState(State::Positions | State::Forces); - const vector& pos = state.getPositions(); - Vec3 origin = pos[0]*originWeights[0] + pos[1]*originWeights[1] + pos[2]*originWeights[2]; - xdir /= sqrt(xdir.dot(xdir)); - zdir /= sqrt(zdir.dot(zdir)); - ydir = zdir.cross(xdir); - ASSERT_EQUAL_VEC(origin+xdir*localPosition[0]+ydir*localPosition[1]+zdir*localPosition[2], pos[3], 1e-10); - - // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. - - double norm = 0.0; - for (int i = 0; i < 3; ++i) { - Vec3 f = state.getForces()[i]; - norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; - } - norm = std::sqrt(norm); - const double delta = 1e-2; - double step = 0.5*delta/norm; - for (int i = 0; i < 3; ++i) { - Vec3 p = positions[i]; - Vec3 f = state.getForces()[i]; - positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); - positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); - } - context.setPositions(positions2); - context.applyConstraints(0.0001); - State state2 = context.getState(State::Energy); - context.setPositions(positions3); - context.applyConstraints(0.0001); - State state3 = context.getState(State::Energy); - ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-3) - } -} - -/** - * Make sure that energy, linear momentum, and angular momentum are all conserved - * when using virtual sites. - */ -void testConservationLaws() { - System system; - NonbondedForce* forceField = new NonbondedForce(); - system.addForce(forceField); - vector positions; - - // Create a linear molecule with a TwoParticleAverage virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.4, 0.6)); - system.addConstraint(0, 1, 2.0); - for (int i = 0; i < 3; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i, j, 0, 1, 0); - } - positions.push_back(Vec3(0, 0, 0)); - positions.push_back(Vec3(2, 0, 0)); - positions.push_back(Vec3()); - - // Create a planar molecule with a ThreeParticleAverage virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(6, new ThreeParticleAverageSite(3, 4, 5, 0.3, 0.5, 0.2)); - system.addConstraint(3, 4, 1.0); - system.addConstraint(3, 5, 1.0); - system.addConstraint(4, 5, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+3, j+3, 0, 1, 0); - } - positions.push_back(Vec3(0, 0, 1)); - positions.push_back(Vec3(1, 0, 1)); - positions.push_back(Vec3(0, 1, 1)); - positions.push_back(Vec3()); - - // Create a tetrahedral molecule with an OutOfPlane virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(10, new OutOfPlaneSite(7, 8, 9, 0.3, 0.5, 0.2)); - system.addConstraint(7, 8, 1.0); - system.addConstraint(7, 9, 1.0); - system.addConstraint(8, 9, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+7, j+7, 0, 1, 0); - } - positions.push_back(Vec3(1, 0, -1)); - positions.push_back(Vec3(2, 0, -1)); - positions.push_back(Vec3(1, 1, -1)); - positions.push_back(Vec3()); - - // Create a molecule with a LocalCoordinatesSite virtual site. - - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(1.0); - system.addParticle(0.0); - system.setVirtualSite(14, new LocalCoordinatesSite(11, 12, 13, Vec3(0.3, 0.3, 0.4), Vec3(1.0, -0.5, -0.5), Vec3(0, -1.0, 1.0), Vec3(0.2, 0.2, 1.0))); - system.addConstraint(11, 12, 1.0); - system.addConstraint(11, 13, 1.0); - system.addConstraint(12, 13, sqrt(2.0)); - for (int i = 0; i < 4; i++) { - forceField->addParticle(0, 1, 10); - for (int j = 0; j < i; j++) - forceField->addException(i+11, j+11, 0, 1, 0); - } - positions.push_back(Vec3(1, 2, 0)); - positions.push_back(Vec3(2, 2, 0)); - positions.push_back(Vec3(1, 3, 0)); - positions.push_back(Vec3()); - - // Simulate it and check conservation laws. - - VerletIntegrator integrator(0.002); - Context context(system, integrator, platform); - context.setPositions(positions); - context.applyConstraints(0.0001); - int numParticles = system.getNumParticles(); - double initialEnergy; - Vec3 initialMomentum, initialAngularMomentum; - for (int i = 0; i < 1000; i++) { - State state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy); - const vector& pos = state.getPositions(); - const vector& vel = state.getVelocities(); - const vector& f = state.getForces(); - double energy = state.getPotentialEnergy(); - for (int j = 0; j < numParticles; j++) { - Vec3 v = vel[j] + f[j]*0.5*integrator.getStepSize(); - energy += 0.5*system.getParticleMass(j)*v.dot(v); - } - if (i == 0) - initialEnergy = energy; - else - ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); - Vec3 momentum; - for (int j = 0; j < numParticles; j++) - momentum += vel[j]*system.getParticleMass(j); - if (i == 0) - initialMomentum = momentum; - else - ASSERT_EQUAL_VEC(initialMomentum, momentum, 1e-10); - Vec3 angularMomentum; - for (int j = 0; j < numParticles; j++) - angularMomentum += pos[j].cross(vel[j])*system.getParticleMass(j); - if (i == 0) - initialAngularMomentum = angularMomentum; - else - ASSERT_EQUAL_VEC(initialAngularMomentum, angularMomentum, 1e-10); - integrator.step(1); - } -} - -int main() { - try { - testMasslessParticle(); - testTwoParticleAverage(); - testThreeParticleAverage(); - testOutOfPlane(); - testLocalCoordinates(); - testConservationLaws(); - } - catch(const exception& e) { - cout << "exception: " << e.what() << endl; - return 1; - } - cout << "Done" << endl; - return 0; +void runPlatformTests() { } diff --git a/tests/TestVariableLangevinIntegrator.h b/tests/TestVariableLangevinIntegrator.h new file mode 100644 index 000000000..2cf8282cd --- /dev/null +++ b/tests/TestVariableLangevinIntegrator.h @@ -0,0 +1,334 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VariableLangevinIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSingleBond() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + VariableLangevinIntegrator integrator(0, 0.1, 1e-6); + HarmonicBondForce* forceField = new HarmonicBondForce(); + forceField->addBond(0, 1, 1.5, 1); + system.addForce(forceField); + Context context(system, integrator, platform); + vector 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); + } + + // Now 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.05); + integrator.step(1); + } +} + +void testTemperature() { + const int numParticles = 8; + const double temp = 100.0; + System system; + VariableLangevinIntegrator integrator(temp, 5.0, 5e-5); + 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 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); + context.setVelocitiesToTemperature(temp); + + // Let it equilibrate. + + integrator.step(5000); + + // Now run it for a while and see if the temperature is correct. + + double ke = 0.0; + for (int i = 0; i < 5000; ++i) { + State state = context.getState(State::Energy); + ke += state.getKineticEnergy(); + integrator.step(5); + } + ke /= 5000; + double expected = 0.5*numParticles*3*BOLTZ*temp; + ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.1); +} + +void testConstraints() { + const int numParticles = 8; + const double temp = 100.0; + System system; + VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); + integrator.setConstraintTolerance(1e-5); + integrator.setRandomNumberSeed(0); + 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); + } + for (int i = 0; i < numParticles-1; ++i) + system.addConstraint(i, i+1, 1.0); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(numParticles); + vector 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 < numParticles-1; ++j) { + Vec3 p1 = state.getPositions()[j]; + Vec3 p2 = state.getPositions()[j+1]; + 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(1.0, dist, 2e-5); + } + integrator.step(1); + } +} + +void testConstrainedMasslessParticles() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + system.addConstraint(0, 1, 1.5); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + VariableLangevinIntegrator integrator(300.0, 2.0, 0.01); + bool failed = false; + try { + // This should throw an exception. + + Context context(system, integrator, platform); + } + catch (exception& ex) { + failed = true; + } + ASSERT(failed); + + // Now make both particles massless, which should work. + + system.setParticleMass(1, 0.0); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(300.0); + integrator.step(1); + State state = context.getState(State::Velocities); + ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +} + +void testRandomSeed() { + const int numParticles = 8; + const double temp = 100.0; + System system; + VariableLangevinIntegrator integrator(temp, 2.0, 1e-5); + 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 positions(numParticles); + vector 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]); + } + } +} + +void testArgonBox() { + const int gridSize = 8; + const double mass = 40.0; // Ar atomic mass + const double temp = 120.0; // K + const double epsilon = BOLTZ * temp; // L-J well depth for Ar + const double sigma = 0.34; // L-J size for Ar in nm + const double density = 0.8; // atoms / sigma^3 + double cellSize = sigma / pow(density, 0.333); + double boxSize = gridSize * cellSize; + double cutoff = 2.0 * sigma; + + // Create a box of argon atoms. + + System system; + NonbondedForce* nonbonded = new NonbondedForce(); + vector positions; + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + const Vec3 half(0.5, 0.5, 0.5); + int numParticles = 0; + for (int i = 0; i < gridSize; i++) { + for (int j = 0; j < gridSize; j++) { + for (int k = 0; k < gridSize; k++) { + system.addParticle(mass); + nonbonded->addParticle(0, sigma, epsilon); + positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); + ++numParticles; + } + } + } + + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + nonbonded->setCutoffDistance(cutoff); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + system.addForce(nonbonded); + + VariableLangevinIntegrator integrator(temp, 6.0, 1e-4); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(temp); + + // Equilibrate. + + integrator.stepTo(2.0); + + // Make sure the temperature is correct. + + double ke = 0.0; + for (int i = 0; i < 1000; ++i) { + double t = 2.0 + 0.02 * (i + 1); + integrator.stepTo(t); + State state = context.getState(State::Energy); + ke += state.getKineticEnergy(); + } + ke /= 1000; + double expected = 1.5 * numParticles * BOLTZ * temp; + ASSERT_USUALLY_EQUAL_TOL(expected, ke, 0.01); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleBond(); + testTemperature(); + testConstraints(); + testConstrainedMasslessParticles(); + testRandomSeed(); + testArgonBox(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestVariableVerletIntegrator.h b/tests/TestVariableVerletIntegrator.h new file mode 100644 index 000000000..133be36e2 --- /dev/null +++ b/tests/TestVariableVerletIntegrator.h @@ -0,0 +1,313 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VariableVerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSingleBond() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + VariableVerletIntegrator integrator(1e-6); + HarmonicBondForce* forceField = new HarmonicBondForce(); + forceField->addBond(0, 1, 1.5, 1); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + + // This is simply a harmonic oscillator, so compare it to the analytical solution. + + const double freq = 1.0; + State state = context.getState(State::Energy); + const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); + for (int i = 0; i < 1000; ++i) { + state = context.getState(State::Positions | State::Velocities | State::Energy); + double time = state.getTime(); + double expectedDist = 1.5+0.5*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*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); + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); + integrator.step(1); + } + ASSERT(state.getTime() > 1.0); +} + +void testConstraints() { + const int numParticles = 8; + const int numConstraints = 5; + System system; + VariableVerletIntegrator integrator(1e-5); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i%2 == 0 ? 5.0 : 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 positions(numParticles); + vector 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. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); + 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); + } + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + if (i == 1) + initialEnergy = energy; + else if (i > 1) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + integrator.step(1); + } + double finalTime = context.getState(State::Positions).getTime(); + ASSERT(finalTime > 0.1); + + // Now try the stepTo() method. + + finalTime += 0.5; + integrator.stepTo(finalTime); + ASSERT_EQUAL(finalTime, context.getState(State::Positions).getTime()); +} + +void testConstrainedClusters() { + const int numParticles = 7; + System system; + VariableVerletIntegrator integrator(1e-5); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i > 1 ? 1.0 : 10.0); + forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); + } + system.addConstraint(0, 1, 1.0); + system.addConstraint(0, 2, 1.0); + system.addConstraint(0, 3, 1.0); + system.addConstraint(0, 4, 1.0); + system.addConstraint(1, 5, 1.0); + system.addConstraint(1, 6, 1.0); + system.addConstraint(2, 3, sqrt(2.0)); + system.addConstraint(2, 4, sqrt(2.0)); + system.addConstraint(3, 4, sqrt(2.0)); + system.addConstraint(5, 6, sqrt(2.0)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(numParticles); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + positions[2] = Vec3(-1, 0, 0); + positions[3] = Vec3(0, 1, 0); + positions[4] = Vec3(0, 0, 1); + positions[5] = Vec3(2, 0, 0); + positions[6] = Vec3(1, 1, 0); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + for (int i = 0; i < numParticles; ++i) + 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. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); + for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); + } + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + if (i == 1) + initialEnergy = energy; + else if (i > 1) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + integrator.step(1); + } + ASSERT(context.getState(State::Positions).getTime() > 0.1); +} + +void testConstrainedMasslessParticles() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + system.addConstraint(0, 1, 1.5); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + VariableVerletIntegrator integrator(0.01); + bool failed = false; + try { + // This should throw an exception. + + Context context(system, integrator, platform); + } + catch (exception& ex) { + failed = true; + } + ASSERT(failed); + + // Now make both particles massless, which should work. + + system.setParticleMass(1, 0.0); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(300.0); + integrator.step(1); + State state = context.getState(State::Velocities); + ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +} + +void testArgonBox() { + const int gridSize = 8; + const double mass = 40.0; // Ar atomic mass + const double temp = 120.0; // K + const double epsilon = BOLTZ * temp; // L-J well depth for Ar + const double sigma = 0.34; // L-J size for Ar in nm + const double density = 0.8; // atoms / sigma^3 + double cellSize = sigma / pow(density, 0.333); + double boxSize = gridSize * cellSize; + double cutoff = 2.0 * sigma; + + // Create a box of argon atoms. + + System system; + NonbondedForce* nonbonded = new NonbondedForce(); + vector positions; + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + const Vec3 half(0.5, 0.5, 0.5); + for (int i = 0; i < gridSize; i++) { + for (int j = 0; j < gridSize; j++) { + for (int k = 0; k < gridSize; k++) { + system.addParticle(mass); + nonbonded->addParticle(0, sigma, epsilon); + positions.push_back((Vec3(i, j, k) + half + Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*0.1) * cellSize); + } + } + } + + nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); + nonbonded->setCutoffDistance(cutoff); + system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); + system.addForce(nonbonded); + + VariableVerletIntegrator integrator(1e-5); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(temp); + + // Equilibrate. + + integrator.stepTo(1.0); + + // Simulate it and see whether energy remains constant. + + State state0 = context.getState(State::Energy); + double initialEnergy = state0.getKineticEnergy() + state0.getPotentialEnergy(); + for (int i = 0; i < 20; i++) { + double t = 1.0 + 0.05*(i+1); + integrator.stepTo(t); + State state = context.getState(State::Energy); + double energy = state.getKineticEnergy() + state.getPotentialEnergy(); + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + } +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleBond(); + testConstraints(); + testConstrainedClusters(); + testConstrainedMasslessParticles(); + testArgonBox(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} + diff --git a/tests/TestVerletIntegrator.h b/tests/TestVerletIntegrator.h new file mode 100644 index 000000000..8b1271009 --- /dev/null +++ b/tests/TestVerletIntegrator.h @@ -0,0 +1,246 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/HarmonicBondForce.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "SimTKOpenMMRealType.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +const double TOL = 1e-5; + +void testSingleBond() { + System system; + system.addParticle(2.0); + system.addParticle(2.0); + VerletIntegrator integrator(0.01); + HarmonicBondForce* forceField = new HarmonicBondForce(); + forceField->addBond(0, 1, 1.5, 1); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + + // This is simply a harmonic oscillator, so compare it to the analytical solution. + + const double freq = 1.0; + State state = context.getState(State::Energy); + const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); + for (int i = 0; i < 1000; ++i) { + state = context.getState(State::Positions | State::Velocities | State::Energy); + double time = state.getTime(); + double expectedDist = 1.5+0.5*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*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); + double energy = state.getKineticEnergy()+state.getPotentialEnergy(); + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + integrator.step(1); + } + ASSERT_EQUAL_TOL(10.0, context.getState(0).getTime(), 1e-5); +} + +void testConstraints() { + const int numParticles = 8; + const int numConstraints = 5; + System system; + VerletIntegrator integrator(0.001); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i%2 == 0 ? 5.0 : 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 positions(numParticles); + vector 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. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); + 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); + } + double energy = state.getPotentialEnergy()+state.getKineticEnergy(); + if (i == 1) + initialEnergy = energy; + else if (i > 1) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + integrator.step(1); + } +} + +void testConstrainedClusters() { + const int numParticles = 7; + System system; + VerletIntegrator integrator(0.001); + integrator.setConstraintTolerance(1e-5); + NonbondedForce* forceField = new NonbondedForce(); + for (int i = 0; i < numParticles; ++i) { + system.addParticle(i > 1 ? 1.0 : 10.0); + forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); + } + system.addConstraint(0, 1, 1.0); + system.addConstraint(0, 2, 1.0); + system.addConstraint(0, 3, 1.0); + system.addConstraint(0, 4, 1.0); + system.addConstraint(1, 5, 1.0); + system.addConstraint(1, 6, 1.0); + system.addConstraint(2, 3, sqrt(2.0)); + system.addConstraint(2, 4, sqrt(2.0)); + system.addConstraint(3, 4, sqrt(2.0)); + system.addConstraint(5, 6, sqrt(2.0)); + system.addForce(forceField); + Context context(system, integrator, platform); + vector positions(numParticles); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + positions[2] = Vec3(-1, 0, 0); + positions[3] = Vec3(0, 1, 0); + positions[4] = Vec3(0, 0, 1); + positions[5] = Vec3(2, 0, 0); + positions[6] = Vec3(1, 1, 0); + vector velocities(numParticles); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + + for (int i = 0; i < numParticles; ++i) + 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. + + double initialEnergy = 0.0; + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces); + for (int j = 0; j < system.getNumConstraints(); ++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, 2e-5); + } + double energy = state.getPotentialEnergy()+state.getKineticEnergy(); + if (i == 1) + initialEnergy = energy; + else if (i > 1) + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + integrator.step(1); + } +} + +void testConstrainedMasslessParticles() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + system.addConstraint(0, 1, 1.5); + vector positions(2); + positions[0] = Vec3(-1, 0, 0); + positions[1] = Vec3(1, 0, 0); + VerletIntegrator integrator(0.01); + bool failed = false; + try { + // This should throw an exception. + + Context context(system, integrator, platform); + } + catch (exception& ex) { + failed = true; + } + ASSERT(failed); + + // Now make both particles massless, which should work. + + system.setParticleMass(1, 0.0); + Context context(system, integrator, platform); + context.setPositions(positions); + context.setVelocitiesToTemperature(300.0); + integrator.step(1); + State state = context.getState(State::Velocities); + ASSERT_EQUAL(0.0, state.getVelocities()[0][0]); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testSingleBond(); + testConstraints(); + testConstrainedClusters(); + testConstrainedMasslessParticles(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestVirtualSites.h b/tests/TestVirtualSites.h new file mode 100644 index 000000000..725ced5ee --- /dev/null +++ b/tests/TestVirtualSites.h @@ -0,0 +1,475 @@ +/* -------------------------------------------------------------------------- * + * 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) 2012-2015 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/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomBondForce.h" +#include "openmm/CustomExternalForce.h" +#include "openmm/LangevinIntegrator.h" +#include "openmm/NonbondedForce.h" +#include "openmm/System.h" +#include "openmm/VerletIntegrator.h" +#include "openmm/VirtualSite.h" +#include "sfmt/SFMT.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +/** + * Check that massless particles are handled correctly. + */ +void testMasslessParticle() { + System system; + system.addParticle(0.0); + system.addParticle(1.0); + CustomBondForce* bonds = new CustomBondForce("-1/r"); + system.addForce(bonds); + vector params; + bonds->addBond(0, 1, params); + VerletIntegrator integrator(0.002); + Context context(system, integrator, platform); + vector positions(2); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + vector velocities(2); + velocities[0] = Vec3(0, 0, 0); + velocities[1] = Vec3(0, 1, 0); + context.setVelocities(velocities); + + // The second particle should move in a circular orbit around the first one. + // Compare it to the analytical solution. + + for (int i = 0; i < 1000; ++i) { + State state = context.getState(State::Positions | State::Velocities | State::Forces); + double time = state.getTime(); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getPositions()[0], 0.0); + ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getVelocities()[0], 0.0); + ASSERT_EQUAL_VEC(Vec3(cos(time), sin(time), 0), state.getPositions()[1], 0.01); + ASSERT_EQUAL_VEC(Vec3(-sin(time), cos(time), 0), state.getVelocities()[1], 0.01); + integrator.step(1); + } +} + +/** + * Test a TwoParticleAverageSite virtual site. + */ +void testTwoParticleAverage() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.8, 0.2)); + CustomExternalForce* forceField = new CustomExternalForce("-a*x"); + system.addForce(forceField); + forceField->addPerParticleParameter("a"); + vector params(1); + params[0] = 0.1; + forceField->addParticle(0, params); + params[0] = 0.2; + forceField->addParticle(1, params); + params[0] = 0.3; + forceField->addParticle(2, params); + LangevinIntegrator integrator(300.0, 0.1, 0.002); + Context context(system, integrator, platform); + vector positions(3); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + context.setPositions(positions); + context.applyConstraints(0.0001); + for (int i = 0; i < 1000; i++) { + State state = context.getState(State::Positions | State::Forces); + const vector& pos = state.getPositions(); + ASSERT_EQUAL_VEC(pos[0]*0.8+pos[1]*0.2, pos[2], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.1+0.3*0.8, 0, 0), state.getForces()[0], 1e-4); + ASSERT_EQUAL_VEC(Vec3(0.2+0.3*0.2, 0, 0), state.getForces()[1], 1e-4); + integrator.step(1); + } +} + +/** + * Test a ThreeParticleAverageSite virtual site. + */ +void testThreeParticleAverage() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(3, new ThreeParticleAverageSite(0, 1, 2, 0.2, 0.3, 0.5)); + CustomExternalForce* forceField = new CustomExternalForce("-a*x"); + system.addForce(forceField); + forceField->addPerParticleParameter("a"); + vector params(1); + params[0] = 0.1; + forceField->addParticle(0, params); + params[0] = 0.2; + forceField->addParticle(1, params); + params[0] = 0.3; + forceField->addParticle(2, params); + params[0] = 0.4; + forceField->addParticle(3, params); + LangevinIntegrator integrator(300.0, 0.1, 0.002); + Context context(system, integrator, platform); + vector positions(4); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + positions[2] = Vec3(0, 1, 0); + context.setPositions(positions); + context.applyConstraints(0.0001); + for (int i = 0; i < 1000; i++) { + State state = context.getState(State::Positions | State::Forces); + const vector& pos = state.getPositions(); + ASSERT_EQUAL_VEC(pos[0]*0.2+pos[1]*0.3+pos[2]*0.5, pos[3], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.1+0.4*0.2, 0, 0), state.getForces()[0], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.2+0.4*0.3, 0, 0), state.getForces()[1], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.3+0.4*0.5, 0, 0), state.getForces()[2], 1e-5); + integrator.step(1); + } +} + +/** + * Test an OutOfPlaneSite virtual site. + */ +void testOutOfPlane() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(3, new OutOfPlaneSite(0, 1, 2, 0.3, 0.4, 0.5)); + CustomExternalForce* forceField = new CustomExternalForce("-a*x"); + system.addForce(forceField); + forceField->addPerParticleParameter("a"); + vector params(1); + params[0] = 0.1; + forceField->addParticle(0, params); + params[0] = 0.2; + forceField->addParticle(1, params); + params[0] = 0.3; + forceField->addParticle(2, params); + params[0] = 0.4; + forceField->addParticle(3, params); + LangevinIntegrator integrator(300.0, 0.1, 0.002); + Context context(system, integrator, platform); + vector positions(4); + positions[0] = Vec3(0, 0, 0); + positions[1] = Vec3(1, 0, 0); + positions[2] = Vec3(0, 1, 0); + context.setPositions(positions); + context.applyConstraints(0.0001); + for (int i = 0; i < 1000; i++) { + State state = context.getState(State::Positions | State::Forces); + const vector& pos = state.getPositions(); + Vec3 v12 = pos[1]-pos[0]; + Vec3 v13 = pos[2]-pos[0]; + Vec3 cross = v12.cross(v13); + ASSERT_EQUAL_VEC(pos[0]+v12*0.3+v13*0.4+cross*0.5, pos[3], 1e-5); + const vector& f = state.getForces(); + ASSERT_EQUAL_VEC(Vec3(0.1+0.2+0.3+0.4, 0, 0), f[0]+f[1]+f[2], 1e-5); + Vec3 f2(0.4*0.3, 0.4*0.5*v13[2], -0.4*0.5*v13[1]); + Vec3 f3(0.4*0.4, -0.4*0.5*v12[2], 0.4*0.5*v12[1]); + ASSERT_EQUAL_VEC(Vec3(0.1+0.4, 0, 0)-f2-f3, f[0], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.2, 0, 0)+f2, f[1], 1e-5); + ASSERT_EQUAL_VEC(Vec3(0.3, 0, 0)+f3, f[2], 1e-5); + integrator.step(1); + } +} + +/** + * Test a LocalCoordinatesSite virtual site. + */ +void testLocalCoordinates() { + const Vec3 originWeights(0.2, 0.3, 0.5); + const Vec3 xWeights(-1.0, 0.5, 0.5); + const Vec3 yWeights(0.0, -1.0, 1.0); + const Vec3 localPosition(0.4, 0.3, 0.2); + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(3, new LocalCoordinatesSite(0, 1, 2, originWeights, xWeights, yWeights, localPosition)); + CustomExternalForce* forceField = new CustomExternalForce("2*x^2+3*y^2+4*z^2"); + system.addForce(forceField); + vector params; + forceField->addParticle(0, params); + forceField->addParticle(1, params); + forceField->addParticle(2, params); + forceField->addParticle(3, params); + LangevinIntegrator integrator(300.0, 0.1, 0.002); + Context context(system, integrator, platform); + vector positions(4), positions2(4), positions3(4); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < 100; i++) { + // Set the particles at random positions. + + Vec3 xdir, ydir, zdir; + do { + for (int j = 0; j < 3; j++) + positions[j] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); + xdir = positions[0]*xWeights[0] + positions[1]*xWeights[1] + positions[2]*xWeights[2]; + ydir = positions[0]*yWeights[0] + positions[1]*yWeights[1] + positions[2]*yWeights[2]; + zdir = xdir.cross(ydir); + if (sqrt(xdir.dot(xdir)) > 0.1 && sqrt(ydir.dot(ydir)) > 0.1 && sqrt(zdir.dot(zdir)) > 0.1) + break; // These positions give a reasonable coordinate system. + } while (true); + context.setPositions(positions); + context.applyConstraints(0.0001); + + // See if the virtual site is positioned correctly. + + State state = context.getState(State::Positions | State::Forces); + const vector& pos = state.getPositions(); + Vec3 origin = pos[0]*originWeights[0] + pos[1]*originWeights[1] + pos[2]*originWeights[2]; + xdir /= sqrt(xdir.dot(xdir)); + zdir /= sqrt(zdir.dot(zdir)); + ydir = zdir.cross(xdir); + ASSERT_EQUAL_VEC(origin+xdir*localPosition[0]+ydir*localPosition[1]+zdir*localPosition[2], pos[3], 1e-5); + + // Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount. + + double norm = 0.0; + for (int i = 0; i < 3; ++i) { + Vec3 f = state.getForces()[i]; + norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; + } + norm = std::sqrt(norm); + const double delta = 1e-2; + double step = 0.5*delta/norm; + for (int i = 0; i < 3; ++i) { + Vec3 p = positions[i]; + Vec3 f = state.getForces()[i]; + positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); + positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step); + } + context.setPositions(positions2); + context.applyConstraints(0.0001); + State state2 = context.getState(State::Energy); + context.setPositions(positions3); + context.applyConstraints(0.0001); + State state3 = context.getState(State::Energy); + ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-3) + } +} + +/** + * Make sure that energy, linear momentum, and angular momentum are all conserved + * when using virtual sites. + */ +void testConservationLaws() { + System system; + NonbondedForce* forceField = new NonbondedForce(); + system.addForce(forceField); + vector positions; + + // Create a linear molecule with a TwoParticleAverage virtual site. + + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(2, new TwoParticleAverageSite(0, 1, 0.4, 0.6)); + system.addConstraint(0, 1, 2.0); + for (int i = 0; i < 3; i++) { + forceField->addParticle(0, 1, 10); + for (int j = 0; j < i; j++) + forceField->addException(i, j, 0, 1, 0); + } + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(2, 0, 0)); + positions.push_back(Vec3()); + + // Create a planar molecule with a ThreeParticleAverage virtual site. + + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(6, new ThreeParticleAverageSite(3, 4, 5, 0.3, 0.5, 0.2)); + system.addConstraint(3, 4, 1.0); + system.addConstraint(3, 5, 1.0); + system.addConstraint(4, 5, sqrt(2.0)); + for (int i = 0; i < 4; i++) { + forceField->addParticle(0, 1, 10); + for (int j = 0; j < i; j++) + forceField->addException(i+3, j+3, 0, 1, 0); + } + positions.push_back(Vec3(0, 0, 1)); + positions.push_back(Vec3(1, 0, 1)); + positions.push_back(Vec3(0, 1, 1)); + positions.push_back(Vec3()); + + // Create a tetrahedral molecule with an OutOfPlane virtual site. + + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(10, new OutOfPlaneSite(7, 8, 9, 0.3, 0.5, 0.2)); + system.addConstraint(7, 8, 1.0); + system.addConstraint(7, 9, 1.0); + system.addConstraint(8, 9, sqrt(2.0)); + for (int i = 0; i < 4; i++) { + forceField->addParticle(0, 1, 10); + for (int j = 0; j < i; j++) + forceField->addException(i+7, j+7, 0, 1, 0); + } + positions.push_back(Vec3(1, 0, -1)); + positions.push_back(Vec3(2, 0, -1)); + positions.push_back(Vec3(1, 1, -1)); + positions.push_back(Vec3()); + + // Create a molecule with a LocalCoordinatesSite virtual site. + + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(0.0); + system.setVirtualSite(14, new LocalCoordinatesSite(11, 12, 13, Vec3(0.3, 0.3, 0.4), Vec3(1.0, -0.5, -0.5), Vec3(0, -1.0, 1.0), Vec3(0.2, 0.2, 1.0))); + system.addConstraint(11, 12, 1.0); + system.addConstraint(11, 13, 1.0); + system.addConstraint(12, 13, sqrt(2.0)); + for (int i = 0; i < 4; i++) { + forceField->addParticle(0, 1, 10); + for (int j = 0; j < i; j++) + forceField->addException(i+11, j+11, 0, 1, 0); + } + positions.push_back(Vec3(1, 2, 0)); + positions.push_back(Vec3(2, 2, 0)); + positions.push_back(Vec3(1, 3, 0)); + positions.push_back(Vec3()); + + // Simulate it and check conservation laws. + + VerletIntegrator integrator(0.002); + Context context(system, integrator, platform); + context.setPositions(positions); + context.applyConstraints(0.0001); + int numParticles = system.getNumParticles(); + double initialEnergy; + Vec3 initialMomentum, initialAngularMomentum; + for (int i = 0; i < 1000; i++) { + State state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy); + const vector& pos = state.getPositions(); + const vector& vel = state.getVelocities(); + const vector& f = state.getForces(); + double energy = state.getPotentialEnergy(); + for (int j = 0; j < numParticles; j++) { + Vec3 v = vel[j] + f[j]*0.5*integrator.getStepSize(); + energy += 0.5*system.getParticleMass(j)*v.dot(v); + } + if (i == 0) + initialEnergy = energy; + else + ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); + Vec3 momentum; + for (int j = 0; j < numParticles; j++) + momentum += vel[j]*system.getParticleMass(j); + if (i == 0) + initialMomentum = momentum; + else + ASSERT_EQUAL_VEC(initialMomentum, momentum, 0.02); + Vec3 angularMomentum; + for (int j = 0; j < numParticles; j++) + angularMomentum += pos[j].cross(vel[j])*system.getParticleMass(j); + if (i == 0) + initialAngularMomentum = angularMomentum; + else + ASSERT_EQUAL_VEC(initialAngularMomentum, angularMomentum, 0.05); + integrator.step(1); + } +} + +/** + * Test a System where multiple virtual sites are all calculated from the same particles. + */ +void testOverlappingSites() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + NonbondedForce* nonbonded = new NonbondedForce(); + system.addForce(nonbonded); + nonbonded->addParticle(1.0, 0.0, 0.0); + nonbonded->addParticle(-0.5, 0.0, 0.0); + nonbonded->addParticle(-0.5, 0.0, 0.0); + vector positions; + positions.push_back(Vec3(0, 0, 0)); + positions.push_back(Vec3(10, 0, 0)); + positions.push_back(Vec3(0, 10, 0)); + for (int i = 0; i < 20; i++) { + system.addParticle(0.0); + double u = 0.1*((i+1)%4); + double v = 0.05*i; + system.setVirtualSite(3+i, new ThreeParticleAverageSite(0, 1, 2, u, v, 1-u-v)); + nonbonded->addParticle(i%2 == 0 ? -1.0 : 1.0, 0.0, 0.0); + positions.push_back(Vec3()); + } + VerletIntegrator i1(0.002); + VerletIntegrator i2(0.002); + Context c1(system, i1, Platform::getPlatformByName("Reference")); + Context c2(system, i2, platform); + c1.setPositions(positions); + c2.setPositions(positions); + c1.applyConstraints(0.0001); + c2.applyConstraints(0.0001); + State s1 = c1.getState(State::Positions | State::Forces); + State s2 = c2.getState(State::Positions | State::Forces); + for (int i = 0; i < system.getNumParticles(); i++) + ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], 1e-5); + for (int i = 0; i < 3; i++) + ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 1e-5); +} + +void runPlatformTests(); + +int main(int argc, char* argv[]) { + try { + initializeTests(argc, argv); + testMasslessParticle(); + testTwoParticleAverage(); + testThreeParticleAverage(); + testOutOfPlane(); + testLocalCoordinates(); + testConservationLaws(); + testOverlappingSites(); + runPlatformTests(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} -- GitLab From cece0cdbe33ab3e338130ff0ce51ed4370128b4a Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Wed, 23 Sep 2015 13:46:43 -0700 Subject: [PATCH 14/49] Fixed a failing test case --- libraries/sfmt/src/SFMT.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/sfmt/src/SFMT.cpp b/libraries/sfmt/src/SFMT.cpp index 13d2e0db2..07c26b0c0 100644 --- a/libraries/sfmt/src/SFMT.cpp +++ b/libraries/sfmt/src/SFMT.cpp @@ -124,11 +124,13 @@ public: }; void SFMT::createCheckpoint(std::ostream& stream) { + stream.write((char*) &data->baseData, sizeof(data->baseData)); stream.write((char*) &data->sfmt, sizeof(data->sfmt)); stream.write((char*) &data->idx, sizeof(data->idx)); } void SFMT::loadCheckpoint(std::istream& stream) { + stream.read((char*) &data->baseData, sizeof(data->baseData)); stream.read((char*) &data->sfmt, sizeof(data->sfmt)); stream.read((char*) &data->idx, sizeof(data->idx)); } -- GitLab From 213fbc03dbe24a05e6d7d6c0e5e3b4b5967a63c1 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Wed, 23 Sep 2015 16:42:22 -0700 Subject: [PATCH 15/49] Added error checking for illegal variable names --- .../internal/CustomCentroidBondForceImpl.h | 3 +- .../internal/CustomCompoundBondForceImpl.h | 3 +- .../openmm/internal/CustomHbondForceImpl.h | 5 +- .../internal/CustomManyParticleForceImpl.h | 3 +- openmmapi/src/CustomCentroidBondForceImpl.cpp | 21 ++++-- openmmapi/src/CustomCompoundBondForceImpl.cpp | 21 ++++-- openmmapi/src/CustomHbondForceImpl.cpp | 17 +++-- openmmapi/src/CustomManyParticleForceImpl.cpp | 24 +++++-- platforms/cpu/src/CpuKernels.cpp | 42 +++++++++++- platforms/reference/src/ReferenceKernels.cpp | 64 ++++++++++++++++++- tests/TestCustomAngleForce.h | 21 ++++++ tests/TestCustomBondForce.h | 20 ++++++ tests/TestCustomCentroidBondForce.h | 27 ++++++++ tests/TestCustomCompoundBondForce.h | 23 +++++++ tests/TestCustomExternalForce.h | 18 ++++++ tests/TestCustomGBForce.h | 20 ++++++ tests/TestCustomHbondForce.h | 21 ++++++ tests/TestCustomManyParticleForce.h | 19 ++++++ tests/TestCustomNonbondedForce.h | 19 ++++++ tests/TestCustomTorsionForce.h | 22 +++++++ 20 files changed, 390 insertions(+), 23 deletions(-) diff --git a/openmmapi/include/openmm/internal/CustomCentroidBondForceImpl.h b/openmmapi/include/openmm/internal/CustomCentroidBondForceImpl.h index f6e4d69ba..345ddf8f6 100644 --- a/openmmapi/include/openmm/internal/CustomCentroidBondForceImpl.h +++ b/openmmapi/include/openmm/internal/CustomCentroidBondForceImpl.h @@ -41,6 +41,7 @@ #include "lepton/ParsedExpression.h" #include #include +#include #include namespace OpenMM { @@ -93,7 +94,7 @@ private: class FunctionPlaceholder; static Lepton::ExpressionTreeNode replaceFunctions(const Lepton::ExpressionTreeNode& node, std::map atoms, std::map >& distances, std::map >& angles, - std::map >& dihedrals); + std::map >& dihedrals, std::set& variables); void addBondsBetweenGroups(int group1, int group2, std::vector >& bonds) const; const CustomCentroidBondForce& owner; Kernel kernel; diff --git a/openmmapi/include/openmm/internal/CustomCompoundBondForceImpl.h b/openmmapi/include/openmm/internal/CustomCompoundBondForceImpl.h index db51ce367..21f432609 100644 --- a/openmmapi/include/openmm/internal/CustomCompoundBondForceImpl.h +++ b/openmmapi/include/openmm/internal/CustomCompoundBondForceImpl.h @@ -40,6 +40,7 @@ #include "lepton/ParsedExpression.h" #include #include +#include #include namespace OpenMM { @@ -83,7 +84,7 @@ private: class FunctionPlaceholder; static Lepton::ExpressionTreeNode replaceFunctions(const Lepton::ExpressionTreeNode& node, std::map atoms, std::map >& distances, std::map >& angles, - std::map >& dihedrals); + std::map >& dihedrals, std::set& variables); const CustomCompoundBondForce& owner; Kernel kernel; }; diff --git a/openmmapi/include/openmm/internal/CustomHbondForceImpl.h b/openmmapi/include/openmm/internal/CustomHbondForceImpl.h index 9d836ff89..baa781b47 100644 --- a/openmmapi/include/openmm/internal/CustomHbondForceImpl.h +++ b/openmmapi/include/openmm/internal/CustomHbondForceImpl.h @@ -9,7 +9,7 @@ * 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. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -40,6 +40,7 @@ #include "lepton/ParsedExpression.h" #include #include +#include #include namespace OpenMM { @@ -84,7 +85,7 @@ private: class FunctionPlaceholder; static Lepton::ExpressionTreeNode replaceFunctions(const Lepton::ExpressionTreeNode& node, std::map atoms, std::map >& distances, std::map >& angles, - std::map >& dihedrals); + std::map >& dihedrals, std::set& variables); const CustomHbondForce& owner; Kernel kernel; }; diff --git a/openmmapi/include/openmm/internal/CustomManyParticleForceImpl.h b/openmmapi/include/openmm/internal/CustomManyParticleForceImpl.h index a5a36dc8f..069fb05ce 100644 --- a/openmmapi/include/openmm/internal/CustomManyParticleForceImpl.h +++ b/openmmapi/include/openmm/internal/CustomManyParticleForceImpl.h @@ -40,6 +40,7 @@ #include "lepton/ParsedExpression.h" #include #include +#include #include namespace OpenMM { @@ -98,7 +99,7 @@ private: class FunctionPlaceholder; static Lepton::ExpressionTreeNode replaceFunctions(const Lepton::ExpressionTreeNode& node, std::map atoms, std::map >& distances, std::map >& angles, - std::map >& dihedrals); + std::map >& dihedrals, std::set& variables); static void generatePermutations(std::vector& values, int numFixed, std::vector >& result); const CustomManyParticleForce& owner; Kernel kernel; diff --git a/openmmapi/src/CustomCentroidBondForceImpl.cpp b/openmmapi/src/CustomCentroidBondForceImpl.cpp index ddfd78448..91895bc80 100644 --- a/openmmapi/src/CustomCentroidBondForceImpl.cpp +++ b/openmmapi/src/CustomCentroidBondForceImpl.cpp @@ -150,24 +150,37 @@ ParsedExpression CustomCentroidBondForceImpl::prepareExpression(const CustomCent functions["dihedral"] = &dihedral; ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions); map groups; + set variables; for (int i = 0; i < force.getNumGroupsPerBond(); i++) { - stringstream name; + stringstream name, x, y, z; name << 'g' << (i+1); + x << 'x' << (i+1); + y << 'y' << (i+1); + z << 'z' << (i+1); groups[name.str()] = i; + variables.insert(x.str()); + variables.insert(y.str()); + variables.insert(z.str()); } - return ParsedExpression(replaceFunctions(expression.getRootNode(), groups, distances, angles, dihedrals)).optimize(); + for (int i = 0; i < force.getNumGlobalParameters(); i++) + variables.insert(force.getGlobalParameterName(i)); + for (int i = 0; i < force.getNumPerBondParameters(); i++) + variables.insert(force.getPerBondParameterName(i)); + return ParsedExpression(replaceFunctions(expression.getRootNode(), groups, distances, angles, dihedrals, variables)).optimize(); } ExpressionTreeNode CustomCentroidBondForceImpl::replaceFunctions(const ExpressionTreeNode& node, map groups, - map >& distances, map >& angles, map >& dihedrals) { + map >& distances, map >& angles, map >& dihedrals, set& variables) { const Operation& op = node.getOperation(); + if (op.getId() == Operation::VARIABLE && variables.find(op.getName()) == variables.end()) + throw OpenMMException("CustomCentroidBondForce: Unknown variable '"+op.getName()+"'"); if (op.getId() != Operation::CUSTOM || (op.getName() != "distance" && op.getName() != "angle" && op.getName() != "dihedral")) { // This is not an angle or dihedral, so process its children. vector children; for (int i = 0; i < (int) node.getChildren().size(); i++) - children.push_back(replaceFunctions(node.getChildren()[i], groups, distances, angles, dihedrals)); + children.push_back(replaceFunctions(node.getChildren()[i], groups, distances, angles, dihedrals, variables)); return ExpressionTreeNode(op.clone(), children); } const Operation::Custom& custom = static_cast(op); diff --git a/openmmapi/src/CustomCompoundBondForceImpl.cpp b/openmmapi/src/CustomCompoundBondForceImpl.cpp index 30a3d1e65..ebcfe8a6a 100644 --- a/openmmapi/src/CustomCompoundBondForceImpl.cpp +++ b/openmmapi/src/CustomCompoundBondForceImpl.cpp @@ -136,24 +136,37 @@ ParsedExpression CustomCompoundBondForceImpl::prepareExpression(const CustomComp functions["dihedral"] = &dihedral; ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions); map atoms; + set variables; for (int i = 0; i < force.getNumParticlesPerBond(); i++) { - stringstream name; + stringstream name, x, y, z; name << 'p' << (i+1); + x << 'x' << (i+1); + y << 'y' << (i+1); + z << 'z' << (i+1); atoms[name.str()] = i; + variables.insert(x.str()); + variables.insert(y.str()); + variables.insert(z.str()); } - return ParsedExpression(replaceFunctions(expression.getRootNode(), atoms, distances, angles, dihedrals)).optimize(); + for (int i = 0; i < force.getNumGlobalParameters(); i++) + variables.insert(force.getGlobalParameterName(i)); + for (int i = 0; i < force.getNumPerBondParameters(); i++) + variables.insert(force.getPerBondParameterName(i)); + return ParsedExpression(replaceFunctions(expression.getRootNode(), atoms, distances, angles, dihedrals, variables)).optimize(); } ExpressionTreeNode CustomCompoundBondForceImpl::replaceFunctions(const ExpressionTreeNode& node, map atoms, - map >& distances, map >& angles, map >& dihedrals) { + map >& distances, map >& angles, map >& dihedrals, set& variables) { const Operation& op = node.getOperation(); + if (op.getId() == Operation::VARIABLE && variables.find(op.getName()) == variables.end()) + throw OpenMMException("CustomCompoundBondForce: Unknown variable '"+op.getName()+"'"); if (op.getId() != Operation::CUSTOM || (op.getName() != "distance" && op.getName() != "angle" && op.getName() != "dihedral")) { // This is not an angle or dihedral, so process its children. vector children; for (int i = 0; i < (int) node.getChildren().size(); i++) - children.push_back(replaceFunctions(node.getChildren()[i], atoms, distances, angles, dihedrals)); + children.push_back(replaceFunctions(node.getChildren()[i], atoms, distances, angles, dihedrals, variables)); return ExpressionTreeNode(op.clone(), children); } const Operation::Custom& custom = static_cast(op); diff --git a/openmmapi/src/CustomHbondForceImpl.cpp b/openmmapi/src/CustomHbondForceImpl.cpp index 5873aa5f6..e8d240863 100644 --- a/openmmapi/src/CustomHbondForceImpl.cpp +++ b/openmmapi/src/CustomHbondForceImpl.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2008-2012 Stanford University and the Authors. * + * Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -215,19 +215,28 @@ ParsedExpression CustomHbondForceImpl::prepareExpression(const CustomHbondForce& atoms["d1"] = 3; atoms["d2"] = 4; atoms["d3"] = 5; - return ParsedExpression(replaceFunctions(expression.getRootNode(), atoms, distances, angles, dihedrals)).optimize(); + set variables; + for (int i = 0; i < force.getNumPerDonorParameters(); i++) + variables.insert(force.getPerDonorParameterName(i)); + for (int i = 0; i < force.getNumPerAcceptorParameters(); i++) + variables.insert(force.getPerAcceptorParameterName(i)); + for (int i = 0; i < force.getNumGlobalParameters(); i++) + variables.insert(force.getGlobalParameterName(i)); + return ParsedExpression(replaceFunctions(expression.getRootNode(), atoms, distances, angles, dihedrals, variables)).optimize(); } ExpressionTreeNode CustomHbondForceImpl::replaceFunctions(const ExpressionTreeNode& node, map atoms, - map >& distances, map >& angles, map >& dihedrals) { + map >& distances, map >& angles, map >& dihedrals, set& variables) { const Operation& op = node.getOperation(); + if (op.getId() == Operation::VARIABLE && variables.find(op.getName()) == variables.end()) + throw OpenMMException("CustomHBondForce: Unknown variable '"+op.getName()+"'"); if (op.getId() != Operation::CUSTOM || op.getNumArguments() < 2) { // This is not an angle or dihedral, so process its children. vector children; for (int i = 0; i < (int) node.getChildren().size(); i++) - children.push_back(replaceFunctions(node.getChildren()[i], atoms, distances, angles, dihedrals)); + children.push_back(replaceFunctions(node.getChildren()[i], atoms, distances, angles, dihedrals, variables)); return ExpressionTreeNode(op.clone(), children); } const Operation::Custom& custom = static_cast(op); diff --git a/openmmapi/src/CustomManyParticleForceImpl.cpp b/openmmapi/src/CustomManyParticleForceImpl.cpp index 8adc53135..a330487e1 100644 --- a/openmmapi/src/CustomManyParticleForceImpl.cpp +++ b/openmmapi/src/CustomManyParticleForceImpl.cpp @@ -165,24 +165,40 @@ ParsedExpression CustomManyParticleForceImpl::prepareExpression(const CustomMany functions["dihedral"] = &dihedral; ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions); map atoms; + set variables; for (int i = 0; i < force.getNumParticlesPerSet(); i++) { - stringstream name; + stringstream name, x, y, z; name << 'p' << (i+1); + x << 'x' << (i+1); + y << 'y' << (i+1); + z << 'z' << (i+1); atoms[name.str()] = i; + variables.insert(x.str()); + variables.insert(y.str()); + variables.insert(z.str()); + for (int j = 0; j < force.getNumPerParticleParameters(); j++) { + stringstream param; + param << force.getPerParticleParameterName(j) << (i+1); + variables.insert(param.str()); + } } - return ParsedExpression(replaceFunctions(expression.getRootNode(), atoms, distances, angles, dihedrals)).optimize(); + for (int i = 0; i < force.getNumGlobalParameters(); i++) + variables.insert(force.getGlobalParameterName(i)); + return ParsedExpression(replaceFunctions(expression.getRootNode(), atoms, distances, angles, dihedrals, variables)).optimize(); } ExpressionTreeNode CustomManyParticleForceImpl::replaceFunctions(const ExpressionTreeNode& node, map atoms, - map >& distances, map >& angles, map >& dihedrals) { + map >& distances, map >& angles, map >& dihedrals, set& variables) { const Operation& op = node.getOperation(); + if (op.getId() == Operation::VARIABLE && variables.find(op.getName()) == variables.end()) + throw OpenMMException("CustomManyParticleForce: Unknown variable '"+op.getName()+"'"); if (op.getId() != Operation::CUSTOM || (op.getName() != "distance" && op.getName() != "angle" && op.getName() != "dihedral")) { // This is not an angle or dihedral, so process its children. vector children; for (int i = 0; i < (int) node.getChildren().size(); i++) - children.push_back(replaceFunctions(node.getChildren()[i], atoms, distances, angles, dihedrals)); + children.push_back(replaceFunctions(node.getChildren()[i], atoms, distances, angles, dihedrals, variables)); return ExpressionTreeNode(op.clone(), children); } const Operation::Custom& custom = static_cast(op); diff --git a/platforms/cpu/src/CpuKernels.cpp b/platforms/cpu/src/CpuKernels.cpp index 709332c73..f10bbc7ad 100644 --- a/platforms/cpu/src/CpuKernels.cpp +++ b/platforms/cpu/src/CpuKernels.cpp @@ -47,6 +47,7 @@ #include "RealVec.h" #include "lepton/CompiledExpression.h" #include "lepton/CustomFunction.h" +#include "lepton/Operation.h" #include "lepton/Parser.h" #include "lepton/ParsedExpression.h" @@ -83,6 +84,17 @@ static ReferenceConstraints& extractConstraints(ContextImpl& context) { return *(ReferenceConstraints*) data->constraints; } +/** + * Make sure an expression doesn't use any undefined variables. + */ +static void validateVariables(const Lepton::ExpressionTreeNode& node, const set& variables) { + const Lepton::Operation& op = node.getOperation(); + if (op.getId() == Lepton::Operation::VARIABLE && variables.find(op.getName()) == variables.end()) + throw OpenMMException("Unknown variable in expression: "+op.getName()); + for (int i = 0; i < (int) node.getChildren().size(); i++) + validateVariables(node.getChildren()[i], variables); +} + /** * Compute the kinetic energy of the system, possibly shifting the velocities in time to account * for a leapfrog integrator. @@ -737,6 +749,14 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C globalParameterNames.push_back(force.getGlobalParameterName(i)); globalParamValues[force.getGlobalParameterName(i)] = force.getGlobalParameterDefaultValue(i); } + set variables; + variables.insert("r"); + for (int i = 0; i < numParameters; i++) { + variables.insert(parameterNames[i]+"1"); + variables.insert(parameterNames[i]+"2"); + } + variables.insert(globalParameterNames.begin(), globalParameterNames.end()); + validateVariables(expression.getRootNode(), variables); // Delete the custom functions. @@ -950,6 +970,18 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB vector > valueGradientExpressions(force.getNumComputedValues()); vector valueExpressions; vector energyExpressions; + set particleVariables, pairVariables; + pairVariables.insert("r"); + particleVariables.insert("x"); + particleVariables.insert("y"); + particleVariables.insert("z"); + for (int i = 0; i < numPerParticleParameters; i++) { + particleVariables.insert(particleParameterNames[i]); + pairVariables.insert(particleParameterNames[i]+"1"); + pairVariables.insert(particleParameterNames[i]+"2"); + } + particleVariables.insert(globalParameterNames.begin(), globalParameterNames.end()); + pairVariables.insert(globalParameterNames.begin(), globalParameterNames.end()); for (int i = 0; i < force.getNumComputedValues(); i++) { string name, expression; CustomGBForce::ComputationType type; @@ -958,15 +990,21 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB valueExpressions.push_back(ex.createCompiledExpression()); valueTypes.push_back(type); valueNames.push_back(name); - if (i == 0) + if (i == 0) { valueDerivExpressions[i].push_back(ex.differentiate("r").createCompiledExpression()); + validateVariables(ex.getRootNode(), pairVariables); + } else { valueGradientExpressions[i].push_back(ex.differentiate("x").createCompiledExpression()); valueGradientExpressions[i].push_back(ex.differentiate("y").createCompiledExpression()); valueGradientExpressions[i].push_back(ex.differentiate("z").createCompiledExpression()); for (int j = 0; j < i; j++) valueDerivExpressions[i].push_back(ex.differentiate(valueNames[j]).createCompiledExpression()); + validateVariables(ex.getRootNode(), particleVariables); } + particleVariables.insert(name); + pairVariables.insert(name+"1"); + pairVariables.insert(name+"2"); } // Parse the expressions for energy terms. @@ -988,10 +1026,12 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB energyGradientExpressions[i].push_back(ex.differentiate("x").createCompiledExpression()); energyGradientExpressions[i].push_back(ex.differentiate("y").createCompiledExpression()); energyGradientExpressions[i].push_back(ex.differentiate("z").createCompiledExpression()); + validateVariables(ex.getRootNode(), particleVariables); } else { energyDerivExpressions[i].push_back(ex.differentiate(valueNames[j]+"1").createCompiledExpression()); energyDerivExpressions[i].push_back(ex.differentiate(valueNames[j]+"2").createCompiledExpression()); + validateVariables(ex.getRootNode(), pairVariables); } } } diff --git a/platforms/reference/src/ReferenceKernels.cpp b/platforms/reference/src/ReferenceKernels.cpp index 99b28c50e..36cbe9886 100644 --- a/platforms/reference/src/ReferenceKernels.cpp +++ b/platforms/reference/src/ReferenceKernels.cpp @@ -77,6 +77,7 @@ #include "openmm/OpenMMException.h" #include "SimTKOpenMMUtilities.h" #include "lepton/CustomFunction.h" +#include "lepton/Operation.h" #include "lepton/Parser.h" #include "lepton/ParsedExpression.h" #include @@ -146,6 +147,17 @@ static ReferenceConstraints& extractConstraints(ContextImpl& context) { return *(ReferenceConstraints*) data->constraints; } +/** + * Make sure an expression doesn't use any undefined variables. + */ +static void validateVariables(const Lepton::ExpressionTreeNode& node, const set& variables) { + const Lepton::Operation& op = node.getOperation(); + if (op.getId() == Lepton::Operation::VARIABLE && variables.find(op.getName()) == variables.end()) + throw OpenMMException("Unknown variable in expression: "+op.getName()); + for (int i = 0; i < (int) node.getChildren().size(); i++) + validateVariables(node.getChildren()[i], variables); +} + /** * Compute the kinetic energy of the system, possibly shifting the velocities in time to account * for a leapfrog integrator. @@ -422,6 +434,11 @@ void ReferenceCalcCustomBondForceKernel::initialize(const System& system, const parameterNames.push_back(force.getPerBondParameterName(i)); for (int i = 0; i < force.getNumGlobalParameters(); i++) globalParameterNames.push_back(force.getGlobalParameterName(i)); + set variables; + variables.insert("r"); + variables.insert(parameterNames.begin(), parameterNames.end()); + variables.insert(globalParameterNames.begin(), globalParameterNames.end()); + validateVariables(expression.getRootNode(), variables); } double ReferenceCalcCustomBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { @@ -536,6 +553,11 @@ void ReferenceCalcCustomAngleForceKernel::initialize(const System& system, const parameterNames.push_back(force.getPerAngleParameterName(i)); for (int i = 0; i < force.getNumGlobalParameters(); i++) globalParameterNames.push_back(force.getGlobalParameterName(i)); + set variables; + variables.insert("theta"); + variables.insert(parameterNames.begin(), parameterNames.end()); + variables.insert(globalParameterNames.begin(), globalParameterNames.end()); + validateVariables(expression.getRootNode(), variables); } double ReferenceCalcCustomAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { @@ -780,6 +802,11 @@ void ReferenceCalcCustomTorsionForceKernel::initialize(const System& system, con parameterNames.push_back(force.getPerTorsionParameterName(i)); for (int i = 0; i < force.getNumGlobalParameters(); i++) globalParameterNames.push_back(force.getGlobalParameterName(i)); + set variables; + variables.insert("theta"); + variables.insert(parameterNames.begin(), parameterNames.end()); + variables.insert(globalParameterNames.begin(), globalParameterNames.end()); + validateVariables(expression.getRootNode(), variables); } double ReferenceCalcCustomTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { @@ -1038,6 +1065,14 @@ void ReferenceCalcCustomNonbondedForceKernel::initialize(const System& system, c globalParameterNames.push_back(force.getGlobalParameterName(i)); globalParamValues[force.getGlobalParameterName(i)] = force.getGlobalParameterDefaultValue(i); } + set variables; + variables.insert("r"); + for (int i = 0; i < numParameters; i++) { + variables.insert(parameterNames[i]+"1"); + variables.insert(parameterNames[i]+"2"); + } + variables.insert(globalParameterNames.begin(), globalParameterNames.end()); + validateVariables(expression.getRootNode(), variables); // Delete the custom functions. @@ -1314,6 +1349,18 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu valueDerivExpressions.resize(force.getNumComputedValues()); valueGradientExpressions.resize(force.getNumComputedValues()); + set particleVariables, pairVariables; + pairVariables.insert("r"); + particleVariables.insert("x"); + particleVariables.insert("y"); + particleVariables.insert("z"); + for (int i = 0; i < numPerParticleParameters; i++) { + particleVariables.insert(particleParameterNames[i]); + pairVariables.insert(particleParameterNames[i]+"1"); + pairVariables.insert(particleParameterNames[i]+"2"); + } + particleVariables.insert(globalParameterNames.begin(), globalParameterNames.end()); + pairVariables.insert(globalParameterNames.begin(), globalParameterNames.end()); for (int i = 0; i < force.getNumComputedValues(); i++) { string name, expression; CustomGBForce::ComputationType type; @@ -1322,15 +1369,21 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu valueExpressions.push_back(ex.createProgram()); valueTypes.push_back(type); valueNames.push_back(name); - if (i == 0) + if (i == 0) { valueDerivExpressions[i].push_back(ex.differentiate("r").optimize().createProgram()); + validateVariables(ex.getRootNode(), pairVariables); + } else { valueGradientExpressions[i].push_back(ex.differentiate("x").optimize().createProgram()); valueGradientExpressions[i].push_back(ex.differentiate("y").optimize().createProgram()); valueGradientExpressions[i].push_back(ex.differentiate("z").optimize().createProgram()); for (int j = 0; j < i; j++) valueDerivExpressions[i].push_back(ex.differentiate(valueNames[j]).optimize().createProgram()); + validateVariables(ex.getRootNode(), particleVariables); } + particleVariables.insert(name); + pairVariables.insert(name+"1"); + pairVariables.insert(name+"2"); } // Parse the expressions for energy terms. @@ -1352,10 +1405,12 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu energyGradientExpressions[i].push_back(ex.differentiate("x").optimize().createProgram()); energyGradientExpressions[i].push_back(ex.differentiate("y").optimize().createProgram()); energyGradientExpressions[i].push_back(ex.differentiate("z").optimize().createProgram()); + validateVariables(ex.getRootNode(), particleVariables); } else { energyDerivExpressions[i].push_back(ex.differentiate(valueNames[j]+"1").optimize().createProgram()); energyDerivExpressions[i].push_back(ex.differentiate(valueNames[j]+"2").optimize().createProgram()); + validateVariables(ex.getRootNode(), pairVariables); } } } @@ -1475,6 +1530,13 @@ void ReferenceCalcCustomExternalForceKernel::initialize(const System& system, co parameterNames.push_back(force.getPerParticleParameterName(i)); for (int i = 0; i < force.getNumGlobalParameters(); i++) globalParameterNames.push_back(force.getGlobalParameterName(i)); + set variables; + variables.insert("x"); + variables.insert("y"); + variables.insert("z"); + variables.insert(parameterNames.begin(), parameterNames.end()); + variables.insert(globalParameterNames.begin(), globalParameterNames.end()); + validateVariables(expression.getRootNode(), variables); } double ReferenceCalcCustomExternalForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { diff --git a/tests/TestCustomAngleForce.h b/tests/TestCustomAngleForce.h index 5d79ad433..6e1e1fbb6 100644 --- a/tests/TestCustomAngleForce.h +++ b/tests/TestCustomAngleForce.h @@ -126,12 +126,33 @@ void testAngles() { } } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + CustomAngleForce* force = new CustomAngleForce("theta+none"); + vector params; + force->addAngle(0, 1, 2, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { try { initializeTests(argc, argv); testAngles(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomBondForce.h b/tests/TestCustomBondForce.h index 5b630c532..c3f55205e 100644 --- a/tests/TestCustomBondForce.h +++ b/tests/TestCustomBondForce.h @@ -130,6 +130,25 @@ void testManyParameters() { ASSERT_EQUAL_TOL(f*2.5, state.getPotentialEnergy(), TOL); } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + CustomBondForce* force = new CustomBondForce("r+none"); + vector params; + force->addBond(0, 1, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -137,6 +156,7 @@ int main(int argc, char* argv[]) { initializeTests(argc, argv); testBonds(); testManyParameters(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomCentroidBondForce.h b/tests/TestCustomCentroidBondForce.h index a648d0e8b..ff76a2bf5 100644 --- a/tests/TestCustomCentroidBondForce.h +++ b/tests/TestCustomCentroidBondForce.h @@ -252,6 +252,32 @@ void testCustomWeights() { ASSERT_EQUAL_VEC(Vec3(0, -2*9*(1.0/3.0), 0), state.getForces()[3], TOL); } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "1+none"); + vector particles; + particles.push_back(0); + force->addGroup(particles); + force->addGroup(particles); + vector groups; + groups.push_back(0); + groups.push_back(1); + vector params; + force->addBond(groups, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -260,6 +286,7 @@ int main(int argc, char* argv[]) { testHarmonicBond(); testComplexFunction(); testCustomWeights(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomCompoundBondForce.h b/tests/TestCustomCompoundBondForce.h index 24d48ae5a..27f0f2cff 100644 --- a/tests/TestCustomCompoundBondForce.h +++ b/tests/TestCustomCompoundBondForce.h @@ -309,6 +309,28 @@ void testMultipleBonds() { ASSERT_EQUAL_VEC(Vec3(0.776, 0.0, -0.084), forces[3], 1e-3); } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + CustomCompoundBondForce* force = new CustomCompoundBondForce(2, "1+none"); + vector particles; + particles.push_back(0); + particles.push_back(1); + vector params; + force->addBond(particles, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -319,6 +341,7 @@ int main(int argc, char* argv[]) { testContinuous2DFunction(); testContinuous3DFunction(); testMultipleBonds(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomExternalForce.h b/tests/TestCustomExternalForce.h index 5575639ed..ad28c18dc 100644 --- a/tests/TestCustomExternalForce.h +++ b/tests/TestCustomExternalForce.h @@ -165,7 +165,24 @@ void testPeriodic() { ASSERT_EQUAL_TOL(delta.dot(delta), state.getPotentialEnergy(), TOL); integrator.step(1); } +} +void testIllegalVariable() { + System system; + system.addParticle(1.0); + CustomExternalForce* force = new CustomExternalForce("x+none"); + vector params; + force->addParticle(0, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); } void runPlatformTests(); @@ -176,6 +193,7 @@ int main(int argc, char* argv[]) { testForce(); testManyParameters(); testPeriodic(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomGBForce.h b/tests/TestCustomGBForce.h index 6840119df..1c9a8c2bb 100644 --- a/tests/TestCustomGBForce.h +++ b/tests/TestCustomGBForce.h @@ -470,6 +470,25 @@ void testExclusions() { } } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + CustomGBForce* force = new CustomGBForce(); + force->addComputedValue("a", "r+none", CustomGBForce::ParticlePair); + vector params; + force->addParticle(params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -483,6 +502,7 @@ int main(int argc, char* argv[]) { testMultipleChainRules(); testPositionDependence(); testExclusions(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomHbondForce.h b/tests/TestCustomHbondForce.h index 344d0d2b5..d398900e3 100644 --- a/tests/TestCustomHbondForce.h +++ b/tests/TestCustomHbondForce.h @@ -225,6 +225,26 @@ void testCustomFunctions() { ASSERT_EQUAL_TOL(0.1*2+0.1*2, state.getPotentialEnergy(), TOL); } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + CustomHbondForce* force = new CustomHbondForce("1+none"); + vector params; + force->addDonor(0, -1, -1, params); + force->addAcceptor(1, -1, -1, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -234,6 +254,7 @@ int main(int argc, char* argv[]) { testExclusions(); testCutoff(); testCustomFunctions(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomManyParticleForce.h b/tests/TestCustomManyParticleForce.h index 5234b2b65..f3cbc7661 100644 --- a/tests/TestCustomManyParticleForce.h +++ b/tests/TestCustomManyParticleForce.h @@ -707,6 +707,24 @@ void testCentralParticleModeLargeSystem() { ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-4); } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + CustomManyParticleForce* force = new CustomManyParticleForce(2, "x1+y2+none"); + vector params; + force->addParticle(params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -725,6 +743,7 @@ int main(int argc, char* argv[]) { testCentralParticleModeNoCutoff(); testCentralParticleModeCutoff(); testCentralParticleModeLargeSystem(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomNonbondedForce.h b/tests/TestCustomNonbondedForce.h index 66e43774b..2f7199171 100644 --- a/tests/TestCustomNonbondedForce.h +++ b/tests/TestCustomNonbondedForce.h @@ -993,6 +993,24 @@ void testMultipleCutoffs() { } } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + CustomNonbondedForce* force = new CustomNonbondedForce("r+none"); + vector params; + force->addParticle(params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -1017,6 +1035,7 @@ int main(int argc, char* argv[]) { testLargeInteractionGroup(); testInteractionGroupLongRangeCorrection(); testMultipleCutoffs(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { diff --git a/tests/TestCustomTorsionForce.h b/tests/TestCustomTorsionForce.h index d98dab3ed..290dbd67e 100644 --- a/tests/TestCustomTorsionForce.h +++ b/tests/TestCustomTorsionForce.h @@ -166,6 +166,27 @@ void testRange() { ASSERT(maxAngle <= M_PI); } +void testIllegalVariable() { + System system; + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + system.addParticle(1.0); + CustomTorsionForce* force = new CustomTorsionForce("theta+none"); + vector params; + force->addTorsion(0, 1, 2, 3, params); + system.addForce(force); + VerletIntegrator integrator(0.001); + bool threwException = false; + try { + Context(system, integrator, platform); + } + catch (const exception& e) { + threwException = true; + } + ASSERT(threwException); +} + void runPlatformTests(); int main(int argc, char* argv[]) { @@ -173,6 +194,7 @@ int main(int argc, char* argv[]) { initializeTests(argc, argv); testTorsions(); testRange(); + testIllegalVariable(); runPlatformTests(); } catch(const exception& e) { -- GitLab From 97f5e6112c10bda4c84eac22698213af69f4317e Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Wed, 23 Sep 2015 16:57:50 -0700 Subject: [PATCH 16/49] Fixed compilation error on Windows --- platforms/cpu/tests/CpuTests.h | 3 +++ platforms/cuda/tests/CudaTests.h | 3 +++ platforms/opencl/tests/OpenCLTests.h | 3 +++ platforms/reference/tests/ReferenceTests.h | 3 +++ 4 files changed, 12 insertions(+) diff --git a/platforms/cpu/tests/CpuTests.h b/platforms/cpu/tests/CpuTests.h index 6bba1f573..58e74c228 100644 --- a/platforms/cpu/tests/CpuTests.h +++ b/platforms/cpu/tests/CpuTests.h @@ -29,6 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif #include "CpuPlatform.h" #include #include diff --git a/platforms/cuda/tests/CudaTests.h b/platforms/cuda/tests/CudaTests.h index db153ec62..7d410f5f1 100644 --- a/platforms/cuda/tests/CudaTests.h +++ b/platforms/cuda/tests/CudaTests.h @@ -29,6 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif #include "CudaPlatform.h" #include diff --git a/platforms/opencl/tests/OpenCLTests.h b/platforms/opencl/tests/OpenCLTests.h index a76ea5aa8..1f2bc1a93 100644 --- a/platforms/opencl/tests/OpenCLTests.h +++ b/platforms/opencl/tests/OpenCLTests.h @@ -29,6 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif #include "OpenCLPlatform.h" #include diff --git a/platforms/reference/tests/ReferenceTests.h b/platforms/reference/tests/ReferenceTests.h index a76269e0f..d128ad557 100644 --- a/platforms/reference/tests/ReferenceTests.h +++ b/platforms/reference/tests/ReferenceTests.h @@ -29,6 +29,9 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ +#ifdef WIN32 + #define _USE_MATH_DEFINES // Needed to get M_PI +#endif #include "ReferencePlatform.h" OpenMM::ReferencePlatform platform; -- GitLab From 1d5c74173329d5e31c1adb74a91faba687f4f392 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Thu, 24 Sep 2015 10:30:12 -0700 Subject: [PATCH 17/49] Added default values for some arguments --- openmmapi/include/openmm/CustomAngleForce.h | 4 ++-- openmmapi/include/openmm/CustomBondForce.h | 4 ++-- openmmapi/include/openmm/CustomCentroidBondForce.h | 8 ++++---- openmmapi/include/openmm/CustomCompoundBondForce.h | 4 ++-- openmmapi/include/openmm/CustomExternalForce.h | 4 ++-- openmmapi/include/openmm/CustomGBForce.h | 2 +- openmmapi/include/openmm/CustomHbondForce.h | 8 ++++---- openmmapi/include/openmm/CustomManyParticleForce.h | 2 +- openmmapi/include/openmm/CustomNonbondedForce.h | 2 +- openmmapi/include/openmm/CustomTorsionForce.h | 4 ++-- tests/TestCustomAngleForce.h | 3 +-- tests/TestCustomBondForce.h | 3 +-- tests/TestCustomCentroidBondForce.h | 3 +-- tests/TestCustomCompoundBondForce.h | 3 +-- tests/TestCustomExternalForce.h | 3 +-- tests/TestCustomGBForce.h | 3 +-- tests/TestCustomHbondForce.h | 5 ++--- tests/TestCustomManyParticleForce.h | 3 +-- tests/TestCustomNonbondedForce.h | 3 +-- tests/TestCustomTorsionForce.h | 3 +-- 20 files changed, 32 insertions(+), 42 deletions(-) diff --git a/openmmapi/include/openmm/CustomAngleForce.h b/openmmapi/include/openmm/CustomAngleForce.h index 0f7c0632f..7e890cef7 100644 --- a/openmmapi/include/openmm/CustomAngleForce.h +++ b/openmmapi/include/openmm/CustomAngleForce.h @@ -171,7 +171,7 @@ public: * @param parameters the list of parameters for the new angle * @return the index of the angle that was added */ - int addAngle(int particle1, int particle2, int particle3, const std::vector& parameters); + int addAngle(int particle1, int particle2, int particle3, const std::vector& parameters=std::vector()); /** * Get the force field parameters for an angle term. * @@ -191,7 +191,7 @@ public: * @param particle3 the index of the third particle connected by the angle * @param parameters the list of parameters for the angle */ - void setAngleParameters(int index, int particle1, int particle2, int particle3, const std::vector& parameters); + void setAngleParameters(int index, int particle1, int particle2, int particle3, const std::vector& parameters=std::vector()); /** * Update the per-angle parameters in a Context to match those stored in this Force object. This method provides * an efficient method to update certain parameters in an existing Context without needing to reinitialize it. diff --git a/openmmapi/include/openmm/CustomBondForce.h b/openmmapi/include/openmm/CustomBondForce.h index fa8660cb0..a366276a5 100644 --- a/openmmapi/include/openmm/CustomBondForce.h +++ b/openmmapi/include/openmm/CustomBondForce.h @@ -170,7 +170,7 @@ public: * @param parameters the list of parameters for the new bond * @return the index of the bond that was added */ - int addBond(int particle1, int particle2, const std::vector& parameters); + int addBond(int particle1, int particle2, const std::vector& parameters=std::vector()); /** * Get the force field parameters for a bond term. * @@ -188,7 +188,7 @@ public: * @param particle2 the index of the second particle connected by the bond * @param parameters the list of parameters for the bond */ - void setBondParameters(int index, int particle1, int particle2, const std::vector& parameters); + void setBondParameters(int index, int particle1, int particle2, const std::vector& parameters=std::vector()); /** * Update the per-bond parameters in a Context to match those stored in this Force object. This method provides * an efficient method to update certain parameters in an existing Context without needing to reinitialize it. diff --git a/openmmapi/include/openmm/CustomCentroidBondForce.h b/openmmapi/include/openmm/CustomCentroidBondForce.h index 985c28c25..dac5ca442 100644 --- a/openmmapi/include/openmm/CustomCentroidBondForce.h +++ b/openmmapi/include/openmm/CustomCentroidBondForce.h @@ -237,7 +237,7 @@ public: * If this is omitted, then particle masses will be used as weights. * @return the index of the group that was added */ - int addGroup(const std::vector& particles, const std::vector& weights = std::vector()); + int addGroup(const std::vector& particles, const std::vector& weights=std::vector()); /** * Get the properties of a group. * @@ -256,7 +256,7 @@ public: * @param weights the weight to use for each particle when computing the center position. * If this is omitted, then particle masses will be used as weights. */ - void setGroupParameters(int index, const std::vector& particles, const std::vector& weights = std::vector()); + void setGroupParameters(int index, const std::vector& particles, const std::vector& weights=std::vector()); /** * Add a bond to the force * @@ -264,7 +264,7 @@ public: * @param parameters the list of per-bond parameter values for the new bond * @return the index of the bond that was added */ - int addBond(const std::vector& groups, const std::vector& parameters); + int addBond(const std::vector& groups, const std::vector& parameters=std::vector()); /** * Get the properties of a bond. * @@ -280,7 +280,7 @@ public: * @param groups the indices of the groups in the bond * @param parameters the list of per-bond parameter values for the bond */ - void setBondParameters(int index, const std::vector& groups, const std::vector& parameters); + void setBondParameters(int index, const std::vector& groups, const std::vector& parameters=std::vector()); /** * Add a tabulated function that may appear in the energy expression. * diff --git a/openmmapi/include/openmm/CustomCompoundBondForce.h b/openmmapi/include/openmm/CustomCompoundBondForce.h index acddf2aba..c67f9d5ec 100644 --- a/openmmapi/include/openmm/CustomCompoundBondForce.h +++ b/openmmapi/include/openmm/CustomCompoundBondForce.h @@ -219,7 +219,7 @@ public: * @param parameters the list of per-bond parameter values for the new bond * @return the index of the bond that was added */ - int addBond(const std::vector& particles, const std::vector& parameters); + int addBond(const std::vector& particles, const std::vector& parameters=std::vector()); /** * Get the properties of a bond. * @@ -235,7 +235,7 @@ public: * @param particles the indices of the particles in the bond * @param parameters the list of per-bond parameter values for the bond */ - void setBondParameters(int index, const std::vector& particles, const std::vector& parameters); + void setBondParameters(int index, const std::vector& particles, const std::vector& parameters=std::vector()); /** * Add a tabulated function that may appear in the energy expression. * diff --git a/openmmapi/include/openmm/CustomExternalForce.h b/openmmapi/include/openmm/CustomExternalForce.h index e0a37d938..7e38dd776 100644 --- a/openmmapi/include/openmm/CustomExternalForce.h +++ b/openmmapi/include/openmm/CustomExternalForce.h @@ -180,7 +180,7 @@ public: * @param parameters the list of parameters for the new force term * @return the index of the particle term that was added */ - int addParticle(int particle, const std::vector& parameters); + int addParticle(int particle, const std::vector& parameters=std::vector()); /** * Get the force field parameters for a force field term. * @@ -196,7 +196,7 @@ public: * @param particle the index of the particle this term is applied to * @param parameters the list of parameters for the force field term */ - void setParticleParameters(int index, int particle, const std::vector& parameters); + void setParticleParameters(int index, int particle, const std::vector& parameters=std::vector()); /** * Update the per-particle parameters in a Context to match those stored in this Force object. This method provides * an efficient method to update certain parameters in an existing Context without needing to reinitialize it. diff --git a/openmmapi/include/openmm/CustomGBForce.h b/openmmapi/include/openmm/CustomGBForce.h index 0a03bbdc8..28576252f 100644 --- a/openmmapi/include/openmm/CustomGBForce.h +++ b/openmmapi/include/openmm/CustomGBForce.h @@ -319,7 +319,7 @@ public: * @param parameters the list of parameters for the new particle * @return the index of the particle that was added */ - int addParticle(const std::vector& parameters); + int addParticle(const std::vector& parameters=std::vector()); /** * Get the nonbonded force parameters for a particle. * diff --git a/openmmapi/include/openmm/CustomHbondForce.h b/openmmapi/include/openmm/CustomHbondForce.h index 1f471a729..fc56f5e68 100644 --- a/openmmapi/include/openmm/CustomHbondForce.h +++ b/openmmapi/include/openmm/CustomHbondForce.h @@ -296,7 +296,7 @@ public: * @param parameters the list of per-donor parameter values for the new donor * @return the index of the donor that was added */ - int addDonor(int d1, int d2, int d3, const std::vector& parameters); + int addDonor(int d1, int d2, int d3, const std::vector& parameters=std::vector()); /** * Get the properties of a donor group. * @@ -320,7 +320,7 @@ public: * less than three particles, this must be -1. * @param parameters the list of per-donor parameter values for the donor */ - void setDonorParameters(int index, int d1, int d2, int d3, const std::vector& parameters); + void setDonorParameters(int index, int d1, int d2, int d3, const std::vector& parameters=std::vector()); /** * Add an acceptor group to the force * @@ -332,7 +332,7 @@ public: * @param parameters the list of per-acceptor parameter values for the new acceptor * @return the index of the acceptor that was added */ - int addAcceptor(int a1, int a2, int a3, const std::vector& parameters); + int addAcceptor(int a1, int a2, int a3, const std::vector& parameters=std::vector()); /** * Get the properties of an acceptor group. * @@ -356,7 +356,7 @@ public: * less than three particles, this must be -1. * @param parameters the list of per-acceptor parameter values for the acceptor */ - void setAcceptorParameters(int index, int a1, int a2, int a3, const std::vector& parameters); + void setAcceptorParameters(int index, int a1, int a2, int a3, const std::vector& parameters=std::vector()); /** * Add a donor-acceptor pair to the list of interactions that should be excluded. * diff --git a/openmmapi/include/openmm/CustomManyParticleForce.h b/openmmapi/include/openmm/CustomManyParticleForce.h index 44e9dbe0f..1c62d9f4f 100644 --- a/openmmapi/include/openmm/CustomManyParticleForce.h +++ b/openmmapi/include/openmm/CustomManyParticleForce.h @@ -348,7 +348,7 @@ public: * @param type the type of the new particle * @return the index of the particle that was added */ - int addParticle(const std::vector& parameters, int type=0); + int addParticle(const std::vector& parameters=std::vector(), int type=0); /** * Get the nonbonded force parameters for a particle. * diff --git a/openmmapi/include/openmm/CustomNonbondedForce.h b/openmmapi/include/openmm/CustomNonbondedForce.h index 05039e7d7..0414139b3 100644 --- a/openmmapi/include/openmm/CustomNonbondedForce.h +++ b/openmmapi/include/openmm/CustomNonbondedForce.h @@ -328,7 +328,7 @@ public: * @param parameters the list of parameters for the new particle * @return the index of the particle that was added */ - int addParticle(const std::vector& parameters); + int addParticle(const std::vector& parameters=std::vector()); /** * Get the nonbonded force parameters for a particle. * diff --git a/openmmapi/include/openmm/CustomTorsionForce.h b/openmmapi/include/openmm/CustomTorsionForce.h index 77ee821ab..7c38269af 100644 --- a/openmmapi/include/openmm/CustomTorsionForce.h +++ b/openmmapi/include/openmm/CustomTorsionForce.h @@ -172,7 +172,7 @@ public: * @param parameters the list of parameters for the new torsion * @return the index of the torsion that was added */ - int addTorsion(int particle1, int particle2, int particle3, int particle4, const std::vector& parameters); + int addTorsion(int particle1, int particle2, int particle3, int particle4, const std::vector& parameters=std::vector()); /** * Get the force field parameters for a torsion term. * @@ -194,7 +194,7 @@ public: * @param particle4 the index of the fourth particle connected by the torsion * @param parameters the list of parameters for the torsion */ - void setTorsionParameters(int index, int particle1, int particle2, int particle3, int particle4, const std::vector& parameters); + void setTorsionParameters(int index, int particle1, int particle2, int particle3, int particle4, const std::vector& parameters=std::vector()); /** * Update the per-torsion parameters in a Context to match those stored in this Force object. This method provides * an efficient method to update certain parameters in an existing Context without needing to reinitialize it. diff --git a/tests/TestCustomAngleForce.h b/tests/TestCustomAngleForce.h index 6e1e1fbb6..2f7e3cde8 100644 --- a/tests/TestCustomAngleForce.h +++ b/tests/TestCustomAngleForce.h @@ -132,8 +132,7 @@ void testIllegalVariable() { system.addParticle(1.0); system.addParticle(1.0); CustomAngleForce* force = new CustomAngleForce("theta+none"); - vector params; - force->addAngle(0, 1, 2, params); + force->addAngle(0, 1, 2); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomBondForce.h b/tests/TestCustomBondForce.h index c3f55205e..4572ab44f 100644 --- a/tests/TestCustomBondForce.h +++ b/tests/TestCustomBondForce.h @@ -135,8 +135,7 @@ void testIllegalVariable() { system.addParticle(1.0); system.addParticle(1.0); CustomBondForce* force = new CustomBondForce("r+none"); - vector params; - force->addBond(0, 1, params); + force->addBond(0, 1); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomCentroidBondForce.h b/tests/TestCustomCentroidBondForce.h index ff76a2bf5..eff0c4058 100644 --- a/tests/TestCustomCentroidBondForce.h +++ b/tests/TestCustomCentroidBondForce.h @@ -264,8 +264,7 @@ void testIllegalVariable() { vector groups; groups.push_back(0); groups.push_back(1); - vector params; - force->addBond(groups, params); + force->addBond(groups); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomCompoundBondForce.h b/tests/TestCustomCompoundBondForce.h index 27f0f2cff..3f24d7c5a 100644 --- a/tests/TestCustomCompoundBondForce.h +++ b/tests/TestCustomCompoundBondForce.h @@ -317,8 +317,7 @@ void testIllegalVariable() { vector particles; particles.push_back(0); particles.push_back(1); - vector params; - force->addBond(particles, params); + force->addBond(particles); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomExternalForce.h b/tests/TestCustomExternalForce.h index ad28c18dc..0718d99f4 100644 --- a/tests/TestCustomExternalForce.h +++ b/tests/TestCustomExternalForce.h @@ -171,8 +171,7 @@ void testIllegalVariable() { System system; system.addParticle(1.0); CustomExternalForce* force = new CustomExternalForce("x+none"); - vector params; - force->addParticle(0, params); + force->addParticle(0); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomGBForce.h b/tests/TestCustomGBForce.h index 1c9a8c2bb..c0821a420 100644 --- a/tests/TestCustomGBForce.h +++ b/tests/TestCustomGBForce.h @@ -475,8 +475,7 @@ void testIllegalVariable() { system.addParticle(1.0); CustomGBForce* force = new CustomGBForce(); force->addComputedValue("a", "r+none", CustomGBForce::ParticlePair); - vector params; - force->addParticle(params); + force->addParticle(); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomHbondForce.h b/tests/TestCustomHbondForce.h index d398900e3..cfd830d42 100644 --- a/tests/TestCustomHbondForce.h +++ b/tests/TestCustomHbondForce.h @@ -230,9 +230,8 @@ void testIllegalVariable() { system.addParticle(1.0); system.addParticle(1.0); CustomHbondForce* force = new CustomHbondForce("1+none"); - vector params; - force->addDonor(0, -1, -1, params); - force->addAcceptor(1, -1, -1, params); + force->addDonor(0, -1, -1); + force->addAcceptor(1, -1, -1); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomManyParticleForce.h b/tests/TestCustomManyParticleForce.h index f3cbc7661..bace473e4 100644 --- a/tests/TestCustomManyParticleForce.h +++ b/tests/TestCustomManyParticleForce.h @@ -711,8 +711,7 @@ void testIllegalVariable() { System system; system.addParticle(1.0); CustomManyParticleForce* force = new CustomManyParticleForce(2, "x1+y2+none"); - vector params; - force->addParticle(params); + force->addParticle(); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomNonbondedForce.h b/tests/TestCustomNonbondedForce.h index 2f7199171..1c20c7c27 100644 --- a/tests/TestCustomNonbondedForce.h +++ b/tests/TestCustomNonbondedForce.h @@ -997,8 +997,7 @@ void testIllegalVariable() { System system; system.addParticle(1.0); CustomNonbondedForce* force = new CustomNonbondedForce("r+none"); - vector params; - force->addParticle(params); + force->addParticle(); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; diff --git a/tests/TestCustomTorsionForce.h b/tests/TestCustomTorsionForce.h index 290dbd67e..f133275d4 100644 --- a/tests/TestCustomTorsionForce.h +++ b/tests/TestCustomTorsionForce.h @@ -173,8 +173,7 @@ void testIllegalVariable() { system.addParticle(1.0); system.addParticle(1.0); CustomTorsionForce* force = new CustomTorsionForce("theta+none"); - vector params; - force->addTorsion(0, 1, 2, 3, params); + force->addTorsion(0, 1, 2, 3); system.addForce(force); VerletIntegrator integrator(0.001); bool threwException = false; -- GitLab From 60d3ef2d7f84bb5ec513811a1443bcaf60c56d96 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Thu, 24 Sep 2015 10:55:58 -0700 Subject: [PATCH 18/49] Updated version number to 7.0 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9dc4a8861..646ba011b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,8 +159,8 @@ ENDIF (NOT CMAKE_CXX_FLAGS_RELEASE) # and make it available to the code so it can be built into the binaries. SET(OPENMM_LIBRARY_NAME OpenMM) -SET(OPENMM_MAJOR_VERSION 6) -SET(OPENMM_MINOR_VERSION 3) +SET(OPENMM_MAJOR_VERSION 7) +SET(OPENMM_MINOR_VERSION 0) SET(OPENMM_BUILD_VERSION 0) SET(OPENMM_COPYRIGHT_YEARS "2008-2015") -- GitLab From 02825c4632f3379f39dfb93f583631ac2912486f Mon Sep 17 00:00:00 2001 From: peastman Date: Thu, 24 Sep 2015 16:52:37 -0700 Subject: [PATCH 19/49] Optimizations to CPU platform --- platforms/cpu/include/CpuKernels.h | 41 ++++++++++++ platforms/cpu/include/CpuLangevinDynamics.h | 15 ++++- platforms/cpu/src/CpuKernelFactory.cpp | 2 + platforms/cpu/src/CpuKernels.cpp | 63 ++++++++++++++++++- platforms/cpu/src/CpuLangevinDynamics.cpp | 42 ++++++++++++- platforms/cpu/src/CpuPlatform.cpp | 1 + .../cpu/tests/TestCpuHarmonicAngleForce.cpp | 63 +++++++++++++++++++ .../include/ReferenceStochasticDynamics.h | 15 ++++- .../ReferenceStochasticDynamics.cpp | 22 ++++--- 9 files changed, 250 insertions(+), 14 deletions(-) create mode 100644 platforms/cpu/tests/TestCpuHarmonicAngleForce.cpp diff --git a/platforms/cpu/include/CpuKernels.h b/platforms/cpu/include/CpuKernels.h index b989316c2..9ac031800 100644 --- a/platforms/cpu/include/CpuKernels.h +++ b/platforms/cpu/include/CpuKernels.h @@ -92,6 +92,46 @@ private: Kernel referenceKernel; }; +/** + * This kernel is invoked by HarmonicAngleForce to calculate the forces acting on the system and the energy of the system. + */ +class CpuCalcHarmonicAngleForceKernel : public CalcHarmonicAngleForceKernel { +public: + CpuCalcHarmonicAngleForceKernel(std::string name, const Platform& platform, CpuPlatform::PlatformData& data) : + CalcHarmonicAngleForceKernel(name, platform), data(data), angleIndexArray(NULL), angleParamArray(NULL) { + } + ~CpuCalcHarmonicAngleForceKernel(); + /** + * Initialize the kernel. + * + * @param system the System this kernel will be applied to + * @param force the HarmonicAngleForce this kernel will be used for + */ + void initialize(const System& system, const HarmonicAngleForce& force); + /** + * Execute the kernel to calculate the forces and/or energy. + * + * @param context the context in which to execute this kernel + * @param includeForces true if forces should be calculated + * @param includeEnergy true if the energy should be calculated + * @return the potential energy due to the force + */ + double execute(ContextImpl& context, bool includeForces, bool includeEnergy); + /** + * Copy changed parameters over to a context. + * + * @param context the context to copy parameters to + * @param force the HarmonicAngleForce to copy the parameters from + */ + void copyParametersToContext(ContextImpl& context, const HarmonicAngleForce& force); +private: + CpuPlatform::PlatformData& data; + int numAngles; + int **angleIndexArray; + RealOpenMM **angleParamArray; + CpuBondForce bondForce; +}; + /** * This kernel is invoked by PeriodicTorsionForce to calculate the forces acting on the system and the energy of the system. */ @@ -229,6 +269,7 @@ private: CpuNeighborList* neighborList; CpuNonbondedForce* nonbonded; Kernel optimizedPme; + CpuBondForce bondForce; }; /** diff --git a/platforms/cpu/include/CpuLangevinDynamics.h b/platforms/cpu/include/CpuLangevinDynamics.h index 416104229..2abe58139 100644 --- a/platforms/cpu/include/CpuLangevinDynamics.h +++ b/platforms/cpu/include/CpuLangevinDynamics.h @@ -1,5 +1,5 @@ -/* Portions copyright (c) 2013 Stanford University and Simbios. +/* Portions copyright (c) 2013-2015 Stanford University and Simbios. * Authors: Peter Eastman * Contributors: * @@ -37,6 +37,7 @@ class CpuLangevinDynamics : public ReferenceStochasticDynamics { public: class Update1Task; class Update2Task; + class Update3Task; /** * Constructor. * @@ -80,9 +81,21 @@ public: void updatePart2(int numberOfAtoms, std::vector& atomCoordinates, std::vector& velocities, std::vector& forces, std::vector& inverseMasses, std::vector& xPrime); + /** + * Third update + * + * @param numberOfAtoms number of atoms + * @param atomCoordinates atom coordinates + * @param velocities velocities + * @param inverseMasses inverse atom masses + */ + void updatePart3(int numberOfAtoms, std::vector& atomCoordinates, std::vector& velocities, + std::vector& inverseMasses, std::vector& xPrime); + private: void threadUpdate1(int threadIndex); void threadUpdate2(int threadIndex); + void threadUpdate3(int threadIndex); OpenMM::ThreadPool& threads; OpenMM::CpuRandom& random; std::vector threadRandom; diff --git a/platforms/cpu/src/CpuKernelFactory.cpp b/platforms/cpu/src/CpuKernelFactory.cpp index 3eccd82e3..4aabd9a1e 100644 --- a/platforms/cpu/src/CpuKernelFactory.cpp +++ b/platforms/cpu/src/CpuKernelFactory.cpp @@ -41,6 +41,8 @@ KernelImpl* CpuKernelFactory::createKernelImpl(std::string name, const Platform& CpuPlatform::PlatformData& data = CpuPlatform::getPlatformData(context); if (name == CalcForcesAndEnergyKernel::Name()) return new CpuCalcForcesAndEnergyKernel(name, platform, data, context); + if (name == CalcHarmonicAngleForceKernel::Name()) + return new CpuCalcHarmonicAngleForceKernel(name, platform, data); if (name == CalcPeriodicTorsionForceKernel::Name()) return new CpuCalcPeriodicTorsionForceKernel(name, platform, data); if (name == CalcRBTorsionForceKernel::Name()) diff --git a/platforms/cpu/src/CpuKernels.cpp b/platforms/cpu/src/CpuKernels.cpp index f10bbc7ad..bca60c267 100644 --- a/platforms/cpu/src/CpuKernels.cpp +++ b/platforms/cpu/src/CpuKernels.cpp @@ -30,6 +30,7 @@ * -------------------------------------------------------------------------- */ #include "CpuKernels.h" +#include "ReferenceAngleBondIxn.h" #include "ReferenceBondForce.h" #include "ReferenceConstraints.h" #include "ReferenceKernelFactory.h" @@ -252,6 +253,64 @@ double CpuCalcForcesAndEnergyKernel::finishComputation(ContextImpl& context, boo return referenceKernel.getAs().finishComputation(context, includeForce, includeEnergy, groups, valid); } +CpuCalcHarmonicAngleForceKernel::~CpuCalcHarmonicAngleForceKernel() { + if (angleIndexArray != NULL) { + for (int i = 0; i < numAngles; i++) { + delete[] angleIndexArray[i]; + delete[] angleParamArray[i]; + } + delete[] angleIndexArray; + delete[] angleParamArray; + } +} + +void CpuCalcHarmonicAngleForceKernel::initialize(const System& system, const HarmonicAngleForce& force) { + numAngles = force.getNumAngles(); + angleIndexArray = new int*[numAngles]; + for (int i = 0; i < numAngles; i++) + angleIndexArray[i] = new int[3]; + angleParamArray = new RealOpenMM*[numAngles]; + for (int i = 0; i < numAngles; i++) + angleParamArray[i] = new RealOpenMM[2]; + for (int i = 0; i < numAngles; ++i) { + int particle1, particle2, particle3; + double angle, k; + force.getAngleParameters(i, particle1, particle2, particle3, angle, k); + angleIndexArray[i][0] = particle1; + angleIndexArray[i][1] = particle2; + angleIndexArray[i][2] = particle3; + angleParamArray[i][0] = (RealOpenMM) angle; + angleParamArray[i][1] = (RealOpenMM) k; + } + bondForce.initialize(system.getNumParticles(), numAngles, 3, angleIndexArray, data.threads); +} + +double CpuCalcHarmonicAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { + vector& posData = extractPositions(context); + vector& forceData = extractForces(context); + RealOpenMM energy = 0; + ReferenceAngleBondIxn angleBond; + bondForce.calculateForce(posData, angleParamArray, forceData, includeEnergy ? &energy : NULL, angleBond); + return energy; +} + +void CpuCalcHarmonicAngleForceKernel::copyParametersToContext(ContextImpl& context, const HarmonicAngleForce& force) { + if (numAngles != force.getNumAngles()) + throw OpenMMException("updateParametersInContext: The number of angles has changed"); + + // Record the values. + + for (int i = 0; i < numAngles; ++i) { + int particle1, particle2, particle3; + double angle, k; + force.getAngleParameters(i, particle1, particle2, particle3, angle, k); + if (particle1 != angleIndexArray[i][0] || particle2 != angleIndexArray[i][1] || particle3 != angleIndexArray[i][2]) + throw OpenMMException("updateParametersInContext: The set of particles in an angle has changed"); + angleParamArray[i][0] = (RealOpenMM) angle; + angleParamArray[i][1] = (RealOpenMM) k; + } +} + CpuCalcPeriodicTorsionForceKernel::~CpuCalcPeriodicTorsionForceKernel() { if (torsionIndexArray != NULL) { for (int i = 0; i < numTorsions; i++) { @@ -479,6 +538,7 @@ void CpuCalcNonbondedForceKernel::initialize(const System& system, const Nonbond bonded14ParamArray[i][1] = static_cast(4.0*depth); bonded14ParamArray[i][2] = static_cast(charge); } + bondForce.initialize(system.getNumParticles(), num14, 2, bonded14IndexArray, data.threads); // Record other parameters. @@ -611,9 +671,8 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo } energy += nonbondedEnergy; if (includeDirect) { - ReferenceBondForce refBondForce; ReferenceLJCoulomb14 nonbonded14; - refBondForce.calculateForce(num14, bonded14IndexArray, posData, bonded14ParamArray, forceData, includeEnergy ? &energy : NULL, nonbonded14); + bondForce.calculateForce(posData, bonded14ParamArray, forceData, includeEnergy ? &energy : NULL, nonbonded14); if (data.isPeriodic) energy += dispersionCoefficient/(boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2]); } diff --git a/platforms/cpu/src/CpuLangevinDynamics.cpp b/platforms/cpu/src/CpuLangevinDynamics.cpp index 576309ffc..5d51c66fb 100644 --- a/platforms/cpu/src/CpuLangevinDynamics.cpp +++ b/platforms/cpu/src/CpuLangevinDynamics.cpp @@ -1,5 +1,5 @@ -/* Portions copyright (c) 2006-2013 Stanford University and Simbios. +/* Portions copyright (c) 2006-2015 Stanford University and Simbios. * Authors: Peter Eastman * Contributors: * @@ -49,6 +49,16 @@ public: CpuLangevinDynamics& owner; }; +class CpuLangevinDynamics::Update3Task : public ThreadPool::Task { +public: + Update3Task(CpuLangevinDynamics& owner) : owner(owner) { + } + void execute(ThreadPool& threads, int threadIndex) { + owner.threadUpdate3(threadIndex); + } + CpuLangevinDynamics& owner; +}; + CpuLangevinDynamics::CpuLangevinDynamics(int numberOfAtoms, RealOpenMM deltaT, RealOpenMM tau, RealOpenMM temperature, ThreadPool& threads, CpuRandom& random) : ReferenceStochasticDynamics(numberOfAtoms, deltaT, tau, temperature), threads(threads), random(random) { } @@ -92,6 +102,23 @@ void CpuLangevinDynamics::updatePart2(int numberOfAtoms, vector& atomCo threads.waitForThreads(); } +void CpuLangevinDynamics::updatePart3(int numberOfAtoms, vector& atomCoordinates, vector& velocities, + vector& inverseMasses, vector& xPrime) { + // Record the parameters for the threads. + + this->numberOfAtoms = numberOfAtoms; + this->atomCoordinates = &atomCoordinates[0]; + this->velocities = &velocities[0]; + this->inverseMasses = &inverseMasses[0]; + this->xPrime = &xPrime[0]; + + // Signal the threads to start running and wait for them to finish. + + Update3Task task(*this); + threads.execute(task); + threads.waitForThreads(); +} + void CpuLangevinDynamics::threadUpdate1(int threadIndex) { const RealOpenMM tau = getTau(); const RealOpenMM vscale = EXP(-getDeltaT()/tau); @@ -122,3 +149,16 @@ void CpuLangevinDynamics::threadUpdate2(int threadIndex) { } } } + +void CpuLangevinDynamics::threadUpdate3(int threadIndex) { + const RealOpenMM invStepSize = 1.0/getDeltaT(); + int start = threadIndex*numberOfAtoms/threads.getNumThreads(); + int end = (threadIndex+1)*numberOfAtoms/threads.getNumThreads(); + + for (int i = start; i < end; ++i) + if (inverseMasses[i] != 0.0) { + velocities[i] = (xPrime[i]-atomCoordinates[i])*invStepSize; + atomCoordinates[i] = xPrime[i]; + } +} + diff --git a/platforms/cpu/src/CpuPlatform.cpp b/platforms/cpu/src/CpuPlatform.cpp index ccd164141..9e40ee7f5 100644 --- a/platforms/cpu/src/CpuPlatform.cpp +++ b/platforms/cpu/src/CpuPlatform.cpp @@ -61,6 +61,7 @@ map CpuPlatform::contextData; CpuPlatform::CpuPlatform() { CpuKernelFactory* factory = new CpuKernelFactory(); registerKernelFactory(CalcForcesAndEnergyKernel::Name(), factory); + registerKernelFactory(CalcHarmonicAngleForceKernel::Name(), factory); registerKernelFactory(CalcPeriodicTorsionForceKernel::Name(), factory); registerKernelFactory(CalcRBTorsionForceKernel::Name(), factory); registerKernelFactory(CalcNonbondedForceKernel::Name(), factory); diff --git a/platforms/cpu/tests/TestCpuHarmonicAngleForce.cpp b/platforms/cpu/tests/TestCpuHarmonicAngleForce.cpp new file mode 100644 index 000000000..7ef0066cb --- /dev/null +++ b/platforms/cpu/tests/TestCpuHarmonicAngleForce.cpp @@ -0,0 +1,63 @@ +/* -------------------------------------------------------------------------- * + * 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-2015 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 "CpuTests.h" +#include "TestHarmonicAngleForce.h" + +void testParallelComputation() { + System system; + const int numParticles = 200; + for (int i = 0; i < numParticles; i++) + system.addParticle(1.0); + HarmonicAngleForce* force = new HarmonicAngleForce(); + for (int i = 2; i < numParticles; i++) + force->addAngle(i-2, i-1, i, 1.1, i); + system.addForce(force); + vector positions(numParticles); + for (int i = 0; i < numParticles; i++) + positions[i] = Vec3(i, i%2, 0); + VerletIntegrator integrator1(0.01); + ReferencePlatform reference; + Context context1(system, integrator1, reference); + context1.setPositions(positions); + State state1 = context1.getState(State::Forces | State::Energy); + VerletIntegrator integrator2(0.01); + Context context2(system, integrator2, platform); + context2.setPositions(positions); + State state2 = context2.getState(State::Forces | State::Energy); + ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-5); + for (int i = 0; i < numParticles; i++) + ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); +} + +void runPlatformTests() { + testParallelComputation(); +} diff --git a/platforms/reference/include/ReferenceStochasticDynamics.h b/platforms/reference/include/ReferenceStochasticDynamics.h index d11ece3ec..3a8b52a45 100644 --- a/platforms/reference/include/ReferenceStochasticDynamics.h +++ b/platforms/reference/include/ReferenceStochasticDynamics.h @@ -111,13 +111,26 @@ class OPENMM_EXPORT ReferenceStochasticDynamics : public ReferenceDynamics { @param atomCoordinates atom coordinates @param velocities velocities @param forces forces - @param masses atom masses + @param inverseMasses inverse atom masses --------------------------------------------------------------------------------------- */ virtual void updatePart2(int numberOfAtoms, std::vector& atomCoordinates, std::vector& velocities, std::vector& forces, std::vector& inverseMasses, std::vector& xPrime); + /**--------------------------------------------------------------------------------------- + + Third update + + @param numberOfAtoms number of atoms + @param atomCoordinates atom coordinates + @param velocities velocities + @param inverseMasses inverse atom masses + + --------------------------------------------------------------------------------------- */ + + virtual void updatePart3(int numberOfAtoms, std::vector& atomCoordinates, std::vector& velocities, + std::vector& inverseMasses, std::vector& xPrime); }; } // namespace OpenMM diff --git a/platforms/reference/src/SimTKReference/ReferenceStochasticDynamics.cpp b/platforms/reference/src/SimTKReference/ReferenceStochasticDynamics.cpp index eb2637ff2..e9033a51e 100644 --- a/platforms/reference/src/SimTKReference/ReferenceStochasticDynamics.cpp +++ b/platforms/reference/src/SimTKReference/ReferenceStochasticDynamics.cpp @@ -163,11 +163,21 @@ void ReferenceStochasticDynamics::updatePart2(int numberOfAtoms, vector for (int ii = 0; ii < numberOfAtoms; ii++) { if (inverseMasses[ii] != 0.0) - for (int jj = 0; jj < 3; jj++) - xPrime[ii][jj] = atomCoordinates[ii][jj]+getDeltaT()*velocities[ii][jj]; + xPrime[ii] = atomCoordinates[ii]+velocities[ii]*getDeltaT(); } } +void ReferenceStochasticDynamics::updatePart3(int numberOfAtoms, vector& atomCoordinates, + vector& velocities, vector& inverseMasses, + vector& xPrime) { + RealOpenMM invStepSize = 1.0/getDeltaT(); + for (int i = 0; i < numberOfAtoms; ++i) + if (inverseMasses[i] != 0) { + velocities[i] = (xPrime[i]-atomCoordinates[i])*invStepSize; + atomCoordinates[i] = xPrime[i]; + } +} + /**--------------------------------------------------------------------------------------- Update -- driver routine for performing stochastic dynamics update of coordinates @@ -221,13 +231,7 @@ void ReferenceStochasticDynamics::update(const OpenMM::System& system, vector atomCoordinates - RealOpenMM invStepSize = 1.0/getDeltaT(); - for (int i = 0; i < numberOfAtoms; ++i) - if (masses[i] != zero) - for (int j = 0; j < 3; ++j) { - velocities[i][j] = invStepSize*(xPrime[i][j]-atomCoordinates[i][j]); - atomCoordinates[i][j] = xPrime[i][j]; - } + updatePart3(numberOfAtoms, atomCoordinates, velocities, inverseMasses, xPrime); ReferenceVirtualSites::computePositions(system, atomCoordinates); incrementTimeStep(); -- GitLab From 10ceb969a641f58ea57d9264944e7cce2c812b08 Mon Sep 17 00:00:00 2001 From: peastman Date: Thu, 24 Sep 2015 17:02:49 -0700 Subject: [PATCH 20/49] Fixed compilation error on Windows --- platforms/reference/include/ReferenceAngleBondIxn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/reference/include/ReferenceAngleBondIxn.h b/platforms/reference/include/ReferenceAngleBondIxn.h index 4a18be67e..c85f1fe8a 100644 --- a/platforms/reference/include/ReferenceAngleBondIxn.h +++ b/platforms/reference/include/ReferenceAngleBondIxn.h @@ -29,7 +29,7 @@ namespace OpenMM { -class ReferenceAngleBondIxn : public ReferenceBondIxn { +class OPENMM_EXPORT ReferenceAngleBondIxn : public ReferenceBondIxn { private: -- GitLab From 15e2ba85ea87e0333c92ad30f34dd0abcd15cf7c Mon Sep 17 00:00:00 2001 From: peastman Date: Fri, 25 Sep 2015 14:15:25 -0700 Subject: [PATCH 21/49] Further optimizations to CPU platform --- .../include/openmm/internal}/gmx_atomic.h | 0 platforms/cpu/src/CpuCustomGBForce.cpp | 2 +- .../cpu/src/CpuCustomManyParticleForce.cpp | 2 +- platforms/cpu/src/CpuCustomNonbondedForce.cpp | 2 +- platforms/cpu/src/CpuGBSAOBCForce.cpp | 2 +- platforms/cpu/src/CpuNonbondedForce.cpp | 2 +- platforms/cpu/src/CpuSETTLE.cpp | 29 +++++++---- plugins/cpupme/src/CpuPmeKernels.cpp | 49 ++++++++++--------- plugins/cpupme/src/CpuPmeKernels.h | 4 +- 9 files changed, 53 insertions(+), 39 deletions(-) rename {platforms/cpu/src => openmmapi/include/openmm/internal}/gmx_atomic.h (100%) diff --git a/platforms/cpu/src/gmx_atomic.h b/openmmapi/include/openmm/internal/gmx_atomic.h similarity index 100% rename from platforms/cpu/src/gmx_atomic.h rename to openmmapi/include/openmm/internal/gmx_atomic.h diff --git a/platforms/cpu/src/CpuCustomGBForce.cpp b/platforms/cpu/src/CpuCustomGBForce.cpp index ead738c61..7d159840d 100644 --- a/platforms/cpu/src/CpuCustomGBForce.cpp +++ b/platforms/cpu/src/CpuCustomGBForce.cpp @@ -28,7 +28,7 @@ #include "SimTKOpenMMUtilities.h" #include "ReferenceForce.h" #include "CpuCustomGBForce.h" -#include "gmx_atomic.h" +#include "openmm/internal/gmx_atomic.h" using namespace OpenMM; using namespace std; diff --git a/platforms/cpu/src/CpuCustomManyParticleForce.cpp b/platforms/cpu/src/CpuCustomManyParticleForce.cpp index 553d6c2e4..5dd56e7e4 100644 --- a/platforms/cpu/src/CpuCustomManyParticleForce.cpp +++ b/platforms/cpu/src/CpuCustomManyParticleForce.cpp @@ -32,7 +32,7 @@ #include "ReferenceTabulatedFunction.h" #include "openmm/internal/CustomManyParticleForceImpl.h" #include "lepton/CustomFunction.h" -#include "gmx_atomic.h" +#include "openmm/internal/gmx_atomic.h" using namespace OpenMM; using namespace std; diff --git a/platforms/cpu/src/CpuCustomNonbondedForce.cpp b/platforms/cpu/src/CpuCustomNonbondedForce.cpp index 71662ebdd..4711857d3 100644 --- a/platforms/cpu/src/CpuCustomNonbondedForce.cpp +++ b/platforms/cpu/src/CpuCustomNonbondedForce.cpp @@ -28,7 +28,7 @@ #include "SimTKOpenMMUtilities.h" #include "ReferenceForce.h" #include "CpuCustomNonbondedForce.h" -#include "gmx_atomic.h" +#include "openmm/internal/gmx_atomic.h" using namespace OpenMM; using namespace std; diff --git a/platforms/cpu/src/CpuGBSAOBCForce.cpp b/platforms/cpu/src/CpuGBSAOBCForce.cpp index 8b6831f92..64d189426 100644 --- a/platforms/cpu/src/CpuGBSAOBCForce.cpp +++ b/platforms/cpu/src/CpuGBSAOBCForce.cpp @@ -25,7 +25,7 @@ #include "CpuGBSAOBCForce.h" #include "SimTKOpenMMRealType.h" #include "openmm/internal/vectorize.h" -#include "gmx_atomic.h" +#include "openmm/internal/gmx_atomic.h" #include #include #include diff --git a/platforms/cpu/src/CpuNonbondedForce.cpp b/platforms/cpu/src/CpuNonbondedForce.cpp index 080543348..c6e380bec 100644 --- a/platforms/cpu/src/CpuNonbondedForce.cpp +++ b/platforms/cpu/src/CpuNonbondedForce.cpp @@ -28,7 +28,7 @@ #include "CpuNonbondedForce.h" #include "ReferenceForce.h" #include "ReferencePME.h" -#include "gmx_atomic.h" +#include "openmm/internal/gmx_atomic.h" #include // In case we're using some primitive version of Visual Studio this will diff --git a/platforms/cpu/src/CpuSETTLE.cpp b/platforms/cpu/src/CpuSETTLE.cpp index 5fe2cd5f2..cb95118a5 100644 --- a/platforms/cpu/src/CpuSETTLE.cpp +++ b/platforms/cpu/src/CpuSETTLE.cpp @@ -6,7 +6,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2013 Stanford University and the Authors. * + * Portions copyright (c) 2013-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -30,6 +30,7 @@ * -------------------------------------------------------------------------- */ #include "CpuSETTLE.h" +#include "openmm/internal/gmx_atomic.h" using namespace OpenMM; using namespace std; @@ -39,10 +40,14 @@ public: ApplyToPositionsTask(vector& atomCoordinates, vector& atomCoordinatesP, vector& inverseMasses, RealOpenMM tolerance, vector& threadSettle) : atomCoordinates(atomCoordinates), atomCoordinatesP(atomCoordinatesP), inverseMasses(inverseMasses), tolerance(tolerance), threadSettle(threadSettle) { + gmx_atomic_set(&atomicCounter, 0); } void execute(ThreadPool& threads, int threadIndex) { - if (threadIndex < threadSettle.size()) { - threadSettle[threadIndex]->apply(atomCoordinates, atomCoordinatesP, inverseMasses, tolerance); + while (true) { + int index = gmx_atomic_fetch_add(&atomicCounter, 1); + if (index >= threadSettle.size()) + break; + threadSettle[index]->apply(atomCoordinates, atomCoordinatesP, inverseMasses, tolerance); } } vector& atomCoordinates; @@ -50,6 +55,7 @@ public: vector& inverseMasses; RealOpenMM tolerance; vector& threadSettle; + gmx_atomic_t atomicCounter; }; class CpuSETTLE::ApplyToVelocitiesTask : public ThreadPool::Task { @@ -57,10 +63,14 @@ public: ApplyToVelocitiesTask(vector& atomCoordinates, vector& velocities, vector& inverseMasses, RealOpenMM tolerance, vector& threadSettle) : atomCoordinates(atomCoordinates), velocities(velocities), inverseMasses(inverseMasses), tolerance(tolerance), threadSettle(threadSettle) { + gmx_atomic_set(&atomicCounter, 0); } void execute(ThreadPool& threads, int threadIndex) { - if (threadIndex < threadSettle.size()) { - threadSettle[threadIndex]->applyToVelocities(atomCoordinates, velocities, inverseMasses, tolerance); + while (true) { + int index = gmx_atomic_fetch_add(&atomicCounter, 1); + if (index >= threadSettle.size()) + break; + threadSettle[index]->applyToVelocities(atomCoordinates, velocities, inverseMasses, tolerance); } } vector& atomCoordinates; @@ -68,17 +78,18 @@ public: vector& inverseMasses; RealOpenMM tolerance; vector& threadSettle; + gmx_atomic_t atomicCounter; }; CpuSETTLE::CpuSETTLE(const System& system, const ReferenceSETTLEAlgorithm& settle, ThreadPool& threads) : threads(threads) { - int numThreads = threads.getNumThreads(); + int numBlocks = 10*threads.getNumThreads(); int numClusters = settle.getNumClusters(); vector mass(system.getNumParticles()); for (int i = 0; i < system.getNumParticles(); i++) mass[i] = system.getParticleMass(i); - for (int i = 0; i < numThreads; i++) { - int start = i*numClusters/numThreads; - int end = (i+1)*numClusters/numThreads; + for (int i = 0; i < numBlocks; i++) { + int start = i*numClusters/numBlocks; + int end = (i+1)*numClusters/numBlocks; if (start != end) { int numThreadClusters = end-start; vector atom1(numThreadClusters), atom2(numThreadClusters), atom3(numThreadClusters); diff --git a/plugins/cpupme/src/CpuPmeKernels.cpp b/plugins/cpupme/src/CpuPmeKernels.cpp index f00661f36..ce1ba2ef3 100644 --- a/plugins/cpupme/src/CpuPmeKernels.cpp +++ b/plugins/cpupme/src/CpuPmeKernels.cpp @@ -49,7 +49,7 @@ static const int PME_ORDER = 5; bool CpuCalcPmeReciprocalForceKernel::hasInitializedThreads = false; int CpuCalcPmeReciprocalForceKernel::numThreads = 0; -static void spreadCharge(int start, int end, float* posq, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) { +static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors, gmx_atomic_t& atomicCounter) { float temp[4]; fvec4 boxSize((float) periodicBoxVectors[0][0], (float) periodicBoxVectors[1][1], (float) periodicBoxVectors[2][2], 0); fvec4 invBoxSize((float) recipBoxVectors[0][0], (float) recipBoxVectors[1][1], (float) recipBoxVectors[2][2], 0); @@ -64,7 +64,11 @@ static void spreadCharge(int start, int end, float* posq, float* grid, int gridx const float epsilonFactor = sqrt(ONE_4PI_EPS0); memset(grid, 0, sizeof(float)*gridx*gridy*gridz); - for (int i = start; i < end; i++) { + while (true) { + int i = gmx_atomic_fetch_add(&atomicCounter, 1); + if (i >= numParticles) + break; + // Find the position relative to the nearest grid point. fvec4 pos(&posq[4*i]); @@ -225,25 +229,15 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid return 0.5*energy; } -static void reciprocalConvolution(int start, int end, fftwf_complex* grid, int gridx, int gridy, int gridz, vector& recipEterm) { - const unsigned int zsize = gridz/2+1; - const unsigned int yzsize = gridy*zsize; - - int firstz = (start == 0 ? 1 : 0); - for (int kx = start; kx < end; kx++) { - for (int ky = 0; ky < gridy; ky++) { - for (int kz = firstz; kz < zsize; kz++) { - int index = kx*yzsize + ky*zsize + kz; - float eterm = recipEterm[index]; - grid[index][0] *= eterm; - grid[index][1] *= eterm; - } - firstz = 0; - } +static void reciprocalConvolution(int start, int end, fftwf_complex* grid, vector& recipEterm) { + for (int index = start; index < end; index++) { + float eterm = recipEterm[index]; + grid[index][0] *= eterm; + grid[index][1] *= eterm; } } -static void interpolateForces(int start, int end, float* posq, float* force, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) { +static void interpolateForces(float* posq, float* force, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors, gmx_atomic_t& atomicCounter) { fvec4 boxSize((float) periodicBoxVectors[0][0], (float) periodicBoxVectors[1][1], (float) periodicBoxVectors[2][2], 0); fvec4 invBoxSize((float) recipBoxVectors[0][0], (float) recipBoxVectors[1][1], (float) recipBoxVectors[2][2], 0); fvec4 recipBoxVec0((float) recipBoxVectors[0][0], (float) recipBoxVectors[0][1], (float) recipBoxVectors[0][2], 0); @@ -254,7 +248,11 @@ static void interpolateForces(int start, int end, float* posq, float* force, flo fvec4 one(1); fvec4 scale(1.0f/(PME_ORDER-1)); const float epsilonFactor = sqrt(ONE_4PI_EPS0); - for (int i = start; i < end; i++) { + while (true) { + int i = gmx_atomic_fetch_add(&atomicCounter, 1); + if (i >= numParticles) + break; + // Find the position relative to the nearest grid point. fvec4 pos(&posq[4*i]); @@ -485,6 +483,7 @@ void CpuCalcPmeReciprocalForceKernel::runMainThread() { break; posq = io->getPosq(); ComputeTask task(*this); + gmx_atomic_set(&atomicCounter, 0); threads.execute(task); // Signal threads to perform charge spreading. threads.waitForThreads(); threads.resumeThreads(); // Signal threads to sum the charge grids. @@ -503,6 +502,7 @@ void CpuCalcPmeReciprocalForceKernel::runMainThread() { threads.resumeThreads(); // Signal threads to perform reciprocal convolution. threads.waitForThreads(); fftwf_execute_dft_c2r(backwardFFT, complexGrid, realGrid); + gmx_atomic_set(&atomicCounter, 0); threads.resumeThreads(); // Signal threads to interpolate forces. threads.waitForThreads(); isFinished = true; @@ -515,14 +515,15 @@ void CpuCalcPmeReciprocalForceKernel::runMainThread() { } void CpuCalcPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int index) { - int particleStart = (index*numParticles)/numThreads; - int particleEnd = ((index+1)*numParticles)/numThreads; int gridxStart = (index*gridx)/numThreads; int gridxEnd = ((index+1)*gridx)/numThreads; int gridSize = (gridx*gridy*gridz+3)/4; int gridStart = 4*((index*gridSize)/numThreads); int gridEnd = 4*(((index+1)*gridSize)/numThreads); - spreadCharge(particleStart, particleEnd, posq, tempGrid[index], gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors); + int complexSize = gridx*gridy*(gridz/2+1); + int complexStart = max(1, ((index*complexSize)/numThreads)); + int complexEnd = (((index+1)*complexSize)/numThreads); + spreadCharge(posq, tempGrid[index], gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter); threads.syncThreads(); int numGrids = tempGrid.size(); for (int i = gridStart; i < gridEnd; i += 4) { @@ -540,9 +541,9 @@ void CpuCalcPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int i threadEnergy[index] = reciprocalEnergy(gridxStart, gridxEnd, complexGrid, gridx, gridy, gridz, alpha, bsplineModuli, periodicBoxVectors, recipBoxVectors); threads.syncThreads(); } - reciprocalConvolution(gridxStart, gridxEnd, complexGrid, gridx, gridy, gridz, recipEterm); + reciprocalConvolution(complexStart, complexEnd, complexGrid, recipEterm); threads.syncThreads(); - interpolateForces(particleStart, particleEnd, posq, &force[0], realGrid, gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors); + interpolateForces(posq, &force[0], realGrid, gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter); } void CpuCalcPmeReciprocalForceKernel::beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy) { diff --git a/plugins/cpupme/src/CpuPmeKernels.h b/plugins/cpupme/src/CpuPmeKernels.h index e542a8359..a9025d83d 100644 --- a/plugins/cpupme/src/CpuPmeKernels.h +++ b/plugins/cpupme/src/CpuPmeKernels.h @@ -9,7 +9,7 @@ * Biological Structures at Stanford, funded under the NIH Roadmap for * * Medical Research, grant U54 GM072970. See https://simtk.org. * * * - * Portions copyright (c) 2013-2014 Stanford University and the Authors. * + * Portions copyright (c) 2013-2015 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * @@ -36,6 +36,7 @@ #include "internal/windowsExportPme.h" #include "openmm/kernels.h" #include "openmm/Vec3.h" +#include "openmm/internal/gmx_atomic.h" #include "openmm/internal/ThreadPool.h" #include #include @@ -130,6 +131,7 @@ private: float* posq; Vec3 periodicBoxVectors[3], recipBoxVectors[3]; bool includeEnergy; + gmx_atomic_t atomicCounter; }; } // namespace OpenMM -- GitLab From 4094773569b056d27ffe9efb8f71f7a84df37689 Mon Sep 17 00:00:00 2001 From: peastman Date: Mon, 28 Sep 2015 11:21:24 -0700 Subject: [PATCH 22/49] Further optimizations to CPU platform --- platforms/cpu/include/CpuNeighborList.h | 2 + platforms/cpu/src/CpuKernels.cpp | 2 +- platforms/cpu/src/CpuNeighborList.cpp | 63 ++++++++++++++++--------- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/platforms/cpu/include/CpuNeighborList.h b/platforms/cpu/include/CpuNeighborList.h index 2430f5f13..7c585ebc9 100644 --- a/platforms/cpu/include/CpuNeighborList.h +++ b/platforms/cpu/include/CpuNeighborList.h @@ -35,6 +35,7 @@ #include "AlignedArray.h" #include "RealVec.h" #include "windowsExportCpu.h" +#include "openmm/internal/gmx_atomic.h" #include "openmm/internal/ThreadPool.h" #include #include @@ -74,6 +75,7 @@ private: int numAtoms; bool usePeriodic; float maxDistance; + gmx_atomic_t atomicCounter; }; } // namespace OpenMM diff --git a/platforms/cpu/src/CpuKernels.cpp b/platforms/cpu/src/CpuKernels.cpp index bca60c267..1b5add793 100644 --- a/platforms/cpu/src/CpuKernels.cpp +++ b/platforms/cpu/src/CpuKernels.cpp @@ -599,7 +599,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo if (nonbondedMethod != NoCutoff) { // Determine whether we need to recompute the neighbor list. - double padding = 0.15*nonbondedCutoff; + double padding = 0.25*nonbondedCutoff; bool needRecompute = false; double closeCutoff2 = 0.25*padding*padding; double farCutoff2 = 0.5*padding*padding; diff --git a/platforms/cpu/src/CpuNeighborList.cpp b/platforms/cpu/src/CpuNeighborList.cpp index 7c716a9fe..5b5d99fd6 100644 --- a/platforms/cpu/src/CpuNeighborList.cpp +++ b/platforms/cpu/src/CpuNeighborList.cpp @@ -59,22 +59,25 @@ public: */ class CpuNeighborList::Voxels { public: - Voxels(int blockSize, float vsy, float vsz, float miny, float maxy, float minz, float maxz, const RealVec* periodicBoxVectors, bool usePeriodic) : - blockSize(blockSize), voxelSizeY(vsy), voxelSizeZ(vsz), miny(miny), maxy(maxy), minz(minz), maxz(maxz), periodicBoxVectors(periodicBoxVectors), usePeriodic(usePeriodic) { - periodicBoxSize[0] = (float) periodicBoxVectors[0][0]; - periodicBoxSize[1] = (float) periodicBoxVectors[1][1]; - periodicBoxSize[2] = (float) periodicBoxVectors[2][2]; - recipBoxSize[0] = (float) (1/periodicBoxVectors[0][0]); - recipBoxSize[1] = (float) (1/periodicBoxVectors[1][1]); - recipBoxSize[2] = (float) (1/periodicBoxVectors[2][2]); - triclinic = (periodicBoxVectors[0][1] != 0.0 || periodicBoxVectors[0][2] != 0.0 || - periodicBoxVectors[1][0] != 0.0 || periodicBoxVectors[1][2] != 0.0 || - periodicBoxVectors[2][0] != 0.0 || periodicBoxVectors[2][1] != 0.0); + Voxels(int blockSize, float vsy, float vsz, float miny, float maxy, float minz, float maxz, const RealVec* boxVectors, bool usePeriodic) : + blockSize(blockSize), voxelSizeY(vsy), voxelSizeZ(vsz), miny(miny), maxy(maxy), minz(minz), maxz(maxz), usePeriodic(usePeriodic) { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + periodicBoxVectors[i][j] = (float) boxVectors[i][j]; + periodicBoxSize[0] = (float) boxVectors[0][0]; + periodicBoxSize[1] = (float) boxVectors[1][1]; + periodicBoxSize[2] = (float) boxVectors[2][2]; + recipBoxSize[0] = (float) (1/boxVectors[0][0]); + recipBoxSize[1] = (float) (1/boxVectors[1][1]); + recipBoxSize[2] = (float) (1/boxVectors[2][2]); + triclinic = (boxVectors[0][1] != 0.0 || boxVectors[0][2] != 0.0 || + boxVectors[1][0] != 0.0 || boxVectors[1][2] != 0.0 || + boxVectors[2][0] != 0.0 || boxVectors[2][1] != 0.0); if (usePeriodic) { - ny = (int) floorf(periodicBoxVectors[1][1]/voxelSizeY+0.5f); - nz = (int) floorf(periodicBoxVectors[2][2]/voxelSizeZ+0.5f); - voxelSizeY = periodicBoxVectors[1][1]/ny; - voxelSizeZ = periodicBoxVectors[2][2]/nz; + ny = (int) floorf(boxVectors[1][1]/voxelSizeY+0.5f); + nz = (int) floorf(boxVectors[2][2]/voxelSizeZ+0.5f); + voxelSizeY = boxVectors[1][1]/ny; + voxelSizeZ = boxVectors[2][2]/nz; } else { ny = max(1, (int) floorf((maxy-miny)/voxelSizeY+0.5f)); @@ -282,9 +285,10 @@ public: // Loop over atoms and check to see if they are neighbors of this block. + const vector >& voxelBins = bins[voxelIndex.y][voxelIndex.z]; for (int range = 0; range < numRanges; range++) { for (int item = rangeStart[range]; item < rangeEnd[range]; item++) { - const int sortedIndex = bins[voxelIndex.y][voxelIndex.z][item].second; + const int sortedIndex = voxelBins[item].second; // Avoid duplicate entries. if (sortedIndex >= lastSortedIndex) @@ -361,7 +365,7 @@ private: int ny, nz; float periodicBoxSize[3], recipBoxSize[3]; bool triclinic; - const RealVec* periodicBoxVectors; + float periodicBoxVectors[3][3]; const bool usePeriodic; vector > > > bins; }; @@ -444,6 +448,7 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray blockAtoms; vector blockAtomX(blockSize), blockAtomY(blockSize), blockAtomZ(blockSize); vector atomVoxelIndex; - for (int i = threadIndex; i < numBlocks; i += numThreads) { + while (true) { + int i = gmx_atomic_fetch_add(&atomicCounter, 1); + if (i >= numBlocks) + break; + // Find the atoms in this block and compute their bounding box. int firstIndex = blockSize*i; @@ -532,15 +541,25 @@ void CpuNeighborList::threadComputeNeighborList(ThreadPool& threads, int threadI // Record the exclusions for this block. + map atomFlags; for (int j = 0; j < atomsInBlock; j++) { const set& atomExclusions = (*exclusions)[sortedAtoms[firstIndex+j]]; char mask = 1<::const_iterator iter = atomExclusions.begin(); iter != atomExclusions.end(); ++iter) { + map::iterator thisAtomFlags = atomFlags.find(*iter); + if (thisAtomFlags == atomFlags.end()) + atomFlags[*iter] = mask; + else + thisAtomFlags->second |= mask; } } + int numNeighbors = blockNeighbors[i].size(); + for (int k = 0; k < numNeighbors; k++) { + int atomIndex = blockNeighbors[i][k]; + map::iterator thisAtomFlags = atomFlags.find(atomIndex); + if (thisAtomFlags != atomFlags.end()) + blockExclusions[i][k] |= thisAtomFlags->second; + } } } -- GitLab From c461ff13af95715904649c9de48e6778ccaa23a5 Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Mon, 28 Sep 2015 16:11:20 -0700 Subject: [PATCH 23/49] Fixed a failing test case under Visual Studio --- tests/TestLangevinIntegrator.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/TestLangevinIntegrator.h b/tests/TestLangevinIntegrator.h index 2f22f334c..a19e5a83f 100644 --- a/tests/TestLangevinIntegrator.h +++ b/tests/TestLangevinIntegrator.h @@ -251,8 +251,8 @@ void testRandomSeed() { 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_EQUAL_TOL(state1.getPositions()[i][j], state2.getPositions()[i][j], 1e-6); + ASSERT_EQUAL_TOL(state3.getPositions()[i][j], state4.getPositions()[i][j], 1e-6); ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]); } } -- GitLab From a2c6e628600afce7032edb2915c6a1d9b671859f Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Tue, 4 Aug 2015 22:48:01 -0400 Subject: [PATCH 24/49] Add a set of unit tests for unit handling in the core API. --- wrappers/python/tests/TestAPIUnits.py | 163 ++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 wrappers/python/tests/TestAPIUnits.py diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py new file mode 100644 index 000000000..e62950965 --- /dev/null +++ b/wrappers/python/tests/TestAPIUnits.py @@ -0,0 +1,163 @@ +import unittest +from simtk.openmm import * +from simtk.openmm.app import * +from simtk.unit import * +import math + +class TestAPIUnits(unittest.TestCase): + """Test the Simulation class""" + + def assertAlmostEqualUnit(self, x1, x2): + self.assertAlmostEqual(x1._value, x2.value_in_unit(x1.unit)) + + def testHarmonicBondForce(self): + """ Tests HarmonicBondForce API features """ + force = HarmonicBondForce() + force.addBond(0, 1, 1.0, 1.0) + force.addBond(2, 3, 1.0*angstroms, + 1.0*kilocalories_per_mole/angstroms**2) + i, j, length, K = force.getBondParameters(0) + self.assertEqual(force.getNumBonds(), 2) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(length, 1.0*nanometers) + self.assertEqual(K, 1*kilojoules_per_mole/nanometers**2) + self.assertIs(length.unit, nanometers) + self.assertIs(K.unit, kilojoules_per_mole/nanometers**2) + + i, j, length, K = force.getBondParameters(1) + self.assertEqual(i, 2) + self.assertEqual(j, 3) + self.assertEqual(length, 1.0*angstroms) + self.assertAlmostEqualUnit(K, 1*kilocalories_per_mole/angstroms**2) + self.assertIs(length.unit, nanometers) + self.assertIs(K.unit, kilojoules_per_mole/nanometers**2) + + def testHarmonicAngleForce(self): + """ Tests HarmonicAngleForce API features """ + force = HarmonicAngleForce() + force.addAngle(0, 1, 2, 180*degrees, + 1.0*kilocalories_per_mole/radians**2) + force.addAngle(1, 2, 3, math.pi/2, 1.0) + self.assertEqual(force.getNumAngles(), 2) + i, j, k, angle, K = force.getAngleParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(angle, 180*degrees) + self.assertEqual(K, 1.0*kilocalories_per_mole/radians**2) + self.assertIs(angle.unit, radians) + self.assertIs(K.unit, kilojoules_per_mole/radians**2) + + i, j, k, angle, K = force.getAngleParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(angle, math.pi/2*radians) + self.assertEqual(K, 1.0*kilojoules_per_mole/radians**2) + self.assertIs(angle.unit, radians) + self.assertIs(K.unit, kilojoules_per_mole/radians**2) + + def testPeriodicTorsionForce(self): + """ Tests PeriodicTorsionForce API features """ + force = PeriodicTorsionForce() + force.addTorsion(0, 1, 2, 3, 1, math.pi, 1) + force.addTorsion(1, 2, 3, 4, 2, 180*degrees, 1*kilocalories_per_mole) + + self.assertEqual(force.getNumTorsions(), 2) + i, j, k, l, per, phase, K = force.getTorsionParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(per, 1) + self.assertFalse(is_quantity(per)) + self.assertEqual(phase, math.pi*radians) + self.assertEqual(K, 1*kilojoules_per_mole) + self.assertIs(phase.unit, radians) + self.assertIs(K.unit, kilojoules_per_mole) + + i, j, k, l, per, phase, K = force.getTorsionParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, 4) + self.assertEqual(per, 2) + self.assertFalse(is_quantity(per)) + self.assertEqual(phase, 180*degrees) + self.assertEqual(K, 1*kilocalories_per_mole) + self.assertIs(phase.unit, radians) + self.assertIs(K.unit, kilojoules_per_mole) + + def testRBTorsionForce(self): + """ Tests the RBTorsionForce API features """ + force = RBTorsionForce() + force.addTorsion(0, 1, 2, 3, 1, 2, 3, 4, 5, 6) + force.addTorsion(1, 2, 3, 4, 1*kilocalories_per_mole, + 2*kilocalories_per_mole, 3*kilocalories_per_mole, + 4*kilocalories_per_mole, 5*kilocalories_per_mole, + 6*kilocalories_per_mole) + + self.assertEqual(force.getNumTorsions(), 2) + i, j, k, l, c0, c1, c2, c3, c4, c5 = force.getTorsionParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(c0, 1*kilojoules_per_mole) + self.assertEqual(c1, 2*kilojoules_per_mole) + self.assertEqual(c2, 3*kilojoules_per_mole) + self.assertEqual(c3, 4*kilojoules_per_mole) + self.assertEqual(c4, 5*kilojoules_per_mole) + self.assertEqual(c5, 6*kilojoules_per_mole) + self.assertIs(c0.unit, kilojoules_per_mole) + self.assertIs(c1.unit, kilojoules_per_mole) + self.assertIs(c2.unit, kilojoules_per_mole) + self.assertIs(c3.unit, kilojoules_per_mole) + self.assertIs(c4.unit, kilojoules_per_mole) + self.assertIs(c5.unit, kilojoules_per_mole) + + i, j, k, l, c0, c1, c2, c3, c4, c5 = force.getTorsionParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, 4) + self.assertAlmostEqualUnit(c0, 1*kilocalories_per_mole) + self.assertAlmostEqualUnit(c1, 2*kilocalories_per_mole) + self.assertAlmostEqualUnit(c2, 3*kilocalories_per_mole) + self.assertAlmostEqualUnit(c3, 4*kilocalories_per_mole) + self.assertAlmostEqualUnit(c4, 5*kilocalories_per_mole) + self.assertAlmostEqualUnit(c5, 6*kilocalories_per_mole) + self.assertIs(c0.unit, kilojoules_per_mole) + self.assertIs(c1.unit, kilojoules_per_mole) + self.assertIs(c2.unit, kilojoules_per_mole) + self.assertIs(c3.unit, kilojoules_per_mole) + self.assertIs(c4.unit, kilojoules_per_mole) + self.assertIs(c5.unit, kilojoules_per_mole) + + def testNonbondedForce(self): + """ Tests the NonbondedForce API features """ + force = NonbondedForce() + force.addParticle(1.0, 1.0, 1.0) + force.addParticle(1.0*coulombs, 1.0*angstroms, + 1.0*kilocalories_per_mole) + + self.assertEqual(force.getNumParticles(), 2) + charge, sigma, epsilon = force.getParticleParameters(0) + self.assertEqual(charge, 1.0*elementary_charge) + self.assertEqual(sigma, 1.0*nanometers) + self.assertEqual(epsilon, 1.0*kilojoules_per_mole) + self.assertIs(charge.unit, elementary_charge) + self.assertIs(sigma.unit, nanometers) + self.assertIs(epsilon.unit, kilojoules_per_mole) + + charge, sigma, epsilon = force.getParticleParameters(1) + self.assertEqual(charge, 1.0*coulombs) + self.assertEqual(sigma, 1.0*angstroms) + self.assertEqual(epsilon, 1.0*kilocalories_per_mole) + self.assertIs(charge.unit, elementary_charge) + self.assertIs(sigma.unit, nanometers) + self.assertIs(epsilon.unit, kilojoules_per_mole) + +if __name__ == '__main__': + unittest.main() -- GitLab From f2301d3416cea312aab806626cbdfeca2cf2a829 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Mon, 10 Aug 2015 16:44:50 -0400 Subject: [PATCH 25/49] Add test for CMAPTorsionForce --- wrappers/python/tests/TestAPIUnits.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index e62950965..abfdd3113 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -2,6 +2,7 @@ import unittest from simtk.openmm import * from simtk.openmm.app import * from simtk.unit import * +import random import math class TestAPIUnits(unittest.TestCase): @@ -159,5 +160,30 @@ class TestAPIUnits(unittest.TestCase): self.assertIs(sigma.unit, nanometers) self.assertIs(epsilon.unit, kilojoules_per_mole) + def testCmapForce(self): + """ Tests the CMAPTorsionForce API features """ + map1 = [random.random() for i in range(24*24)] + map2 = [random.random() for i in range(12*12)] * kilocalories_per_mole + force = CMAPTorsionForce() + force.addMap(24, map1) + force.addMap(12, map2) + force.addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4) + force.addTorsion(1, 5, 6, 7, 8, 6, 7, 8, 9) + force.addTorsion(0, 10, 11, 12, 13, 11, 12, 13, 14) + force.addTorsion(1, 15, 16, 17, 18, 16, 17, 18, 19) + + self.assertEqual(force.getNumTorsions(), 4) + self.assertEqual(force.getNumMaps(), 2) + self.assertEqual(force.getMapParameters(0)[0], 24) + self.assertEqual(force.getMapParameters(1)[0], 12) + self.assertIs(force.getMapParameters(0)[1].unit, kilojoules_per_mole) + self.assertIs(force.getMapParameters(1)[1].unit, kilojoules_per_mole) + + for x, y in zip(force.getMapParameters(0)[1], map1): + self.assertAlmostEqual(x.value_in_unit(kilojoules_per_mole), y) + + for x, y in zip(force.getMapParameters(1)[1], map2): + self.assertAlmostEqualUnit(x, y) + if __name__ == '__main__': unittest.main() -- GitLab From d04154b4fda4e2a410d3736742a65f9a4df28767 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Tue, 1 Sep 2015 12:14:26 -0400 Subject: [PATCH 26/49] Add API tests for all of the Custom*Forces. Turns out CustomManyParticleForce is broken when adding per-particle parameters with units. --- wrappers/python/tests/TestAPIUnits.py | 332 ++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index abfdd3113..0b4d6e0d5 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -1,3 +1,5 @@ +from __future__ import division + import unittest from simtk.openmm import * from simtk.openmm.app import * @@ -160,6 +162,27 @@ class TestAPIUnits(unittest.TestCase): self.assertIs(sigma.unit, nanometers) self.assertIs(epsilon.unit, kilojoules_per_mole) + force.setCutoffDistance(10*angstroms) + self.assertEqual(force.getCutoffDistance(), 1*nanometers) + force.setCutoffDistance(1) + self.assertEqual(force.getCutoffDistance(), 1*nanometers) + + force.setSwitchingDistance(8*angstroms) + self.assertEqual(force.getSwitchingDistance(), 0.8*nanometers) + self.assertIs(force.getSwitchingDistance().unit, nanometer) + + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(NonbondedForce.NoCutoff) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(NonbondedForce.CutoffNonPeriodic) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(NonbondedForce.CutoffPeriodic) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(NonbondedForce.Ewald) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(NonbondedForce.PME) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + def testCmapForce(self): """ Tests the CMAPTorsionForce API features """ map1 = [random.random() for i in range(24*24)] @@ -185,5 +208,314 @@ class TestAPIUnits(unittest.TestCase): for x, y in zip(force.getMapParameters(1)[1], map2): self.assertAlmostEqualUnit(x, y) + def testCustomBondForce(self): + """ Tests the CustomBondForce API features """ + force = CustomBondForce('1/2*k*(r-r0)^2') + force.addPerBondParameter('r0') + force.addBond(0, 1, [0.1]) + force.addBond(1, 2, [1.0*angstroms]) + + self.assertEqual(force.getNumBonds(), 2) + i, j, req = force.getBondParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(req[0], 0.1) + + i, j, req = force.getBondParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(req[0], 0.1) + + def testCustomAngleForce(self): + """ Tests the CustomAngleForce API features """ + force = CustomAngleForce('1/2*k*(theta-theta0)^2') + force.addPerAngleParameter('theta0') + force.addAngle(0, 1, 2, [math.pi / 2]) + force.addAngle(3, 4, 5, [90*degrees]) + + self.assertEqual(force.getNumAngles(), 2) + i, j, k, theta = force.getAngleParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(theta[0], math.pi / 2) + + i, j, k, theta = force.getAngleParameters(1) + self.assertEqual(i, 3) + self.assertEqual(j, 4) + self.assertEqual(k, 5) + self.assertEqual(theta[0], math.pi / 2) + + def testCustomTorsionForce(self): + """ Tests the CustomTorsionForce API features """ + force = CustomTorsionForce('1/2*k*(theta-theta0)^2') + force.addTorsion(0, 1, 2, 3, [math.pi]) + force.addTorsion(4, 5, 6, 7, [180*degrees]) + + self.assertEqual(force.getNumTorsions(), 2) + i, j, k, l, theta = force.getTorsionParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(theta[0], math.pi) + + i, j, k, l, theta = force.getTorsionParameters(1) + self.assertEqual(i, 4) + self.assertEqual(j, 5) + self.assertEqual(k, 6) + self.assertEqual(l, 7) + self.assertEqual(theta[0], math.pi) + + def testCustomCompoundBondForce(self): + """ Tests the CustomCompoundBondForce API features """ + force = CustomCompoundBondForce(4, 'kb*distance(p1, p2)*distance(p2, p3)*distance(p3, p4)+' + 'ka*angle(p1, p2, p3)*angle(p2, p3, p4)+' + 'kd*dihedral(p1, p2, p3, p4)') + force.addPerBondParameter('kb') + force.addPerBondParameter('ka') + force.addPerBondParameter('kd') + force.addBond([0, 1, 2, 3], [1.0, 2.0, 3.0]) + force.addBond([4, 5, 6, 7], [1.0*kilocalories_per_mole/angstroms, + 2.0*kilocalories_per_mole/radians, + 3.0*kilocalories_per_mole] + ) + + self.assertEqual(force.getNumBonds(), 2) + (i, j, k, l), (kb, ka, kd) = force.getBondParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(kb, 1) + self.assertEqual(ka, 2) + self.assertEqual(kd, 3) + + (i, j, k, l), (kb, ka, kd) = force.getBondParameters(1) + self.assertEqual(i, 4) + self.assertEqual(j, 5) + self.assertEqual(k, 6) + self.assertEqual(l, 7) + self.assertEqual(kb, 1*10*4.184) + self.assertEqual(ka, 2*4.184) + self.assertEqual(kd, 3*4.184) + + def testCustomExternalForce(self): + """ Tests the CustomExternalForce API features """ + force = CustomExternalForce('1/2*k*k2*((x-x0)^2+(y-y0)^2+(z-z0)^2)') + force.addGlobalParameter('k', 10*kilocalories_per_mole/angstroms**2) + force.addGlobalParameter('k2', 20) + force.addPerParticleParameter('x0') + force.addPerParticleParameter('y0') + force.addPerParticleParameter('z0') + force.addParticle(0, [1.0, 2.0, 3.0]) + force.addParticle(1, [1.0*angstroms, 2.0*angstroms, 3.0*angstroms]) + + self.assertEqual(force.getNumParticles(), 2) + self.assertEqual(force.getNumGlobalParameters(), 2) + self.assertEqual(force.getGlobalParameterName(0), 'k') + self.assertEqual(force.getGlobalParameterName(1), 'k2') + self.assertEqual(force.getGlobalParameterDefaultValue(0), 1000*4.184) + self.assertEqual(force.getGlobalParameterDefaultValue(1), 20) + + i, (x0, y0, z0) = force.getParticleParameters(0) + self.assertEqual(i, 0) + self.assertEqual(x0, 1) + self.assertEqual(y0, 2) + self.assertEqual(z0, 3) + + i, (x0, y0, z0) = force.getParticleParameters(1) + self.assertEqual(i, 1) + self.assertAlmostEqual(x0, 1/10) + self.assertAlmostEqual(y0, 2/10) + self.assertAlmostEqual(z0, 3/10) + + def testCustomGBForce(self): + """ Tests the CustomGBForce API features """ + force = CustomGBForce() + force.addPerParticleParameter('q') + force.addPerParticleParameter('radius') + force.addPerParticleParameter('scale') + force.addGlobalParameter('extDiel', 78.5) + force.addGlobalParameter('intDiel', 1.0) + force.addComputedValue('I', + 'step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*' + '(r-sr2^2/r)+0.5*log(L/U)/r+C);' + 'U=r+sr2; C=2*(1/or1-1/L)*step(sr2-r-or1);' + 'L=max(or1, D); D=abs(r-sr2); sr2=scale2*or2;' + 'or1=radius1-0.009; or2=radius2-0.009', + CustomGBForce.ParticlePairNoExclusions + ) + force.addComputedValue('B', + '1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);' + 'psi=I*or; or=radius-0.009', + CustomGBForce.SingleParticle + ) + force.addEnergyTerm('-138.935456*(1/intDiel-1/extDiel)*q1*q2/f;' + 'f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))', + CustomGBForce.ParticlePair + ) + + force.setNonbondedMethod(CustomGBForce.CutoffPeriodic) + + force.addParticle([1.0, 0.1, 0.5]) + force.addParticle([-1.0*coulombs, 1.0*angstroms, 0.5]) + + self.assertEqual(force.getNumParticles(), 2) + self.assertEqual(force.getNumComputedValues(), 2) + self.assertEqual(force.getNumEnergyTerms(), 1) + self.assertEqual(force.getNumPerParticleParameters(), 3) + self.assertEqual(force.getPerParticleParameterName(0), 'q') + self.assertEqual(force.getPerParticleParameterName(1), 'radius') + self.assertEqual(force.getPerParticleParameterName(2), 'scale') + self.assertTrue(force.usesPeriodicBoundaryConditions()) + + force.setNonbondedMethod(CustomGBForce.NoCutoff) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomGBForce.CutoffNonPeriodic) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + + q, rad, scale = force.getParticleParameters(0) + self.assertEqual(q, 1.0) + self.assertEqual(rad, 0.1) + self.assertEqual(scale, 0.5) + + q, rad, scale = force.getParticleParameters(1) + self.assertEqual(q, -6.24150962915265e+18) # very electronegative + self.assertEqual(rad, 0.1) + self.assertEqual(scale, 0.5) + + force.setCutoffDistance(12*angstroms) + self.assertAlmostEqualUnit(force.getCutoffDistance(), 1.2*nanometers) + force.setCutoffDistance(1) + self.assertEqual(force.getCutoffDistance(), 1*nanometers) + + def testCustomHBondForce(self): + """ Tests the CustomHbondForce API features """ + force = CustomHbondForce('kd*(distance(a1,d1)-r0)^2 + ' + 'ka*(angle(a1,d1,d2)-theta0)^2') + force.addPerAcceptorParameter('r0') + force.addPerAcceptorParameter('ka') + force.addPerDonorParameter('theta0') + force.addPerDonorParameter('kd') + force.setCutoffDistance(10*angstroms) + + self.assertEqual(force.getNumPerAcceptorParameters(), 2) + self.assertEqual(force.getNumPerDonorParameters(), 2) + self.assertEqual(force.getCutoffDistance(), 1*nanometers) + self.assertIs(force.getCutoffDistance().unit, nanometer) + + force.addAcceptor(0, 1, 2, [0.2, 10.0]) + force.addAcceptor(3, -1, -1, [4*angstroms, + 20.0*kilocalories_per_mole/angstroms**2]) + force.addDonor(4, 5, 6, [math.pi, 30]) + force.addDonor(7, 8, -1, [180*degrees, + 40*kilocalories_per_mole/radians**2]) + + self.assertEqual(force.getNumAcceptors(), 2) + self.assertEqual(force.getNumDonors(), 2) + + i, j, k, (r0, ka) = force.getAcceptorParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(r0, 0.2) + self.assertEqual(ka, 10) + + i, j, k, (r0, ka) = force.getAcceptorParameters(1) + self.assertEqual(i, 3) + self.assertEqual(j, -1) + self.assertEqual(k, -1) + self.assertEqual(r0, 0.4) + self.assertEqual(ka, 20*4.184*100) + + i, j, k, (theta0, kd) = force.getDonorParameters(0) + self.assertEqual(i, 4) + self.assertEqual(j, 5) + self.assertEqual(k, 6) + self.assertEqual(theta0, math.pi) + self.assertEqual(kd, 30) + + i, j, k, (theta0, kd) = force.getDonorParameters(1) + self.assertEqual(i, 7) + self.assertEqual(j, 8) + self.assertEqual(k, -1) + self.assertEqual(theta0, math.pi) + self.assertEqual(kd, 40*4.184) + + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomHbondForce.NoCutoff) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomHbondForce.CutoffNonPeriodic) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomHbondForce.CutoffPeriodic) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + + def testCustomNonbondedForce(self): + """ Tests the CustomNonbondedForce API features """ + force = CustomNonbondedForce('4*diel*q1*q2/r+sqrt(p1*p2)/r^2-sqrt(m1*m2)/r^3') + force.addGlobalParameter('diel', 1.0) + force.addPerParticleParameter('q') + force.addPerParticleParameter('p') + force.addPerParticleParameter('m') + force.addParticle([1, 2, 3]) + force.addParticle([1*coulombs, 2*kilocalories_per_mole*angstroms**2, 3*kilocalories_per_mole*angstroms**3]) + + self.assertEqual(force.getNumParticles(), 2) + charge, sigma, epsilon = force.getParticleParameters(0) + self.assertEqual(charge, 1) + self.assertEqual(sigma, 2) + self.assertEqual(epsilon, 3) + + charge, sigma, epsilon = force.getParticleParameters(1) + self.assertEqual(charge, 6.24150962915265e+18) # very electronegative + self.assertEqual(sigma, 2*4.184/100) + self.assertAlmostEqual(epsilon, 3*4.184/1000) + + force.setCutoffDistance(10*angstroms) + self.assertEqual(force.getCutoffDistance(), 1*nanometers) + force.setCutoffDistance(1) + self.assertEqual(force.getCutoffDistance(), 1*nanometers) + + force.setSwitchingDistance(8*angstroms) + self.assertEqual(force.getSwitchingDistance(), 0.8*nanometers) + self.assertIs(force.getSwitchingDistance().unit, nanometer) + + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomNonbondedForce.NoCutoff) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomNonbondedForce.CutoffNonPeriodic) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(CustomNonbondedForce.CutoffPeriodic) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + + def testCustomManyParticleForce(self): + """ Tests the CustomManyParticleForce API features """ + force = CustomManyParticleForce(3, + "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;" + "theta1=k1*angle(p1,p2,p3); theta2=k2*angle(p2,p3,p1); theta3=k3*angle(p3,p1,p2);" + "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)") + force.setPermutationMode(CustomManyParticleForce.SinglePermutation) + force.setTypeFilter(0, [0]) + force.setTypeFilter(1, [1]) + force.setTypeFilter(2, [2]) + + force.addGlobalParameter('C', 1.0*kilocalories_per_mole) + force.addPerParticleParameter('k') + + self.assertEqual(force.getNumGlobalParameters(), 1) + self.assertEqual(force.getGlobalParameterName(0), 'C') + self.assertEqual(force.getGlobalParameterDefaultValue(0), 4.184) + self.assertEqual(force.getNumPerParticleParameters(), 1) + + force.addParticle([10], 0) + force.addParticle([20], 1) + force.addParticle([30*kilocalories_per_mole], 2) + + self.assertEqual(force.getNumParticles(), 3) + self.assertEqual(force.getParticleParameters(0)[0][0], 10) + self.assertEqual(force.getParticleParameters(1)[0][0], 20) + self.assertEqual(force.getParticleParameters(2)[0][0], 30*4.184) + if __name__ == '__main__': unittest.main() -- GitLab From 9e800ced94f76a68145b104b7c3be0445f1dfe40 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Thu, 17 Sep 2015 15:00:39 -0400 Subject: [PATCH 27/49] Add units to the returned bond cubic and quartic terms and add tests for AmoebaBondForce. --- .../src/swig_doxygen/swigInputConfig.py | 4 +-- wrappers/python/tests/TestAPIUnits.py | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index d2bbb281e..79c725149 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -224,8 +224,8 @@ UNITS = { ("AmoebaAngleForce", "getAmoebaGlobalAngleSextic") : ( None,()), ("AmoebaAngleForce", "getAngleParameters") : ( None, (None, None, None, 'unit.radian', 'unit.kilojoule_per_mole/(unit.radian*unit.radian)')), -("AmoebaBondForce", "getAmoebaGlobalBondCubic") : ( None,()), -("AmoebaBondForce", "getAmoebaGlobalBondQuartic") : ( None,()), +("AmoebaBondForce", "getAmoebaGlobalBondCubic") : ( '1/unit.nanometer',()), +("AmoebaBondForce", "getAmoebaGlobalBondQuartic") : ( '1/unit.nanometer**2',()), ("AmoebaBondForce", "getBondParameters") : ( None, (None, None, 'unit.nanometer', 'unit.kilojoule_per_mole/(unit.nanometer*unit.nanometer)')), ("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleCubic") : ( None,()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 0b4d6e0d5..2137c24b6 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -517,5 +517,36 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(force.getParticleParameters(1)[0][0], 20) self.assertEqual(force.getParticleParameters(2)[0][0], 30*4.184) + def testAmoebaBondForce(self): + """ Tests the AmoebaBondForce API features """ + force1 = AmoebaBondForce() + force2 = AmoebaBondForce() + force1.setAmoebaGlobalBondCubic(1.5) + force2.setAmoebaGlobalBondCubic(1.5/angstrom) + force1.setAmoebaGlobalBondQuartic(1.5) + force2.setAmoebaGlobalBondQuartic(1.5/angstrom**2) + + self.assertEqual(force1.getAmoebaGlobalBondCubic(), 1.5/nanometer) + self.assertEqual(force2.getAmoebaGlobalBondCubic(), 1.5/angstrom) + self.assertEqual(force1.getAmoebaGlobalBondQuartic(), 1.5/nanometer**2) + self.assertAlmostEqualUnit(force2.getAmoebaGlobalBondQuartic(), 1.5/angstrom**2) + + force1.addBond(0, 1, 0.15, 10.0) + force1.addBond(1, 2, 1.5*angstroms, 10.0*kilocalories_per_mole/angstroms**2) + + self.assertEqual(force1.getNumBonds(), 2) + self.assertEqual(force2.getNumBonds(), 0) + + i, j, req, k = force1.getBondParameters(0) + self.assertEqual(req, 0.15*nanometers) + self.assertEqual(k, 10.0*kilojoules_per_mole/nanometers**2) + + i, j, req, k = force1.getBondParameters(1) + self.assertAlmostEqualUnit(req, 1.5*angstroms) + self.assertAlmostEqualUnit(k, 10.0*kilocalories_per_mole/angstroms**2) + + def testAmoebaAngleForce(self): + """ Tests the AmoebaAngleForce API features """ + if __name__ == '__main__': unittest.main() -- GitLab From 6281f23fc404f0ff01db05655dcc0479b796f454 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Thu, 17 Sep 2015 15:53:17 -0400 Subject: [PATCH 28/49] Add a test for AmoebaAngleForce. There's a problem here, though, since the input angles are in degrees (unlike *every* other angle force out there), and stripUnits automatically reduces all angles to radians if they come in with units. The approach here is to *slightly* change the API, so that AmoebaAngleForce.addAngle interprets input angles <2*pi as radians, and >2*pi as degrees. This is heuristic, but should work in every case out in the wild so far. I've also updated the documentation to reflect this behavior, and fixed the units attached to the return value of AmoebaAngleForce.getAngleParameters() to return degrees instead of radians. --- .../include/openmm/AmoebaAngleForce.h | 6 +-- .../amoeba/openmmapi/src/AmoebaAngleForce.cpp | 4 +- .../src/swig_doxygen/swigInputConfig.py | 10 ++--- wrappers/python/tests/TestAPIUnits.py | 43 +++++++++++++++++++ 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h b/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h index dc778dff2..5f3d3eebb 100644 --- a/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h +++ b/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h @@ -127,7 +127,7 @@ public: * @param particle1 the index of the first particle connected by the angle * @param particle2 the index of the second particle connected by the angle * @param particle3 the index of the third particle connected by the angle - * @param length the angle measured in degrees + * @param length the equilibrium angle, measured in degrees if >2*pi, otherwise interpreted as radians * @param quadratic k the quadratic force constant for the angle, measured in kJ/mol/radian^2 * @return the index of the angle that was added */ @@ -140,7 +140,7 @@ public: * @param particle1 the index of the first particle connected by the angle * @param particle2 the index of the second particle connected by the angle * @param particle3 the index of the third particle connected by the angle - * @param length the equilibrium angle, measured in degress + * @param length the equilibrium angle, measured in degrees if >2*pi, otherwise interpreted as radians * @param quadratic k the quadratic force constant for the angle, measured in kJ/mol/radian^2 */ void getAngleParameters(int index, int& particle1, int& particle2, int& particle3, double& length, double& quadraticK) const; @@ -152,7 +152,7 @@ public: * @param particle1 the index of the first particle connected by the angle * @param particle2 the index of the second particle connected by the angle * @param particle3 the index of the third particle connected by the angle - * @param length the equilibrium angle, measured in degrees + * @param length the equilibrium angle, measured in degrees if >2*pi, otherwise interpreted as radians * @param quadratic k the quadratic force constant for the angle, measured in kJ/mol/radian^2 */ void setAngleParameters(int index, int particle1, int particle2, int particle3, double length, double quadraticK); diff --git a/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp b/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp index 0cec83e80..e2ef94975 100644 --- a/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp +++ b/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp @@ -29,6 +29,7 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ +#include #include "openmm/Force.h" #include "openmm/OpenMMException.h" #include "openmm/AmoebaAngleForce.h" @@ -41,6 +42,7 @@ AmoebaAngleForce::AmoebaAngleForce() { } int AmoebaAngleForce::addAngle(int particle1, int particle2, int particle3, double length, double quadraticK) { + length = length < 2*M_PI ? length * 180.0/M_PI : length; angles.push_back(AngleInfo(particle1, particle2, particle3, length, quadraticK)); return angles.size()-1; } @@ -59,7 +61,7 @@ void AmoebaAngleForce::setAngleParameters(int index, int particle1, int particle angles[index].particle1 = particle1; angles[index].particle2 = particle2; angles[index].particle3 = particle3; - angles[index].length = length; + angles[index].length = length < 2*M_PI ? length * 180.0/M_PI : length; angles[index].quadraticK = quadraticK; } diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index 79c725149..367a15ca0 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -218,11 +218,11 @@ UNITS = { ("AmoebaGeneralizedKirkwoodForce", "getProbeRadius") : ( 'unit.nanometer', ()), ("AmoebaGeneralizedKirkwoodForce", "getSurfaceAreaFactor") : ( '(unit.nanometer*unit.nanometer)/unit.kilojoule_per_mole',()), -("AmoebaAngleForce", "getAmoebaGlobalAngleCubic") : ( None,()), -("AmoebaAngleForce", "getAmoebaGlobalAngleQuartic") : ( None,()), -("AmoebaAngleForce", "getAmoebaGlobalAnglePentic") : ( None,()), -("AmoebaAngleForce", "getAmoebaGlobalAngleSextic") : ( None,()), -("AmoebaAngleForce", "getAngleParameters") : ( None, (None, None, None, 'unit.radian', 'unit.kilojoule_per_mole/(unit.radian*unit.radian)')), +("AmoebaAngleForce", "getAmoebaGlobalAngleCubic") : ( '1/unit.radian',()), +("AmoebaAngleForce", "getAmoebaGlobalAngleQuartic") : ( '1/unit.radian**2',()), +("AmoebaAngleForce", "getAmoebaGlobalAnglePentic") : ( '1/unit.radian**3',()), +("AmoebaAngleForce", "getAmoebaGlobalAngleSextic") : ( '1/unit.radian**4',()), +("AmoebaAngleForce", "getAngleParameters") : ( None, (None, None, None, 'unit.degree', 'unit.kilojoule_per_mole/(unit.radian*unit.radian)')), ("AmoebaBondForce", "getAmoebaGlobalBondCubic") : ( '1/unit.nanometer',()), ("AmoebaBondForce", "getAmoebaGlobalBondQuartic") : ( '1/unit.nanometer**2',()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 2137c24b6..cbebd8bb9 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -547,6 +547,49 @@ class TestAPIUnits(unittest.TestCase): def testAmoebaAngleForce(self): """ Tests the AmoebaAngleForce API features """ + force = AmoebaAngleForce() + force.setAmoebaGlobalAngleCubic(1.0) + force.setAmoebaGlobalAngleQuartic(2.0/radians**2) + force.setAmoebaGlobalAnglePentic(3.0/degrees**3) + force.setAmoebaGlobalAngleSextic(4.0) + + self.assertEqual(force.getAmoebaGlobalAngleCubic(), 1.0/radians) + self.assertEqual(force.getAmoebaGlobalAngleQuartic(), 2.0/radians**2) + self.assertAlmostEqualUnit(force.getAmoebaGlobalAnglePentic(), 3.0/degrees**3) + self.assertEqual(force.getAmoebaGlobalAngleSextic(), 4.0/radians**4) + + force.addAngle(0, 1, 2, math.pi*radians, 1.5*kilocalories_per_mole/radians**2) + force.addAngle(1, 2, 3, 180*degrees, 1.5*kilocalories_per_mole/radians**2) + force.addAngle(2, 3, 4, 109.4, 1.5) + + self.assertEqual(force.getNumAngles(), 3) + + i, j, k, t, tk = force.getAngleParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertAlmostEqualUnit(t, math.pi*radians) + self.assertIs(t.unit, degree) + self.assertAlmostEqualUnit(tk, 1.5*kilocalories_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + + i, j, k, t, tk = force.getAngleParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertAlmostEqualUnit(t, 180*degrees) + self.assertIs(t.unit, degree) + self.assertAlmostEqualUnit(tk, 1.5*kilocalories_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + + i, j, k, t, tk = force.getAngleParameters(2) + self.assertEqual(i, 2) + self.assertEqual(j, 3) + self.assertEqual(k, 4) + self.assertAlmostEqualUnit(t, 109.4*degrees) + self.assertIs(t.unit, degree) + self.assertAlmostEqualUnit(tk, 1.5*kilojoules_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) if __name__ == '__main__': unittest.main() -- GitLab From 39a871df79700bb02eae267a9738483513c82565 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Thu, 17 Sep 2015 16:02:31 -0400 Subject: [PATCH 29/49] getAngleParameters always *returns* degrees... --- plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h b/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h index 5f3d3eebb..7a8261f02 100644 --- a/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h +++ b/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h @@ -140,7 +140,7 @@ public: * @param particle1 the index of the first particle connected by the angle * @param particle2 the index of the second particle connected by the angle * @param particle3 the index of the third particle connected by the angle - * @param length the equilibrium angle, measured in degrees if >2*pi, otherwise interpreted as radians + * @param length the equilibrium angle, measured in degrees * @param quadratic k the quadratic force constant for the angle, measured in kJ/mol/radian^2 */ void getAngleParameters(int index, int& particle1, int& particle2, int& particle3, double& length, double& quadraticK) const; -- GitLab From 792b89eea7566204b476f0c7ef4a9b7e0cce8817 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Thu, 17 Sep 2015 16:27:26 -0400 Subject: [PATCH 30/49] Make return units for AmoebaGeneralizedKirkwoodForce consistent with what the docstring says it should be (kJ/nm^2) -- the swig input generator had the inverse. Adds a test case for the AmoebaGeneralizedKirkwoodForce API. --- .../src/swig_doxygen/swigInputConfig.py | 2 +- wrappers/python/tests/TestAPIUnits.py | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index 367a15ca0..98fc6c03f 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -216,7 +216,7 @@ UNITS = { ("AmoebaGeneralizedKirkwoodForce", "getDielectricOffset") : ( 'unit.nanometer', ()), ("AmoebaGeneralizedKirkwoodForce", "getIncludeCavityTerm") : ( None,()), ("AmoebaGeneralizedKirkwoodForce", "getProbeRadius") : ( 'unit.nanometer', ()), -("AmoebaGeneralizedKirkwoodForce", "getSurfaceAreaFactor") : ( '(unit.nanometer*unit.nanometer)/unit.kilojoule_per_mole',()), +("AmoebaGeneralizedKirkwoodForce", "getSurfaceAreaFactor") : ( 'unit.kilojoule_per_mole/(unit.nanometer*unit.nanometer)',()), ("AmoebaAngleForce", "getAmoebaGlobalAngleCubic") : ( '1/unit.radian',()), ("AmoebaAngleForce", "getAmoebaGlobalAngleQuartic") : ( '1/unit.radian**2',()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index cbebd8bb9..12c10dac1 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -591,5 +591,50 @@ class TestAPIUnits(unittest.TestCase): self.assertAlmostEqualUnit(tk, 1.5*kilojoules_per_mole/radians**2) self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + def testGeneralizedKirkwood(self): + """ Tests the AmoebaGeneralizedKirkwoodForce API features """ + force = AmoebaGeneralizedKirkwoodForce() + + self.assertEqual(force.getProbeRadius(), 0.14*nanometer) # default + force.setProbeRadius(0.16) + self.assertEqual(force.getProbeRadius(), 0.16*nanometer) + self.assertIs(force.getProbeRadius().unit, nanometer) + force.setProbeRadius(1.4*angstrom) + self.assertEqual(force.getProbeRadius(), 1.4*angstrom) + self.assertIs(force.getProbeRadius().unit, nanometer) + + self.assertEqual(force.getSoluteDielectric(), 1.0) # default + force.setSoluteDielectric(2.0) + self.assertEqual(force.getSoluteDielectric(), 2.0) + + self.assertEqual(force.getSolventDielectric(), 78.3) # default + force.setSolventDielectric(80) + self.assertEqual(force.getSolventDielectric(), 80) + + self.assertEqual(force.getSurfaceAreaFactor(), + -170.35173066268223*kilojoule_per_mole/nanometer**2) # default + force.setSurfaceAreaFactor(-1.0*kilocalorie_per_mole/angstrom**2) + self.assertAlmostEqualUnit(force.getSurfaceAreaFactor(), + -1.0*kilocalorie_per_mole/angstrom**2) # default + + force.addParticle(1.0*coulomb, 1.0*angstroms, 0.5) + force.addParticle(1.0, 1.0, 0.4) + + self.assertEqual(force.getNumParticles(), 2) + + q, r, s = force.getParticleParameters(0) + self.assertAlmostEqualUnit(q, 1.0*coulomb) + self.assertIs(q.unit, elementary_charge) + self.assertEqual(r, 1.0*angstroms) + self.assertIs(r.unit, nanometer) + self.assertEqual(s, 0.5) + + q, r, s = force.getParticleParameters(1) + self.assertAlmostEqualUnit(q, 1.0*elementary_charge) + self.assertIs(q.unit, elementary_charge) + self.assertEqual(r, 1.0*nanometer) + self.assertIs(r.unit, nanometer) + self.assertEqual(s, 0.4) + if __name__ == '__main__': unittest.main() -- GitLab From 751518909fc916128ef5b74b89f2a6418ddfc041 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Thu, 17 Sep 2015 16:49:39 -0400 Subject: [PATCH 31/49] Add tests for AmoebaInPlaneAngleForce and add return units to the Taylor expansion coefficients. --- .../src/swig_doxygen/swigInputConfig.py | 8 ++-- wrappers/python/tests/TestAPIUnits.py | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index 98fc6c03f..239290e50 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -228,10 +228,10 @@ UNITS = { ("AmoebaBondForce", "getAmoebaGlobalBondQuartic") : ( '1/unit.nanometer**2',()), ("AmoebaBondForce", "getBondParameters") : ( None, (None, None, 'unit.nanometer', 'unit.kilojoule_per_mole/(unit.nanometer*unit.nanometer)')), -("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleCubic") : ( None,()), -("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleQuartic") : ( None,()), -("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAnglePentic") : ( None,()), -("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleSextic") : ( None,()), +("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleCubic") : ( '1/unit.radian',()), +("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleQuartic") : ( '1/unit.radian**2',()), +("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAnglePentic") : ( '1/unit.radian**3',()), +("AmoebaInPlaneAngleForce", "getAmoebaGlobalInPlaneAngleSextic") : ( '1/unit.radian**4',()), ("AmoebaInPlaneAngleForce", "getAngleParameters") : ( None, (None, None, None, None, 'unit.radian', 'unit.kilojoule_per_mole/(unit.radian*unit.radian)')), ("AmoebaMultipoleForce", "getNumMultipoles") : ( None,()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 12c10dac1..ddebd7e6f 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -636,5 +636,50 @@ class TestAPIUnits(unittest.TestCase): self.assertIs(r.unit, nanometer) self.assertEqual(s, 0.4) + def testAmoebaInPlaneAngleForce(self): + """ Tests the AmoebaInPlaneAngleForce API features """ + force = AmoebaInPlaneAngleForce() + + force.setAmoebaGlobalInPlaneAngleCubic(1.0) + self.assertEqual(force.getAmoebaGlobalInPlaneAngleCubic(), 1/radian) + self.assertEqual(str(force.getAmoebaGlobalInPlaneAngleCubic().unit), '/radian') + + force.setAmoebaGlobalInPlaneAngleQuartic(1.0/degrees**2) + self.assertAlmostEqualUnit(force.getAmoebaGlobalInPlaneAngleQuartic(), 1/degrees**2) + self.assertEqual(str(force.getAmoebaGlobalInPlaneAngleQuartic().unit), '/(radian**2)') + + force.setAmoebaGlobalInPlaneAnglePentic(1.0/radians**3) + self.assertEqual(force.getAmoebaGlobalInPlaneAnglePentic(), 1/radian**3) + self.assertEqual(str(force.getAmoebaGlobalInPlaneAnglePentic().unit), '/(radian**3)') + + force.setAmoebaGlobalInPlaneAngleSextic(1.0/radians**4) + self.assertEqual(force.getAmoebaGlobalInPlaneAngleSextic(), 1/radian**4) + self.assertEqual(str(force.getAmoebaGlobalInPlaneAngleSextic().unit), '/(radian**4)') + + force.addAngle(0, 1, 2, 3, math.pi, 1.0) + force.addAngle(1, 2, 3, 4, 180*degrees, 1.0*kilocalories_per_mole/radians**2) + + self.assertEqual(force.getNumAngles(), 2) + + i, j, k, l, t, tk = force.getAngleParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(t, math.pi*radians) + self.assertIs(t.unit, radians) + self.assertEqual(tk, 1.0*kilojoules_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + + i, j, k, l, t, tk = force.getAngleParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, 4) + self.assertEqual(t, 180*degrees) + self.assertIs(t.unit, radians) + self.assertEqual(tk, 1.0*kilocalorie_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + if __name__ == '__main__': unittest.main() -- GitLab From 48437a223cbad5eb2b4392719bb45c96bd6764d4 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 18 Sep 2015 11:34:02 -0400 Subject: [PATCH 32/49] Fix windows issue. --- plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp b/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp index e2ef94975..d9473ef57 100644 --- a/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp +++ b/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp @@ -29,6 +29,7 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ +#define _USE_MATH_DEFINES 1 /* Needed for Windows */ #include #include "openmm/Force.h" #include "openmm/OpenMMException.h" -- GitLab From 1644cc458aa7f3efb5a0583abed5b6bcda829724 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 18 Sep 2015 15:25:43 -0400 Subject: [PATCH 33/49] Try to add tests for AmoebaOutOfPlaneBendForce. The units added to the cubic/quartic/pentic/etc. terms are NOT working for some reason. --- .../src/swig_doxygen/swigInputBuilder.py | 5 ++- .../src/swig_doxygen/swigInputConfig.py | 8 ++-- wrappers/python/tests/TestAPIUnits.py | 41 +++++++++++++++++++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputBuilder.py b/wrappers/python/src/swig_doxygen/swigInputBuilder.py index a06896a5b..27f413c2f 100755 --- a/wrappers/python/src/swig_doxygen/swigInputBuilder.py +++ b/wrappers/python/src/swig_doxygen/swigInputBuilder.py @@ -10,6 +10,7 @@ import getopt import re import xml.etree.ElementTree as etree from distutils.version import LooseVersion +import copy try: from html.parser import HTMLParser @@ -20,7 +21,6 @@ except ImportError: INDENT = " " docTags = {'emphasis':'i', 'bold':'b', 'itemizedlist':'ul', 'listitem':'li', 'preformatted':'pre', 'computeroutput':'tt', 'subscript':'sub'} - def striphtmltags(s): """Strip a couple html tags used inside docstrings in the C++ source to produce something more easily read as plain text. @@ -477,10 +477,11 @@ class SwigInputBuilder: valueUnits=[None, ()] index=0 - if valueUnits[0]: + if valueUnits[0] is not None: sys.stdout.write("%s.%s() returns %s\n" % (shortClassName, methName, valueUnits[0])) if len(valueUnits[1])>0: + print('IT IS GREATER THAN 1') addText = "%s%sval[%d]=unit.Quantity(val[%d], %s)\n" \ % (addText, INDENT, index, index, diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index 239290e50..e3a67d40c 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -268,10 +268,10 @@ UNITS = { ("AmoebaMultipoleForce", "getSystemMultipoleMoments") : ( None, ()), ("AmoebaOutOfPlaneBendForce", "getNumOutOfPlaneBends") : ( None, ()), -("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendCubic") : ( None,()), -("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendQuartic") : ( None,()), -("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendPentic") : ( None,()), -("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendSextic") : ( None,()), +("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendCubic") : ( '1/unit.radian',()), +("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendQuartic") : ( '1/unit.radian**2',()), +("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendPentic") : ( '1/unit.radian**3',()), +("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendSextic") : ( '1/unit.radian**4',()), ("AmoebaOutOfPlaneBendForce", "getOutOfPlaneBendParameters") : ( None, (None, None, None, None, 'unit.kilojoule_per_mole')), ("AmoebaPiTorsionForce", "getNumPiTorsions") : ( None, ()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index ddebd7e6f..1bf80b678 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -681,5 +681,46 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(tk, 1.0*kilocalorie_per_mole/radians**2) self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + def testAmoebaOutOfPlaneBendForce(self): + """ Tests the AmoebaOutOfPlaneBendForce API features """ + force = AmoebaOutOfPlaneBendForce() + + force.setAmoebaGlobalOutOfPlaneBendCubic(1.0) + self.assertEqual(force.getAmoebaGlobalOutOfPlaneBendCubic(), 1/radian) + self.assertEqual(str(force.getAmoebaGlobalOutOfPlaneBendCubic().unit), '/radian') + + force.setAmoebaGlobalOutOfPlaneBendQuartic(1.0/degrees**2) + self.assertAlmostEqualUnit(force.getAmoebaGlobalOutOfPlaneBendQuartic(), 1/degrees**2) + self.assertEqual(str(force.getAmoebaGlobalOutOfPlaneBendQuartic().unit), '/(radian**2)') + + force.setAmoebaGlobalOutOfPlaneBendPentic(1.0/radians**3) + self.assertEqual(force.getAmoebaGlobalOutOfPlaneBendPentic(), 1/radian**3) + self.assertEqual(str(force.getAmoebaGlobalOutOfPlaneBendPentic().unit), '/(radian**3)') + + force.setAmoebaGlobalOutOfPlaneBendSextic(1.0/radians**4) + self.assertEqual(force.getAmoebaGlobalOutOfPlaneBendSextic(), 1/radian**4) + self.assertEqual(str(force.getAmoebaGlobalOutOfPlaneBendSextic().unit), '/(radian**4)') + + force.addOutOfPlaneBend(0, 1, 2, 3, 1.0) + force.addOutOfPlaneBend(1, 2, 3, 4, 1.0*kilocalories_per_mole/radians**2) + + self.assertEqual(force.getNumOutOfPlaneBends(), 2) + + i, j, k, l, tk = force.getOutOfPlaneBendParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(tk, 1.0*kilojoules_per_mole) + self.assertIs(tk.unit, kilojoules_per_mole) + + i, j, k, l, tk = force.getOutOfPlaneBendParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, 4) + self.assertEqual(tk, 1.0*kilocalorie_per_mole) + self.assertIs(tk.unit, kilojoules_per_mole) + if __name__ == '__main__': unittest.main() -- GitLab From df20dcacdeebd468cfea49b0863e3dae2f910dce Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 18 Sep 2015 16:13:53 -0400 Subject: [PATCH 34/49] Get the out of plane bend taylor coefficient units sorted out. --- .../openmmapi/include/openmm/AmoebaOutOfPlaneBendForce.h | 8 ++++---- wrappers/python/src/swig_doxygen/swigInputBuilder.py | 7 +++---- wrappers/python/src/swig_doxygen/swigInputConfig.py | 2 +- wrappers/python/tests/TestAPIUnits.py | 8 ++++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/plugins/amoeba/openmmapi/include/openmm/AmoebaOutOfPlaneBendForce.h b/plugins/amoeba/openmmapi/include/openmm/AmoebaOutOfPlaneBendForce.h index ab4f27129..aaa555758 100644 --- a/plugins/amoeba/openmmapi/include/openmm/AmoebaOutOfPlaneBendForce.h +++ b/plugins/amoeba/openmmapi/include/openmm/AmoebaOutOfPlaneBendForce.h @@ -74,7 +74,7 @@ public: * * @return global cubicK term */ - double getAmoebaGlobalOutOfPlaneBendCubic(void) const; + double getAmoebaGlobalOutOfPlaneBendCubic() const; /** * Set the global cubic term @@ -88,7 +88,7 @@ public: * * @return global quartic term */ - double getAmoebaGlobalOutOfPlaneBendQuartic(void) const; + double getAmoebaGlobalOutOfPlaneBendQuartic() const; /** * Set the global pentic term @@ -102,7 +102,7 @@ public: * * @return global penticK term */ - double getAmoebaGlobalOutOfPlaneBendPentic(void) const; + double getAmoebaGlobalOutOfPlaneBendPentic() const; /** * Set the global sextic term @@ -116,7 +116,7 @@ public: * * @return global sexticK term */ - double getAmoebaGlobalOutOfPlaneBendSextic(void) const; + double getAmoebaGlobalOutOfPlaneBendSextic() const; /** * Add an out-of-plane bend term to the force field. diff --git a/wrappers/python/src/swig_doxygen/swigInputBuilder.py b/wrappers/python/src/swig_doxygen/swigInputBuilder.py index 27f413c2f..855c6e39b 100755 --- a/wrappers/python/src/swig_doxygen/swigInputBuilder.py +++ b/wrappers/python/src/swig_doxygen/swigInputBuilder.py @@ -481,7 +481,6 @@ class SwigInputBuilder: sys.stdout.write("%s.%s() returns %s\n" % (shortClassName, methName, valueUnits[0])) if len(valueUnits[1])>0: - print('IT IS GREATER THAN 1') addText = "%s%sval[%d]=unit.Quantity(val[%d], %s)\n" \ % (addText, INDENT, index, index, @@ -492,10 +491,10 @@ class SwigInputBuilder: % (addText, INDENT, valueUnits[0]) for vUnit in valueUnits[1]: - if vUnit!=None: - addText = "%s%sval[%s]=unit.Quantity(val[%s], %s)\n" \ + if vUnit is not None: + addText = "%s%sval[%s]=unit.Quantity(val[%s], %s)\n" \ % (addText, INDENT, index, index, vUnit) - index+=1 + index+=1 if key in self.configModule.STEAL_OWNERSHIP: for argNum in self.configModule.STEAL_OWNERSHIP[key]: diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index e3a67d40c..ece1d383c 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -272,7 +272,7 @@ UNITS = { ("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendQuartic") : ( '1/unit.radian**2',()), ("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendPentic") : ( '1/unit.radian**3',()), ("AmoebaOutOfPlaneBendForce", "getAmoebaGlobalOutOfPlaneBendSextic") : ( '1/unit.radian**4',()), -("AmoebaOutOfPlaneBendForce", "getOutOfPlaneBendParameters") : ( None, (None, None, None, None, 'unit.kilojoule_per_mole')), +("AmoebaOutOfPlaneBendForce", "getOutOfPlaneBendParameters") : ( None, (None, None, None, None, 'unit.kilojoule_per_mole/unit.radians**2')), ("AmoebaPiTorsionForce", "getNumPiTorsions") : ( None, ()), ("AmoebaPiTorsionForce", "getPiTorsionParameters") : ( None, (None, None, None, None, None, None, 'unit.kilojoule_per_mole')), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 1bf80b678..c59906731 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -711,16 +711,16 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(j, 1) self.assertEqual(k, 2) self.assertEqual(l, 3) - self.assertEqual(tk, 1.0*kilojoules_per_mole) - self.assertIs(tk.unit, kilojoules_per_mole) + self.assertEqual(tk, 1.0*kilojoules_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) i, j, k, l, tk = force.getOutOfPlaneBendParameters(1) self.assertEqual(i, 1) self.assertEqual(j, 2) self.assertEqual(k, 3) self.assertEqual(l, 4) - self.assertEqual(tk, 1.0*kilocalorie_per_mole) - self.assertIs(tk.unit, kilojoules_per_mole) + self.assertEqual(tk, 1.0*kilocalorie_per_mole/radians**2) + self.assertIs(tk.unit, kilojoules_per_mole/radians**2) if __name__ == '__main__': unittest.main() -- GitLab From ed3e8a110eaba6ec4a36e4228def5422e865bd3c Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 18 Sep 2015 16:45:48 -0400 Subject: [PATCH 35/49] Correct the returned units for StretchBendForce and add unit tests for it. --- .../src/swig_doxygen/swigInputConfig.py | 2 +- wrappers/python/tests/TestAPIUnits.py | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index ece1d383c..99e8c84b3 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -278,7 +278,7 @@ UNITS = { ("AmoebaPiTorsionForce", "getPiTorsionParameters") : ( None, (None, None, None, None, None, None, 'unit.kilojoule_per_mole')), ("AmoebaStretchBendForce", "getNumStretchBends") : ( None, ()), -("AmoebaStretchBendForce", "getStretchBendParameters") : ( None, (None, None, None, 'unit.nanometer', 'unit.nanometer', 'unit.radian', 'unit.kilojoule_per_mole/unit.nanometer/unit.degree', 'unit.kilojoule_per_mole/unit.nanometer/unit.degree')), +("AmoebaStretchBendForce", "getStretchBendParameters") : ( None, (None, None, None, 'unit.nanometer', 'unit.nanometer', 'unit.radian', 'unit.kilojoule_per_mole/unit.nanometer/unit.radian', 'unit.kilojoule_per_mole/unit.nanometer/unit.radian')), ("AmoebaTorsionTorsionForce", "getNumTorsionTorsions") : ( None, ()), ("AmoebaTorsionTorsionForce", "getNumTorsionTorsionGrids") : ( None, ()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index c59906731..70eab3080 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -722,5 +722,75 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(tk, 1.0*kilocalorie_per_mole/radians**2) self.assertIs(tk.unit, kilojoules_per_mole/radians**2) + def testAmoebaPiTorsionForce(self): + """ Tests the AmoebaPiTorsionForce API features """ + force = AmoebaPiTorsionForce() + + force.addPiTorsion(0, 1, 2, 3, 4, 5, 1.0) + force.addPiTorsion(1, 2, 3, 4, 5, 6, 1.0*kilocalories_per_mole) + + self.assertEqual(force.getNumPiTorsions(), 2) + + i, j, k, l, m, n, tk = force.getPiTorsionParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(m, 4) + self.assertEqual(n, 5) + self.assertEqual(tk, 1.0*kilojoules_per_mole) + self.assertIs(tk.unit, kilojoule_per_mole) + + i, j, k, l, m, n, tk = force.getPiTorsionParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, 4) + self.assertEqual(m, 5) + self.assertEqual(n, 6) + self.assertEqual(tk, 1.0*kilocalories_per_mole) + self.assertIs(tk.unit, kilojoule_per_mole) + + def testAmoebaStretchBendForce(self): + """ Tests the AmoebaStretchBendForce API features """ + force = AmoebaStretchBendForce() + + force.addStretchBend(0, 1, 2, 0.10, 0.12, math.pi/2, 10.0, 12.0) + force.addStretchBend(1, 2, 3, 1.0*angstroms, 1.2*angstroms, 60*degrees, + 10.0*kilocalories_per_mole/angstroms/radians, + 12.0*kilocalories_per_mole/angstroms/radians) + + self.assertEqual(force.getNumStretchBends(), 2) + + i, j, k, r1, r2, t, k1, k2 = force.getStretchBendParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(r1, 0.1*nanometers) + self.assertIs(r1.unit, nanometers) + self.assertEqual(r2, 0.12*nanometers) + self.assertIs(r2.unit, nanometers) + self.assertEqual(t, math.pi/2*radians) + self.assertIs(t.unit, radians) + self.assertEqual(k1, 10*kilojoules_per_mole/nanometers/radians) + self.assertIs(k1.unit, kilojoules_per_mole/nanometers/radians) + self.assertEqual(k2, 12*kilojoules_per_mole/nanometers/radians) + self.assertIs(k2.unit, kilojoules_per_mole/nanometers/radians) + + i, j, k, r1, r2, t, k1, k2 = force.getStretchBendParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(r1, 1.0*angstroms) + self.assertIs(r1.unit, nanometers) + self.assertEqual(r2, 1.2*angstroms) + self.assertIs(r2.unit, nanometers) + self.assertAlmostEqualUnit(t, 60*degrees) + self.assertIs(t.unit, radians) + self.assertEqual(k1, 10*kilocalories_per_mole/angstroms/radians) + self.assertIs(k1.unit, kilojoules_per_mole/nanometers/radians) + self.assertEqual(k2, 12*kilocalories_per_mole/angstroms/radians) + self.assertIs(k2.unit, kilojoules_per_mole/nanometers/radians) + if __name__ == '__main__': unittest.main() -- GitLab From f7e4653a34ee45a8d117118e644565a1ee4dcf65 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 18 Sep 2015 17:06:53 -0400 Subject: [PATCH 36/49] Add a test for AmoebaTorsionTorsionForce that fails because stripUnits doesn't work for the input variable type. --- .../forcefield-scripts/processTinkerForceField.py | 1 - wrappers/python/tests/TestAPIUnits.py | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/devtools/forcefield-scripts/processTinkerForceField.py b/devtools/forcefield-scripts/processTinkerForceField.py index 40787d2f3..8080381ce 100644 --- a/devtools/forcefield-scripts/processTinkerForceField.py +++ b/devtools/forcefield-scripts/processTinkerForceField.py @@ -1017,7 +1017,6 @@ if( isAmoeba ): torsionTorsionUnit = 1.0 outputString = """ """ tinkerXmlFile.write( "%s\n" % (outputString ) ) - conversion = 41.84/radian torsionTorsions = forces['tortors'] for (index, torsionTorsion) in enumerate(torsionTorsions): torInfo = torsionTorsion[0] diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 70eab3080..5be85dd7d 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -792,5 +792,19 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(k2, 12*kilocalories_per_mole/angstroms/radians) self.assertIs(k2.unit, kilojoules_per_mole/nanometers/radians) + def testAmoebaTorsionTorsionForce(self): + """ Tests the AmoebaTorsionTorsionForce API features """ + force = AmoebaTorsionTorsionForce() + + grid1 = [[[i, j, random.random(), random.random(), random.random(), random.random()] + for j in range(-180, 180, 24)] for i in range(-180, 180, 24)] + kcal = kilocalories_per_mole + grid2 = [[[i*degrees, j*degrees, random.random()*kcal, + random.random()*kcal/radians, random.random()*kcal/radians, + random.random()*kcal/radians**2] + for j in range(-180, 0, 10)] for i in range(-180, 0, 10)] + force.setTorsionTorsionGrid(0, grid1) + force.setTorsionTorsionGrid(0, grid2) + if __name__ == '__main__': unittest.main() -- GitLab From 7fbb9c8f48ecb075b48748c30d5c108279bc6124 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 25 Sep 2015 15:27:44 -0400 Subject: [PATCH 37/49] SWIG 3.0.5 has expanded args too --- wrappers/python/src/swig_doxygen/swigInputBuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputBuilder.py b/wrappers/python/src/swig_doxygen/swigInputBuilder.py index 855c6e39b..f56a539d5 100755 --- a/wrappers/python/src/swig_doxygen/swigInputBuilder.py +++ b/wrappers/python/src/swig_doxygen/swigInputBuilder.py @@ -157,7 +157,7 @@ class SwigInputBuilder: skipAdditionalMethods=[], SWIG_VERSION='3.0.2'): self.nodeByID={} - self.SWIG_COMPACT_ARGUMENTS = LooseVersion(SWIG_VERSION) < LooseVersion('3.0.6') + self.SWIG_COMPACT_ARGUMENTS = LooseVersion(SWIG_VERSION) < LooseVersion('3.0.5') self.configModule = __import__(os.path.splitext(configFilename)[0]) -- GitLab From 3e42a37290db1f20417020707caa5564eed72531 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Mon, 28 Sep 2015 22:07:23 -0400 Subject: [PATCH 38/49] - Update/finish Torsion-Torsion test - Remove API change for AmoebaAngleForce so it goes back to only taking degrees. Handle conversion via a pythonprepend (since stripUnits is done in C++ now). - Do the same thing for TorsionTorsionForce, since angles are in degrees again - Add AmoebaVdwForce and AmoebaWcaForce tests --- .../include/openmm/AmoebaAngleForce.h | 4 +- .../amoeba/openmmapi/src/AmoebaAngleForce.cpp | 5 +- .../swig_doxygen/swig_lib/python/pythoncode.i | 72 ++++++- wrappers/python/tests/TestAPIUnits.py | 180 +++++++++++++++++- 4 files changed, 251 insertions(+), 10 deletions(-) diff --git a/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h b/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h index 7a8261f02..0e6a828a6 100644 --- a/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h +++ b/plugins/amoeba/openmmapi/include/openmm/AmoebaAngleForce.h @@ -127,7 +127,7 @@ public: * @param particle1 the index of the first particle connected by the angle * @param particle2 the index of the second particle connected by the angle * @param particle3 the index of the third particle connected by the angle - * @param length the equilibrium angle, measured in degrees if >2*pi, otherwise interpreted as radians + * @param length the equilibrium angle, measured in degrees * @param quadratic k the quadratic force constant for the angle, measured in kJ/mol/radian^2 * @return the index of the angle that was added */ @@ -152,7 +152,7 @@ public: * @param particle1 the index of the first particle connected by the angle * @param particle2 the index of the second particle connected by the angle * @param particle3 the index of the third particle connected by the angle - * @param length the equilibrium angle, measured in degrees if >2*pi, otherwise interpreted as radians + * @param length the equilibrium angle, measured in degrees * @param quadratic k the quadratic force constant for the angle, measured in kJ/mol/radian^2 */ void setAngleParameters(int index, int particle1, int particle2, int particle3, double length, double quadraticK); diff --git a/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp b/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp index d9473ef57..0cec83e80 100644 --- a/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp +++ b/plugins/amoeba/openmmapi/src/AmoebaAngleForce.cpp @@ -29,8 +29,6 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ -#define _USE_MATH_DEFINES 1 /* Needed for Windows */ -#include #include "openmm/Force.h" #include "openmm/OpenMMException.h" #include "openmm/AmoebaAngleForce.h" @@ -43,7 +41,6 @@ AmoebaAngleForce::AmoebaAngleForce() { } int AmoebaAngleForce::addAngle(int particle1, int particle2, int particle3, double length, double quadraticK) { - length = length < 2*M_PI ? length * 180.0/M_PI : length; angles.push_back(AngleInfo(particle1, particle2, particle3, length, quadraticK)); return angles.size()-1; } @@ -62,7 +59,7 @@ void AmoebaAngleForce::setAngleParameters(int index, int particle1, int particle angles[index].particle1 = particle1; angles[index].particle2 = particle2; angles[index].particle3 = particle3; - angles[index].length = length < 2*M_PI ? length * 180.0/M_PI : length; + angles[index].length = length; angles[index].quadraticK = quadraticK; } diff --git a/wrappers/python/src/swig_doxygen/swig_lib/python/pythoncode.i b/wrappers/python/src/swig_doxygen/swig_lib/python/pythoncode.i index d3c217f92..a9c3b91e4 100644 --- a/wrappers/python/src/swig_doxygen/swig_lib/python/pythoncode.i +++ b/wrappers/python/src/swig_doxygen/swig_lib/python/pythoncode.i @@ -2,9 +2,10 @@ try: import numpy -except: - pass +except ImportError: + numpy = None +import copy import sys import math RMIN_PER_SIGMA=math.pow(2, 1/6.0) @@ -224,3 +225,70 @@ class State(_object): self._system = args[0] self._integrator = args[1] %} + +%pythonprepend OpenMM::AmoebaAngleForce::addAngle %{ + try: + length = args[3] + if isinstance(args, tuple): + args = list(args) + except (NameError, UnboundLocalError): + if unit.is_quantity(length): + length = length.value_in_unit(unit.degree) + else: + if unit.is_quantity(length): + args[3] = length.value_in_unit(unit.degree) +%} + +%pythonprepend OpenMM::AmoebaAngleForce::setAngleParameters %{ + try: + length = args[4] + if isinstance(args, tuple): + args = list(args) + except (NameError, UnboundLocalError): + if unit.is_quantity(length): + length = length.value_in_unit(unit.degree) + else: + if unit.is_quantity(length): + args[4] = length.value_in_unit(unit.degree) +%} + +%pythonprepend OpenMM::AmoebaTorsionTorsionForce::setTorsionTorsionGrid %{ + def deunitize_grid(grid): + if isinstance(grid, tuple): + grid = list(grid) + for i, row in enumerate(grid): + if isinstance(row, tuple): + row = list(row) + grid[i] = row + for i, column in enumerate(row): + if isinstance(column, tuple): + column = list(column) + row[i] = column + # Data is angle, angle, energy, de/dang1, de/dang2, d^2e/dang1dang2 + if unit.is_quantity(column[0]): + column[0] = column[0].value_in_unit(unit.degree) + if unit.is_quantity(column[1]): + column[1] = column[1].value_in_unit(unit.degree) + if unit.is_quantity(column[2]): + column[2] = column[2].value_in_unit(unit.kilojoule_per_mole) + if len(column) > 3 and unit.is_quantity(column[3]): + column[3] = column[3].value_in_unit(unit.kilojoule_per_mole/unit.radians) + if len(column) > 4 and unit.is_quantity(column[4]): + column[4] = column[4].value_in_unit(unit.kilojoule_per_mole/unit.radians) + if len(column) > 5 and unit.is_quantity(column[5]): + column[5] = column[5].value_in_unit(unit.kilojoule_per_mole/unit.radians**2) + return grid + try: + grid = copy.deepcopy(args[1]) + if isinstance(args, tuple): + args = list(args) + except (NameError, UnboundLocalError): + try: + # Support numpy arrays + grid = grid.tolist() + except AttributeError: + grid = copy.deepcopy(grid) + grid = deunitize_grid(grid) + else: + args[1] = deunitize_grid(grid) +%} diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 5be85dd7d..f5f2ec394 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -799,12 +799,188 @@ class TestAPIUnits(unittest.TestCase): grid1 = [[[i, j, random.random(), random.random(), random.random(), random.random()] for j in range(-180, 180, 24)] for i in range(-180, 180, 24)] kcal = kilocalories_per_mole - grid2 = [[[i*degrees, j*degrees, random.random()*kcal, + grid2 = [[[i*math.pi/180*radians, j*math.pi/180*radians, random.random()*kcal, random.random()*kcal/radians, random.random()*kcal/radians, random.random()*kcal/radians**2] for j in range(-180, 0, 10)] for i in range(-180, 0, 10)] + grid3 = [[[i, j, random.random()*kcal] + for j in range(-180, 180, 24)] for i in range(-180, 180, 24)] force.setTorsionTorsionGrid(0, grid1) - force.setTorsionTorsionGrid(0, grid2) + force.setTorsionTorsionGrid(1, grid2) + force.setTorsionTorsionGrid(2, grid3) + + self.assertEqual(force.getNumTorsionTorsionGrids(), 3) + + # Check the grids + g1 = force.getTorsionTorsionGrid(0) + for row1, row2 in zip(g1, grid1): + for column1, column2 in zip(row1, row2): + self.assertEqual(len(column1), len(column2)) + for x1, x2 in zip(column1, column2): + self.assertEqual(x1, x2) + g2 = force.getTorsionTorsionGrid(1) + for row1, row2 in zip(g2, grid2): + for column1, column2 in zip(row1, row2): + self.assertEqual(column1[0], column2[0].value_in_unit(degree)) + self.assertEqual(column1[1], column2[1].value_in_unit(degree)) + self.assertEqual(column1[2], column2[2].value_in_unit(kilojoules_per_mole)) + self.assertEqual(column1[3], column2[3].value_in_unit(kilojoules_per_mole/radian)) + self.assertEqual(column1[4], column2[4].value_in_unit(kilojoules_per_mole/radian)) + self.assertEqual(column1[5], column2[5].value_in_unit(kilojoules_per_mole/radian**2)) + g3 = force.getTorsionTorsionGrid(2) + for row1, row2 in zip(g3, grid3): + for column1, column2 in zip(row1, row2): + self.assertEqual(len(column1), 6) + self.assertEqual(len(column2), 3) + self.assertEqual(column1[0], column2[0]) + self.assertEqual(column1[1], column2[1]) + self.assertEqual(column1[2], column2[2].value_in_unit(kilojoules_per_mole)) + + force.addTorsionTorsion(0, 1, 2, 3, 4, 5, 0) + force.addTorsionTorsion(1, 2, 3, 4, 5, 6, 1) + force.addTorsionTorsion(2, 3, 4, 5, 6, 7, 2) + + self.assertEqual(force.getNumTorsionTorsions(), 3) + + i, j, k, l, m, ch, g = force.getTorsionTorsionParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, 2) + self.assertEqual(l, 3) + self.assertEqual(m, 4) + self.assertEqual(ch, 5) + self.assertEqual(g, 0) + + i, j, k, l, m, ch, g = force.getTorsionTorsionParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, 4) + self.assertEqual(m, 5) + self.assertEqual(ch, 6) + self.assertEqual(g, 1) + + def testAmoebaVdwForce(self): + """ Tests the AmoebaVdwForce API features """ + force = AmoebaVdwForce() + + self.assertEqual(force.getSigmaCombiningRule(), 'CUBIC-MEAN') + force.setSigmaCombiningRule('ARITHMETIC') + self.assertEqual(force.getSigmaCombiningRule(), 'ARITHMETIC') + force.setSigmaCombiningRule('GEOMETRIC') + self.assertEqual(force.getSigmaCombiningRule(), 'GEOMETRIC') + + self.assertEqual(force.getEpsilonCombiningRule(), 'HHG') + force.setEpsilonCombiningRule('HARMONIC') + self.assertEqual(force.getEpsilonCombiningRule(), 'HARMONIC') + force.setEpsilonCombiningRule('GEOMETRIC') + self.assertEqual(force.getEpsilonCombiningRule(), 'GEOMETRIC') + force.setEpsilonCombiningRule('ARITHMETIC') + self.assertEqual(force.getEpsilonCombiningRule(), 'ARITHMETIC') + + self.assertTrue(force.getUseDispersionCorrection()) + force.setUseDispersionCorrection(False) + self.assertFalse(force.getUseDispersionCorrection()) + + self.assertIs(force.getNonbondedMethod(), AmoebaVdwForce.NoCutoff) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(AmoebaVdwForce.CutoffPeriodic) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + self.assertIs(force.getNonbondedMethod(), AmoebaVdwForce.CutoffPeriodic) + + force.setCutoff(10.0*angstroms) + self.assertEqual(force.getCutoff(), 10.0*angstroms) + self.assertIs(force.getCutoff().unit, nanometers) + + force.addParticle(0, 0.1, 1.0, 1.0) + force.addParticle(1, 1.0*angstroms, 1.0*kilocalories_per_mole, 0.5) + force.addParticle(1, 0.8*angstroms, 2.0*kilocalories_per_mole, 0.25) + + self.assertEqual(force.getNumParticles(), 3) + + p, sig, eps, scale = force.getParticleParameters(0) + self.assertEqual(p, 0) + self.assertEqual(sig, 0.1*nanometers) + self.assertIs(sig.unit, nanometers) + self.assertEqual(eps, 1.0*kilojoules_per_mole) + self.assertIs(eps.unit, kilojoules_per_mole) + self.assertEqual(scale, 1.0) + + p, sig, eps, scale = force.getParticleParameters(1) + self.assertEqual(p, 1) + self.assertEqual(sig, 1.0*angstroms) + self.assertIs(sig.unit, nanometers) + self.assertEqual(eps, 1.0*kilocalories_per_mole) + self.assertIs(eps.unit, kilojoules_per_mole) + self.assertEqual(scale, 0.5) + + p, sig, eps, scale = force.getParticleParameters(2) + self.assertEqual(p, 1) + self.assertAlmostEqualUnit(sig, 0.8*angstroms) + self.assertIs(sig.unit, nanometers) + self.assertEqual(eps, 2.0*kilocalories_per_mole) + self.assertIs(eps.unit, kilojoules_per_mole) + self.assertEqual(scale, 0.25) + + def testAmoebaWcaDispersionForce(self): + """ Tests the AmoebaWcaDispersionForce API features """ + force = AmoebaWcaDispersionForce() + + self.assertEqual(force.getDispoff(), 0.26*nanometer) + self.assertEqual(force.getAwater(), 0.033428*nanometer**-3) + self.assertEqual(force.getEpsh(), 0.0135*kilojoule_per_mole) + self.assertEqual(force.getEpso(), 0.11*kilojoule_per_mole) + self.assertEqual(force.getRminh(), 1.3275*nanometer) + self.assertEqual(force.getRmino(), 1.7025*nanometer) + self.assertEqual(force.getShctd(), 0.81) + self.assertEqual(force.getSlevy(), 1.0) + + force.setDispoff(3*angstroms) + self.assertAlmostEqualUnit(force.getDispoff(), 3*angstroms) + self.assertIs(force.getDispoff().unit, nanometer) + + force.setAwater(3*angstroms**-3) + self.assertAlmostEqualUnit(force.getAwater(), 3*angstroms**-3) + self.assertEqual(1*force.getAwater().unit, 1*nanometer**-3) + + force.setEpsh(1*kilocalorie_per_mole) + self.assertEqual(force.getEpsh(), 1*kilocalorie_per_mole) + self.assertIs(force.getEpsh().unit, kilojoule_per_mole) + + force.setEpso(1*kilocalorie_per_mole) + self.assertEqual(force.getEpso(), 1*kilocalorie_per_mole) + self.assertIs(force.getEpso().unit, kilojoule_per_mole) + + force.setRminh(20*angstroms) + self.assertEqual(force.getRminh(), 20*angstroms) + self.assertIs(force.getRminh().unit, nanometer) + + force.setRmino(30*angstroms) + self.assertEqual(force.getRmino(), 30*angstroms) + self.assertIs(force.getRmino().unit, nanometer) + + force.setShctd(1) + self.assertEqual(force.getShctd(), 1) + + force.setSlevy(2) + self.assertEqual(force.getSlevy(), 2) + + force.addParticle(0.5, 1) + force.addParticle(3*angstroms, 1*kilocalorie_per_mole) + + self.assertEqual(force.getNumParticles(), 2) + + sig, eps = force.getParticleParameters(0) + self.assertEqual(sig, 0.5*nanometer) + self.assertIs(sig.unit, nanometer) + self.assertEqual(eps, 1*kilojoule_per_mole) + self.assertIs(eps.unit, kilojoule_per_mole) + + sig, eps = force.getParticleParameters(1) + self.assertAlmostEqualUnit(sig, 3*angstrom) + self.assertIs(sig.unit, nanometer) + self.assertEqual(eps, 1*kilocalorie_per_mole) + self.assertIs(eps.unit, kilojoule_per_mole) if __name__ == '__main__': unittest.main() -- GitLab From ad98f7648ab5f5c93668c9004835c0c0e56761b6 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Mon, 28 Sep 2015 23:21:39 -0400 Subject: [PATCH 39/49] Add units to AmoebaMultipoleForce.getMultipoleParameters (check that these are right). Add a test for AmoebaMultipoleForce. --- .../src/swig_doxygen/swigInputConfig.py | 4 +- wrappers/python/tests/TestAPIUnits.py | 59 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index 99e8c84b3..cd4388049 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -256,7 +256,9 @@ UNITS = { # void getCovalentMap(int index, CovalentType typeId, std::vector& covalentAtoms ) # void getCovalentMaps(int index, std::vector < std::vector >& covalentLists ) -("AmoebaMultipoleForce", "getMultipoleParameters") : ( None, ()), +("AmoebaMultipoleForce", "getMultipoleParameters") : ( None, ('unit.elementary_charge', 'unit.elementary_charge/unit.nanometer', + 'unit.elementary_charge/unit.nanometer**2', None, None, None, None, None, None, + 'unit.nanometer**3')), ("AmoebaMultipoleForce", "getCovalentMap") : ( None, ()), ("AmoebaMultipoleForce", "getCovalentMaps") : ( None, ()), ("AmoebaMultipoleForce", "getScalingDistanceCutoff") : ( 'unit.nanometer', ()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index f5f2ec394..c3b93f859 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -13,6 +13,10 @@ class TestAPIUnits(unittest.TestCase): def assertAlmostEqualUnit(self, x1, x2): self.assertAlmostEqual(x1._value, x2.value_in_unit(x1.unit)) + def assertAlmostEqualUnitArray(self, a1, a2): + for x1, x2 in zip(a1._value, a2.value_in_unit(a1.unit)): + self.assertAlmostEqual(x1, x2) + def testHarmonicBondForce(self): """ Tests HarmonicBondForce API features """ force = HarmonicBondForce() @@ -982,5 +986,60 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(eps, 1*kilocalorie_per_mole) self.assertIs(eps.unit, kilojoule_per_mole) + def testAmoebaMultipoleForce(self): + """ Tests the AmoebaMultipoleForce API features """ + force = AmoebaMultipoleForce() + self.assertIs(force.getNonbondedMethod(), AmoebaMultipoleForce.NoCutoff) + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.setNonbondedMethod(AmoebaMultipoleForce.PME) + self.assertIs(force.getNonbondedMethod(), AmoebaMultipoleForce.PME) + self.assertTrue(force.usesPeriodicBoundaryConditions()) + + self.assertEqual(force.getCutoffDistance(), 1*nanometer) + self.assertIs(force.getCutoffDistance().unit, nanometer) + force.setCutoffDistance(8*angstroms) + self.assertEqual(force.getCutoffDistance(), 8*angstrom) + self.assertIs(force.getCutoffDistance().unit, nanometer) + + self.assertEqual(force.getPolarizationType(), AmoebaMultipoleForce.Mutual) + force.setPolarizationType(AmoebaMultipoleForce.Direct) + self.assertEqual(force.getPolarizationType(), AmoebaMultipoleForce.Direct) + force.setPolarizationType(AmoebaMultipoleForce.Mutual) + self.assertEqual(force.getPolarizationType(), AmoebaMultipoleForce.Mutual) + + force.addMultipole(1.0, [0.5, 0, -0.5], list(range(9)), + AmoebaMultipoleForce.ZThenX, 1, 2, 3, 0.5, 0.5, 1.0) + force.addMultipole(1.0*elementary_charge, [0.5, 0, -0.5]*elementary_charge/angstrom, + list(range(9))*elementary_charge/angstrom**2, + AmoebaMultipoleForce.Bisector, 2, 3, 4, 0.5, 0.5, 1.0*angstrom**3) + + self.assertEqual(force.getNumMultipoles(), 2) + + q, mu, quad, ax, i, j, k, thole, damp, polarity = force.getMultipoleParameters(0) + + self.assertEqual(q, 1.0*elementary_charge) + self.assertEqual(mu, (0.5, 0, -0.5)*elementary_charge/nanometer) + self.assertEqual(quad, tuple(range(9))*elementary_charge/nanometer**2) + self.assertEqual(ax, AmoebaMultipoleForce.ZThenX) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(thole, 0.5) + self.assertEqual(damp, 0.5) + self.assertEqual(polarity, 1*nanometer**3) + + q, mu, quad, ax, i, j, k, thole, damp, polarity = force.getMultipoleParameters(1) + + self.assertEqual(q, 1.0*elementary_charge) + self.assertEqual(mu, (0.5, 0, -0.5)*elementary_charge/angstrom) + self.assertAlmostEqualUnitArray(quad, tuple(range(9))*elementary_charge/angstrom**2) + self.assertEqual(ax, AmoebaMultipoleForce.Bisector) + self.assertEqual(i, 2) + self.assertEqual(j, 3) + self.assertEqual(k, 4) + self.assertEqual(thole, 0.5) + self.assertEqual(damp, 0.5) + self.assertAlmostEqualUnit(polarity, 1*angstrom**3) + if __name__ == '__main__': unittest.main() -- GitLab From 7d0d0f43ccc7c1166b82919ff0b45dde9e6559fa Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Mon, 28 Sep 2015 23:45:15 -0400 Subject: [PATCH 40/49] Add tests for VerletIntegrator, VariableVerletIntegrator, LangevinIntegrator, and VariableLangevinIntegrator --- wrappers/python/tests/TestAPIUnits.py | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index c3b93f859..c5a9b1f60 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -1041,5 +1041,50 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(damp, 0.5) self.assertAlmostEqualUnit(polarity, 1*angstrom**3) + def testVerletIntegrator(self): + """ Tests the VerletIntegrator API features """ + integrator = VerletIntegrator(1.0) + self.assertEqual(integrator.getStepSize(), 1.0*picosecond) + self.assertEqual(integrator.getConstraintTolerance(), 1e-5) + integrator.setConstraintTolerance(1e-6) + self.assertEqual(integrator.getConstraintTolerance(), 1e-6) + + integrator = VerletIntegrator(1.0*femtoseconds) + self.assertEqual(integrator.getStepSize(), 1.0*femtoseconds) + + def testVariableVerletIntegrator(self): + """ Tests the VariableVerletIntegrator API features """ + integrator = VariableVerletIntegrator(0.1) + self.assertEqual(integrator.getErrorTolerance(), 0.1) + integrator.setErrorTolerance(0.01) + self.assertEqual(integrator.getErrorTolerance(), 0.01) + self.assertEqual(integrator.getConstraintTolerance(), 1e-5) + integrator.setConstraintTolerance(1e-6) + self.assertEqual(integrator.getConstraintTolerance(), 1e-6) + + def testLangevinIntegrator(self): + """ Tests the LangevinIntegrator API features """ + integrator = LangevinIntegrator(300, 0.1, 1) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + self.assertEqual(integrator.getFriction(), 0.1/picosecond) + self.assertEqual(integrator.getStepSize(), 1*picosecond) + + integrator = LangevinIntegrator(300*kelvin, 0.1/microsecond, 1*femtosecond) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + self.assertAlmostEqualUnit(integrator.getFriction(), 0.1/microsecond) + self.assertEqual(integrator.getStepSize(), 1*femtosecond) + + def testVariableLangevinIntegrator(self): + """ Tests the VariableLangevinIntegrator API features """ + integrator = VariableLangevinIntegrator(300, 0.1, 0.1) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + self.assertEqual(integrator.getFriction(), 0.1/picosecond) + self.assertEqual(integrator.getErrorTolerance(), 0.1) + + integrator = VariableLangevinIntegrator(300*kelvin, 0.1/microsecond, 0.01) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + self.assertAlmostEqualUnit(integrator.getFriction(), 0.1/microsecond) + self.assertEqual(integrator.getErrorTolerance(), 0.01) + if __name__ == '__main__': unittest.main() -- GitLab From c14055361e7308c7b00a6cd27056b56f4195adcc Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Tue, 29 Sep 2015 00:08:15 -0400 Subject: [PATCH 41/49] Add tests for BrownianIntegrator, AndersenThermostat, DrudeSCFIntegrator, and DrudeLangevinIntegrator. --- wrappers/python/tests/TestAPIUnits.py | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index c5a9b1f60..3e526ae7f 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -1086,5 +1086,55 @@ class TestAPIUnits(unittest.TestCase): self.assertAlmostEqualUnit(integrator.getFriction(), 0.1/microsecond) self.assertEqual(integrator.getErrorTolerance(), 0.01) + def testBrownianIntegrator(self): + """ Tests the BrownianIntegrator API features """ + integrator = BrownianIntegrator(300, 0.1, 1) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + self.assertEqual(integrator.getFriction(), 0.1/picosecond) + self.assertEqual(integrator.getStepSize(), 1*picosecond) + + integrator = BrownianIntegrator(300*kelvin, 0.1/microsecond, 1*femtosecond) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + self.assertAlmostEqualUnit(integrator.getFriction(), 0.1/microsecond) + self.assertEqual(integrator.getStepSize(), 1*femtosecond) + + def testAndersenThermostat(self): + """ Tests the AndersenThermostat API features """ + force = AndersenThermostat(300*kelvin, 1/microsecond) + self.assertEqual(force.getDefaultTemperature(), 300*kelvin) + self.assertAlmostEqualUnit(force.getDefaultCollisionFrequency(), 1/microsecond) + + force.setDefaultTemperature(298.15) + force.setDefaultCollisionFrequency(1) + self.assertEqual(force.getDefaultTemperature(), 298.15*kelvin) + self.assertAlmostEqualUnit(force.getDefaultCollisionFrequency(), 1/picosecond) + + def testDrudeSCFIntegrator(self): + """ Tests the DrudeSCFIntegrator API features """ + integrator = DrudeSCFIntegrator(0.002) + self.assertEqual(integrator.getStepSize(), 0.002*picoseconds) + self.assertAlmostEqualUnit(integrator.getMinimizationErrorTolerance(), + 0.1*kilojoule_per_mole/nanometer) + integrator.setMinimizationErrorTolerance(1*kilocalorie_per_mole/angstrom) + self.assertAlmostEqualUnit(integrator.getMinimizationErrorTolerance(), + 1*kilocalorie_per_mole/angstrom) + + def testDrudeLangevinIntegrator(self): + """ Tests the DrudeLangevinIntegrator API features """ + integrator = DrudeLangevinIntegrator(300*kelvin, 1.0/microsecond, + 100*kelvin, 1/picosecond, 0.1*femtosecond) + self.assertEqual(integrator.getTemperature(), 300*kelvin) + integrator.setTemperature(298.15) + self.assertEqual(integrator.getTemperature(), 298.15*kelvin) + self.assertAlmostEqualUnit(integrator.getFriction(), 1/microsecond) + integrator.setFriction(1) + self.assertEqual(integrator.getFriction(), 1/picosecond) + self.assertEqual(integrator.getDrudeTemperature(), 100*kelvin) + integrator.setDrudeTemperature(50) + self.assertEqual(integrator.getDrudeTemperature(), 50*kelvin) + self.assertEqual(integrator.getStepSize(), 0.1*femtosecond) + integrator.setStepSize(0.0005) + self.assertEqual(integrator.getStepSize(), 0.0005*picosecond) + if __name__ == '__main__': unittest.main() -- GitLab From 8f1a60d4fa5fd041961cf19ef4513934db858ea1 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Tue, 29 Sep 2015 00:28:10 -0400 Subject: [PATCH 42/49] Add units to getters for DrudeForce and add a test case for it. --- .../src/swig_doxygen/swigInputConfig.py | 3 + wrappers/python/tests/TestAPIUnits.py | 65 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index cd4388049..553dd6abb 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -378,6 +378,9 @@ UNITS = { ("CustomTorsionForce", "getPerTorsionParameterName") : (None, ()), ("CustomTorsionForce", "getGlobalParameterName") : (None, ()), ("CustomTorsionForce", "getTorsionParameters") : (None, ()), +("DrudeForce", "getParticleParameters") : (None, (None, None, None, None, None, 'unit.elementary_charge', 'unit.nanometer**3', None, None)), +("DrudeForce", "getNumScreenedPairs") : (None, ()), +("DrudeForce", "getScreenedPairParameters") : (None, ()), ("GBSAOBCForce", "getParticleParameters") : (None, ('unit.elementary_charge', 'unit.nanometer', None)), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 3e526ae7f..56a6f29ca 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -521,6 +521,71 @@ class TestAPIUnits(unittest.TestCase): self.assertEqual(force.getParticleParameters(1)[0][0], 20) self.assertEqual(force.getParticleParameters(2)[0][0], 30*4.184) + def testDrudeForce(self): + """ Tests the DrudeForce API features """ + force = DrudeForce() + self.assertFalse(force.usesPeriodicBoundaryConditions()) + force.addParticle(0, 1, -1, -1, -1, 1, 1, 0, 0) + force.addParticle(1, 2, 3, -1, -1, 1*elementary_charge, 1*angstrom**3, 0.5, 0) + force.addParticle(2, 3, 4, 5, 6, 1*elementary_charge, 10*angstrom**3, 0.5, 0.5) + force.addScreenedPair(0, 1, 0.5) + force.addScreenedPair(1, 2, 0.25) + force.addScreenedPair(0, 2, 0.125) + + self.assertEqual(force.getNumParticles(), 3) + self.assertEqual(force.getNumScreenedPairs(), 3) + + i, j, k, l, m, q, a, an12, an34 = force.getParticleParameters(0) + + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(k, -1) + self.assertEqual(l, -1) + self.assertEqual(m, -1) + self.assertEqual(q, 1*elementary_charge) + self.assertEqual(a, 1*nanometer**3) + self.assertEqual(an12, 0) + self.assertEqual(an34, 0) + + i, j, k, l, m, q, a, an12, an34 = force.getParticleParameters(1) + + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(k, 3) + self.assertEqual(l, -1) + self.assertEqual(m, -1) + self.assertEqual(q, 1*elementary_charge) + self.assertAlmostEqualUnit(a, 1*angstrom**3) + self.assertEqual(an12, 0.5) + self.assertEqual(an34, 0) + + i, j, k, l, m, q, a, an12, an34 = force.getParticleParameters(2) + + self.assertEqual(i, 2) + self.assertEqual(j, 3) + self.assertEqual(k, 4) + self.assertEqual(l, 5) + self.assertEqual(m, 6) + self.assertEqual(q, 1*elementary_charge) + self.assertAlmostEqualUnit(a, 10*angstrom**3) + self.assertEqual(an12, 0.5) + self.assertEqual(an34, 0.5) + + i, j, thole = force.getScreenedPairParameters(0) + self.assertEqual(i, 0) + self.assertEqual(j, 1) + self.assertEqual(thole, 0.5) + + i, j, thole = force.getScreenedPairParameters(1) + self.assertEqual(i, 1) + self.assertEqual(j, 2) + self.assertEqual(thole, 0.25) + + i, j, thole = force.getScreenedPairParameters(2) + self.assertEqual(i, 0) + self.assertEqual(j, 2) + self.assertEqual(thole, 0.125) + def testAmoebaBondForce(self): """ Tests the AmoebaBondForce API features """ force1 = AmoebaBondForce() -- GitLab From e585fb6e2cc1986c218e56c6f737392eabf94e69 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Tue, 29 Sep 2015 00:31:45 -0400 Subject: [PATCH 43/49] Add a simple test for CustomIntegrator. --- wrappers/python/tests/TestAPIUnits.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index 56a6f29ca..f2903eee8 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -1201,5 +1201,16 @@ class TestAPIUnits(unittest.TestCase): integrator.setStepSize(0.0005) self.assertEqual(integrator.getStepSize(), 0.0005*picosecond) + def testCustomIntegrator(self): + """ Tests the CustomIntegrator API features """ + integrator = CustomIntegrator(1.0) + self.assertEqual(integrator.getStepSize(), 1.0*picosecond) + self.assertEqual(integrator.getConstraintTolerance(), 1e-5) + integrator.setConstraintTolerance(1e-6) + self.assertEqual(integrator.getConstraintTolerance(), 1e-6) + + integrator = CustomIntegrator(1.0*femtoseconds) + self.assertEqual(integrator.getStepSize(), 1.0*femtoseconds) + if __name__ == '__main__': unittest.main() -- GitLab From 9570ab9cf5b40ae7ac789de877ccf68bc5211d8e Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Wed, 30 Sep 2015 12:00:04 -0400 Subject: [PATCH 44/49] Fix very irritating behavior on some Mac systems. Hard-code CC and CXX to clang for Macs, since gcc/g++ will *not* work with Anaconda, despite the fact that distutils will try to use them. System Python, homebrew, and MacPorts on Macs will always use clang, so this hack should always work and fix issues with users that have GCC installed from MacPorts or homebrew *and* Anaconda. --- wrappers/python/setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wrappers/python/setup.py b/wrappers/python/setup.py index 47a760fa4..11adbd208 100644 --- a/wrappers/python/setup.py +++ b/wrappers/python/setup.py @@ -193,6 +193,13 @@ def buildKeywordDictionary(major_version_num=MAJOR_VERSION_NUM, if platform.system() == 'Darwin': extra_compile_args += ['-stdlib=libc++', '-mmacosx-version-min=10.7'] extra_link_args += ['-stdlib=libc++', '-mmacosx-version-min=10.7', '-Wl', '-rpath', openmm_lib_path] + # Hard-code CC and CXX to clang, since gcc/g++ will *not* work with + # Anaconda, despite the fact that distutils will try to use them. + # System Python, homebrew, and MacPorts on Macs will always use + # clang, so this hack should always work and fix issues with users + # that have GCC installed from MacPorts or homebrew *and* Anaconda + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' library_dirs=[openmm_lib_path] include_dirs=openmm_include_path.split(';') -- GitLab From 29137fd33faad049591fd53427183d1a42ec2b8d Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Wed, 30 Sep 2015 11:02:35 -0700 Subject: [PATCH 45/49] Don't try to build tests if BUILD_TESTING is off --- platforms/cuda/CMakeLists.txt | 4 ++-- platforms/opencl/CMakeLists.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platforms/cuda/CMakeLists.txt b/platforms/cuda/CMakeLists.txt index 26670f85a..72af67add 100644 --- a/platforms/cuda/CMakeLists.txt +++ b/platforms/cuda/CMakeLists.txt @@ -13,9 +13,9 @@ #---------------------------------------------------- set(OPENMM_BUILD_CUDA_TESTS TRUE CACHE BOOL "Whether to build CUDA test cases") -if(OPENMM_BUILD_CUDA_TESTS) +if(BUILD_TESTING AND OPENMM_BUILD_CUDA_TESTS) SUBDIRS (tests) -endif(OPENMM_BUILD_CUDA_TESTS) +endif(BUILD_TESTING AND OPENMM_BUILD_CUDA_TESTS) # The source is organized into subdirectories, but we handle them all from # this CMakeLists file rather than letting CMake visit them as SUBDIRS. diff --git a/platforms/opencl/CMakeLists.txt b/platforms/opencl/CMakeLists.txt index 2386334fe..4b8e4d189 100644 --- a/platforms/opencl/CMakeLists.txt +++ b/platforms/opencl/CMakeLists.txt @@ -13,9 +13,9 @@ #---------------------------------------------------- set(OPENMM_BUILD_OPENCL_TESTS TRUE CACHE BOOL "Whether to build OpenCL test cases") -if(OPENMM_BUILD_OPENCL_TESTS) +if(BUILD_TESTING AND OPENMM_BUILD_OPENCL_TESTS) SUBDIRS (tests) -endif(OPENMM_BUILD_OPENCL_TESTS) +endif(BUILD_TESTING AND OPENMM_BUILD_OPENCL_TESTS) # The source is organized into subdirectories, but we handle them all from # this CMakeLists file rather than letting CMake visit them as SUBDIRS. -- GitLab From 8d0fee51a1529095e4905c00cfc32cd27aa4088d Mon Sep 17 00:00:00 2001 From: peastman Date: Thu, 1 Oct 2015 11:00:43 -0700 Subject: [PATCH 46/49] More optimizations to CPU platform --- CMakeLists.txt | 2 +- libraries/vecmath/include/neon_mathfun.h | 301 ++++++++ libraries/vecmath/include/sse_mathfun.h | 711 ++++++++++++++++++ libraries/vecmath/src/vecmath.cpp | 7 + .../include/openmm/internal/vectorize_neon.h | 12 + .../include/openmm/internal/vectorize_pnacl.h | 8 + .../include/openmm/internal/vectorize_sse.h | 12 + platforms/cpu/src/CpuGBSAOBCForce.cpp | 2 +- platforms/cpu/src/CpuNonbondedForce.cpp | 61 +- tests/TestVectorize.cpp | 2 + 10 files changed, 1094 insertions(+), 24 deletions(-) create mode 100644 libraries/vecmath/include/neon_mathfun.h create mode 100644 libraries/vecmath/include/sse_mathfun.h create mode 100644 libraries/vecmath/src/vecmath.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 646ba011b..3e920274a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ ENDIF(${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT}) # The source is organized into subdirectories, but we handle them all from # this CMakeLists file rather than letting CMake visit them as SUBDIRS. -SET(OPENMM_SOURCE_SUBDIRS . openmmapi olla libraries/jama libraries/quern libraries/lepton libraries/sfmt libraries/lbfgs libraries/hilbert libraries/csha1 platforms/reference serialization libraries/validate libraries/irrxml) +SET(OPENMM_SOURCE_SUBDIRS . openmmapi olla libraries/jama libraries/quern libraries/lepton libraries/sfmt libraries/lbfgs libraries/hilbert libraries/csha1 platforms/reference serialization libraries/validate libraries/irrxml libraries/vecmath) IF(WIN32) SET(OPENMM_SOURCE_SUBDIRS ${OPENMM_SOURCE_SUBDIRS} libraries/pthreads) ELSE(WIN32) diff --git a/libraries/vecmath/include/neon_mathfun.h b/libraries/vecmath/include/neon_mathfun.h new file mode 100644 index 000000000..f51a61e17 --- /dev/null +++ b/libraries/vecmath/include/neon_mathfun.h @@ -0,0 +1,301 @@ +/* NEON implementation of sin, cos, exp and log + + Inspired by Intel Approximate Math library, and based on the + corresponding algorithms of the cephes math library +*/ + +/* Copyright (C) 2011 Julien Pommier + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + (this is the zlib license) +*/ + +#include + +typedef float32x4_t v4sf; // vector of 4 float +typedef uint32x4_t v4su; // vector of 4 uint32 +typedef int32x4_t v4si; // vector of 4 uint32 + +#define c_inv_mant_mask ~0x7f800000u +#define c_cephes_SQRTHF 0.707106781186547524 +#define c_cephes_log_p0 7.0376836292E-2 +#define c_cephes_log_p1 - 1.1514610310E-1 +#define c_cephes_log_p2 1.1676998740E-1 +#define c_cephes_log_p3 - 1.2420140846E-1 +#define c_cephes_log_p4 + 1.4249322787E-1 +#define c_cephes_log_p5 - 1.6668057665E-1 +#define c_cephes_log_p6 + 2.0000714765E-1 +#define c_cephes_log_p7 - 2.4999993993E-1 +#define c_cephes_log_p8 + 3.3333331174E-1 +#define c_cephes_log_q1 -2.12194440e-4 +#define c_cephes_log_q2 0.693359375 + +/* natural logarithm computed for 4 simultaneous float + return NaN for x <= 0 +*/ +v4sf log_ps(v4sf x) { + v4sf one = vdupq_n_f32(1); + + x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */ + v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0)); + + v4si ux = vreinterpretq_s32_f32(x); + + v4si emm0 = vshrq_n_s32(ux, 23); + + /* keep only the fractional part */ + ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask)); + ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f))); + x = vreinterpretq_f32_s32(ux); + + emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f)); + v4sf e = vcvtq_f32_s32(emm0); + + e = vaddq_f32(e, one); + + /* part2: + if( x < SQRTHF ) { + e -= 1; + x = x + x - 1.0; + } else { x = x - 1.0; } + */ + v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF)); + v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask)); + x = vsubq_f32(x, one); + e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask))); + x = vaddq_f32(x, tmp); + + v4sf z = vmulq_f32(x,x); + + v4sf y = vdupq_n_f32(c_cephes_log_p0); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7)); + y = vmulq_f32(y, x); + y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8)); + y = vmulq_f32(y, x); + + y = vmulq_f32(y, z); + + + tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1)); + y = vaddq_f32(y, tmp); + + + tmp = vmulq_f32(z, vdupq_n_f32(0.5f)); + y = vsubq_f32(y, tmp); + + tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2)); + x = vaddq_f32(x, y); + x = vaddq_f32(x, tmp); + x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN + return x; +} + +#define c_exp_hi 88.3762626647949f +#define c_exp_lo -88.3762626647949f + +#define c_cephes_LOG2EF 1.44269504088896341 +#define c_cephes_exp_C1 0.693359375 +#define c_cephes_exp_C2 -2.12194440e-4 + +#define c_cephes_exp_p0 1.9875691500E-4 +#define c_cephes_exp_p1 1.3981999507E-3 +#define c_cephes_exp_p2 8.3334519073E-3 +#define c_cephes_exp_p3 4.1665795894E-2 +#define c_cephes_exp_p4 1.6666665459E-1 +#define c_cephes_exp_p5 5.0000001201E-1 + +/* exp() computed for 4 float at once */ +v4sf exp_ps(v4sf x) { + v4sf tmp, fx; + + v4sf one = vdupq_n_f32(1); + x = vminq_f32(x, vdupq_n_f32(c_exp_hi)); + x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo)); + + /* express exp(x) as exp(g + n*log(2)) */ + fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF)); + + /* perform a floorf */ + tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx)); + + /* if greater, substract 1 */ + v4su mask = vcgtq_f32(tmp, fx); + mask = vandq_u32(mask, vreinterpretq_u32_f32(one)); + + + fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask)); + + tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1)); + v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2)); + x = vsubq_f32(x, tmp); + x = vsubq_f32(x, z); + + static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 }; + v4sf y = vld1q_dup_f32(cephes_exp_p+0); + v4sf c1 = vld1q_dup_f32(cephes_exp_p+1); + v4sf c2 = vld1q_dup_f32(cephes_exp_p+2); + v4sf c3 = vld1q_dup_f32(cephes_exp_p+3); + v4sf c4 = vld1q_dup_f32(cephes_exp_p+4); + v4sf c5 = vld1q_dup_f32(cephes_exp_p+5); + + y = vmulq_f32(y, x); + z = vmulq_f32(x,x); + y = vaddq_f32(y, c1); + y = vmulq_f32(y, x); + y = vaddq_f32(y, c2); + y = vmulq_f32(y, x); + y = vaddq_f32(y, c3); + y = vmulq_f32(y, x); + y = vaddq_f32(y, c4); + y = vmulq_f32(y, x); + y = vaddq_f32(y, c5); + + y = vmulq_f32(y, z); + y = vaddq_f32(y, x); + y = vaddq_f32(y, one); + + /* build 2^n */ + int32x4_t mm; + mm = vcvtq_s32_f32(fx); + mm = vaddq_s32(mm, vdupq_n_s32(0x7f)); + mm = vshlq_n_s32(mm, 23); + v4sf pow2n = vreinterpretq_f32_s32(mm); + + y = vmulq_f32(y, pow2n); + return y; +} + +#define c_minus_cephes_DP1 -0.78515625 +#define c_minus_cephes_DP2 -2.4187564849853515625e-4 +#define c_minus_cephes_DP3 -3.77489497744594108e-8 +#define c_sincof_p0 -1.9515295891E-4 +#define c_sincof_p1 8.3321608736E-3 +#define c_sincof_p2 -1.6666654611E-1 +#define c_coscof_p0 2.443315711809948E-005 +#define c_coscof_p1 -1.388731625493765E-003 +#define c_coscof_p2 4.166664568298827E-002 +#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI + +/* evaluation of 4 sines & cosines at once. + + The code is the exact rewriting of the cephes sinf function. + Precision is excellent as long as x < 8192 (I did not bother to + take into account the special handling they have for greater values + -- it does not return garbage for arguments over 8192, though, but + the extra precision is missing). + + Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the + surprising but correct result. + + Note also that when you compute sin(x), cos(x) is available at + almost no extra price so both sin_ps and cos_ps make use of + sincos_ps.. + */ +void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x + v4sf xmm1, xmm2, xmm3, y; + + v4su emm2; + + v4su sign_mask_sin, sign_mask_cos; + sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0)); + x = vabsq_f32(x); + + /* scale by 4/Pi */ + y = vmulq_f32(x, vdupq_n_f32(c_cephes_FOPI)); + + /* store the integer part of y in mm0 */ + emm2 = vcvtq_u32_f32(y); + /* j=(j+1) & (~1) (see the cephes sources) */ + emm2 = vaddq_u32(emm2, vdupq_n_u32(1)); + emm2 = vandq_u32(emm2, vdupq_n_u32(~1)); + y = vcvtq_f32_u32(emm2); + + /* get the polynom selection mask + there is one polynom for 0 <= x <= Pi/4 + and another one for Pi/4 + +/* yes I know, the top of this file is quite ugly */ + +#ifdef _MSC_VER /* visual c++ */ +# define ALIGN16_BEG __declspec(align(16)) +# define ALIGN16_END +#else /* gcc or icc */ +# define ALIGN16_BEG +# define ALIGN16_END __attribute__((aligned(16))) +#endif + +/* __m128 is ugly to write */ +typedef __m128 v4sf; // vector of 4 float (sse1) + +#ifdef USE_SSE2 +# include +typedef __m128i v4si; // vector of 4 int (sse2) +#else +typedef __m64 v2si; // vector of 2 int (mmx) +#endif + +/* declare some SSE constants -- why can't I figure a better way to do that? */ +#define _PS_CONST(Name, Val) \ + static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val } +#define _PI32_CONST(Name, Val) \ + static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val } +#define _PS_CONST_TYPE(Name, Type, Val) \ + static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val } + +_PS_CONST(1 , 1.0f); +_PS_CONST(0p5, 0.5f); +/* the smallest non denormalized float number */ +_PS_CONST_TYPE(min_norm_pos, int, 0x00800000); +_PS_CONST_TYPE(mant_mask, int, 0x7f800000); +_PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000); + +_PS_CONST_TYPE(sign_mask, int, (int)0x80000000); +_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000); + +_PI32_CONST(1, 1); +_PI32_CONST(inv1, ~1); +_PI32_CONST(2, 2); +_PI32_CONST(4, 4); +_PI32_CONST(0x7f, 0x7f); + +_PS_CONST(cephes_SQRTHF, 0.707106781186547524); +_PS_CONST(cephes_log_p0, 7.0376836292E-2); +_PS_CONST(cephes_log_p1, - 1.1514610310E-1); +_PS_CONST(cephes_log_p2, 1.1676998740E-1); +_PS_CONST(cephes_log_p3, - 1.2420140846E-1); +_PS_CONST(cephes_log_p4, + 1.4249322787E-1); +_PS_CONST(cephes_log_p5, - 1.6668057665E-1); +_PS_CONST(cephes_log_p6, + 2.0000714765E-1); +_PS_CONST(cephes_log_p7, - 2.4999993993E-1); +_PS_CONST(cephes_log_p8, + 3.3333331174E-1); +_PS_CONST(cephes_log_q1, -2.12194440e-4); +_PS_CONST(cephes_log_q2, 0.693359375); + +#ifndef USE_SSE2 +typedef union xmm_mm_union { + __m128 xmm; + __m64 mm[2]; +} xmm_mm_union; + +#define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \ + xmm_mm_union u; u.xmm = xmm_; \ + mm0_ = u.mm[0]; \ + mm1_ = u.mm[1]; \ +} + +#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \ + xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \ + } + +#endif // USE_SSE2 + +/* natural logarithm computed for 4 simultaneous float + return NaN for x <= 0 +*/ +v4sf log_ps(v4sf x) { +#ifdef USE_SSE2 + v4si emm0; +#else + v2si mm0, mm1; +#endif + v4sf one = *(v4sf*)_ps_1; + + v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps()); + + x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */ + +#ifndef USE_SSE2 + /* part 1: x = frexpf(x, &e); */ + COPY_XMM_TO_MM(x, mm0, mm1); + mm0 = _mm_srli_pi32(mm0, 23); + mm1 = _mm_srli_pi32(mm1, 23); +#else + emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23); +#endif + /* keep only the fractional part */ + x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask); + x = _mm_or_ps(x, *(v4sf*)_ps_0p5); + +#ifndef USE_SSE2 + /* now e=mm0:mm1 contain the really base-2 exponent */ + mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f); + mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f); + v4sf e = _mm_cvtpi32x2_ps(mm0, mm1); + _mm_empty(); /* bye bye mmx */ +#else + emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f); + v4sf e = _mm_cvtepi32_ps(emm0); +#endif + + e = _mm_add_ps(e, one); + + /* part2: + if( x < SQRTHF ) { + e -= 1; + x = x + x - 1.0; + } else { x = x - 1.0; } + */ + v4sf mask = _mm_cmplt_ps(x, *(v4sf*)_ps_cephes_SQRTHF); + v4sf tmp = _mm_and_ps(x, mask); + x = _mm_sub_ps(x, one); + e = _mm_sub_ps(e, _mm_and_ps(one, mask)); + x = _mm_add_ps(x, tmp); + + + v4sf z = _mm_mul_ps(x,x); + + v4sf y = *(v4sf*)_ps_cephes_log_p0; + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p1); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p2); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p3); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p4); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p5); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p6); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p7); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p8); + y = _mm_mul_ps(y, x); + + y = _mm_mul_ps(y, z); + + + tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q1); + y = _mm_add_ps(y, tmp); + + + tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5); + y = _mm_sub_ps(y, tmp); + + tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q2); + x = _mm_add_ps(x, y); + x = _mm_add_ps(x, tmp); + x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN + return x; +} + +_PS_CONST(exp_hi, 88.3762626647949f); +_PS_CONST(exp_lo, -88.3762626647949f); + +_PS_CONST(cephes_LOG2EF, 1.44269504088896341); +_PS_CONST(cephes_exp_C1, 0.693359375); +_PS_CONST(cephes_exp_C2, -2.12194440e-4); + +_PS_CONST(cephes_exp_p0, 1.9875691500E-4); +_PS_CONST(cephes_exp_p1, 1.3981999507E-3); +_PS_CONST(cephes_exp_p2, 8.3334519073E-3); +_PS_CONST(cephes_exp_p3, 4.1665795894E-2); +_PS_CONST(cephes_exp_p4, 1.6666665459E-1); +_PS_CONST(cephes_exp_p5, 5.0000001201E-1); + +v4sf exp_ps(v4sf x) { + v4sf tmp = _mm_setzero_ps(), fx; +#ifdef USE_SSE2 + v4si emm0; +#else + v2si mm0, mm1; +#endif + v4sf one = *(v4sf*)_ps_1; + + x = _mm_min_ps(x, *(v4sf*)_ps_exp_hi); + x = _mm_max_ps(x, *(v4sf*)_ps_exp_lo); + + /* express exp(x) as exp(g + n*log(2)) */ + fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF); + fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5); + + /* how to perform a floorf with SSE: just below */ +#ifndef USE_SSE2 + /* step 1 : cast to int */ + tmp = _mm_movehl_ps(tmp, fx); + mm0 = _mm_cvttps_pi32(fx); + mm1 = _mm_cvttps_pi32(tmp); + /* step 2 : cast back to float */ + tmp = _mm_cvtpi32x2_ps(mm0, mm1); +#else + emm0 = _mm_cvttps_epi32(fx); + tmp = _mm_cvtepi32_ps(emm0); +#endif + /* if greater, substract 1 */ + v4sf mask = _mm_cmpgt_ps(tmp, fx); + mask = _mm_and_ps(mask, one); + fx = _mm_sub_ps(tmp, mask); + + tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1); + v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2); + x = _mm_sub_ps(x, tmp); + x = _mm_sub_ps(x, z); + + z = _mm_mul_ps(x,x); + + v4sf y = *(v4sf*)_ps_cephes_exp_p0; + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p1); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p2); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p3); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p4); + y = _mm_mul_ps(y, x); + y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p5); + y = _mm_mul_ps(y, z); + y = _mm_add_ps(y, x); + y = _mm_add_ps(y, one); + + /* build 2^n */ +#ifndef USE_SSE2 + z = _mm_movehl_ps(z, fx); + mm0 = _mm_cvttps_pi32(fx); + mm1 = _mm_cvttps_pi32(z); + mm0 = _mm_add_pi32(mm0, *(v2si*)_pi32_0x7f); + mm1 = _mm_add_pi32(mm1, *(v2si*)_pi32_0x7f); + mm0 = _mm_slli_pi32(mm0, 23); + mm1 = _mm_slli_pi32(mm1, 23); + + v4sf pow2n; + COPY_MM_TO_XMM(mm0, mm1, pow2n); + _mm_empty(); +#else + emm0 = _mm_cvttps_epi32(fx); + emm0 = _mm_add_epi32(emm0, *(v4si*)_pi32_0x7f); + emm0 = _mm_slli_epi32(emm0, 23); + v4sf pow2n = _mm_castsi128_ps(emm0); +#endif + y = _mm_mul_ps(y, pow2n); + return y; +} + +_PS_CONST(minus_cephes_DP1, -0.78515625); +_PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4); +_PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8); +_PS_CONST(sincof_p0, -1.9515295891E-4); +_PS_CONST(sincof_p1, 8.3321608736E-3); +_PS_CONST(sincof_p2, -1.6666654611E-1); +_PS_CONST(coscof_p0, 2.443315711809948E-005); +_PS_CONST(coscof_p1, -1.388731625493765E-003); +_PS_CONST(coscof_p2, 4.166664568298827E-002); +_PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI + + +/* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so + it runs also on old athlons XPs and the pentium III of your grand + mother. + + The code is the exact rewriting of the cephes sinf function. + Precision is excellent as long as x < 8192 (I did not bother to + take into account the special handling they have for greater values + -- it does not return garbage for arguments over 8192, though, but + the extra precision is missing). + + Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the + surprising but correct result. + + Performance is also surprisingly good, 1.33 times faster than the + macos vsinf SSE2 function, and 1.5 times faster than the + __vrs4_sinf of amd's ACML (which is only available in 64 bits). Not + too bad for an SSE1 function (with no special tuning) ! + However the latter libraries probably have a much better handling of NaN, + Inf, denormalized and other special arguments.. + + On my core 1 duo, the execution of this function takes approximately 95 cycles. + + From what I have observed on the experiments with Intel AMath lib, switching to an + SSE2 version would improve the perf by only 10%. + + Since it is based on SSE intrinsics, it has to be compiled at -O2 to + deliver full speed. +*/ +v4sf sin_ps(v4sf x) { // any x + v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y; + +#ifdef USE_SSE2 + v4si emm0, emm2; +#else + v2si mm0, mm1, mm2, mm3; +#endif + sign_bit = x; + /* take the absolute value */ + x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask); + /* extract the sign bit (upper one) */ + sign_bit = _mm_and_ps(sign_bit, *(v4sf*)_ps_sign_mask); + + /* scale by 4/Pi */ + y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI); + +#ifdef USE_SSE2 + /* store the integer part of y in mm0 */ + emm2 = _mm_cvttps_epi32(y); + /* j=(j+1) & (~1) (see the cephes sources) */ + emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1); + emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1); + y = _mm_cvtepi32_ps(emm2); + + /* get the swap sign flag */ + emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4); + emm0 = _mm_slli_epi32(emm0, 29); + /* get the polynom selection mask + there is one polynom for 0 <= x <= Pi/4 + and another one for Pi/4::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter) { - if (*iter > i) { - int j = *iter; - fvec4 deltaR; - fvec4 posJ((float) atomCoordinates[j][0], (float) atomCoordinates[j][1], (float) atomCoordinates[j][2], 0.0f); - float r2; - getDeltaR(posJ, posI, deltaR, r2, false, boxSize, invBoxSize); - float r = sqrtf(r2); - float inverseR = 1/r; - float chargeProd = ONE_4PI_EPS0*posq[4*i+3]*posq[4*j+3]; - float alphaR = alphaEwald*r; - float erfAlphaR = erf(alphaR); - if (erfAlphaR > 1e-6f) { - float dEdR = (float) (chargeProd * inverseR * inverseR * inverseR); - dEdR = (float) (dEdR * (erfAlphaR-TWO_OVER_SQRT_PI*alphaR*exp(-alphaR*alphaR))); - fvec4 result = deltaR*dEdR; - (fvec4(forces+4*i)-result).store(forces+4*i); - (fvec4(forces+4*j)+result).store(forces+4*j); - if (includeEnergy) - threadEnergy[threadIndex] -= chargeProd*inverseR*erfAlphaR; + threads.syncThreads(); + const int groupSize = max(1, numberOfAtoms/(10*numThreads)); + while (true) { + int start = gmx_atomic_fetch_add(reinterpret_cast(atomicCounter), groupSize); + if (start >= numberOfAtoms) + break; + int end = min(start+groupSize, numberOfAtoms); + for (int i = start; i < end; i++) { + fvec4 posI(posq[4*i], posq[4*i+1], posq[4*i+2], 0.0f); + float scaledChargeI = (float) (ONE_4PI_EPS0*posq[4*i+3]); + for (set::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter) { + if (*iter > i) { + int j = *iter; + fvec4 deltaR; + fvec4 posJ(posq[4*j], posq[4*j+1], posq[4*j+2], 0.0f); + float r2; + getDeltaR(posJ, posI, deltaR, r2, false, boxSize, invBoxSize); + float r = sqrtf(r2); + float alphaR = alphaEwald*r; + float erfAlphaR = erf(alphaR); + if (erfAlphaR > 1e-6f) { + float inverseR = 1/r; + float chargeProdOverR = scaledChargeI*posq[4*j+3]*inverseR; + float dEdR = chargeProdOverR*inverseR*inverseR; + dEdR = dEdR * (erfAlphaR-(float)TWO_OVER_SQRT_PI*alphaR*(float)exp(-alphaR*alphaR)); + fvec4 result = deltaR*dEdR; + (fvec4(forces+4*i)-result).store(forces+4*i); + (fvec4(forces+4*j)+result).store(forces+4*j); + if (includeEnergy) + threadEnergy[threadIndex] -= chargeProdOverR*erfAlphaR; + } } } } diff --git a/tests/TestVectorize.cpp b/tests/TestVectorize.cpp index 04fcd91b6..66cfc3c3e 100644 --- a/tests/TestVectorize.cpp +++ b/tests/TestVectorize.cpp @@ -149,6 +149,8 @@ void testMathFunctions() { ASSERT_VEC4_EQUAL(max(f1, f2), 1.1, 1.9, 1.3, -3.8); ASSERT_VEC4_EQUAL(sqrt(fvec4(1.5, 3.1, 4.0, 15.0)), sqrt(1.5), sqrt(3.1), sqrt(4.0), sqrt(15.0)); ASSERT_VEC4_EQUAL(rsqrt(fvec4(1.5, 3.1, 4.0, 15.0)), 1.0/sqrt(1.5), 1.0/sqrt(3.1), 1.0/sqrt(4.0), 1.0/sqrt(15.0)); + ASSERT_VEC4_EQUAL(exp(fvec4(-2.1, -0.5, 1.5, 3.1)), expf(-2.1), expf(-0.5), expf(1.5), expf(3.1)); + ASSERT_VEC4_EQUAL(log(fvec4(1.5, 3.1, 4.0, 15.0)), logf(1.5), logf(3.1), logf(4.0), logf(15.0)); ASSERT_EQUAL_TOL(f1[0]*f2[0]+f1[1]*f2[1]+f1[2]*f2[2], dot3(f1, f2), 1e-6); ASSERT_EQUAL_TOL(f1[0]*f2[0]+f1[1]*f2[1]+f1[2]*f2[2]+f1[3]*f2[3], dot4(f1, f2), 1e-6); ASSERT(any(f1 > 0.5)); -- GitLab From 0412e25d00f4560f2a666cb67e051f10541a3b9d Mon Sep 17 00:00:00 2001 From: Peter Eastman Date: Thu, 1 Oct 2015 11:27:06 -0700 Subject: [PATCH 47/49] Fixed compilation errors on Windows --- libraries/vecmath/include/neon_mathfun.h | 11 ++++++----- libraries/vecmath/include/sse_mathfun.h | 11 ++++++----- libraries/vecmath/src/vecmath.cpp | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libraries/vecmath/include/neon_mathfun.h b/libraries/vecmath/include/neon_mathfun.h index f51a61e17..2cffed939 100644 --- a/libraries/vecmath/include/neon_mathfun.h +++ b/libraries/vecmath/include/neon_mathfun.h @@ -26,6 +26,7 @@ */ #include +#include "openmm/internal/windowsExport.h" typedef float32x4_t v4sf; // vector of 4 float typedef uint32x4_t v4su; // vector of 4 uint32 @@ -48,7 +49,7 @@ typedef int32x4_t v4si; // vector of 4 uint32 /* natural logarithm computed for 4 simultaneous float return NaN for x <= 0 */ -v4sf log_ps(v4sf x) { +OPENMM_EXPORT v4sf log_ps(v4sf x) { v4sf one = vdupq_n_f32(1); x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */ @@ -133,7 +134,7 @@ v4sf log_ps(v4sf x) { #define c_cephes_exp_p5 5.0000001201E-1 /* exp() computed for 4 float at once */ -v4sf exp_ps(v4sf x) { +OPENMM_EXPORT v4sf exp_ps(v4sf x) { v4sf tmp, fx; v4sf one = vdupq_n_f32(1); @@ -219,7 +220,7 @@ v4sf exp_ps(v4sf x) { almost no extra price so both sin_ps and cos_ps make use of sincos_ps.. */ -void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x +OPENMM_EXPORT void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x v4sf xmm1, xmm2, xmm3, y; v4su emm2; @@ -286,13 +287,13 @@ void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x *ycos = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc)); } -v4sf sin_ps(v4sf x) { +OPENMM_EXPORT v4sf sin_ps(v4sf x) { v4sf ysin, ycos; sincos_ps(x, &ysin, &ycos); return ysin; } -v4sf cos_ps(v4sf x) { +OPENMM_EXPORT v4sf cos_ps(v4sf x) { v4sf ysin, ycos; sincos_ps(x, &ysin, &ycos); return ycos; diff --git a/libraries/vecmath/include/sse_mathfun.h b/libraries/vecmath/include/sse_mathfun.h index 2a7862ac9..708598604 100644 --- a/libraries/vecmath/include/sse_mathfun.h +++ b/libraries/vecmath/include/sse_mathfun.h @@ -30,6 +30,7 @@ */ #include +#include "openmm/internal/windowsExport.h" /* yes I know, the top of this file is quite ugly */ @@ -109,7 +110,7 @@ typedef union xmm_mm_union { /* natural logarithm computed for 4 simultaneous float return NaN for x <= 0 */ -v4sf log_ps(v4sf x) { +OPENMM_EXPORT v4sf log_ps(v4sf x) { #ifdef USE_SSE2 v4si emm0; #else @@ -211,7 +212,7 @@ _PS_CONST(cephes_exp_p3, 4.1665795894E-2); _PS_CONST(cephes_exp_p4, 1.6666665459E-1); _PS_CONST(cephes_exp_p5, 5.0000001201E-1); -v4sf exp_ps(v4sf x) { +OPENMM_EXPORT v4sf exp_ps(v4sf x) { v4sf tmp = _mm_setzero_ps(), fx; #ifdef USE_SSE2 v4si emm0; @@ -329,7 +330,7 @@ _PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI Since it is based on SSE intrinsics, it has to be compiled at -O2 to deliver full speed. */ -v4sf sin_ps(v4sf x) { // any x +OPENMM_EXPORT v4sf sin_ps(v4sf x) { // any x v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y; #ifdef USE_SSE2 @@ -446,7 +447,7 @@ v4sf sin_ps(v4sf x) { // any x } /* almost the same as sin_ps */ -v4sf cos_ps(v4sf x) { // any x +OPENMM_EXPORT v4sf cos_ps(v4sf x) { // any x v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, y; #ifdef USE_SSE2 v4si emm0, emm2; @@ -565,7 +566,7 @@ v4sf cos_ps(v4sf x) { // any x /* since sin_ps and cos_ps are almost identical, sincos_ps could replace both of them.. it is almost as fast, and gives you a free cosine with your sine */ -void sincos_ps(v4sf x, v4sf *s, v4sf *c) { +OPENMM_EXPORT void sincos_ps(v4sf x, v4sf *s, v4sf *c) { v4sf xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y; #ifdef USE_SSE2 v4si emm0, emm2, emm4; diff --git a/libraries/vecmath/src/vecmath.cpp b/libraries/vecmath/src/vecmath.cpp index 4e56f9dd6..cfb725e9a 100644 --- a/libraries/vecmath/src/vecmath.cpp +++ b/libraries/vecmath/src/vecmath.cpp @@ -2,6 +2,7 @@ #include "neon_mathfun.h" #else #if !defined(__PNACL__) + #define USE_SSE2 #include "sse_mathfun.h" #endif #endif -- GitLab From 7513142b29ca36bb453f81a4fdc18b691cfc08c7 Mon Sep 17 00:00:00 2001 From: peastman Date: Thu, 1 Oct 2015 12:06:49 -0700 Subject: [PATCH 48/49] Fixed a bug --- platforms/cpu/src/CpuNonbondedForce.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platforms/cpu/src/CpuNonbondedForce.cpp b/platforms/cpu/src/CpuNonbondedForce.cpp index 51d4a47fc..81be848e6 100644 --- a/platforms/cpu/src/CpuNonbondedForce.cpp +++ b/platforms/cpu/src/CpuNonbondedForce.cpp @@ -370,13 +370,13 @@ void CpuNonbondedForce::threadComputeDirect(ThreadPool& threads, int threadIndex break; int end = min(start+groupSize, numberOfAtoms); for (int i = start; i < end; i++) { - fvec4 posI(posq[4*i], posq[4*i+1], posq[4*i+2], 0.0f); + fvec4 posI((float) atomCoordinates[i][0], (float) atomCoordinates[i][1], (float) atomCoordinates[i][2], 0.0f); float scaledChargeI = (float) (ONE_4PI_EPS0*posq[4*i+3]); for (set::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter) { if (*iter > i) { int j = *iter; fvec4 deltaR; - fvec4 posJ(posq[4*j], posq[4*j+1], posq[4*j+2], 0.0f); + fvec4 posJ((float) atomCoordinates[j][0], (float) atomCoordinates[j][1], (float) atomCoordinates[j][2], 0.0f); float r2; getDeltaR(posJ, posI, deltaR, r2, false, boxSize, invBoxSize); float r = sqrtf(r2); -- GitLab From 28423ca1af945b14cc83349ca07b8c6f9ba48fe1 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Thu, 1 Oct 2015 15:11:23 -0400 Subject: [PATCH 49/49] Fix units of returned dipoles and quadrupoles from AmoebaMultipoleForce. Now that I have my head on straight, that is. --- wrappers/python/src/swig_doxygen/swigInputConfig.py | 4 ++-- wrappers/python/tests/TestAPIUnits.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/wrappers/python/src/swig_doxygen/swigInputConfig.py b/wrappers/python/src/swig_doxygen/swigInputConfig.py index 553dd6abb..db3481871 100755 --- a/wrappers/python/src/swig_doxygen/swigInputConfig.py +++ b/wrappers/python/src/swig_doxygen/swigInputConfig.py @@ -256,8 +256,8 @@ UNITS = { # void getCovalentMap(int index, CovalentType typeId, std::vector& covalentAtoms ) # void getCovalentMaps(int index, std::vector < std::vector >& covalentLists ) -("AmoebaMultipoleForce", "getMultipoleParameters") : ( None, ('unit.elementary_charge', 'unit.elementary_charge/unit.nanometer', - 'unit.elementary_charge/unit.nanometer**2', None, None, None, None, None, None, +("AmoebaMultipoleForce", "getMultipoleParameters") : ( None, ('unit.elementary_charge', 'unit.elementary_charge*unit.nanometer', + 'unit.elementary_charge*unit.nanometer**2', None, None, None, None, None, None, 'unit.nanometer**3')), ("AmoebaMultipoleForce", "getCovalentMap") : ( None, ()), ("AmoebaMultipoleForce", "getCovalentMaps") : ( None, ()), diff --git a/wrappers/python/tests/TestAPIUnits.py b/wrappers/python/tests/TestAPIUnits.py index f2903eee8..f07475286 100644 --- a/wrappers/python/tests/TestAPIUnits.py +++ b/wrappers/python/tests/TestAPIUnits.py @@ -1074,8 +1074,8 @@ class TestAPIUnits(unittest.TestCase): force.addMultipole(1.0, [0.5, 0, -0.5], list(range(9)), AmoebaMultipoleForce.ZThenX, 1, 2, 3, 0.5, 0.5, 1.0) - force.addMultipole(1.0*elementary_charge, [0.5, 0, -0.5]*elementary_charge/angstrom, - list(range(9))*elementary_charge/angstrom**2, + force.addMultipole(1.0*elementary_charge, [0.5, 0, -0.5]*elementary_charge*angstrom, + list(range(9))*elementary_charge*angstrom**2, AmoebaMultipoleForce.Bisector, 2, 3, 4, 0.5, 0.5, 1.0*angstrom**3) self.assertEqual(force.getNumMultipoles(), 2) @@ -1083,8 +1083,8 @@ class TestAPIUnits(unittest.TestCase): q, mu, quad, ax, i, j, k, thole, damp, polarity = force.getMultipoleParameters(0) self.assertEqual(q, 1.0*elementary_charge) - self.assertEqual(mu, (0.5, 0, -0.5)*elementary_charge/nanometer) - self.assertEqual(quad, tuple(range(9))*elementary_charge/nanometer**2) + self.assertEqual(mu, (0.5, 0, -0.5)*elementary_charge*nanometer) + self.assertEqual(quad, tuple(range(9))*elementary_charge*nanometer**2) self.assertEqual(ax, AmoebaMultipoleForce.ZThenX) self.assertEqual(i, 1) self.assertEqual(j, 2) @@ -1096,8 +1096,8 @@ class TestAPIUnits(unittest.TestCase): q, mu, quad, ax, i, j, k, thole, damp, polarity = force.getMultipoleParameters(1) self.assertEqual(q, 1.0*elementary_charge) - self.assertEqual(mu, (0.5, 0, -0.5)*elementary_charge/angstrom) - self.assertAlmostEqualUnitArray(quad, tuple(range(9))*elementary_charge/angstrom**2) + self.assertEqual(mu, (0.5, 0, -0.5)*elementary_charge*angstrom) + self.assertAlmostEqualUnitArray(quad, tuple(range(9))*elementary_charge*angstrom**2) self.assertEqual(ax, AmoebaMultipoleForce.Bisector) self.assertEqual(i, 2) self.assertEqual(j, 3) -- GitLab