Commit 56f05a6c authored by Peter Eastman's avatar Peter Eastman
Browse files

LocalEnergyMinimizer works with constraints. Also added Context::applyConstraints().

parent 4b061bed
......@@ -248,6 +248,51 @@ void ReferenceUpdateStateDataKernel::setPeriodicBoxVectors(ContextImpl& context,
box[2] = (RealOpenMM) c[2];
}
void ReferenceApplyConstraintsKernel::initialize(const System& system) {
int numParticles = system.getNumParticles();
masses = new RealOpenMM[numParticles];
inverseMasses = new RealOpenMM[numParticles];
for (int i = 0; i < numParticles; ++i) {
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
inverseMasses[i] = 1.0/masses[i];
}
numConstraints = system.getNumConstraints();
constraintIndices = allocateIntArray(numConstraints, 2);
constraintDistances = new RealOpenMM[numConstraints];
for (int i = 0; i < numConstraints; ++i) {
int particle1, particle2;
double distance;
system.getConstraintParameters(i, particle1, particle2, distance);
constraintIndices[i][0] = particle1;
constraintIndices[i][1] = particle2;
constraintDistances[i] = static_cast<RealOpenMM>(distance);
}
}
ReferenceApplyConstraintsKernel::~ReferenceApplyConstraintsKernel() {
if (constraints)
delete constraints;
if (masses)
delete[] masses;
if (inverseMasses)
delete[] inverseMasses;
if (constraintIndices)
disposeIntArray(constraintIndices, numConstraints);
if (constraintDistances)
delete[] constraintDistances;
}
void ReferenceApplyConstraintsKernel::apply(ContextImpl& context, double tol) {
if (constraints == NULL) {
vector<ReferenceCCMAAlgorithm::AngleInfo> angles;
findAnglesForCCMA(context.getSystem(), angles);
constraints = new ReferenceCCMAAlgorithm(context.getSystem().getNumParticles(), numConstraints, constraintIndices, constraintDistances, masses, angles, tol);
}
RealOpenMM** positions = extractPositions(context);
constraints->setTolerance(tol);
constraints->apply(data.numParticles, positions, positions, inverseMasses);
}
ReferenceCalcHarmonicBondForceKernel::~ReferenceCalcHarmonicBondForceKernel() {
disposeIntArray(bondIndexArray, numBonds);
disposeRealArray(bondParamArray, numBonds);
......
......@@ -176,6 +176,38 @@ private:
ReferencePlatform::PlatformData& data;
};
/**
* This kernel modifies the positions of particles to enforce distance constraints.
*/
class ReferenceApplyConstraintsKernel : public ApplyConstraintsKernel {
public:
ReferenceApplyConstraintsKernel(std::string name, const Platform& platform, ReferencePlatform::PlatformData& data) :
ApplyConstraintsKernel(name, platform), data(data), constraints(0), masses(0), inverseMasses(0), constraintDistances(0), constraintIndices(0) {
}
~ReferenceApplyConstraintsKernel();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
*/
void initialize(const System& system);
/**
* Update particle positions to enforce constraints.
*
* @param context the context in which to execute this kernel
* @param tol the distance tolerance within which constraints must be satisfied.
*/
void apply(ContextImpl& context, double tol);
private:
ReferencePlatform::PlatformData& data;
ReferenceConstraintAlgorithm* constraints;
RealOpenMM* masses;
RealOpenMM* inverseMasses;
RealOpenMM* constraintDistances;
int** constraintIndices;
int numConstraints;
};
/**
* This kernel is invoked by HarmonicBondForce to calculate the forces acting on the system and the energy of the system.
*/
......
......@@ -42,6 +42,7 @@ ReferencePlatform::ReferencePlatform() {
ReferenceKernelFactory* factory = new ReferenceKernelFactory();
registerKernelFactory(CalcForcesAndEnergyKernel::Name(), factory);
registerKernelFactory(UpdateStateDataKernel::Name(), factory);
registerKernelFactory(ApplyConstraintsKernel::Name(), factory);
registerKernelFactory(CalcHarmonicBondForceKernel::Name(), factory);
registerKernelFactory(CalcCustomBondForceKernel::Name(), factory);
registerKernelFactory(CalcHarmonicAngleForceKernel::Name(), factory);
......
......@@ -320,11 +320,9 @@ RealOpenMM ReferenceCCMAAlgorithm::getTolerance( void ) const {
@param tolerance new tolerance
@return tolerance
--------------------------------------------------------------------------------------- */
int ReferenceCCMAAlgorithm::setTolerance( RealOpenMM tolerance ){
void ReferenceCCMAAlgorithm::setTolerance( RealOpenMM tolerance ){
// ---------------------------------------------------------------------------------------
......@@ -334,9 +332,6 @@ int ReferenceCCMAAlgorithm::setTolerance( RealOpenMM tolerance ){
// ---------------------------------------------------------------------------------------
_tolerance = tolerance;;
return ReferenceDynamics::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
......
......@@ -124,11 +124,9 @@ class OPENMM_EXPORT ReferenceCCMAAlgorithm : public ReferenceConstraintAlgorithm
@param tolerance new tolerance
@return tolerance
--------------------------------------------------------------------------------------- */
int setTolerance( RealOpenMM tolerance );
void setTolerance( RealOpenMM tolerance );
/**---------------------------------------------------------------------------------------
......
......@@ -35,6 +35,22 @@ public:
virtual ~ReferenceConstraintAlgorithm() {};
/**---------------------------------------------------------------------------------------
Get the constraint tolerance
--------------------------------------------------------------------------------------- */
virtual RealOpenMM getTolerance() const = 0;
/**---------------------------------------------------------------------------------------
Set the constraint tolerance
--------------------------------------------------------------------------------------- */
virtual void setTolerance(RealOpenMM tolerance) = 0;
/**---------------------------------------------------------------------------------------
Apply constraint algorithm
......
......@@ -190,11 +190,9 @@ RealOpenMM ReferenceShakeAlgorithm::getTolerance( void ) const {
@param tolerance new tolerance
@return tolerance
--------------------------------------------------------------------------------------- */
int ReferenceShakeAlgorithm::setTolerance( RealOpenMM tolerance ){
void ReferenceShakeAlgorithm::setTolerance( RealOpenMM tolerance ){
// ---------------------------------------------------------------------------------------
......@@ -204,9 +202,6 @@ int ReferenceShakeAlgorithm::setTolerance( RealOpenMM tolerance ){
// ---------------------------------------------------------------------------------------
_tolerance = tolerance;;
return ReferenceDynamics::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
......
......@@ -115,12 +115,10 @@ class ReferenceShakeAlgorithm : public ReferenceConstraintAlgorithm {
Set tolerance
@param tolerance new tolerance
@return tolerance
--------------------------------------------------------------------------------------- */
int setTolerance( RealOpenMM tolerance );
void setTolerance( RealOpenMM tolerance );
/**---------------------------------------------------------------------------------------
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "../../../tests/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 "sfmt/SFMT.h"
#include <iostream>
#include <vector>
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<Vec3> 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);
ReferencePlatform platform;
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 = 50;
const int numParticles = numMolecules*2;
const double cutoff = 2.0;
const double boxSize = 5.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<Vec3> 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.
ReferencePlatform platform;
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, substracting 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/(4*numMolecules));
ASSERT(forceNorm < 3*tolerance);
}
int main() {
try {
testHarmonicBonds();
testLargeSystem();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment