Commit 855ece90 authored by leeping's avatar leeping
Browse files

Merge branch 'master' of https://github.com/SimTk/openmm

parents 471bea82 a42c55ad
/* Portions copyright (c) 2006-2012 Stanford University and Simbios. /* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Pande Group * Contributors: Pande Group
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
...@@ -234,9 +234,8 @@ void ReferenceStochasticDynamics::update(const OpenMM::System& system, vector<Re ...@@ -234,9 +234,8 @@ void ReferenceStochasticDynamics::update(const OpenMM::System& system, vector<Re
updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime ); updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime );
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm(); ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if( referenceConstraintAlgorithm ){ if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply( numberOfAtoms, atomCoordinates, xPrime, inverseMasses ); referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
}
// copy xPrime -> atomCoordinates // copy xPrime -> atomCoordinates
......
/* Portions copyright (c) 2006-2012 Stanford University and Simbios. /* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Pande Group * Contributors: Pande Group
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
...@@ -278,10 +278,8 @@ void ReferenceVariableStochasticDynamics::update(const OpenMM::System& system, v ...@@ -278,10 +278,8 @@ void ReferenceVariableStochasticDynamics::update(const OpenMM::System& system, v
updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime ); updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime );
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm(); ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if( referenceConstraintAlgorithm ){ if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply( numberOfAtoms, atomCoordinates, xPrime, referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
inverseMasses );
}
// copy xPrime -> atomCoordinates // copy xPrime -> atomCoordinates
......
/* Portions copyright (c) 2006-2012 Stanford University and Simbios. /* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group * Contributors: Peter Eastman, Pande Group
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
...@@ -155,7 +155,7 @@ void ReferenceVariableVerletDynamics::update(const OpenMM::System& system, vecto ...@@ -155,7 +155,7 @@ void ReferenceVariableVerletDynamics::update(const OpenMM::System& system, vecto
} }
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm(); ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if (referenceConstraintAlgorithm) if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply(numberOfAtoms, atomCoordinates, xPrime, inverseMasses); referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
// Update the positions and velocities. // Update the positions and velocities.
......
/* Portions copyright (c) 2006-2012 Stanford University and Simbios. /* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group * Contributors: Peter Eastman, Pande Group
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
...@@ -130,8 +130,8 @@ void ReferenceVerletDynamics::update(const OpenMM::System& system, vector<RealVe ...@@ -130,8 +130,8 @@ void ReferenceVerletDynamics::update(const OpenMM::System& system, vector<RealVe
} }
} }
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm(); ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if( referenceConstraintAlgorithm ) if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply( numberOfAtoms, atomCoordinates, xPrime, inverseMasses ); referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
// Update the positions and velocities. // Update the positions and velocities.
......
...@@ -164,6 +164,38 @@ void testConstraints() { ...@@ -164,6 +164,38 @@ void testConstraints() {
} }
} }
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> 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() { void testRandomSeed() {
const int numParticles = 8; const int numParticles = 8;
const double temp = 100.0; const double temp = 100.0;
...@@ -228,6 +260,7 @@ int main() { ...@@ -228,6 +260,7 @@ int main() {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testConstrainedMasslessParticles();
testRandomSeed(); testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
......
...@@ -159,7 +159,7 @@ void testConstraints() { ...@@ -159,7 +159,7 @@ void testConstraints() {
* Test an integrator that applies constraints directly to velocities. * Test an integrator that applies constraints directly to velocities.
*/ */
void testVelocityConstraints() { void testVelocityConstraints() {
const int numParticles = 8; const int numParticles = 10;
ReferencePlatform platform; ReferencePlatform platform;
System system; System system;
CustomIntegrator integrator(0.002); CustomIntegrator integrator(0.002);
...@@ -176,7 +176,21 @@ void testVelocityConstraints() { ...@@ -176,7 +176,21 @@ void testVelocityConstraints() {
system.addParticle(i%2 == 0 ? 5.0 : 10.0); system.addParticle(i%2 == 0 ? 5.0 : 10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
} }
for (int i = 0; i < numParticles-1; ++i)
// 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.addConstraint(i, i+1, 1.0);
system.addForce(forceField); system.addForce(forceField);
Context context(system, integrator, platform); Context context(system, integrator, platform);
...@@ -196,6 +210,7 @@ void testVelocityConstraints() { ...@@ -196,6 +210,7 @@ void testVelocityConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
integrator.step(2);
State state = context.getState(State::Positions | State::Velocities | State::Energy); State state = context.getState(State::Positions | State::Velocities | State::Energy);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
...@@ -213,14 +228,51 @@ void testVelocityConstraints() { ...@@ -213,14 +228,51 @@ void testVelocityConstraints() {
} }
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = state.getKineticEnergy()+state.getPotentialEnergy();
if (i == 1) if (i == 0)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 0)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(2);
} }
} }
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> 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() * Test an integrator with an AndersenThermostat to see if updateContextState()
* is being handled correctly. * is being handled correctly.
...@@ -651,6 +703,7 @@ int main() { ...@@ -651,6 +703,7 @@ int main() {
testSingleBond(); testSingleBond();
testConstraints(); testConstraints();
testVelocityConstraints(); testVelocityConstraints();
testConstrainedMasslessParticles();
testWithThermostat(); testWithThermostat();
testMonteCarlo(); testMonteCarlo();
testSum(); testSum();
......
...@@ -171,6 +171,38 @@ void testConstraints() { ...@@ -171,6 +171,38 @@ void testConstraints() {
} }
} }
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> 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() { void testRandomSeed() {
const int numParticles = 8; const int numParticles = 8;
const double temp = 100.0; const double temp = 100.0;
...@@ -235,6 +267,7 @@ int main() { ...@@ -235,6 +267,7 @@ int main() {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testConstrainedMasslessParticles();
testRandomSeed(); testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
......
...@@ -86,7 +86,7 @@ void verifyNeighborList(NeighborList& list, int numParticles, vector<RealVec>& p ...@@ -86,7 +86,7 @@ void verifyNeighborList(NeighborList& list, int numParticles, vector<RealVec>& p
for (int j = i+1; j < numParticles; j++) for (int j = i+1; j < numParticles; j++)
if (distance2(positions[i], positions[j], periodicBoxSize) <= cutoff*cutoff) if (distance2(positions[i], positions[j], periodicBoxSize) <= cutoff*cutoff)
count++; count++;
ASSERT(count == list.size()); ASSERT_EQUAL(count, list.size());
} }
void testPeriodic() { void testPeriodic() {
...@@ -112,16 +112,15 @@ void testPeriodic() { ...@@ -112,16 +112,15 @@ void testPeriodic() {
int main() int main()
{ {
try { try {
testNeighborList(); testNeighborList();
testPeriodic(); testPeriodic();
}
cout << "Test Passed" << endl; catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0; return 0;
} }
catch (...) {
cerr << "*** ERROR: Test Failed ***" << endl;
return 1;
}
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of 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 <iostream>
#include <vector>
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;
ReferencePlatform 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<Vec3> positions(numParticles);
vector<Vec3> 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);
}
}
}
int main(int argc, char* argv[]) {
try {
testConstraints();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -173,6 +173,38 @@ void testConstraints() { ...@@ -173,6 +173,38 @@ void testConstraints() {
} }
} }
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> 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() { void testRandomSeed() {
const int numParticles = 8; const int numParticles = 8;
const double temp = 100.0; const double temp = 100.0;
...@@ -296,6 +328,7 @@ int main() { ...@@ -296,6 +328,7 @@ int main() {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testConstrainedMasslessParticles();
testRandomSeed(); testRandomSeed();
testArgonBox(); testArgonBox();
} }
......
...@@ -210,6 +210,38 @@ void testConstrainedClusters() { ...@@ -210,6 +210,38 @@ void testConstrainedClusters() {
ASSERT(context.getState(State::Positions).getTime() > 0.1); ASSERT(context.getState(State::Positions).getTime() > 0.1);
} }
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> 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 testArgonBox() { void testArgonBox() {
const int gridSize = 8; const int gridSize = 8;
const double mass = 40.0; // Ar atomic mass const double mass = 40.0; // Ar atomic mass
...@@ -272,6 +304,7 @@ int main() { ...@@ -272,6 +304,7 @@ int main() {
testSingleBond(); testSingleBond();
testConstraints(); testConstraints();
testConstrainedClusters(); testConstrainedClusters();
testConstrainedMasslessParticles();
testArgonBox(); testArgonBox();
} }
catch(const exception& e) { catch(const exception& e) {
......
...@@ -200,11 +200,44 @@ void testConstrainedClusters() { ...@@ -200,11 +200,44 @@ void testConstrainedClusters() {
} }
} }
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> 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() { int main() {
try { try {
testSingleBond(); testSingleBond();
testConstraints(); testConstraints();
testConstrainedClusters(); testConstrainedClusters();
testConstrainedMasslessParticles();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#endif #endif
#include "CpuPmeKernels.h" #include "CpuPmeKernels.h"
#include "SimTKOpenMMRealType.h" #include "SimTKOpenMMRealType.h"
#include "openmm/internal/hardware.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <smmintrin.h> #include <smmintrin.h>
...@@ -48,78 +49,6 @@ int CpuCalcPmeReciprocalForceKernel::numThreads = 0; ...@@ -48,78 +49,6 @@ int CpuCalcPmeReciprocalForceKernel::numThreads = 0;
#define EXTRACT_FLOAT(v, element) _mm_cvtss_f32(_mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, element))) #define EXTRACT_FLOAT(v, element) _mm_cvtss_f32(_mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, element)))
// Define function to get the number of processors.
#ifdef __APPLE__
#include <sys/sysctl.h>
#include <dlfcn.h>
#else
#ifdef WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <unistd.h>
#endif
#endif
static int getNumProcessors() {
#ifdef __APPLE__
int ncpu;
size_t len = 4;
if (sysctlbyname("hw.logicalcpu", &ncpu, &len, NULL, 0) == 0)
return ncpu;
else
return 1;
#else
#ifdef WIN32
SYSTEM_INFO siSysInfo;
int ncpu;
GetSystemInfo(&siSysInfo);
ncpu = siSysInfo.dwNumberOfProcessors;
if (ncpu < 1)
ncpu = 1;
return ncpu;
#else
long nProcessorsOnline = sysconf(_SC_NPROCESSORS_ONLN);
if (nProcessorsOnline == -1)
return 1;
else
return (int) nProcessorsOnline;
#endif
#endif
}
// Define a function to check the CPU's capabilities.
#ifdef _WIN32
#define cpuid __cpuid
#else
static void cpuid(int cpuInfo[4], int infoType){
#ifdef __LP64__
__asm__ __volatile__ (
"cpuid":
"=a" (cpuInfo[0]),
"=b" (cpuInfo[1]),
"=c" (cpuInfo[2]),
"=d" (cpuInfo[3]) :
"a" (infoType)
);
#else
__asm__ __volatile__ (
"pushl %%ebx\n"
"cpuid\n"
"movl %%ebx, %1\n"
"popl %%ebx\n" :
"=a" (cpuInfo[0]),
"=r" (cpuInfo[1]),
"=c" (cpuInfo[2]),
"=d" (cpuInfo[3]) :
"a" (infoType)
);
#endif
}
#endif
static void spreadCharge(int start, int end, float* posq, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3 periodicBoxSize) { static void spreadCharge(int start, int end, float* posq, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3 periodicBoxSize) {
float temp[4]; float temp[4];
__m128 boxSize = _mm_set_ps(0, (float) periodicBoxSize[2], (float) periodicBoxSize[1], (float) periodicBoxSize[0]); __m128 boxSize = _mm_set_ps(0, (float) periodicBoxSize[2], (float) periodicBoxSize[1], (float) periodicBoxSize[0]);
...@@ -164,6 +93,8 @@ static void spreadCharge(int start, int end, float* posq, float* grid, int gridx ...@@ -164,6 +93,8 @@ static void spreadCharge(int start, int end, float* posq, float* grid, int gridx
int gridIndexX = _mm_extract_epi32(gridIndex, 0); int gridIndexX = _mm_extract_epi32(gridIndex, 0);
int gridIndexY = _mm_extract_epi32(gridIndex, 1); int gridIndexY = _mm_extract_epi32(gridIndex, 1);
int gridIndexZ = _mm_extract_epi32(gridIndex, 2); int gridIndexZ = _mm_extract_epi32(gridIndex, 2);
if (gridIndexX < 0)
return; // This happens when a simulation blows up and coordinates become NaN.
int zindex[PME_ORDER]; int zindex[PME_ORDER];
for (int j = 0; j < PME_ORDER; j++) { for (int j = 0; j < PME_ORDER; j++) {
zindex[j] = gridIndexZ+j; zindex[j] = gridIndexZ+j;
...@@ -359,6 +290,8 @@ static void interpolateForces(int start, int end, float* posq, float* force, flo ...@@ -359,6 +290,8 @@ static void interpolateForces(int start, int end, float* posq, float* force, flo
int gridIndexX = _mm_extract_epi32(gridIndex, 0); int gridIndexX = _mm_extract_epi32(gridIndex, 0);
int gridIndexY = _mm_extract_epi32(gridIndex, 1); int gridIndexY = _mm_extract_epi32(gridIndex, 1);
int gridIndexZ = _mm_extract_epi32(gridIndex, 2); int gridIndexZ = _mm_extract_epi32(gridIndex, 2);
if (gridIndexX < 0)
return; // This happens when a simulation blows up and coordinates become NaN.
int zindex[PME_ORDER]; int zindex[PME_ORDER];
for (int j = 0; j < PME_ORDER; j++) { for (int j = 0; j < PME_ORDER; j++) {
zindex[j] = gridIndexZ+j; zindex[j] = gridIndexZ+j;
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "SimTKOpenMMUtilities.h" #include "SimTKOpenMMUtilities.h"
#include "ReferenceCCMAAlgorithm.h" #include "ReferenceConstraints.h"
#include "ReferenceVirtualSites.h" #include "ReferenceVirtualSites.h"
#include <set> #include <set>
...@@ -56,20 +56,6 @@ static vector<RealVec>& extractForces(ContextImpl& context) { ...@@ -56,20 +56,6 @@ static vector<RealVec>& extractForces(ContextImpl& context) {
return *((vector<RealVec>*) data->forces); return *((vector<RealVec>*) data->forces);
} }
static void findAnglesForCCMA(const System& system, vector<ReferenceCCMAAlgorithm::AngleInfo>& angles) {
for (int i = 0; i < system.getNumForces(); i++) {
const HarmonicAngleForce* force = dynamic_cast<const HarmonicAngleForce*>(&system.getForce(i));
if (force != NULL) {
for (int j = 0; j < force->getNumAngles(); j++) {
int atom1, atom2, atom3;
double angle, k;
force->getAngleParameters(j, atom1, atom2, atom3, angle, k);
angles.push_back(ReferenceCCMAAlgorithm::AngleInfo(atom1, atom2, atom3, (RealOpenMM)angle));
}
}
}
}
static double computeShiftedKineticEnergy(ContextImpl& context, vector<double>& inverseMasses, double timeShift, ReferenceConstraintAlgorithm* constraints) { static double computeShiftedKineticEnergy(ContextImpl& context, vector<double>& inverseMasses, double timeShift, ReferenceConstraintAlgorithm* constraints) {
const System& system = context.getSystem(); const System& system = context.getSystem();
int numParticles = system.getNumParticles(); int numParticles = system.getNumParticles();
...@@ -91,7 +77,7 @@ static double computeShiftedKineticEnergy(ContextImpl& context, vector<double>& ...@@ -91,7 +77,7 @@ static double computeShiftedKineticEnergy(ContextImpl& context, vector<double>&
if (constraints != NULL) { if (constraints != NULL) {
constraints->setTolerance(1e-4); constraints->setTolerance(1e-4);
constraints->applyToVelocities(numParticles, posData, shiftedVel, inverseMasses); constraints->applyToVelocities(posData, shiftedVel, inverseMasses);
} }
// Compute the kinetic energy. // Compute the kinetic energy.
...@@ -271,21 +257,19 @@ void ReferenceIntegrateDrudeLangevinStepKernel::initialize(const System& system, ...@@ -271,21 +257,19 @@ void ReferenceIntegrateDrudeLangevinStepKernel::initialize(const System& system,
// Prepare constraints. // Prepare constraints.
int numConstraints = system.getNumConstraints(); if (system.getNumConstraints() > 0) {
if (numConstraints > 0) { vector<pair<int, int> > constraintIndices;
vector<pair<int, int> > constraintIndices(numConstraints); vector<RealOpenMM> constraintDistances;
vector<RealOpenMM> constraintDistances(numConstraints); for (int i = 0; i < system.getNumConstraints(); ++i) {
for (int i = 0; i < numConstraints; ++i) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
system.getConstraintParameters(i, particle1, particle2, distance); system.getConstraintParameters(i, particle1, particle2, distance);
constraintIndices[i].first = particle1; if (system.getParticleMass(particle1) != 0 || system.getParticleMass(particle2) != 0) {
constraintIndices[i].second = particle2; constraintIndices.push_back(make_pair(particle1, particle2));
constraintDistances[i] = static_cast<RealOpenMM>(distance); constraintDistances.push_back(distance);
}
} }
vector<ReferenceCCMAAlgorithm::AngleInfo> angles; constraints = new ReferenceConstraints(system, (RealOpenMM) integrator.getConstraintTolerance());
findAnglesForCCMA(system, angles);
constraints = new ReferenceCCMAAlgorithm(system.getNumParticles(), numConstraints, constraintIndices, constraintDistances, particleMass, angles, (RealOpenMM)integrator.getConstraintTolerance());
} }
} }
...@@ -347,7 +331,7 @@ void ReferenceIntegrateDrudeLangevinStepKernel::execute(ContextImpl& context, co ...@@ -347,7 +331,7 @@ void ReferenceIntegrateDrudeLangevinStepKernel::execute(ContextImpl& context, co
// Apply constraints. // Apply constraints.
if (constraints != NULL) if (constraints != NULL)
constraints->apply(numParticles, pos, xPrime, particleInvMass); constraints->apply(pos, xPrime, particleInvMass);
// Record the constrained positions and velocities. // Record the constrained positions and velocities.
...@@ -395,21 +379,19 @@ void ReferenceIntegrateDrudeSCFStepKernel::initialize(const System& system, cons ...@@ -395,21 +379,19 @@ void ReferenceIntegrateDrudeSCFStepKernel::initialize(const System& system, cons
// Prepare constraints. // Prepare constraints.
int numConstraints = system.getNumConstraints(); if (system.getNumConstraints() > 0) {
if (numConstraints > 0) { vector<pair<int, int> > constraintIndices;
vector<pair<int, int> > constraintIndices(numConstraints); vector<RealOpenMM> constraintDistances;
vector<RealOpenMM> constraintDistances(numConstraints); for (int i = 0; i < system.getNumConstraints(); ++i) {
for (int i = 0; i < numConstraints; ++i) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
system.getConstraintParameters(i, particle1, particle2, distance); system.getConstraintParameters(i, particle1, particle2, distance);
constraintIndices[i].first = particle1; if (system.getParticleMass(particle1) != 0 || system.getParticleMass(particle2) != 0) {
constraintIndices[i].second = particle2; constraintIndices.push_back(make_pair(particle1, particle2));
constraintDistances[i] = static_cast<RealOpenMM>(distance); constraintDistances.push_back(distance);
}
} }
vector<ReferenceCCMAAlgorithm::AngleInfo> angles; constraints = new ReferenceConstraints(system, (RealOpenMM) integrator.getConstraintTolerance());
findAnglesForCCMA(system, angles);
constraints = new ReferenceCCMAAlgorithm(system.getNumParticles(), numConstraints, constraintIndices, constraintDistances, particleMass, angles, (RealOpenMM)integrator.getConstraintTolerance());
} }
// Initialize the energy minimizer. // Initialize the energy minimizer.
...@@ -443,7 +425,7 @@ void ReferenceIntegrateDrudeSCFStepKernel::execute(ContextImpl& context, const D ...@@ -443,7 +425,7 @@ void ReferenceIntegrateDrudeSCFStepKernel::execute(ContextImpl& context, const D
// Apply constraints. // Apply constraints.
if (constraints != NULL) if (constraints != NULL)
constraints->apply(numParticles, pos, xPrime, particleInvMass); constraints->apply(pos, xPrime, particleInvMass);
// Record the constrained positions and velocities. // Record the constrained positions and velocities.
......
...@@ -47,6 +47,9 @@ namespace OpenMM { ...@@ -47,6 +47,9 @@ namespace OpenMM {
* springs to form a ring. This allows certain quantum mechanical effects to be efficiently * springs to form a ring. This allows certain quantum mechanical effects to be efficiently
* simulated. * simulated.
* *
* By default this Integrator applies a PILE thermostat to the system to simulate constant
* temperature dynamics. You can disable the thermostat by calling setApplyThermostat(false).
*
* Because this Integrator simulates many copies of the System at once, it must be used * Because this Integrator simulates many copies of the System at once, it must be used
* differently from other Integrators. Instead of setting positions and velocities by * differently from other Integrators. Instead of setting positions and velocities by
* calling methods of the Context, you should use the corresponding methods of the Integrator * calling methods of the Context, you should use the corresponding methods of the Integrator
...@@ -127,6 +130,18 @@ public: ...@@ -127,6 +130,18 @@ public:
void setFriction(double coeff) { void setFriction(double coeff) {
friction = coeff; friction = coeff;
} }
/**
* Get whether a thermostat is applied to the system.
*/
bool getApplyThermostat() const {
return applyThermostat;
}
/**
* Set whether a thermostat is applied to the system.
*/
void setApplyThermostat(bool apply) {
applyThermostat = apply;
}
/** /**
* Get the random number seed. See setRandomNumberSeed() for details. * Get the random number seed. See setRandomNumberSeed() for details.
*/ */
...@@ -213,6 +228,7 @@ protected: ...@@ -213,6 +228,7 @@ protected:
private: private:
double temperature, friction; double temperature, friction;
int numCopies, randomNumberSeed; int numCopies, randomNumberSeed;
bool applyThermostat;
std::map<int, int> contractions; std::map<int, int> contractions;
bool forcesAreValid, hasSetPosition, hasSetVelocity, isFirstStep; bool forcesAreValid, hasSetPosition, hasSetVelocity, isFirstStep;
Kernel kernel; Kernel kernel;
......
...@@ -42,7 +42,7 @@ using namespace OpenMM; ...@@ -42,7 +42,7 @@ using namespace OpenMM;
using namespace std; using namespace std;
RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictionCoeff, double stepSize, const map<int, int>& contractions) : RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictionCoeff, double stepSize, const map<int, int>& contractions) :
numCopies(numCopies), contractions(contractions), forcesAreValid(false), hasSetPosition(false), hasSetVelocity(false), isFirstStep(true) { numCopies(numCopies), applyThermostat(true), contractions(contractions), forcesAreValid(false), hasSetPosition(false), hasSetVelocity(false), isFirstStep(true) {
setTemperature(temperature); setTemperature(temperature);
setFriction(frictionCoeff); setFriction(frictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
...@@ -51,7 +51,7 @@ RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictio ...@@ -51,7 +51,7 @@ RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictio
} }
RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictionCoeff, double stepSize) : RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictionCoeff, double stepSize) :
numCopies(numCopies), forcesAreValid(false), hasSetPosition(false), hasSetVelocity(false), isFirstStep(true) { numCopies(numCopies), applyThermostat(true), forcesAreValid(false), hasSetPosition(false), hasSetVelocity(false), isFirstStep(true) {
setTemperature(temperature); setTemperature(temperature);
setFriction(frictionCoeff); setFriction(frictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
......
...@@ -205,7 +205,8 @@ void CudaIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDIntegr ...@@ -205,7 +205,8 @@ void CudaIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDIntegr
void* frictionPtr = (useDoublePrecision ? (void*) &friction : (void*) &frictionFloat); void* frictionPtr = (useDoublePrecision ? (void*) &friction : (void*) &frictionFloat);
int randomIndex = integration.prepareRandomNumbers(numParticles*numCopies); int randomIndex = integration.prepareRandomNumbers(numParticles*numCopies);
void* pileArgs[] = {&velocities->getDevicePointer(), &integration.getRandom().getDevicePointer(), &randomIndex, dtPtr, kTPtr, frictionPtr}; void* pileArgs[] = {&velocities->getDevicePointer(), &integration.getRandom().getDevicePointer(), &randomIndex, dtPtr, kTPtr, frictionPtr};
cu.executeKernel(pileKernel, pileArgs, numParticles*numCopies, workgroupSize); if (integrator.getApplyThermostat())
cu.executeKernel(pileKernel, pileArgs, numParticles*numCopies, workgroupSize);
// Update positions and velocities. // Update positions and velocities.
...@@ -223,8 +224,10 @@ void CudaIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDIntegr ...@@ -223,8 +224,10 @@ void CudaIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDIntegr
// Apply the PILE-L thermostat again. // Apply the PILE-L thermostat again.
randomIndex = integration.prepareRandomNumbers(numParticles*numCopies); if (integrator.getApplyThermostat()) {
cu.executeKernel(pileKernel, pileArgs, numParticles*numCopies, workgroupSize); randomIndex = integration.prepareRandomNumbers(numParticles*numCopies);
cu.executeKernel(pileKernel, pileArgs, numParticles*numCopies, workgroupSize);
}
// Update the time and step count. // Update the time and step count.
......
...@@ -431,6 +431,71 @@ void testContractions() { ...@@ -431,6 +431,71 @@ void testContractions() {
ASSERT_USUALLY_EQUAL_TOL(expectedKE, meanKE, 1e-2); ASSERT_USUALLY_EQUAL_TOL(expectedKE, meanKE, 1e-2);
} }
void testWithoutThermostat() {
const int numParticles = 20;
const int numCopies = 10;
const double temperature = 300.0;
const double mass = 2.0;
// Create a chain of particles.
System system;
HarmonicBondForce* bonds = new HarmonicBondForce();
system.addForce(bonds);
for (int i = 0; i < numParticles; i++) {
system.addParticle(mass);
if (i > 0)
bonds->addBond(i-1, i, 1.0, 1000.0);
}
RPMDIntegrator integ(numCopies, temperature, 1.0, 0.001);
integ.setApplyThermostat(false);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<vector<Vec3> > positions(numCopies);
for (int i = 0; i < numCopies; i++) {
positions[i].resize(numParticles);
for (int j = 0; j < numParticles; j++)
positions[i][j] = Vec3(0.95*j, 0.01*genrand_real2(sfmt), 0.01*genrand_real2(sfmt));
integ.setPositions(i, positions[i]);
}
// Simulate it and see if the energy remains constant.
double initialEnergy;
int numSteps = 100;
const double hbar = 1.054571628e-34*AVOGADRO/(1000*1e-12);
const double wn = numCopies*BOLTZ*temperature/hbar;
const double springConstant = mass*wn*wn;
for (int i = 0; i < numSteps; i++) {
integ.step(1);
// Sum the energies of all the copies.
double energy = 0.0;
for (int j = 0; j < numCopies; j++) {
State state = integ.getState(j, State::Positions | State::Energy);
positions[j] = state.getPositions();
energy += state.getPotentialEnergy()+state.getKineticEnergy();
}
// Add the energy from the springs connecting copies.
for (int j = 0; j < numCopies; j++) {
int previous = (j == 0 ? numCopies-1 : j-1);
for (int k = 0; k < numParticles; k++) {
Vec3 delta = positions[j][k]-positions[previous][k];
energy += 0.5*springConstant*delta.dot(delta);
}
}
if (i == 0)
initialEnergy = energy;
else
ASSERT_EQUAL_TOL(initialEnergy, energy, 1e-4);
}
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
registerRPMDCudaKernelFactories(); registerRPMDCudaKernelFactories();
...@@ -441,6 +506,7 @@ int main(int argc, char* argv[]) { ...@@ -441,6 +506,7 @@ int main(int argc, char* argv[]) {
testCMMotionRemoval(); testCMMotionRemoval();
testVirtualSites(); testVirtualSites();
testContractions(); testContractions();
testWithoutThermostat();
} }
catch(const std::exception& e) { catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl; std::cout << "exception: " << e.what() << std::endl;
......
...@@ -223,7 +223,8 @@ void OpenCLIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDInte ...@@ -223,7 +223,8 @@ void OpenCLIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDInte
stepKernel.setArg<cl_float>(4, (cl_float) (integrator.getTemperature()*BOLTZ)); stepKernel.setArg<cl_float>(4, (cl_float) (integrator.getTemperature()*BOLTZ));
velocitiesKernel.setArg<cl_float>(2, (cl_float) dt); velocitiesKernel.setArg<cl_float>(2, (cl_float) dt);
} }
cl.executeKernel(pileKernel, numParticles*numCopies, workgroupSize); if (integrator.getApplyThermostat())
cl.executeKernel(pileKernel, numParticles*numCopies, workgroupSize);
// Update positions and velocities. // Update positions and velocities.
...@@ -238,8 +239,10 @@ void OpenCLIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDInte ...@@ -238,8 +239,10 @@ void OpenCLIntegrateRPMDStepKernel::execute(ContextImpl& context, const RPMDInte
// Apply the PILE-L thermostat again. // Apply the PILE-L thermostat again.
pileKernel.setArg<cl_uint>(2, integration.prepareRandomNumbers(numParticles*numCopies)); if (integrator.getApplyThermostat()) {
cl.executeKernel(pileKernel, numParticles*numCopies, workgroupSize); pileKernel.setArg<cl_uint>(2, integration.prepareRandomNumbers(numParticles*numCopies));
cl.executeKernel(pileKernel, numParticles*numCopies, workgroupSize);
}
// Update the time and step count. // Update the time and step count.
......
...@@ -432,6 +432,71 @@ void testContractions() { ...@@ -432,6 +432,71 @@ void testContractions() {
ASSERT_USUALLY_EQUAL_TOL(expectedKE, meanKE, 1e-2); ASSERT_USUALLY_EQUAL_TOL(expectedKE, meanKE, 1e-2);
} }
void testWithoutThermostat() {
const int numParticles = 20;
const int numCopies = 10;
const double temperature = 300.0;
const double mass = 2.0;
// Create a chain of particles.
System system;
HarmonicBondForce* bonds = new HarmonicBondForce();
system.addForce(bonds);
for (int i = 0; i < numParticles; i++) {
system.addParticle(mass);
if (i > 0)
bonds->addBond(i-1, i, 1.0, 1000.0);
}
RPMDIntegrator integ(numCopies, temperature, 1.0, 0.001);
integ.setApplyThermostat(false);
Platform& platform = Platform::getPlatformByName("OpenCL");
Context context(system, integ, platform);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<vector<Vec3> > positions(numCopies);
for (int i = 0; i < numCopies; i++) {
positions[i].resize(numParticles);
for (int j = 0; j < numParticles; j++)
positions[i][j] = Vec3(0.95*j, 0.01*genrand_real2(sfmt), 0.01*genrand_real2(sfmt));
integ.setPositions(i, positions[i]);
}
// Simulate it and see if the energy remains constant.
double initialEnergy;
int numSteps = 100;
const double hbar = 1.054571628e-34*AVOGADRO/(1000*1e-12);
const double wn = numCopies*BOLTZ*temperature/hbar;
const double springConstant = mass*wn*wn;
for (int i = 0; i < numSteps; i++) {
integ.step(1);
// Sum the energies of all the copies.
double energy = 0.0;
for (int j = 0; j < numCopies; j++) {
State state = integ.getState(j, State::Positions | State::Energy);
positions[j] = state.getPositions();
energy += state.getPotentialEnergy()+state.getKineticEnergy();
}
// Add the energy from the springs connecting copies.
for (int j = 0; j < numCopies; j++) {
int previous = (j == 0 ? numCopies-1 : j-1);
for (int k = 0; k < numParticles; k++) {
Vec3 delta = positions[j][k]-positions[previous][k];
energy += 0.5*springConstant*delta.dot(delta);
}
}
if (i == 0)
initialEnergy = energy;
else
ASSERT_EQUAL_TOL(initialEnergy, energy, 1e-4);
}
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
registerRPMDOpenCLKernelFactories(); registerRPMDOpenCLKernelFactories();
...@@ -442,6 +507,7 @@ int main(int argc, char* argv[]) { ...@@ -442,6 +507,7 @@ int main(int argc, char* argv[]) {
testCMMotionRemoval(); testCMMotionRemoval();
testVirtualSites(); testVirtualSites();
testContractions(); testContractions();
testWithoutThermostat();
} }
catch(const std::exception& e) { catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl; std::cout << "exception: " << e.what() << std::endl;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment