Commit 5c4be2f0 authored by Peter Eastman's avatar Peter Eastman
Browse files

Created reference implementation of BrownianIntegrator

parent 2cfc6821
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "gbsa/CpuObc.h" #include "gbsa/CpuObc.h"
#include "SimTKReference/ReferenceAngleBondIxn.h" #include "SimTKReference/ReferenceAngleBondIxn.h"
#include "SimTKReference/ReferenceBondForce.h" #include "SimTKReference/ReferenceBondForce.h"
#include "SimTKReference/ReferenceBrownianDynamics.h"
#include "SimTKReference/ReferenceHarmonicBondIxn.h" #include "SimTKReference/ReferenceHarmonicBondIxn.h"
#include "SimTKReference/ReferenceLJCoulomb14.h" #include "SimTKReference/ReferenceLJCoulomb14.h"
#include "SimTKReference/ReferenceLJCoulombIxn.h" #include "SimTKReference/ReferenceLJCoulombIxn.h"
...@@ -258,7 +259,7 @@ void ReferenceIntegrateVerletStepKernel::initialize(const vector<double>& masses ...@@ -258,7 +259,7 @@ void ReferenceIntegrateVerletStepKernel::initialize(const vector<double>& masses
void ReferenceIntegrateVerletStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double stepSize) { void ReferenceIntegrateVerletStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double stepSize) {
} }
#include <iostream>
ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() { ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() {
if (dynamics) if (dynamics)
delete dynamics; delete dynamics;
...@@ -310,13 +311,54 @@ void ReferenceIntegrateLangevinStepKernel::execute(Stream& positions, Stream& ve ...@@ -310,13 +311,54 @@ void ReferenceIntegrateLangevinStepKernel::execute(Stream& positions, Stream& ve
dynamics->update(positions.getSize(), posData, velData, forceData, masses); dynamics->update(positions.getSize(), posData, velData, forceData, masses);
} }
ReferenceIntegrateBrownianStepKernel::~ReferenceIntegrateBrownianStepKernel() {
if (dynamics)
delete dynamics;
if (shake)
delete shake;
if (masses)
delete[] masses;
if (constraintIndices)
disposeIntArray(constraintIndices, numConstraints);
if (shakeParameters)
disposeRealArray(shakeParameters, numConstraints);
}
void ReferenceIntegrateBrownianStepKernel::initialize(const vector<double>& masses, const vector<vector<int> >& constraintIndices, void ReferenceIntegrateBrownianStepKernel::initialize(const vector<double>& masses, const vector<vector<int> >& constraintIndices,
const vector<double>& constraintLengths) { const vector<double>& constraintLengths) {
this->masses = new RealOpenMM[masses.size()];
for (int i = 0; i < masses.size(); ++i)
this->masses[i] = masses[i];
numConstraints = constraintIndices.size();
this->constraintIndices = allocateIntArray(numConstraints, 2);
for (int i = 0; i < numConstraints; ++i) {
this->constraintIndices[i][0] = constraintIndices[i][0];
this->constraintIndices[i][1] = constraintIndices[i][1];
}
shakeParameters = allocateRealArray(constraintLengths.size(), 1);
for (int i = 0; i < constraintLengths.size(); ++i)
shakeParameters[i][0] = constraintLengths[i];
} }
void ReferenceIntegrateBrownianStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize) { void ReferenceIntegrateBrownianStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize) {
RealOpenMM** posData = ((ReferenceFloatStreamImpl&) positions.getImpl()).getData();
RealOpenMM** velData = ((ReferenceFloatStreamImpl&) velocities.getImpl()).getData();
RealOpenMM** forceData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) forces.getImpl()).getData()); // Reference code needs to be made const correct
if (dynamics == 0 || temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
// Recreate the computation objects with the new parameters.
if (dynamics) {
delete dynamics;
delete shake;
}
dynamics = new ReferenceBrownianDynamics(positions.getSize(), stepSize, friction, temperature);
shake = new ReferenceShakeAlgorithm(numConstraints, constraintIndices, shakeParameters);
dynamics->setReferenceShakeAlgorithm(shake);
prevTemp = temperature;
prevFriction = friction;
prevStepSize = stepSize;
}
dynamics->update(positions.getSize(), posData, velData, forceData, masses);
} }
void ReferenceApplyAndersenThermostatKernel::initialize(const vector<double>& masses) { void ReferenceApplyAndersenThermostatKernel::initialize(const vector<double>& masses) {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "SimTKUtilities/SimTKOpenMMRealType.h" #include "SimTKUtilities/SimTKOpenMMRealType.h"
class CpuObc; class CpuObc;
class ReferenceBrownianDynamics;
class ReferenceStochasticDynamics; class ReferenceStochasticDynamics;
class ReferenceShakeAlgorithm; class ReferenceShakeAlgorithm;
...@@ -203,8 +204,10 @@ private: ...@@ -203,8 +204,10 @@ private:
*/ */
class ReferenceIntegrateBrownianStepKernel : public IntegrateBrownianStepKernel { class ReferenceIntegrateBrownianStepKernel : public IntegrateBrownianStepKernel {
public: public:
ReferenceIntegrateBrownianStepKernel(std::string name, const Platform& platform) : IntegrateBrownianStepKernel(name, platform) { ReferenceIntegrateBrownianStepKernel(std::string name, const Platform& platform) : IntegrateBrownianStepKernel(name, platform),
dynamics(0), shake(0), masses(0), shakeParameters(0), constraintIndices(0) {
} }
~ReferenceIntegrateBrownianStepKernel();
/** /**
* Initialize the kernel, setting up all parameters related to integrator. * Initialize the kernel, setting up all parameters related to integrator.
* *
...@@ -225,6 +228,14 @@ public: ...@@ -225,6 +228,14 @@ public:
* @param stepSize the integration step size * @param stepSize the integration step size
*/ */
void execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize); void execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize);
private:
ReferenceBrownianDynamics* dynamics;
ReferenceShakeAlgorithm* shake;
RealOpenMM* masses;
RealOpenMM** shakeParameters;
int** constraintIndices;
int numConstraints;
double prevTemp, prevFriction, prevStepSize;
}; };
/** /**
......
/* Portions copyright (c) 2006-2008 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group
*
* 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 <string.h>
#include <sstream>
#include "../SimTKUtilities/SimTKOpenMMCommon.h"
#include "../SimTKUtilities/SimTKOpenMMLog.h"
#include "../SimTKUtilities/SimTKOpenMMUtilities.h"
#include "ReferenceBrownianDynamics.h"
/**---------------------------------------------------------------------------------------
ReferenceBrownianDynamics constructor
@param numberOfAtoms number of atoms
@param deltaT delta t for dynamics
@param friction friction coefficient
@param temperature temperature
--------------------------------------------------------------------------------------- */
ReferenceBrownianDynamics::ReferenceBrownianDynamics( int numberOfAtoms,
RealOpenMM deltaT, RealOpenMM friction,
RealOpenMM temperature ) :
ReferenceDynamics( numberOfAtoms, deltaT, temperature ), friction( friction ) {
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceBrownianDynamics::ReferenceBrownianDynamics";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
// ---------------------------------------------------------------------------------------
if( friction <= zero ){
std::stringstream message;
message << methodName;
message << " input frction value=" << friction << " is invalid -- setting to 1.";
SimTKOpenMMLog::printError( message );
this->friction = one;
}
allocate2DArrays( numberOfAtoms, 3, Max2DArrays );
allocate1DArrays( numberOfAtoms, Max1DArrays );
}
/**---------------------------------------------------------------------------------------
ReferenceBrownianDynamics destructor
--------------------------------------------------------------------------------------- */
ReferenceBrownianDynamics::~ReferenceBrownianDynamics( ){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceBrownianDynamics::~ReferenceBrownianDynamics";
// ---------------------------------------------------------------------------------------
}
/**---------------------------------------------------------------------------------------
Get the friction coefficient
@return friction
--------------------------------------------------------------------------------------- */
RealOpenMM ReferenceBrownianDynamics::getFriction( void ) const {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceBrownianDynamics::getFriction";
// ---------------------------------------------------------------------------------------
return friction;
}
/**---------------------------------------------------------------------------------------
Print parameters
@param message message
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceBrownianDynamics::printParameters( std::stringstream& message ) const {
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceBrownianDynamics::printParameters";
// ---------------------------------------------------------------------------------------
// print parameters
ReferenceDynamics::printParameters( message );
message << " friction=" << getFriction();
message << " T=" << getTemperature();
return ReferenceDynamics::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
Update -- driver routine for performing Brownian dynamics update of coordinates
and velocities
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities velocities
@param forces forces
@param masses atom masses
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceBrownianDynamics::update( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities,
RealOpenMM** forces, RealOpenMM* masses ){
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceBrownianDynamics::update";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static int debug = 0;
// ---------------------------------------------------------------------------------------
// get work arrays
RealOpenMM** xPrime = get2DArrayAtIndex( xPrime2D );
RealOpenMM* inverseMasses = get1DArrayAtIndex( InverseMasses );
// first-time-through initialization
if( getTimeStep() == 0 ){
std::stringstream message;
message << methodName;
int errors = 0;
// invert masses
for( int ii = 0; ii < numberOfAtoms; ii++ ){
if( masses[ii] <= zero ){
message << "mass at atom index=" << ii << " (" << masses[ii] << ") is <= 0" << std::endl;
errors++;
} else {
inverseMasses[ii] = one/masses[ii];
}
}
// exit if errors
if( errors ){
SimTKOpenMMLog::printError( message );
}
}
// Perform the integration.
const RealOpenMM noiseAmplitude = sqrt(2.0*BOLTZ*getTemperature()*getDeltaT()/getFriction());
const RealOpenMM forceScale = getDeltaT()/getFriction();
for (int i = 0; i < numberOfAtoms; ++i) {
for (int j = 0; j < 3; ++j) {
xPrime[i][j] = atomCoordinates[i][j] + forceScale*forces[i][j] + noiseAmplitude*getNormallyDistributedRandomNumber();
}
}
ReferenceShakeAlgorithm* referenceShakeAlgorithm = getReferenceShakeAlgorithm();
if( referenceShakeAlgorithm )
referenceShakeAlgorithm->applyShake( numberOfAtoms, atomCoordinates, xPrime, inverseMasses );
// Update the positions and velocities.
RealOpenMM velocityScale = 1.0/getDeltaT();
for (int i = 0; i < numberOfAtoms; ++i) {
for (int j = 0; j < 3; ++j) {
velocities[i][j] = velocityScale*(xPrime[i][j] - atomCoordinates[i][j]);
atomCoordinates[i][j] = xPrime[i][j];
}
}
incrementTimeStep();
return ReferenceDynamics::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
Write state
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities velocities
@param forces forces
@param masses atom masses
@param state 0 if initial state; otherwise nonzero
@param baseFileName base file name
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceBrownianDynamics::writeState( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities,
RealOpenMM** forces, RealOpenMM* masses,
int state, const std::string& baseFileName ) const {
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceBrownianDynamics::writeState";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static const int threeI = 3;
// ---------------------------------------------------------------------------------------
std::stringstream stateFileName;
stateFileName << baseFileName;
stateFileName << "_Step" << getTimeStep();
// stateFileName << "_State" << state;
stateFileName << ".txt";
// ---------------------------------------------------------------------------------------
// open file -- return if unsuccessful
FILE* stateFile = NULL;
#ifdef WIN32
fopen_s( &stateFile, stateFileName.str().c_str(), "w" );
#else
stateFile = fopen( stateFileName.str().c_str(), "w" );
#endif
// ---------------------------------------------------------------------------------------
// diagnostics
if( stateFile != NULL ){
std::stringstream message;
message << methodName;
message << " Opened file=<" << stateFileName.str() << ">.\n";
SimTKOpenMMLog::printMessage( message );
} else {
std::stringstream message;
message << methodName;
message << " could not open file=<" << stateFileName.str() << "> -- abort output.\n";
SimTKOpenMMLog::printMessage( message );
return ReferenceDynamics::ErrorReturn;
}
// ---------------------------------------------------------------------------------------
StringVector scalarNameI;
IntVector scalarI;
StringVector scalarNameR;
RealOpenMMVector scalarR;
StringVector scalarNameR1;
RealOpenMMPtrVector scalarR1;
StringVector scalarNameR2;
RealOpenMMPtrPtrVector scalarR2;
scalarI.push_back( getNumberOfAtoms() );
scalarNameI.push_back( "Atoms" );
scalarI.push_back( getTimeStep() );
scalarNameI.push_back( "Timestep" );
if( state == 0 || state == -1 ){
scalarR.push_back( getDeltaT() );
scalarNameR.push_back( "delta_t" );
scalarR.push_back( getTemperature() );
scalarNameR.push_back( "T" );
scalarR.push_back( getFriction() );
scalarNameR.push_back( "Friction" );
scalarR1.push_back( masses );
scalarNameR1.push_back( "mass" );
scalarR2.push_back( atomCoordinates );
scalarNameR2.push_back( "coord" );
scalarR2.push_back( velocities );
scalarNameR2.push_back( "velocities" );
scalarR2.push_back( forces );
scalarNameR2.push_back( "forces" );
if( state == -1 ){
RealOpenMM** xPrime = get2DArrayAtIndex( xPrime2D );
scalarR2.push_back( xPrime );
scalarNameR2.push_back( "xPrime" );
}
} else {
scalarR2.push_back( atomCoordinates );
scalarNameR2.push_back( "coord" );
scalarR2.push_back( velocities );
scalarNameR2.push_back( "velocities" );
}
writeStateToFile( stateFile, scalarNameI, scalarI, scalarNameR, scalarR, getNumberOfAtoms(), scalarNameR1, scalarR1, threeI, scalarNameR2, scalarR2 );
(void) fclose( stateFile );
return ReferenceDynamics::DefaultReturn;
}
/* Portions copyright (c) 2006-2008 Stanford University and Simbios.
* Contributors: Pande Group
*
* 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.
*/
#ifndef __ReferenceBrownianDynamics_H__
#define __ReferenceBrownianDynamics_H__
#include "ReferenceDynamics.h"
// ---------------------------------------------------------------------------------------
class ReferenceBrownianDynamics : public ReferenceDynamics {
private:
enum TwoDArrayIndicies { xPrime2D, Max2DArrays };
enum OneDArrayIndicies { InverseMasses, Max1DArrays };
RealOpenMM friction;
public:
/**---------------------------------------------------------------------------------------
Constructor
@param numberOfAtoms number of atoms
@param deltaT delta t for dynamics
@param friction friction coefficient
@param temperature temperature
--------------------------------------------------------------------------------------- */
ReferenceBrownianDynamics( int numberOfAtoms, RealOpenMM deltaT, RealOpenMM friction, RealOpenMM temperature );
/**---------------------------------------------------------------------------------------
Destructor
--------------------------------------------------------------------------------------- */
~ReferenceBrownianDynamics( );
/**---------------------------------------------------------------------------------------
Get the friction coefficient
@return friction
--------------------------------------------------------------------------------------- */
RealOpenMM getFriction( void ) const;
/**---------------------------------------------------------------------------------------
Print parameters
@param message message
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int printParameters( std::stringstream& message ) const;
/**---------------------------------------------------------------------------------------
Update
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities velocities
@param forces forces
@param masses atom masses
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int update( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities, RealOpenMM** forces, RealOpenMM* masses );
/**---------------------------------------------------------------------------------------
Write state
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities velocities
@param forces forces
@param masses atom masses
@param state 0 if initial state; otherwise nonzero
@param baseFileName base file name
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int writeState( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities, RealOpenMM** forces, RealOpenMM* masses,
int state, const std::string& baseFileName ) const;
};
// ---------------------------------------------------------------------------------------
#endif // __ReferenceBrownianDynamics_H__
/* -------------------------------------------------------------------------- *
* 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 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 BrownianIntegrator.
*/
#include "../../../tests/AssertionUtilities.h"
#include "OpenMMContext.h"
#include "ReferencePlatform.h"
#include "StandardMMForceField.h"
#include "System.h"
#include "BrownianIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "../src/sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleBond() {
ReferencePlatform platform;
System system(2, 0);
system.setAtomMass(0, 2.0);
system.setAtomMass(1, 2.0);
double dt = 0.01;
BrownianIntegrator integrator(0, 0.1, dt);
StandardMMForceField* forceField = new StandardMMForceField(2, 1, 0, 0, 0);
forceField->setBondParameters(0, 0, 1, 1.5, 1);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// This is simply an overdamped harmonic oscillator, so compare it to the analytical solution.
double rate = 2*1.0/0.1;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Velocities);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::exp(-rate*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
if (i > 0) {
double expectedSpeed = -0.5*rate*std::exp(-rate*(time-0.5*dt));
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.11);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.11);
}
integrator.step(1);
}
}
void testTemperature() {
const int numAtoms = 8;
const int numBonds = numAtoms-1;
const double temp = 100.0;
ReferencePlatform platform;
System system(numAtoms, 0);
BrownianIntegrator integrator(temp, 2.0, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(numAtoms, numBonds, 0, 0, 0);
for (int i = 0; i < numAtoms; ++i) {
system.setAtomMass(i, 2.0);
// forceField->setAtomParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
for (int i = 0; i < numBonds; ++i)
forceField->setBondParameters(i, i, i+1, 1.0, i);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(numAtoms);
for (int i = 0; i < numAtoms; ++i)
positions[i] = Vec3(i, 0, 0);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(1000);
// Now run it for a while and see if the temperature is correct.
double pe = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Energy);
pe += state.getPotentialEnergy();
integrator.step(1);
}
pe /= 1000;
double expected = 0.5*numBonds*BOLTZ*temp;
ASSERT_EQUAL_TOL(expected, pe, 3*expected/std::sqrt(1000.0));
}
void testConstraints() {
const int numAtoms = 8;
const double temp = 100.0;
ReferencePlatform platform;
System system(numAtoms, numAtoms-1);
BrownianIntegrator integrator(temp, 2.0, 0.001);
StandardMMForceField* forceField = new StandardMMForceField(numAtoms, 0, 0, 0, 0);
for (int i = 0; i < numAtoms; ++i) {
system.setAtomMass(i, 10.0);
forceField->setAtomParameters(i, (i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
for (int i = 0; i < numAtoms-1; ++i)
system.setConstraintParameters(i, i, i+1, 1.0);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(numAtoms);
vector<Vec3> velocities(numAtoms);
init_gen_rand(0);
for (int i = 0; i < numAtoms; ++i) {
positions[i] = Vec3(i/2, (i+1)/2, 0);
velocities[i] = Vec3(genrand_real2()-0.5, genrand_real2()-0.5, genrand_real2()-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions);
for (int j = 0; j < numAtoms-1; ++j) {
Vec3 p1 = state.getPositions()[j];
Vec3 p2 = state.getPositions()[j+1];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(1.0, dist, 2e-4);
}
integrator.step(1);
}
}
int main() {
try {
testSingleBond();
testTemperature();
testConstraints();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -157,9 +157,9 @@ void testConstraints() { ...@@ -157,9 +157,9 @@ void testConstraints() {
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions); State state = context.getState(State::Positions);
for (int i = 0; i < numAtoms-1; ++i) { for (int j = 0; j < numAtoms-1; ++j) {
Vec3 p1 = state.getPositions()[i]; Vec3 p1 = state.getPositions()[j];
Vec3 p2 = state.getPositions()[i+1]; Vec3 p2 = state.getPositions()[j+1];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(1.0, dist, 1e-4); ASSERT_EQUAL_TOL(1.0, dist, 1e-4);
} }
......
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