Unverified Commit 5f374e1d authored by Andy Simmonett's avatar Andy Simmonett Committed by GitHub
Browse files

Nosé Hoover Middle scheme (#2600)

* Convert Nose-Hoover into LF middle scheme by copying NH kernels

* Rebrand VelocityVerletIntegrator as NoseHooverIntegrator

* Consolidate NH tests

* NoseHooverChainKernel begone

* Make Windows builds happy

* Add missing header for Windows build

* Fix mistake in CommonKernels header

* Add 6th Yoshida-Suzuki and make it the default
parent 7ff86be6
...@@ -66,8 +66,7 @@ ReferencePlatform::ReferencePlatform() { ...@@ -66,8 +66,7 @@ ReferencePlatform::ReferencePlatform() {
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory); registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory); registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(IntegrateVerletStepKernel::Name(), factory); registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
registerKernelFactory(IntegrateVelocityVerletStepKernel::Name(), factory); registerKernelFactory(IntegrateNoseHooverStepKernel::Name(), factory);
registerKernelFactory(NoseHooverChainKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory); registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory); registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory);
registerKernelFactory(IntegrateBrownianStepKernel::Name(), factory); registerKernelFactory(IntegrateBrownianStepKernel::Name(), factory);
......
...@@ -68,27 +68,27 @@ double ReferenceNoseHooverChain::propagate(double kineticEnergy, vector<double>& ...@@ -68,27 +68,27 @@ double ReferenceNoseHooverChain::propagate(double kineticEnergy, vector<double>&
for (int mts = 0; mts < numMTS; ++mts) { for (int mts = 0; mts < numMTS; ++mts) {
for (const auto &ys : YSWeights) { for (const auto &ys : YSWeights) {
double wdt = ys * timeStep / numMTS; double wdt = ys * timeStep / numMTS;
chainVelocities.back() += 0.25 * wdt * chainForces.back(); chainVelocities.back() += 0.5 * wdt * chainForces.back();
for (int bead = chainLength - 2; bead >= 0; --bead) { for (int bead = chainLength - 2; bead >= 0; --bead) {
double aa = exp(-0.125 * wdt * chainVelocities[bead + 1]); double aa = exp(-0.25 * wdt * chainVelocities[bead + 1]);
chainVelocities[bead] = aa * (chainVelocities[bead] * aa + 0.25 * wdt * chainForces[bead]); chainVelocities[bead] = aa * (chainVelocities[bead] * aa + 0.5 * wdt * chainForces[bead]);
} }
// update particle velocities // update particle velocities
double aa = exp(-0.5 * wdt * chainVelocities[0]); double aa = exp(-wdt * chainVelocities[0]);
scale *= aa; scale *= aa;
// update the thermostat positions // update the thermostat positions
for (int bead = 0; bead < chainLength; ++bead) { for (int bead = 0; bead < chainLength; ++bead) {
chainPositions[bead] += 0.5 * chainVelocities[bead] * wdt; chainPositions[bead] += chainVelocities[bead] * wdt;
} }
// update the forces // update the forces
chainForces[0] = (scale * scale * KE2 - numDOFs * kT) / chainMasses[0]; chainForces[0] = (scale * scale * KE2 - numDOFs * kT) / chainMasses[0];
// update thermostat velocities // update thermostat velocities
for (int bead = 0; bead < chainLength - 1; ++bead) { for (int bead = 0; bead < chainLength - 1; ++bead) {
double aa = exp(-0.125 * wdt * chainVelocities[bead + 1]); double aa = exp(-0.25 * wdt * chainVelocities[bead + 1]);
chainVelocities[bead] = aa * (aa * chainVelocities[bead] + 0.25 * wdt * chainForces[bead]); chainVelocities[bead] = aa * (aa * chainVelocities[bead] + 0.5 * wdt * chainForces[bead]);
chainForces[bead + 1] = (chainMasses[bead] * chainVelocities[bead] * chainVelocities[bead] - kT) / chainMasses[bead + 1]; chainForces[bead + 1] = (chainMasses[bead] * chainVelocities[bead] * chainVelocities[bead] - kT) / chainMasses[bead + 1];
} }
chainVelocities[chainLength-1] += 0.25 * wdt * chainForces.back(); chainVelocities[chainLength-1] += 0.5 * wdt * chainForces.back();
} // YS loop } // YS loop
} // MTS loop } // MTS loop
return scale; return scale;
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "SimTKOpenMMUtilities.h" #include "SimTKOpenMMUtilities.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "ReferenceVelocityVerletDynamics.h" #include "ReferenceNoseHooverDynamics.h"
#include "ReferenceVirtualSites.h" #include "ReferenceVirtualSites.h"
#include <cstdio> #include <cstdio>
...@@ -39,7 +39,7 @@ using namespace OpenMM; ...@@ -39,7 +39,7 @@ using namespace OpenMM;
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
ReferenceVelocityVerletDynamics constructor ReferenceNoseHooverDynamics constructor
@param numberOfAtoms number of atoms @param numberOfAtoms number of atoms
@param deltaT delta t for dynamics @param deltaT delta t for dynamics
...@@ -48,19 +48,21 @@ using namespace OpenMM; ...@@ -48,19 +48,21 @@ using namespace OpenMM;
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
ReferenceVelocityVerletDynamics::ReferenceVelocityVerletDynamics(int numberOfAtoms, double deltaT) : ReferenceNoseHooverDynamics::ReferenceNoseHooverDynamics(int numberOfAtomsIn, double deltaT) :
ReferenceDynamics(numberOfAtoms, deltaT, 0.0) { ReferenceDynamics(numberOfAtomsIn, deltaT, 0.0) {
numberOfAtoms = numberOfAtomsIn;
xPrime.resize(numberOfAtoms); xPrime.resize(numberOfAtoms);
inverseMasses.resize(numberOfAtoms); inverseMasses.resize(numberOfAtoms);
oldx.resize(numberOfAtoms);
} }
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
ReferenceVelocityVerletDynamics destructor ReferenceNoseHooverDynamics destructor
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
ReferenceVelocityVerletDynamics::~ReferenceVelocityVerletDynamics() { ReferenceNoseHooverDynamics::~ReferenceNoseHooverDynamics() {
} }
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -79,7 +81,7 @@ ReferenceVelocityVerletDynamics::~ReferenceVelocityVerletDynamics() { ...@@ -79,7 +81,7 @@ ReferenceVelocityVerletDynamics::~ReferenceVelocityVerletDynamics() {
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const OpenMM::System& system, vector<Vec3>& atomCoordinates, void ReferenceNoseHooverDynamics::BAstep(OpenMM::ContextImpl &context, const OpenMM::System& system, vector<Vec3>& atomCoordinates,
vector<Vec3>& velocities, vector<Vec3>& velocities,
vector<Vec3>& forces, vector<double>& masses, double tolerance, bool &forcesAreValid, vector<Vec3>& forces, vector<double>& masses, double tolerance, bool &forcesAreValid,
const std::vector<int> & atomList, const std::vector<std::tuple<int, int, double>> &pairList, const std::vector<int> & atomList, const std::vector<std::tuple<int, int, double>> &pairList,
...@@ -88,10 +90,8 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const ...@@ -88,10 +90,8 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const
// first-time-through initialization // first-time-through initialization
if (!forcesAreValid) context.calcForcesAndEnergy(true, false); if (!forcesAreValid) context.calcForcesAndEnergy(true, false);
int numberOfAtoms = system.getNumParticles();
if (getTimeStep() == 0) { if (getTimeStep() == 0) {
// invert masses // invert masses
for (int ii = 0; ii < numberOfAtoms; ii++) { for (int ii = 0; ii < numberOfAtoms; ii++) {
if (masses[ii] == 0.0) if (masses[ii] == 0.0)
inverseMasses[ii] = 0.0; inverseMasses[ii] = 0.0;
...@@ -100,22 +100,20 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const ...@@ -100,22 +100,20 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const
} }
} }
//// Perform the integration.
const double halfdt = 0.5*getDeltaT();
// Regular atoms // Regular atoms
for (const auto &atom : atomList) { for (const auto &atom : atomList) {
if (masses[atom] != 0.0) { if (masses[atom] != 0.0) {
velocities[atom] += 0.5 * inverseMasses[atom]*forces[atom]*getDeltaT(); velocities[atom] += inverseMasses[atom]*forces[atom]*getDeltaT();
xPrime[atom] = atomCoordinates[atom];
atomCoordinates[atom] += velocities[atom]*getDeltaT();
} }
} }
// Connected particles // Connected particles
for (const auto &pair : pairList) { for (const auto &pair : pairList) {
const auto &atom1 = std::get<0>(pair); const auto &atom1 = std::get<0>(pair);
const auto &atom2 = std::get<1>(pair); const auto &atom2 = std::get<1>(pair);
double m1 = system.getParticleMass(atom1); double m1 = masses[atom1];
double m2 = system.getParticleMass(atom2); double m2 = masses[atom2];
double mass1fract = m1 / (m1 + m2); double mass1fract = m1 / (m1 + m2);
double mass2fract = m2 / (m1 + m2); double mass2fract = m2 / (m1 + m2);
double invRedMass = (m1 * m2 != 0.0) ? (m1 + m2)/(m1 * m2) : 0.0; double invRedMass = (m1 * m2 != 0.0) ? (m1 + m2)/(m1 * m2) : 0.0;
...@@ -124,26 +122,52 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const ...@@ -124,26 +122,52 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const
Vec3 relVel = velocities[atom2] - velocities[atom1]; Vec3 relVel = velocities[atom2] - velocities[atom1];
Vec3 comForce = forces[atom1] + forces[atom2]; Vec3 comForce = forces[atom1] + forces[atom2];
Vec3 relForce = mass1fract*forces[atom2] - mass2fract*forces[atom1]; Vec3 relForce = mass1fract*forces[atom2] - mass2fract*forces[atom1];
comVel += 0.5 * comForce * getDeltaT() * invTotMass; comVel += comForce * getDeltaT() * invTotMass;
relVel += 0.5 * relForce * getDeltaT() * invRedMass; relVel += relForce * getDeltaT() * invRedMass;
if (m1 != 0.0) { if (m1 != 0.0) {
velocities[atom1] = comVel - relVel*mass2fract; velocities[atom1] = comVel - relVel*mass2fract;
xPrime[atom1] = atomCoordinates[atom1];
atomCoordinates[atom1] += velocities[atom1]*getDeltaT();
} }
if (m2 != 0.0) { if (m2 != 0.0) {
velocities[atom2] = comVel + relVel*mass1fract; velocities[atom2] = comVel + relVel*mass1fract;
xPrime[atom2] = atomCoordinates[atom2];
atomCoordinates[atom2] += velocities[atom2]*getDeltaT();
} }
} }
// ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if (referenceConstraintAlgorithm) {
referenceConstraintAlgorithm->applyToVelocities(atomCoordinates, velocities, inverseMasses, tolerance);
}
for (int atom = 0; atom < numberOfAtoms; ++atom) {
if (masses[atom] != 0.0) {
xPrime[atom] = atomCoordinates[atom] + velocities[atom]*halfdt;
}
}
}
void ReferenceNoseHooverDynamics::ABstep(OpenMM::ContextImpl &context, const OpenMM::System& system, vector<Vec3>& atomCoordinates,
vector<Vec3>& velocities,
vector<Vec3>& forces, vector<double>& masses, double tolerance, bool &forcesAreValid,
const std::vector<int> & atomList, const std::vector<std::tuple<int, int, double>> &pairList,
double maxPairDistance) {
const double halfdt = 0.5*getDeltaT();
for (int atom = 0; atom < numberOfAtoms; ++atom) {
if (masses[atom] != 0.0) {
xPrime[atom] += velocities[atom]*halfdt;
oldx[atom] = xPrime[atom];
}
}
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm(); ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if (referenceConstraintAlgorithm) if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply(xPrime, atomCoordinates, inverseMasses, tolerance); referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses, tolerance);
for (int i = 0; i < numberOfAtoms; i++) {
if (inverseMasses[i] != 0.0) {
velocities[i] += (xPrime[i]-oldx[i])/getDeltaT();
atomCoordinates[i] = xPrime[i];
}
}
// Apply hard wall constraints. // Apply hard wall constraints.
if (maxPairDistance > 0) { if (maxPairDistance > 0) {
...@@ -157,9 +181,6 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const ...@@ -157,9 +181,6 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const
if (rInv*maxPairDistance < 1.0) { if (rInv*maxPairDistance < 1.0) {
// The constraint has been violated, so make the inter-particle distance "bounce" // The constraint has been violated, so make the inter-particle distance "bounce"
// off the hard wall. // off the hard wall.
//if (rInv*maxPairDistance < 0.5)
// throw OpenMMException("Drude particle moved too far beyond hard wall constraint");
// TODO: Review this - I commented it out to make the NoseHooverThermostat test work
Vec3 bondDir = delta*rInv; Vec3 bondDir = delta*rInv;
Vec3 vel1 = velocities[atom1]; Vec3 vel1 = velocities[atom1];
Vec3 vel2 = velocities[atom2]; Vec3 vel2 = velocities[atom2];
...@@ -213,50 +234,7 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const ...@@ -213,50 +234,7 @@ void ReferenceVelocityVerletDynamics::update(OpenMM::ContextImpl &context, const
} }
} /* end of hard wall constraint part */ } /* end of hard wall constraint part */
ReferenceVirtualSites::computePositions(context.getSystem(), atomCoordinates);
ReferenceVirtualSites::computePositions(system, atomCoordinates);
context.calcForcesAndEnergy(true, false);
forcesAreValid = true;
for (int i = 0; i < numberOfAtoms; ++i) {
if (masses[i] != 0.0)
for (int j = 0; j < 3; ++j) {
xPrime[i][j] += velocities[i][j]*getDeltaT();
}
}
// Update the positions and velocities.
// Regular atoms
for (const auto &atom : atomList) {
if (masses[atom] != 0.0) {
velocities[atom] += 0.5 * inverseMasses[atom]*forces[atom]*getDeltaT() + (atomCoordinates[atom] - xPrime[atom])/getDeltaT();
}
}
// Connected particles
for (const auto &pair : pairList) {
const auto &atom1 = std::get<0>(pair);
const auto &atom2 = std::get<1>(pair);
double m1 = system.getParticleMass(atom1);
double m2 = system.getParticleMass(atom2);
double mass1fract = m1 / (m1 + m2);
double mass2fract = m2 / (m1 + m2);
double invRedMass = (m1 * m2 != 0.0) ? (m1 + m2)/(m1 * m2) : 0.0;
double invTotMass = (m1 + m2 != 0.0) ? 1.0 /(m1 + m2) : 0.0;
Vec3 comVel = velocities[atom1]*mass1fract + velocities[atom2]*mass2fract;
Vec3 relVel = velocities[atom2] - velocities[atom1];
Vec3 comForce = forces[atom1] + forces[atom2];
Vec3 relForce = mass1fract*forces[atom2] - mass2fract*forces[atom1];
comVel += 0.5 * comForce * getDeltaT() * invTotMass;
relVel += 0.5 * relForce * getDeltaT() * invRedMass;
if (m1 != 0.0) {
velocities[atom1] = comVel - relVel*mass2fract + (atomCoordinates[atom1] - xPrime[atom1])/getDeltaT();
}
if (m2 != 0.0) {
velocities[atom2] = comVel + relVel*mass1fract + (atomCoordinates[atom2] - xPrime[atom2])/getDeltaT();
}
}
if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->applyToVelocities(atomCoordinates, velocities, inverseMasses, tolerance);
incrementTimeStep(); incrementTimeStep();
} }
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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 "ReferenceTests.h"
#include "TestNoseHooverThermostat.h"
void runPlatformTests() {
}
...@@ -66,7 +66,7 @@ public: ...@@ -66,7 +66,7 @@ public:
*/ */
DrudeNoseHooverIntegrator(double temperature, double collisionFrequency, DrudeNoseHooverIntegrator(double temperature, double collisionFrequency,
double drudeTemperature, double drudeCollisionFrequency, double stepSize, double drudeTemperature, double drudeCollisionFrequency, double stepSize,
int chainLength = 3, int numMTS = 3, int numYoshidaSuzuki = 3); int chainLength = 3, int numMTS = 3, int numYoshidaSuzuki = 7);
virtual ~DrudeNoseHooverIntegrator(); virtual ~DrudeNoseHooverIntegrator();
/** /**
......
...@@ -82,10 +82,8 @@ void DrudeNoseHooverIntegrator::initialize(ContextImpl& contextRef) { ...@@ -82,10 +82,8 @@ void DrudeNoseHooverIntegrator::initialize(ContextImpl& contextRef) {
context = &contextRef; context = &contextRef;
owner = &contextRef.getOwner(); owner = &contextRef.getOwner();
vvKernel = context->getPlatform().createKernel(IntegrateVelocityVerletStepKernel::Name(), contextRef); kernel = context->getPlatform().createKernel(IntegrateNoseHooverStepKernel::Name(), contextRef);
vvKernel.getAs<IntegrateVelocityVerletStepKernel>().initialize(contextRef.getSystem(), *this); kernel.getAs<IntegrateNoseHooverStepKernel>().initialize(contextRef.getSystem(), *this);
nhcKernel = context->getPlatform().createKernel(NoseHooverChainKernel::Name(), contextRef);
nhcKernel.getAs<NoseHooverChainKernel>().initialize();
forcesAreValid = false; forcesAreValid = false;
// check for drude particles and build the Nose-Hoover Chains // check for drude particles and build the Nose-Hoover Chains
...@@ -138,14 +136,14 @@ double DrudeNoseHooverIntegrator::computeDrudeKineticEnergy() { ...@@ -138,14 +136,14 @@ double DrudeNoseHooverIntegrator::computeDrudeKineticEnergy() {
double kE = 0.0; double kE = 0.0;
for (const auto &nhc: noseHooverChains){ for (const auto &nhc: noseHooverChains){
if (nhc.getThermostatedPairs().size() != 0) { if (nhc.getThermostatedPairs().size() != 0) {
kE += nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc, true).second; kE += kernel.getAs<IntegrateNoseHooverStepKernel>().computeMaskedKineticEnergy(*context, nhc, true).second;
} }
} }
return kE; return kE;
} }
double DrudeNoseHooverIntegrator::computeTotalKineticEnergy() { double DrudeNoseHooverIntegrator::computeTotalKineticEnergy() {
return vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this); return kernel.getAs<IntegrateNoseHooverStepKernel>().computeKineticEnergy(*context, *this);
} }
std::vector<Vec3> DrudeNoseHooverIntegrator::getVelocitiesForTemperature(const System &system, double temperature, std::vector<Vec3> DrudeNoseHooverIntegrator::getVelocitiesForTemperature(const System &system, double temperature,
......
...@@ -141,6 +141,15 @@ void testWaterBox() { ...@@ -141,6 +141,15 @@ void testWaterBox() {
// Equilibrate // Equilibrate
integ.step(1500); integ.step(1500);
double TOL = 1.5;
try {
if (platform.getPropertyValue(context, "Precision") != "double") {
TOL = 2.0;
}
} catch(OpenMMException) {
// The defaults above are for double precision, which is assumed in this case
}
// Compute the internal and center of mass temperatures. // Compute the internal and center of mass temperatures.
double totalKE = 0; double totalKE = 0;
const int numSteps = 500; const int numSteps = 500;
...@@ -162,7 +171,7 @@ void testWaterBox() { ...@@ -162,7 +171,7 @@ void testWaterBox() {
double conserved = PE + fullKE + heatBathEnergy; double conserved = PE + fullKE + heatBathEnergy;
meanConserved = (i*meanConserved + conserved)/(i+1); meanConserved = (i*meanConserved + conserved)/(i+1);
totalKE += KE; totalKE += KE;
ASSERT(fabs(meanConserved - conserved) < 0.3); ASSERT(fabs(meanConserved - conserved) < TOL);
} }
totalKE /= numSteps; totalKE /= numSteps;
ASSERT_USUALLY_EQUAL_TOL(temperature, meanTemp, 0.03); ASSERT_USUALLY_EQUAL_TOL(temperature, meanTemp, 0.03);
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "SimTKOpenMMRealType.h" #include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h" #include "sfmt/SFMT.h"
#include <iostream> #include <iostream>
#include <algorithm>
#include <numeric>
#include <vector> #include <vector>
using namespace OpenMM; using namespace OpenMM;
...@@ -47,7 +49,7 @@ using namespace std; ...@@ -47,7 +49,7 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
void testVVSingleBond() { void testSingleBond() {
System system; System system;
system.addParticle(2.0); system.addParticle(2.0);
system.addParticle(2.0); system.addParticle(2.0);
...@@ -82,11 +84,11 @@ void testVVSingleBond() { ...@@ -82,11 +84,11 @@ void testVVSingleBond() {
ASSERT_EQUAL_TOL(10.0, context.getState(0).getTime(), 1e-5); ASSERT_EQUAL_TOL(10.0, context.getState(0).getTime(), 1e-5);
} }
void testVVConstraints() { void testConstraints() {
const int numParticles = 8; const int numParticles = 8;
const int numConstraints = 5; const int numConstraints = 5;
System system; System system;
NoseHooverIntegrator integrator(0.001); NoseHooverIntegrator integrator(0.0005);
integrator.setConstraintTolerance(1e-5); integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce(); NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) { for (int i = 0; i < numParticles; ++i) {
...@@ -135,10 +137,10 @@ void testVVConstraints() { ...@@ -135,10 +137,10 @@ void testVVConstraints() {
} }
} }
void testVVConstrainedClusters() { void testConstrainedClusters() {
const int numParticles = 7; const int numParticles = 7;
System system; System system;
NoseHooverIntegrator integrator(0.001); NoseHooverIntegrator integrator(0.0005);
integrator.setConstraintTolerance(1e-5); integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce(); NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) { for (int i = 0; i < numParticles; ++i) {
...@@ -197,7 +199,7 @@ void testVVConstrainedClusters() { ...@@ -197,7 +199,7 @@ void testVVConstrainedClusters() {
} }
} }
void testVVConstrainedMasslessParticles() { void testConstrainedMasslessParticles() {
System system; System system;
system.addParticle(0.0); system.addParticle(0.0);
system.addParticle(1.0); system.addParticle(1.0);
...@@ -297,17 +299,235 @@ void testInitialTemperature() { ...@@ -297,17 +299,235 @@ void testInitialTemperature() {
ASSERT_USUALLY_EQUAL_TOL(targetTemperature, temperature, 0.01); ASSERT_USUALLY_EQUAL_TOL(targetTemperature, temperature, 0.01);
} }
void testHarmonicOscillator() {
const double mass = 1.0;
double temperature = 300;
double frequency = 1;
double mts = 1, ys = 1, chain_length = 3;
System system;
system.addParticle(mass);
vector<Vec3> positions(1);
positions[0] = Vec3(0.5,0.5,0.5);
vector<Vec3> velocities(1);
velocities[0] = Vec3(0, 0, 0);
auto harmonic_restraint = new CustomExternalForce("0.5*(x^2+y^2+z^2)");
harmonic_restraint->addParticle(0);
system.addForce(harmonic_restraint);
NoseHooverIntegrator integrator(0.001);
integrator.addThermostat(temperature, frequency, chain_length, mts, ys);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
double mean_temperature=0;
// equilibration
integrator.step(2000);
for (size_t i=0; i < 2500; i++){
integrator.step(10);
State state = context.getState(State::Energy | State::Positions | State::Velocities);
double kinetic_energy = state.getKineticEnergy();
double temp = kinetic_energy/(0.5*3*BOLTZ);
mean_temperature = (i*mean_temperature + temp)/(i+1);
double PE = state.getPotentialEnergy();
double time = state.getTime();
double energy = kinetic_energy + PE + integrator.computeHeatBathEnergy();
}
ASSERT_EQUAL_TOL(temperature, mean_temperature, 0.02);
}
int makeDimerBox(System& system, std::vector<Vec3>& positions, bool constrain=true, int numMolecules=20, double bondLength=0.1){
double boxLength = 2; // nm
Vec3 a(boxLength, 0.0, 0.0);
Vec3 b(0.0, boxLength, 0.0);
Vec3 c(0.0, 0.0, boxLength);
double mass = 20;
double bondForceConstant = 30000; //0.001;
int numDOF = 0;
NonbondedForce* forceField = new NonbondedForce();
HarmonicBondForce* bondForce = new HarmonicBondForce();
for(int molecule = 0; molecule < numMolecules; ++molecule) {
int particle1 = system.addParticle(mass);
int particle2 = system.addParticle(mass);
forceField->addParticle(0.0, 0.1, 1.0);
forceField->addParticle(0.0, 0.1, 1.0);
forceField->addException(particle1, particle2, 0, 0, 0);
bondForce->addBond(particle1, particle2, bondLength, bondForceConstant);
numDOF += 6;
if (constrain) {
system.addConstraint(particle1, particle2, bondLength);
numDOF -= 1;
}
}
forceField->setCutoffDistance(.99*boxLength/2);
forceField->setSwitchingDistance(.88*boxLength/2);
forceField->setUseSwitchingFunction(true);
forceField->setUseDispersionCorrection(false);
forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
system.addForce(forceField);
system.addForce(bondForce);
system.setDefaultPeriodicBoxVectors(a, b, c);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numMolecules; i++) {
while (true) {
Vec3 pos = Vec3(boxLength*genrand_real2(sfmt), boxLength*genrand_real2(sfmt), boxLength*genrand_real2(sfmt));
Vec3 pos1 = pos + Vec3(0,0, bondLength/2);
Vec3 pos2 = pos + Vec3(0,0,-bondLength/2);
double minDist = 2*boxLength;
for (int j = 0; j < i; j++) {
Vec3 delta = pos1-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
delta = pos2-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
}
if (minDist > 0.15) {
positions[2*i+0] = pos1;
positions[2*i+1] = pos2;
break;
}
}
}
return numDOF;
}
void testDimerBox(bool constrain=true) {
// Check conservation of system + bath energy for a harmonic oscillator
int numMolecules = 20;
double bondLength = 0.1;
double bondLengthSquared = bondLength * bondLength;
System system;
std::vector<Vec3> positions(numMolecules*2);
int numDOF = makeDimerBox(system, positions, constrain, numMolecules, bondLength);
bool simpleConstruct = true;
double temperature = 300; // kelvin
double collisionFrequency = 200; // 1/ps
int numMTS = 3;
int numYS = 3;
int chainLength = 5;
auto integrator = simpleConstruct ? NoseHooverIntegrator(temperature, collisionFrequency, 0.001, chainLength, numMTS, numYS)
: NoseHooverIntegrator(0.001);
if (!simpleConstruct)
integrator.addThermostat(temperature, collisionFrequency, chainLength, numMTS, numYS);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(temperature);
int nSteps = 5000;
double mean_temp = 0.0;
std::vector<double> energies(nSteps);
for (int i = 0; i < nSteps; ++i) {
integrator.step(1);
State state = context.getState(State::Energy | (constrain ? State::Positions : 0));
if (constrain) {
auto positions = state.getPositions();
for(int i = 0; i < numMolecules; ++i) {
Vec3 delta = positions[2*i+1] - positions[2*i];
double dR2 = delta.dot(delta);
ASSERT_EQUAL_TOL(bondLengthSquared, dR2, 1e-4);
}
}
double KE = state.getKineticEnergy();
double PE = state.getPotentialEnergy();
double time = state.getTime();
double instantaneous_temperature = 2 * KE / (BOLTZ * numDOF);
mean_temp = (i*mean_temp + instantaneous_temperature)/(i+1);
double energy = KE + PE + integrator.computeHeatBathEnergy();
energies[i] = energy;
}
double sum = std::accumulate(energies.begin(), energies.end(), 0.0);
double mean = sum / energies.size();
double sq_sum = std::inner_product(energies.begin(), energies.end(), energies.begin(), 0.0);
double std = std::sqrt(sq_sum / energies.size() - mean * mean);
double relative_std = std / mean;
// Check mean temperature
ASSERT_USUALLY_EQUAL_TOL(temperature, mean_temp, 1e-2);
// Check fluctuation of conserved (total bath + system) energy
ASSERT_USUALLY_EQUAL_TOL(relative_std, 0, 5e-3);
}
void testCheckpoints() {
// Create a system with Drude-like particles to be thermostated as a pair, as well as another
// particle to be thermostated independently, to test all integrator features.
double timeStep = 0.001;
NoseHooverIntegrator integrator(timeStep), newIntegrator(timeStep);
System system;
double mass = 1;
system.addParticle(8*mass);
system.addParticle(mass);
system.addParticle(5*mass);
HarmonicBondForce* force = new HarmonicBondForce();
force->addBond(0, 1, 0.1, 50.0);
force->addBond(0, 2, 0.1, 50.0);
system.addForce(force);
double kineticEnergy = 1e6;
double temperature=300, collisionFrequency=1, chainLength=3, numMTS=3, numYS=3;
chainLength = 10;
integrator.addSubsystemThermostat(std::vector<int>{2}, std::vector<std::pair<int,int>>{{0,1}}, temperature, collisionFrequency, temperature, collisionFrequency,
chainLength, numMTS, numYS);
newIntegrator.addSubsystemThermostat(std::vector<int>{2}, std::vector<std::pair<int,int>>{{0,1}}, temperature, collisionFrequency, temperature, collisionFrequency,
chainLength, numMTS, numYS);
Context context(system, integrator, platform);
Context newContext(system, newIntegrator, platform);
std::vector<Vec3> positions(3);
std::vector<Vec3> velocities(3);
positions[1] = {0.1, 0.0, 0.0};
velocities[1] = {0.1,0.2,-0.2};
positions[2] = {-0.1, 0.001, 0.001};
velocities[2] = {-0.1,0.2,-0.2};
context.setPositions(positions);
context.setVelocities(velocities);
// Run a short simulation and checkpoint..
integrator.step(500);
std::stringstream checkpoint;
context.createCheckpoint(checkpoint);
// Now continue the simulation
integrator.step(5);
// And try the same, starting from the checkpoint
newContext.loadCheckpoint(checkpoint);
newIntegrator.step(5);
State state1 = context.getState(State::Positions | State::Velocities);
State state2 = newContext.getState(State::Positions | State::Velocities);
ASSERT_EQUAL_VEC(state1.getPositions()[0], state2.getPositions()[0], 1e-6);
ASSERT_EQUAL_VEC(state1.getPositions()[1], state2.getPositions()[1], 1e-6);
ASSERT_EQUAL_VEC(state1.getVelocities()[0], state2.getVelocities()[0], 1e-6);
ASSERT_EQUAL_VEC(state1.getVelocities()[1], state2.getVelocities()[1], 1e-6);
}
void testAPIChangeNumParticles() {
bool constrain = true;
int numMolecules = 20;
double bondLength = 0.1;
double bondLengthSquared = bondLength * bondLength;
System system;
std::vector<Vec3> positions(numMolecules*2);
int numDOF = makeDimerBox(system, positions, constrain, numMolecules, bondLength);
}
void runPlatformTests(); void runPlatformTests();
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
initializeTests(argc, argv); initializeTests(argc, argv);
testVVSingleBond(); // Underlying integrator tests
testVVConstraints(); testSingleBond();
testVVConstrainedClusters(); testConstraints();
testVVConstrainedMasslessParticles(); testConstrainedClusters();
testConstrainedMasslessParticles();
testThreeParticleVirtualSite(); testThreeParticleVirtualSite();
testInitialTemperature(); testInitialTemperature();
// Thermostat tests
testHarmonicOscillator();
bool constrain;
constrain = false; testDimerBox(constrain);
constrain = true; testDimerBox(constrain);
testCheckpoints();
runPlatformTests(); runPlatformTests();
} }
catch(const exception& e) { catch(const exception& e) {
......
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/NoseHooverChain.h"
#include "openmm/NoseHooverIntegrator.h"
#include "openmm/Context.h"
#include "openmm/State.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/CustomExternalForce.h"
#include "openmm/System.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace OpenMM;
using namespace std;
void testHarmonicOscillator() {
const double mass = 1.0;
double temperature = 300;
double frequency = 1;
double mts = 1, ys = 1, chain_length = 3;
System system;
system.addParticle(mass);
vector<Vec3> positions(1);
positions[0] = Vec3(0.5,0.5,0.5);
vector<Vec3> velocities(1);
velocities[0] = Vec3(0, 0, 0);
auto harmonic_restraint = new CustomExternalForce("0.5*(x^2+y^2+z^2)");
harmonic_restraint->addParticle(0);
system.addForce(harmonic_restraint);
NoseHooverIntegrator integrator(0.001);
integrator.addThermostat(temperature, frequency, chain_length, mts, ys);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
double mean_temperature=0;
// equilibration
integrator.step(2000);
for (size_t i=0; i < 2500; i++){
integrator.step(10);
State state = context.getState(State::Energy | State::Positions | State::Velocities);
double kinetic_energy = state.getKineticEnergy();
double temp = kinetic_energy/(0.5*3*BOLTZ);
mean_temperature = (i*mean_temperature + temp)/(i+1);
double PE = state.getPotentialEnergy();
double time = state.getTime();
double energy = kinetic_energy + PE + integrator.computeHeatBathEnergy();
}
ASSERT_EQUAL_TOL(temperature, mean_temperature, 0.02);
}
int makeDimerBox(System& system, std::vector<Vec3>& positions, bool constrain=true, int numMolecules=20, double bondLength=0.1){
double boxLength = 2; // nm
Vec3 a(boxLength, 0.0, 0.0);
Vec3 b(0.0, boxLength, 0.0);
Vec3 c(0.0, 0.0, boxLength);
double mass = 20;
double bondForceConstant = 30000; //0.001;
int numDOF = 0;
NonbondedForce* forceField = new NonbondedForce();
HarmonicBondForce* bondForce = new HarmonicBondForce();
for(int molecule = 0; molecule < numMolecules; ++molecule) {
int particle1 = system.addParticle(mass);
int particle2 = system.addParticle(mass);
forceField->addParticle(0.0, 0.1, 1.0);
forceField->addParticle(0.0, 0.1, 1.0);
forceField->addException(particle1, particle2, 0, 0, 0);
bondForce->addBond(particle1, particle2, bondLength, bondForceConstant);
numDOF += 6;
if (constrain) {
system.addConstraint(particle1, particle2, bondLength);
numDOF -= 1;
}
}
forceField->setCutoffDistance(.99*boxLength/2);
forceField->setSwitchingDistance(.88*boxLength/2);
forceField->setUseSwitchingFunction(true);
forceField->setUseDispersionCorrection(false);
forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
system.addForce(forceField);
system.addForce(bondForce);
system.setDefaultPeriodicBoxVectors(a, b, c);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numMolecules; i++) {
while (true) {
Vec3 pos = Vec3(boxLength*genrand_real2(sfmt), boxLength*genrand_real2(sfmt), boxLength*genrand_real2(sfmt));
Vec3 pos1 = pos + Vec3(0,0, bondLength/2);
Vec3 pos2 = pos + Vec3(0,0,-bondLength/2);
double minDist = 2*boxLength;
for (int j = 0; j < i; j++) {
Vec3 delta = pos1-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
delta = pos2-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
}
if (minDist > 0.15) {
positions[2*i+0] = pos1;
positions[2*i+1] = pos2;
break;
}
}
}
return numDOF;
}
void testDimerBox(bool constrain=true) {
// Check conservation of system + bath energy for a harmonic oscillator
int numMolecules = 20;
double bondLength = 0.1;
double bondLengthSquared = bondLength * bondLength;
System system;
std::vector<Vec3> positions(numMolecules*2);
int numDOF = makeDimerBox(system, positions, constrain, numMolecules, bondLength);
bool simpleConstruct = true;
double temperature = 300; // kelvin
double collisionFrequency = 200; // 1/ps
int numMTS = 3;
int numYS = 3;
int chainLength = 5;
auto integrator = simpleConstruct ? NoseHooverIntegrator(temperature, collisionFrequency, 0.001, chainLength, numMTS, numYS)
: NoseHooverIntegrator(0.001);
if (!simpleConstruct)
integrator.addThermostat(temperature, collisionFrequency, chainLength, numMTS, numYS);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(temperature);
int nSteps = 5000;
double mean_temp = 0.0;
std::vector<double> energies(nSteps);
for (int i = 0; i < nSteps; ++i) {
integrator.step(1);
State state = context.getState(State::Energy | (constrain ? State::Positions : 0));
if (constrain) {
auto positions = state.getPositions();
for(int i = 0; i < numMolecules; ++i) {
Vec3 delta = positions[2*i+1] - positions[2*i];
double dR2 = delta.dot(delta);
ASSERT_EQUAL_TOL(bondLengthSquared, dR2, 1e-4);
}
}
double KE = state.getKineticEnergy();
double PE = state.getPotentialEnergy();
double time = state.getTime();
double instantaneous_temperature = 2 * KE / (BOLTZ * numDOF);
mean_temp = (i*mean_temp + instantaneous_temperature)/(i+1);
double energy = KE + PE + integrator.computeHeatBathEnergy();
energies[i] = energy;
}
double sum = std::accumulate(energies.begin(), energies.end(), 0.0);
double mean = sum / energies.size();
double sq_sum = std::inner_product(energies.begin(), energies.end(), energies.begin(), 0.0);
double std = std::sqrt(sq_sum / energies.size() - mean * mean);
double relative_std = std / mean;
// Check mean temperature
ASSERT_USUALLY_EQUAL_TOL(temperature, mean_temp, 1e-2);
// Check fluctuation of conserved (total bath + system) energy
ASSERT_USUALLY_EQUAL_TOL(relative_std, 0, 1e-3);
}
void testCheckpoints() {
// Create a system with Drude-like particles to be thermostated as a pair, as well as another
// particle to be thermostated independently, to test all integrator features.
double timeStep = 0.001;
NoseHooverIntegrator integrator(timeStep), newIntegrator(timeStep);
System system;
double mass = 1;
system.addParticle(8*mass);
system.addParticle(mass);
system.addParticle(5*mass);
HarmonicBondForce* force = new HarmonicBondForce();
force->addBond(0, 1, 0.1, 50.0);
force->addBond(0, 2, 0.1, 50.0);
system.addForce(force);
double kineticEnergy = 1e6;
double temperature=300, collisionFrequency=1, chainLength=3, numMTS=3, numYS=3;
chainLength = 10;
integrator.addSubsystemThermostat(std::vector<int>{2}, std::vector<std::pair<int,int>>{{0,1}}, temperature, collisionFrequency, temperature, collisionFrequency,
chainLength, numMTS, numYS);
newIntegrator.addSubsystemThermostat(std::vector<int>{2}, std::vector<std::pair<int,int>>{{0,1}}, temperature, collisionFrequency, temperature, collisionFrequency,
chainLength, numMTS, numYS);
Context context(system, integrator, platform);
Context newContext(system, newIntegrator, platform);
std::vector<Vec3> positions(3);
std::vector<Vec3> velocities(3);
positions[1] = {0.1, 0.0, 0.0};
velocities[1] = {0.1,0.2,-0.2};
positions[2] = {-0.1, 0.001, 0.001};
velocities[2] = {-0.1,0.2,-0.2};
context.setPositions(positions);
context.setVelocities(velocities);
// Run a short simulation and checkpoint..
integrator.step(500);
std::stringstream checkpoint;
context.createCheckpoint(checkpoint);
// Now continue the simulation
integrator.step(5);
// And try the same, starting from the checkpoint
newContext.loadCheckpoint(checkpoint);
newIntegrator.step(5);
State state1 = context.getState(State::Positions | State::Velocities);
State state2 = newContext.getState(State::Positions | State::Velocities);
ASSERT_EQUAL_VEC(state1.getPositions()[0], state2.getPositions()[0], 1e-6);
ASSERT_EQUAL_VEC(state1.getPositions()[1], state2.getPositions()[1], 1e-6);
ASSERT_EQUAL_VEC(state1.getVelocities()[0], state2.getVelocities()[0], 1e-6);
ASSERT_EQUAL_VEC(state1.getVelocities()[1], state2.getVelocities()[1], 1e-6);
}
void testAPIChangeNumParticles() {
bool constrain = true;
int numMolecules = 20;
double bondLength = 0.1;
double bondLengthSquared = bondLength * bondLength;
System system;
std::vector<Vec3> positions(numMolecules*2);
int numDOF = makeDimerBox(system, positions, constrain, numMolecules, bondLength);
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testHarmonicOscillator();
bool constrain;
constrain = false; testDimerBox(constrain);
constrain = true; testDimerBox(constrain);
testCheckpoints();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -63,11 +63,10 @@ SKIP_METHODS = [('State', 'getPositions'), ...@@ -63,11 +63,10 @@ SKIP_METHODS = [('State', 'getPositions'),
('InitializeForcesKernel',), ('InitializeForcesKernel',),
('IntegrateBrownianStepKernel',), ('IntegrateBrownianStepKernel',),
('IntegrateLangevinStepKernel',), ('IntegrateLangevinStepKernel',),
('IntegrateNoseHooverStepKernel',),
('IntegrateVariableLangevinStepKernel',), ('IntegrateVariableLangevinStepKernel',),
('IntegrateVariableVerletStepKernel',), ('IntegrateVariableVerletStepKernel',),
('IntegrateVerletStepKernel',), ('IntegrateVerletStepKernel',),
('IntegrateVelocityVerletStepKernel',),
('NoseHooverChainKernel',),
('IntegrateCustomStepKernel',), ('IntegrateCustomStepKernel',),
('Kernel',), ('Kernel',),
('KernelFactory',), ('KernelFactory',),
......
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