diff --git a/CMakeLists.txt b/CMakeLists.txt index 5edc5d57febb4e05df0582ac89b5f70ffa2b21a2..9dc4a886113c798c994a84b16e2374516e991d46 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/libraries/sfmt/src/SFMT.cpp b/libraries/sfmt/src/SFMT.cpp index 13d2e0db25eedf77fef596b4c41a23201754f0e8..07c26b0c0e3eae47623d63d04dd3034d1170e951 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)); } diff --git a/platforms/cpu/tests/CpuTests.h b/platforms/cpu/tests/CpuTests.h new file mode 100644 index 0000000000000000000000000000000000000000..6bba1f57329794edfd56536842afd808f72423af --- /dev/null +++ b/platforms/cpu/tests/CpuTests.h @@ -0,0 +1,43 @@ +/* -------------------------------------------------------------------------- * + * 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" +#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 0000000000000000000000000000000000000000..8751111585599979bed13c45921e55efa77577b3 --- /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/TestCpuCustomGBForce.cpp b/platforms/cpu/tests/TestCpuCustomGBForce.cpp index 6bdaf72d7b93b64b2dd91d6756dc525421a13a66..8d3b307e34c9da6b28aebc88be233af4ae189e5e 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 03a6f803ce82480288ddbc47bbb55253050ad3d7..ae8f595bc9fec2771b83100c64ad6dad1ea0e597 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 fed1bc2b0becdd68760b2ce601ca184aed570823..0c82130e14d2cc7766d0055be810428f37d24afd 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/TestCpuEwald.cpp b/platforms/cpu/tests/TestCpuEwald.cpp index b18d1ee6c0b151a14471f0aa2b0ee44e94154dbf..30a1361c75d0ef42dc281ac9024a200071eeb754 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 972cfe003846e7d3cc68d64e1183d6679ce0309d..df121cef8540324eca9d0ed3704344e96d9d1bc9 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 7d740178beca41b268ff10e73d63c42221e8c8fe..c5b988f8f285b4fb3d1048c4307934f21a247853 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 65dc0dd65f8ea83cf9fb6b2c8cb73f6b0fb2769c..dce296d33af39082a6d9d552c1748a11da995f49 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/TestCpuPeriodicTorsionForce.cpp b/platforms/cpu/tests/TestCpuPeriodicTorsionForce.cpp index aa660f207769643e6d86d59365c43d3ff3edd55b..9e03ea01eef4fec43523006e5c4c8b48b1cdd6c4 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 c35ae7d02d325477ae36a6dd50a8e5dfbab46bdf..db3b5a37ed68d675d6c59c7482e9469b72ee84ed 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/cpu/tests/TestCpuSettle.cpp b/platforms/cpu/tests/TestCpuSettle.cpp index 9cf9a2b3dc5d7a941c4ddff5e333c0b6d27573d5..e5a9315c3e9563bb147fa513ba580921be2af4b7 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/CudaTests.h b/platforms/cuda/tests/CudaTests.h new file mode 100644 index 0000000000000000000000000000000000000000..db153ec628c772efb9d7a8abb348bf12a6644dfe --- /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])); +} diff --git a/platforms/cuda/tests/TestCudaAndersenThermostat.cpp b/platforms/cuda/tests/TestCudaAndersenThermostat.cpp index 7656136b4f1397aab283d75e784c7b861d848511..30e41d4804f33a6f80fc29b10cb92b9d3b58ac7e 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 cfb05f0e6cab36e9445c2ffd8107910bbc089c05..ed96d7d6ca84006a7fa79640018cb97fb6f1643b 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 6a95ade0fbcdd4cbf245b4810041b60661ce72ef..fb9598262ffce1d135270fcc4f113c9f38c5aaa9 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 d7140ef24754f74b524e3e990d0ade745cebdcbd..72a111c35a590c3c8f450c48065b60bc38a40471 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/TestCudaCheckpoints.cpp b/platforms/cuda/tests/TestCudaCheckpoints.cpp index ee72c6b726f79b9bbe1684ccf594bbdd105616ae..3ed747e6ee229e61cd691dac38dd0bfd6872e17b 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/TestCudaCustomAngleForce.cpp b/platforms/cuda/tests/TestCudaCustomAngleForce.cpp index 0e62d9e108e9ed78a50d542367d53717d5046a35..e832d1d18d81a8cc1bbf4b1648a03fc2f37bad1c 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 1d8c83434b81a65e8d77610389788cd56c0eb377..6fadcdca6e1ae905282e231d501e975665529fda 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 bd186d0dda3966e7dee8c74239275698798ce708..ac619558c12883155144e7b20e2fb2c7448cdd60 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 fdd61f61b9ae24adba48519174e6acd582c98064..2dad6e68cc5c8893f552e760431dfd6657f9961c 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 b024ab48d5c2201922a6ca8818667759319ea8db..b770bfcce4fd0c702160f878fc70a736aad7ca49 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 cac8c38ae05a90e986c657df933d602cef2c4300..5b5dcc3643ee4d9cfcb3560a3a850b065b9ccc0f 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/TestCudaCustomHbondForce.cpp b/platforms/cuda/tests/TestCudaCustomHbondForce.cpp index a4e9b769a643d0e17599f64bf44d9b6ef1a0ba85..ae50000504aca4ce78677d14e39e66d5ff70f8b8 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 ca7acd42375525d3157028b13413e1c50b3ceff4..369b9375b152f68ceb734ff7b678d62cd9371434 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 95c7a17ee224a51384219227d295a2141b50909b..76a657b00ed1ee65d4abd268c06869d8ff357532 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 2f11c14108c94f2a02a793b343212bd83cced487..57165f63b17935ec442be274bd3e509625225be6 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 b6f17d69b75dbd163fae0d80e728edb2776df526..3693a80df58be279f7b0e3d2a3f4e4a4004d337e 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/TestCudaEwald.cpp b/platforms/cuda/tests/TestCudaEwald.cpp index 6f8aca66f47f02247d55e118b8d6a297ee2ecc94..9efc4eaa4425ad16b2f4ccf98e03ac0531625190 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 87e01f19aae35de88932d2276247a4e61e987775..6efdd1a7e943ca1e318fccb47aece280b374d374 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/TestCudaHarmonicAngleForce.cpp b/platforms/cuda/tests/TestCudaHarmonicAngleForce.cpp index f16b49dc759f4d08b3d40439d8544936d1699607..45bbd94b43b9ef29314092a858f926191e7d1ddb 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 0ccd2db0c716c658a775ae0df0f91c36cebc1c7c..dc4c22957ed46eb3d60a44716a98f2addaa7875d 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/cuda/tests/TestCudaLangevinIntegrator.cpp b/platforms/cuda/tests/TestCudaLangevinIntegrator.cpp index 2b2e2e6e188ba1a99e38272efb45d74350cb563b..6e0eb66ac636a87b9817ecaa76afc9b0d2bda522 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 fc1108fa1d218637abf36af1c4c428ce9ec83ba2..1a99b37cb9ea2bbe9b3692b6417482023540d26c 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 8c25014814d63a9ba04ee827637f0c097593e98b..84a7f5711866756f20091d6a5707363b9b78a81e 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 08db822f13baa044a3bbdc63305437062322d631..836d0532ba4b56f1dd26fb2c973962a69c718065 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 602d51ed2b58a96a995b0e92ddea302b4534a3cb..989c2c38ec635bee9815b90af8e18dc13d26b439 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/TestCudaPeriodicTorsionForce.cpp b/platforms/cuda/tests/TestCudaPeriodicTorsionForce.cpp index 82349da6e8ece73c399d84ff6c14c889c6e42ba5..ef1acf85e590cf61ad11fd09b865175587f045a9 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 0db592c0848c9f6a84048a6fa85ad08366bc8398..aa0cfd5a3b15c7a5e8c9d0c8445b5cd11cfac50d 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: * * * @@ -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/cuda/tests/TestCudaSettle.cpp b/platforms/cuda/tests/TestCudaSettle.cpp index 925d0c039dbb9a8caddd618a12aa4934d2a299e9..878b8842777ef3c73404160824289d46a215cb40 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/TestCudaVariableLangevinIntegrator.cpp b/platforms/cuda/tests/TestCudaVariableLangevinIntegrator.cpp index 7abb555a514997ced76a9d0e04388b6d056860ff..349e6142fb6a253bb011ce47d4c57cf3ac787a8d 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 1be1b48619adfe9b36cfd4ac1936a9f9a9f56992..5385e26d7f421fd09f62af152e5281a7802a0c2b 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 811094587902b200b85c60970b67010417a7ebe7..30f8c5d3c6e12d0537cc16b308fd66216a33df63 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 be9149b8227ea819bb4a5bec765cba6e646cc0d0..bc70454e5c08d37c79e93526cdc88f98df776a72 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/cuda/tests/nacl_amorph.dat b/platforms/cuda/tests/nacl_amorph.dat deleted file mode 100644 index 7e8cbafdf6d6339aea85d8303ea91c547314f0ed..0000000000000000000000000000000000000000 --- 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/OpenCLTests.h b/platforms/opencl/tests/OpenCLTests.h new file mode 100644 index 0000000000000000000000000000000000000000..a76ea5aa8ef4e5745c368a227b2fdea4db32ff6e --- /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])); +} diff --git a/platforms/opencl/tests/TestOpenCLAndersenThermostat.cpp b/platforms/opencl/tests/TestOpenCLAndersenThermostat.cpp index aefa830980fc54794c94dc0486bf6cde586ec10c..33ba5dafe6d9d274d909fcc9307d938cbea9db16 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 75d6043cedc598747508d87df1dc739bc2549aef..adf6ca352c3e6a747cf79b2af587c0998306aca4 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 10deec8579b240f5a107868ec29a1cc0d253c2a7..d519c6c1a5874e697ddcf6a48aa2ab86e6dea2a6 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 c0aa145c57afa0e99b72e815c3b3dbaf5051a67f..d8d2a17574f8c1b511a8a02b1fbaec9156ad2d1c 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/TestOpenCLCheckpoints.cpp b/platforms/opencl/tests/TestOpenCLCheckpoints.cpp index a03a57d76757d0bef13957702b14225e8a0d3bb0..97c440afc24c9a12f627754c1f2bf4621e922d4f 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/TestOpenCLCustomAngleForce.cpp b/platforms/opencl/tests/TestOpenCLCustomAngleForce.cpp index 19a4befc9ef3bac2d7e657e0815886a1581e88e4..30757bc2ab51cb2e5304debd45dda9d432b486d2 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 357b674b87ae35aeb615ba4b454f1a38c271a1a0..8153c0ea6db148c1aa42b667873f8150041f5753 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 1bbd34443b93938c33bad07e0303fbd2d2e0b3e8..4b6615a22b42cd9e2a669a9ee807a21772c0a1aa 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 8e7d6fd82c563f001319436a0e5ee972d5033e04..5cc47af23dde37082b08a5f399c4646cd1e4f733 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 58dc7ffb4197d22ed6592e79af78501c35a16928..d544018d0658fa6a48d1671e55c232ecb8376ff0 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 d94e09351f5be05b78ebb5893f0dd93068f39e35..f5351d9fc225eb520f418fd118153b26bcfafaf2 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/TestOpenCLCustomHbondForce.cpp b/platforms/opencl/tests/TestOpenCLCustomHbondForce.cpp index a990d23942afdb125b139af004aedf61185854d6..380fdf2e93e9c4946dec03a2628da3f39569f55f 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 6db85d4e5be120b138dd58028abf448d91238e14..4d3381b85d6558e3324099fb9d13d0361c281c0c 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 29b35f38709bb1ad7ce52c86c59901e4f465141a..a94e8ed35d4b35f957697cb39428c989e4c3a7ea 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 652ddd7a9d7cfac1c444fd92786e22b326a18152..6782c2958e5df0942d90a19556f33eb94a65f197 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 63a64e15e8efb2ce76fc6c36c1be570930d50eac..7be950621546d2da36f0289b92e869349cdefa56 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/opencl/tests/TestOpenCLEwald.cpp b/platforms/opencl/tests/TestOpenCLEwald.cpp index f53b6f884be8f95019ac1d7a337480b75ded98c8..a9a05d9e668231d4eacbda61f869d77cdc43c02b 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 d406c4c583f7c4a871d5555c5eb898e76d31bf80..388c3ab4ac78513e53d7ab937ba3c6a57c6bec59 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/TestOpenCLHarmonicAngleForce.cpp b/platforms/opencl/tests/TestOpenCLHarmonicAngleForce.cpp index ca950a229fff9513736d205c14bcacc515bf3b39..d3bacd9084f6ed2c21ceafd5fe90000e381f27b3 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 94c50c4bce07dc0734a17e5d1795af869e38a37b..e2acdc512ef98cff7900a97ec38e3382ba6f2e41 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/opencl/tests/TestOpenCLLangevinIntegrator.cpp b/platforms/opencl/tests/TestOpenCLLangevinIntegrator.cpp index d423cd5d3ab36721a425ce1b0b227a0a389ae88a..ddbe4efeec65fa4745f03e4a32f5c6a04ddc2f21 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 7ec3458cf0b950dede30e857d5eb5f31a40ae36f..c7012c5220535e5f2f9b1d434cf8c1cb4d670dbd 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 93da2412addd8e9d53be61be1a5f331eeccc9f40..2fffb0b05f8cbf907027e295dc16567844168584 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 72053c5ecaa59e12f73ae192c804a6615479e22c..d8025599bfc90e9cc1432cc4563422e143c45014 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 16ea4cd0ab0c771a483754bb59cd5a3fbb033ea4..7ed2003dd9bb3fb115201f894cd2a0f07251c7ad 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/TestOpenCLPeriodicTorsionForce.cpp b/platforms/opencl/tests/TestOpenCLPeriodicTorsionForce.cpp index 5b60ce940822916b74c1ab6dd170e7f00d30ee37..8710f8d21c897e6ea3c0740b4451276755af74ab 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 e5da88f6a39aaa1c4c07e1e79cb032a7e3685242..3525af580e5a3e76c8ca0d01c023e567e52acaec 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/opencl/tests/TestOpenCLSettle.cpp b/platforms/opencl/tests/TestOpenCLSettle.cpp index 919d5647c165a3fa1150fd935abffa75c58825fa..93d89da27afaf65e5dceb7a04afcf514ea201d69 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/TestOpenCLVariableLangevinIntegrator.cpp b/platforms/opencl/tests/TestOpenCLVariableLangevinIntegrator.cpp index 613e4acf02107b230b21022cf2829d6469aca86d..dd424404faf6bdf7d02ff14a8c094ccd641756e3 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 523462e6a37a9f336e756ca17f29c4b97afeecfb..c8ca9155ec7c25c8dd4de6901fc23c22abf2ac7b 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 ae1a7f588e468fc95bdce6c61fdc3acbc1f63b3b..681b748422bcdce141697a91c486879b3f265375 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 09e690fe142c424ec1ead4bcc8f9cd6152ef5e0a..1cc5cdca5b6a683bce287a30eed85e676fc442f2 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/opencl/tests/nacl_amorph.dat b/platforms/opencl/tests/nacl_amorph.dat deleted file mode 100644 index 7e8cbafdf6d6339aea85d8303ea91c547314f0ed..0000000000000000000000000000000000000000 --- 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/ReferenceTests.h b/platforms/reference/tests/ReferenceTests.h new file mode 100644 index 0000000000000000000000000000000000000000..a76269e0f96bb848cc19c7a5df9c3300b761dfa7 --- /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[]) { +} diff --git a/platforms/reference/tests/TestReferenceAndersenThermostat.cpp b/platforms/reference/tests/TestReferenceAndersenThermostat.cpp index 5e61024ce6fd97aa938c4e94673b3bc3e7694c3d..39a79bb6e64b22f0f2989bf83721d8ce7f3dee0c 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 c50e9ffc22246ae76bfe44207bc371fe099206c2..71d19d0f4768e89812282a20ae1f721dcfa52a48 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 f0e7223658ea12ffe0db73e75c23063501bcf6cd..b84f408b4bc7b7b368322abec4a4ff8d4ecced17 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 7e8403277da5b16230aeb8f8f182f0d3b44a3fab..200223e8703c47be0579edd8e71e9749526cb973 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/TestReferenceCheckpoints.cpp b/platforms/reference/tests/TestReferenceCheckpoints.cpp index 4356494b286ef61413c00bb3614e98f18466af8b..b2c2d5a08ecf3a74599e1ce311a18297d9212084 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/TestReferenceCustomAngleForce.cpp b/platforms/reference/tests/TestReferenceCustomAngleForce.cpp index b892397e6408807e21cf99b08a34214ffa10656c..98eb5e2bb8128f0a1682488801a2a28fe34f4590 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 a50bc3e01981c9776269f873aaef3e6df1aa7952..b149d62351624f5fc31ba9a028e4b9bbfafd4a77 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 90e590292bccf0f6af557a041aa32de56883c7e4..ea7fb8d73a966404362ba90fbf4bd6ad3bbd4337 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 00c109c754cd1322be9856c1e7248b0a0dc1645b..d93d9b619d055fe189d2004cee8d536943dce594 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 38baea67549733aa49887852210f48ee49a0ebd2..ab5f703141d3120ef8f5dd807c3b468df6e4c8f8 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 1997566b3f3dff63a4311d9183453dc78c4ca885..2f4612c2033e04196a2e8743bc3d2f54631e1f42 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/TestReferenceCustomHbondForce.cpp b/platforms/reference/tests/TestReferenceCustomHbondForce.cpp index e0dd8c1dd01bd1a50aab2aff00ea080a6e7af66b..a477075e8375c18c0ec08329479dd02b19af87ef 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 01090cc3534d243e639b6e7ee4a3ea72f8d18fe6..d2e9c74324c17443ef0ee98b7b1d99989b5b586f 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 ec3f926a5cacb04ffa1d78d297f81b983c1b0dbf..92036f04901f6c196bf856b8dfe515f52df5240e 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 f922c3ffe53606f90afad9434306006a358b9f14..3ed4bfcd195810a812f5e11ad774658ed3a7ece0 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 b2dcb3e5bf96fd380ad4e1b1b78516e190b80f9f..20516986777bf4e2c3c2844e94f594b47db1fb7e 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/platforms/reference/tests/TestReferenceEwald.cpp b/platforms/reference/tests/TestReferenceEwald.cpp index a7ebc7518fb8d7996e27c1764817410ac4c90449..eb9e7a3ee9bf8e74bdb88280bcb776bc3cf7caab 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 c50c64f961c03a6942911ec79c6e69670ee7d614..d233ee3f0ec954809b0f5b29eb5339003bd19b85 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/TestReferenceHarmonicAngleForce.cpp b/platforms/reference/tests/TestReferenceHarmonicAngleForce.cpp index c8b70172560d63993f32b724406732050a5a47e9..cef07b8a033d4d63c2eff7024bde4a8b1e77524c 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 cccf3c4f3d4723838d33cd40a3afc2c5551f3132..6c51f37f37c837a2e62d3dd65e376a54938fd20a 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/platforms/reference/tests/TestReferenceLangevinIntegrator.cpp b/platforms/reference/tests/TestReferenceLangevinIntegrator.cpp index c2ccefe205a3cfcc97b9e1f9c0b85657cce90747..d1ae238b8e9a39f70eb00dc3ce06b3441f6af4c3 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 44e2da4131013df56f72fd4bad47fdd31226b25f..23df183f1b9ff8d139b5bf47b3e38e89a7465ceb 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 031b8c9f58fc853093d8a1cea9a61c1077ea64b3..977e30f3e3536be92b62e324de33f85e73eb36e2 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 65c513e96d960849bd47fdf164364200445fd451..1bd119dfc3eddf1acbf1ba327a32735eec90deae 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 2f3a52e57ee448ba2a201444f0846a27036c142f..20c51385ec9aba6f4796b0d0bf1a9101228a980b 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/TestReferencePeriodicTorsionForce.cpp b/platforms/reference/tests/TestReferencePeriodicTorsionForce.cpp index ba7580b6c459e24863d4b167f03e5e5b4d455f87..c872e849c30d46e7172e5379b031e587bcf58552 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 c7f80b6c9001db9abd79d83a1e1154f1d2d5c833..266f5a5c942d1100d48275caa5242d1015550262 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/platforms/reference/tests/TestReferenceSettle.cpp b/platforms/reference/tests/TestReferenceSettle.cpp index e63892bd96aefcdb6978edbb65f746c3ec02e8f0..658e14be695cc1db53d63ef042b40e31886bf340 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/TestReferenceVariableLangevinIntegrator.cpp b/platforms/reference/tests/TestReferenceVariableLangevinIntegrator.cpp index d6fa874fc939587c8e40530578a9190df016e0b1..e201686a23837d34a42ad631861e3a67d9b6a4df 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 1204004864836a284fc58263a5fdf895ef000a71..dc0abd34ce1bd853e7d871e97cd3eb711720e568 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 c3eb060e895b34ddc93264b2d5b7f28d6db05edf..48c1a11d8fe3386f130b1f166cf7b1c763136166 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 ff4afab9e5e0f2d86a8ff8423dc55260ad9697a4..57be3478dd350f91353b9c07ef9f8be931d9dd1c 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/platforms/reference/tests/nacl_amorph.dat b/platforms/reference/tests/nacl_amorph.dat deleted file mode 100644 index 7e8cbafdf6d6339aea85d8303ea91c547314f0ed..0000000000000000000000000000000000000000 --- 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 1a48685b334b37e434ea3ee890ee5c8905b94784..0000000000000000000000000000000000000000 --- 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 9eed185006576281d79f90a9a1b5141d2031edd9..0000000000000000000000000000000000000000 --- 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 c7b2067a4fac06ffe97013f783504495e982fef6..0000000000000000000000000000000000000000 --- 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 c6e2f5695b378ee6be7c389ab921af7c735b4377..0000000000000000000000000000000000000000 --- 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 34db43d003bc67813cf3e12fb0a6798dddee3383..0000000000000000000000000000000000000000 --- 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/TestAndersenThermostat.h b/tests/TestAndersenThermostat.h new file mode 100644 index 0000000000000000000000000000000000000000..7168144328799849dbb7d9dfb846d991fb3c3e78 --- /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 0000000000000000000000000000000000000000..2dd858bda9c8260bed81d2c8acac229acd19e836 --- /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 0000000000000000000000000000000000000000..54a2b90f66ce3254a8251686e3a0c3d10b561332 --- /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 0000000000000000000000000000000000000000..cc100181e16014fa927186e00c00e24b46a5bf9e --- /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/TestCheckpoints.h b/tests/TestCheckpoints.h new file mode 100644 index 0000000000000000000000000000000000000000..c5dbd08b5c72959e38679ab0b766ea568acc124e --- /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/TestCustomAngleForce.h b/tests/TestCustomAngleForce.h new file mode 100644 index 0000000000000000000000000000000000000000..5d79ad43373b11f3609a9ecc2246b26b950ac8b8 --- /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 0000000000000000000000000000000000000000..5b630c53254c2986c05b4cb68aa66e6867c3e201 --- /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 0000000000000000000000000000000000000000..a648d0e8bb0f95ff93ec96b3b2e141dafc3467a2 --- /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 0000000000000000000000000000000000000000..24d48ae5ad06ec6f0a972cbdb81bd879d483ff31 --- /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 0000000000000000000000000000000000000000..5575639ed0aa186a20b86127c5de966e50762a2b --- /dev/null +++ b/tests/TestCustomExternalForce.h @@ -0,0 +1,189 @@ +/* -------------------------------------------------------------------------- * + * 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 0000000000000000000000000000000000000000..6840119df78be36d4a8e48898a8fa5dffaa1bcf9 --- /dev/null +++ b/tests/TestCustomGBForce.h @@ -0,0 +1,495 @@ + +/* -------------------------------------------------------------------------- * + * 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); + 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())); + } + } +} + +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/TestCustomHbondForce.h b/tests/TestCustomHbondForce.h new file mode 100644 index 0000000000000000000000000000000000000000..344d0d2b5841131e6fe5450f717d0f80049a9334 --- /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 0000000000000000000000000000000000000000..1ca894d2e936c7dc88079a35346a18cbe5f6c885 --- /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 0000000000000000000000000000000000000000..5234b2b6523e8f4fc36e2ac2b854a4c1360ef503 --- /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 0000000000000000000000000000000000000000..66e43774b0610f8ca60afe6337a3946b60fb2bfa --- /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 0000000000000000000000000000000000000000..d98dab3ede863004f962d89553cd666c03f9522d --- /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; +} + + + diff --git a/tests/TestEwald.h b/tests/TestEwald.h new file mode 100644 index 0000000000000000000000000000000000000000..2ee8a425d4fc7566644344cff6fb6df9ee6e1ef7 --- /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 0000000000000000000000000000000000000000..ba5b323d745e4c79e92054eed0ddeea050e6af61 --- /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/TestHarmonicAngleForce.h b/tests/TestHarmonicAngleForce.h new file mode 100644 index 0000000000000000000000000000000000000000..e371d9b6c28fb418e273f9d72e2a3bc7b68a5df6 --- /dev/null +++ b/tests/TestHarmonicAngleForce.h @@ -0,0 +1,110 @@ +/* -------------------------------------------------------------------------- * + * 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. * + * -------------------------------------------------------------------------- */ + +#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 0000000000000000000000000000000000000000..c94214a2e32b75b55747105b2a2f10c9281a1bf1 --- /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; +} + diff --git a/tests/TestLangevinIntegrator.h b/tests/TestLangevinIntegrator.h new file mode 100644 index 0000000000000000000000000000000000000000..2f22f334c89a4615958d9f9b1b2590f1133d0a35 --- /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 0000000000000000000000000000000000000000..6f7899bb1917cead8bc3adffe0267765f9d60cc3 --- /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 0000000000000000000000000000000000000000..149ff63e928ca2bf247bc29f27e2dd7d4264cfe5 --- /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 0000000000000000000000000000000000000000..e02209ed7a543f514e9a0bae68885f294b7399a4 --- /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 0000000000000000000000000000000000000000..56031818426532e4afd558b19454ef37af07b991 --- /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/TestPeriodicTorsionForce.h b/tests/TestPeriodicTorsionForce.h new file mode 100644 index 0000000000000000000000000000000000000000..1e73cf41ffcf02121d600a93d8dba2f160a43477 --- /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 0000000000000000000000000000000000000000..eea5067ce14c8c5029712cb38eb2b17d322d4c36 --- /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; +} diff --git a/tests/TestSettle.h b/tests/TestSettle.h new file mode 100644 index 0000000000000000000000000000000000000000..3e1818ff15f1d163716b13efe9ec789778a96ae9 --- /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/tests/TestVariableLangevinIntegrator.h b/tests/TestVariableLangevinIntegrator.h new file mode 100644 index 0000000000000000000000000000000000000000..2cf8282cd146b8cfa950d535c69d9b7a40cee7a7 --- /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 0000000000000000000000000000000000000000..133be36e211cc2f27573a542607e780ff2e3ec6e --- /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 0000000000000000000000000000000000000000..8b1271009d9057cdf32b1833491bd77225b4b908 --- /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 0000000000000000000000000000000000000000..725ced5eec20f154cac6fb89e83e3cdefbfbba87 --- /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; +} 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