Commit eb0bba22 authored by Peter Eastman's avatar Peter Eastman
Browse files

Implemented setting random seed for reference platform, as well as adding it...

Implemented setting random seed for reference platform, as well as adding it as an option to BrownianIntegrator and AndersenThermostat.
parent 630bdd40
...@@ -76,10 +76,28 @@ public: ...@@ -76,10 +76,28 @@ public:
double getDefaultCollisionFrequency() { double getDefaultCollisionFrequency() {
return defaultFreq; return defaultFreq;
} }
/**
* Get the random number seed. See setRandomNumberSeed() for details.
*/
int getRandomNumberSeed() const {
return randomNumberSeed;
}
/**
* Set the random number seed. The precise meaning of this parameter is undefined, and is left up
* to each Platform to interpret in an appropriate way. It is guaranteed that if two simulations
* are run with different random number seeds, the sequence of collisions will be different. On
* the other hand, no guarantees are made about the behavior of simulations that use the same seed.
* In particular, Platforms are permitted to use non-deterministic algorithms which produce different
* results on successive runs, even if those runs were initialized identically.
*/
void setRandomNumberSeed(int seed) {
randomNumberSeed = seed;
}
protected: protected:
ForceImpl* createImpl(); ForceImpl* createImpl();
private: private:
double defaultTemp, defaultFreq; double defaultTemp, defaultFreq;
int randomNumberSeed;
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -78,6 +78,23 @@ public: ...@@ -78,6 +78,23 @@ public:
void setFriction(double coeff) { void setFriction(double coeff) {
friction = coeff; friction = coeff;
} }
/**
* Get the random number seed. See setRandomNumberSeed() for details.
*/
int getRandomNumberSeed() const {
return randomNumberSeed;
}
/**
* Set the random number seed. The precise meaning of this parameter is undefined, and is left up
* to each Platform to interpret in an appropriate way. It is guaranteed that if two simulations
* are run with different random number seeds, the sequence of random forces will be different. On
* the other hand, no guarantees are made about the behavior of simulations that use the same seed.
* In particular, Platforms are permitted to use non-deterministic algorithms which produce different
* results on successive runs, even if those runs were initialized identically.
*/
void setRandomNumberSeed(int seed) {
randomNumberSeed = seed;
}
/** /**
* Advance a simulation through time by taking a series of time steps. * Advance a simulation through time by taking a series of time steps.
* *
...@@ -97,6 +114,7 @@ protected: ...@@ -97,6 +114,7 @@ protected:
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
private: private:
double temperature, friction; double temperature, friction;
int randomNumberSeed;
OpenMMContextImpl* context; OpenMMContextImpl* context;
Kernel kernel; Kernel kernel;
}; };
......
...@@ -79,16 +79,21 @@ public: ...@@ -79,16 +79,21 @@ public:
friction = coeff; friction = coeff;
} }
/** /**
* Get the random number seed * Get the random number seed. See setRandomNumberSeed() for details.
*/ */
int getRandomNumberSeed(void ) const { int getRandomNumberSeed() const {
return randomNumberSeed; return randomNumberSeed;
} }
/** /**
* Set the random number seed * Set the random number seed. The precise meaning of this parameter is undefined, and is left up
* to each Platform to interpret in an appropriate way. It is guaranteed that if two simulations
* are run with different random number seeds, the sequence of random forces will be different. On
* the other hand, no guarantees are made about the behavior of simulations that use the same seed.
* In particular, Platforms are permitted to use non-deterministic algorithms which produce different
* results on successive runs, even if those runs were initialized identically.
*/ */
void setRandomNumberSeed(int inputRandomNumberSeed) { void setRandomNumberSeed(int seed) {
randomNumberSeed = inputRandomNumberSeed; randomNumberSeed = seed;
} }
/** /**
* Advance a simulation through time by taking a series of time steps. * Advance a simulation through time by taking a series of time steps.
......
...@@ -31,11 +31,13 @@ ...@@ -31,11 +31,13 @@
#include "AndersenThermostat.h" #include "AndersenThermostat.h"
#include "internal/AndersenThermostatImpl.h" #include "internal/AndersenThermostatImpl.h"
#include <ctime>
using namespace OpenMM; using namespace OpenMM;
AndersenThermostat::AndersenThermostat(double defaultTemperature, double defaultCollisionFrequency) : AndersenThermostat::AndersenThermostat(double defaultTemperature, double defaultCollisionFrequency) :
defaultTemp(defaultTemperature), defaultFreq(defaultCollisionFrequency) { defaultTemp(defaultTemperature), defaultFreq(defaultCollisionFrequency) {
setRandomNumberSeed((int) time(NULL));
} }
ForceImpl* AndersenThermostat::createImpl() { ForceImpl* AndersenThermostat::createImpl() {
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "OpenMMContext.h" #include "OpenMMContext.h"
#include "internal/OpenMMContextImpl.h" #include "internal/OpenMMContextImpl.h"
#include "kernels.h" #include "kernels.h"
#include <ctime>
#include <string> #include <string>
using namespace OpenMM; using namespace OpenMM;
...@@ -44,6 +45,7 @@ BrownianIntegrator::BrownianIntegrator(double temperature, double frictionCoeff, ...@@ -44,6 +45,7 @@ BrownianIntegrator::BrownianIntegrator(double temperature, double frictionCoeff,
setFriction(frictionCoeff); setFriction(frictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
setConstraintTolerance(1e-4); setConstraintTolerance(1e-4);
setRandomNumberSeed((int) time(NULL));
} }
void BrownianIntegrator::initialize(OpenMMContextImpl& contextRef) { void BrownianIntegrator::initialize(OpenMMContextImpl& contextRef) {
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "OpenMMContext.h" #include "OpenMMContext.h"
#include "internal/OpenMMContextImpl.h" #include "internal/OpenMMContextImpl.h"
#include "kernels.h" #include "kernels.h"
#include <ctime>
#include <string> #include <string>
using namespace OpenMM; using namespace OpenMM;
...@@ -44,7 +45,7 @@ LangevinIntegrator::LangevinIntegrator(double temperature, double frictionCoeff, ...@@ -44,7 +45,7 @@ LangevinIntegrator::LangevinIntegrator(double temperature, double frictionCoeff,
setFriction(frictionCoeff); setFriction(frictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
setConstraintTolerance(1e-4); setConstraintTolerance(1e-4);
setRandomNumberSeed(1); setRandomNumberSeed((int) time(NULL));
} }
void LangevinIntegrator::initialize(OpenMMContextImpl& contextRef) { void LangevinIntegrator::initialize(OpenMMContextImpl& contextRef) {
......
...@@ -432,15 +432,9 @@ CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() { ...@@ -432,15 +432,9 @@ CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) { void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
initializeIntegration(system, data, integrator); initializeIntegration(system, data, integrator);
_gpuContext* gpu = data.gpu;
// if LangevinIntegrator seed does not equal default value or is less than/equal to 0, then gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
// set gpu seed and redo random values gpuInitializeRandoms(gpu);
if( integrator.getRandomNumberSeed() <= 1 ){
_gpuContext* gpu = data.gpu;
gpu->seed = static_cast<unsigned long>( integrator.getRandomNumberSeed() );
gpuInitializeRandoms( gpu );
}
prevStepSize = -1.0; prevStepSize = -1.0;
} }
...@@ -478,6 +472,9 @@ CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() { ...@@ -478,6 +472,9 @@ CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
void CudaIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) { void CudaIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
initializeIntegration(system, data, integrator); initializeIntegration(system, data, integrator);
_gpuContext* gpu = data.gpu;
gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
gpuInitializeRandoms(gpu);
prevStepSize = -1.0; prevStepSize = -1.0;
} }
...@@ -512,6 +509,9 @@ CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() { ...@@ -512,6 +509,9 @@ CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
} }
void CudaApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) { void CudaApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
_gpuContext* gpu = data.gpu;
gpu->seed = (unsigned long) thermostat.getRandomNumberSeed();
gpuInitializeRandoms(gpu);
prevStepSize = -1.0; prevStepSize = -1.0;
} }
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <ctime>
#include <cmath> #include <cmath>
#include <map> #include <map>
#include <algorithm> #include <algorithm>
...@@ -1199,7 +1198,7 @@ int gpuAllocateInitialBuffers(gpuContext gpu) ...@@ -1199,7 +1198,7 @@ int gpuAllocateInitialBuffers(gpuContext gpu)
gpu->psAtomIndex->_pSysStream[0][i] = i; gpu->psAtomIndex->_pSysStream[0][i] = i;
gpu->psAtomIndex->Upload(); gpu->psAtomIndex->Upload();
// Determine randoms // Determine randoms
gpu->seed = (unsigned long)time(NULL) & 0x000fffff; gpu->seed = 1;
gpu->sim.randomFrames = 95; gpu->sim.randomFrames = 95;
gpu->sim.randomIterations = gpu->sim.randomFrames; gpu->sim.randomIterations = gpu->sim.randomFrames;
gpu->sim.randoms = gpu->sim.randomFrames * gpu->sim.paddedNumberOfAtoms - 5 * GRID; gpu->sim.randoms = gpu->sim.randomFrames * gpu->sim.paddedNumberOfAtoms - 5 * GRID;
...@@ -1215,35 +1214,6 @@ int gpuAllocateInitialBuffers(gpuContext gpu) ...@@ -1215,35 +1214,6 @@ int gpuAllocateInitialBuffers(gpuContext gpu)
gpu->sim.pRandom2b = gpu->psRandom2->_pDevStream[0] + gpu->sim.totalRandoms; gpu->sim.pRandom2b = gpu->psRandom2->_pDevStream[0] + gpu->sim.totalRandoms;
gpu->sim.pRandomPosition = gpu->psRandomPosition->_pDevStream[0]; gpu->sim.pRandomPosition = gpu->psRandomPosition->_pDevStream[0];
gpu->sim.pRandomSeed = gpu->psRandomSeed->_pDevStream[0]; gpu->sim.pRandomSeed = gpu->psRandomSeed->_pDevStream[0];
for (int i = 0; i < (int) gpu->sim.blocks; i++)
{
gpu->psRandomPosition->_pSysStream[0][i] = 0;
}
int seed = gpu->seed | ((gpu->seed ^ 0xffffffff) << 16);
srand(seed);
for (int i = 0; i < (int) (gpu->sim.blocks * gpu->sim.random_threads_per_block); i++)
{
gpu->psRandomSeed->_pSysStream[0][i].x = rand();
gpu->psRandomSeed->_pSysStream[0][i].y = rand();
gpu->psRandomSeed->_pSysStream[0][i].z = rand();
gpu->psRandomSeed->_pSysStream[0][i].w = rand();
}
float randomValue = 0.0f;
for (int i = 0; i < (int) gpu->sim.totalRandomsTimesTwo; i++)
{
gpu->psRandom4->_pSysStream[0][i].x = randomValue;
gpu->psRandom4->_pSysStream[0][i].y = randomValue;
gpu->psRandom4->_pSysStream[0][i].z = randomValue;
gpu->psRandom4->_pSysStream[0][i].w = randomValue;
gpu->psRandom2->_pSysStream[0][i].x = randomValue;
gpu->psRandom2->_pSysStream[0][i].y = randomValue;
}
gpu->psRandomSeed->Upload();
gpu->psRandom4->Upload();
gpu->psRandom2->Upload();
gpu->psRandomPosition->Upload();
// Allocate and clear linear momentum buffer // Allocate and clear linear momentum buffer
gpu->psLinearMomentum = new CUDAStream<float4>(gpu->sim.blocks, 1); gpu->psLinearMomentum = new CUDAStream<float4>(gpu->sim.blocks, 1);
......
...@@ -141,12 +141,11 @@ void kBrownianUpdatePart2(gpuContext gpu) ...@@ -141,12 +141,11 @@ void kBrownianUpdatePart2(gpuContext gpu)
LAUNCHERROR("kBrownianUpdatePart2"); LAUNCHERROR("kBrownianUpdatePart2");
// Update randoms if necessary // Update randoms if necessary
static int iteration = 0; gpu->iterations++;
iteration++; if (gpu->iterations == gpu->sim.randomIterations)
if (iteration == gpu->sim.randomIterations)
{ {
kGenerateRandoms(gpu); kGenerateRandoms(gpu);
iteration = 0; gpu->iterations = 0;
} }
} }
...@@ -94,12 +94,11 @@ void kCalculateAndersenThermostat(gpuContext gpu) ...@@ -94,12 +94,11 @@ void kCalculateAndersenThermostat(gpuContext gpu)
LAUNCHERROR("kCalculateAndersenThermostat"); LAUNCHERROR("kCalculateAndersenThermostat");
// Update randoms if necessary // Update randoms if necessary
static int iteration = 0; gpu->iterations++;
iteration++; if (gpu->iterations == gpu->sim.randomIterations)
if (iteration == gpu->sim.randomIterations)
{ {
kGenerateRandoms(gpu); kGenerateRandoms(gpu);
iteration = 0; gpu->iterations = 0;
} }
} }
...@@ -720,12 +720,11 @@ void kUpdatePart2(gpuContext gpu) ...@@ -720,12 +720,11 @@ void kUpdatePart2(gpuContext gpu)
} }
// Update randoms if necessary // Update randoms if necessary
static int iteration = 0; gpu->iterations++;
iteration++; if (gpu->iterations == gpu->sim.randomIterations)
if (iteration == gpu->sim.randomIterations)
{ {
kGenerateRandoms(gpu); kGenerateRandoms(gpu);
iteration = 0; gpu->iterations = 0;
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008 Stanford University and the Authors. * * Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -86,9 +86,71 @@ void testTemperature() { ...@@ -86,9 +86,71 @@ void testTemperature() {
ASSERT_EQUAL_TOL(expected, ke, 3*expected/std::sqrt(1000.0)); ASSERT_EQUAL_TOL(expected, ke, 3*expected/std::sqrt(1000.0));
} }
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
CudaPlatform platform;
System system(numParticles, 0);
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce(numParticles, 0);
for (int i = 0; i < numParticles; ++i) {
system.setParticleMass(i, 2.0);
forceField->setParticleParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
AndersenThermostat* thermostat = new AndersenThermostat(temp, collisionFreq);
system.addForce(thermostat);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
thermostat->setRandomNumberSeed(5);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
thermostat->setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() { int main() {
try { try {
testTemperature(); testTemperature();
testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008 Stanford University and the Authors. * * Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -168,11 +168,71 @@ void testConstraints() { ...@@ -168,11 +168,71 @@ void testConstraints() {
} }
} }
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
CudaPlatform platform;
System system(numParticles, 0);
BrownianIntegrator integrator(temp, 2.0, 0.001);
NonbondedForce* forceField = new NonbondedForce(numParticles, 0);
for (int i = 0; i < numParticles; ++i) {
system.setParticleMass(i, 2.0);
forceField->setParticleParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() { int main() {
try { try {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008 Stanford University and the Authors. * * Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -173,11 +173,71 @@ void testConstraints() { ...@@ -173,11 +173,71 @@ void testConstraints() {
} }
} }
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
CudaPlatform platform;
System system(numParticles, 0);
LangevinIntegrator integrator(temp, 2.0, 0.01);
NonbondedForce* forceField = new NonbondedForce(numParticles, 0);
for (int i = 0; i < numParticles; ++i) {
system.setParticleMass(i, 2.0);
forceField->setParticleParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() { int main() {
try { try {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "System.h" #include "System.h"
#include "internal/OpenMMContextImpl.h" #include "internal/OpenMMContextImpl.h"
#include "Integrator.h" #include "Integrator.h"
#include "SimTKUtilities/SimTKOpenMMUtilities.h"
#include <cmath> #include <cmath>
#include <limits> #include <limits>
...@@ -538,6 +539,7 @@ void ReferenceIntegrateLangevinStepKernel::initialize(const System& system, cons ...@@ -538,6 +539,7 @@ void ReferenceIntegrateLangevinStepKernel::initialize(const System& system, cons
constraintIndices[i][1] = particle2; constraintIndices[i][1] = particle2;
shakeParameters[i][0] = static_cast<RealOpenMM>(distance); shakeParameters[i][0] = static_cast<RealOpenMM>(distance);
} }
SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) integrator.getRandomNumberSeed());
} }
void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, const LangevinIntegrator& integrator) { void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, const LangevinIntegrator& integrator) {
...@@ -599,6 +601,7 @@ void ReferenceIntegrateBrownianStepKernel::initialize(const System& system, cons ...@@ -599,6 +601,7 @@ void ReferenceIntegrateBrownianStepKernel::initialize(const System& system, cons
constraintIndices[i][1] = particle2; constraintIndices[i][1] = particle2;
shakeParameters[i][0] = static_cast<RealOpenMM>(distance); shakeParameters[i][0] = static_cast<RealOpenMM>(distance);
} }
SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) integrator.getRandomNumberSeed());
} }
void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, const BrownianIntegrator& integrator) { void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, const BrownianIntegrator& integrator) {
...@@ -643,6 +646,7 @@ void ReferenceApplyAndersenThermostatKernel::initialize(const System& system, co ...@@ -643,6 +646,7 @@ void ReferenceApplyAndersenThermostatKernel::initialize(const System& system, co
for (int i = 0; i < numParticles; ++i) for (int i = 0; i < numParticles; ++i)
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i)); masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
this->thermostat = new ReferenceAndersenThermostat(); this->thermostat = new ReferenceAndersenThermostat();
SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) thermostat.getRandomNumberSeed());
} }
void ReferenceApplyAndersenThermostatKernel::execute(OpenMMContextImpl& context) { void ReferenceApplyAndersenThermostatKernel::execute(OpenMMContextImpl& context) {
......
/* Portions copyright (c) 2006 Stanford University and Simbios. /* Portions copyright (c) 2006-2009 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
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
uint32_t SimTKOpenMMUtilities::_randomNumberSeed = 0; uint32_t SimTKOpenMMUtilities::_randomNumberSeed = 0;
bool SimTKOpenMMUtilities::_randomInitialized = false; bool SimTKOpenMMUtilities::_randomInitialized = false;
bool SimTKOpenMMUtilities::nextGaussianIsValid = false;
RealOpenMM SimTKOpenMMUtilities::nextGaussian = 0;
/* --------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------
...@@ -1428,15 +1430,14 @@ int SimTKOpenMMUtilities::addTwoDimArray( int dimension1, int dimension2, ...@@ -1428,15 +1430,14 @@ int SimTKOpenMMUtilities::addTwoDimArray( int dimension1, int dimension2,
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
RealOpenMM SimTKOpenMMUtilities::getNormallyDistributedRandomNumber( void ) { RealOpenMM SimTKOpenMMUtilities::getNormallyDistributedRandomNumber( void ) {
static bool nextValueIsValid = false; if (nextGaussianIsValid) {
static RealOpenMM nextValue = 0; nextGaussianIsValid = false;
if (nextValueIsValid) { return nextGaussian;
nextValueIsValid = false;
return nextValue;
} }
if (!_randomInitialized) { if (!_randomInitialized) {
init_gen_rand(_randomNumberSeed); init_gen_rand(_randomNumberSeed);
_randomInitialized = true; _randomInitialized = true;
nextGaussianIsValid = false;
} }
// Use the polar form of the Box-Muller transformation to generate two Gaussian random numbers. // Use the polar form of the Box-Muller transformation to generate two Gaussian random numbers.
...@@ -1448,8 +1449,8 @@ RealOpenMM SimTKOpenMMUtilities::getNormallyDistributedRandomNumber( void ) { ...@@ -1448,8 +1449,8 @@ RealOpenMM SimTKOpenMMUtilities::getNormallyDistributedRandomNumber( void ) {
r2 = x*x + y*y; r2 = x*x + y*y;
} while (r2 >= 1.0 || r2 == 0.0); } while (r2 >= 1.0 || r2 == 0.0);
RealOpenMM multiplier = static_cast<RealOpenMM>( sqrt((-2.0*log(r2))/r2) ); RealOpenMM multiplier = static_cast<RealOpenMM>( sqrt((-2.0*log(r2))/r2) );
nextValue = y*multiplier; nextGaussian = y*multiplier;
nextValueIsValid = true; nextGaussianIsValid = true;
return x*multiplier; return x*multiplier;
} }
...@@ -1465,8 +1466,10 @@ RealOpenMM SimTKOpenMMUtilities::getUniformlyDistributedRandomNumber( void ) { ...@@ -1465,8 +1466,10 @@ RealOpenMM SimTKOpenMMUtilities::getUniformlyDistributedRandomNumber( void ) {
if (!_randomInitialized) { if (!_randomInitialized) {
init_gen_rand(_randomNumberSeed); init_gen_rand(_randomNumberSeed);
_randomInitialized = true; _randomInitialized = true;
nextGaussianIsValid = false;
} }
return static_cast<RealOpenMM>( genrand_real2() ); RealOpenMM value = static_cast<RealOpenMM>( genrand_real2() );
return value;
} }
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -1507,5 +1510,5 @@ void SimTKOpenMMUtilities::setRandomNumberSeed( uint32_t seed ) { ...@@ -1507,5 +1510,5 @@ void SimTKOpenMMUtilities::setRandomNumberSeed( uint32_t seed ) {
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
_randomNumberSeed = seed; _randomNumberSeed = seed;
init_gen_rand(_randomNumberSeed); _randomInitialized = false;
} }
/* Portions copyright (c) 2006 Stanford University and Simbios. /* Portions copyright (c) 2006-2009 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
...@@ -58,6 +58,8 @@ class OPENMM_EXPORT SimTKOpenMMUtilities { ...@@ -58,6 +58,8 @@ class OPENMM_EXPORT SimTKOpenMMUtilities {
static uint32_t _randomNumberSeed; static uint32_t _randomNumberSeed;
static bool _randomInitialized; static bool _randomInitialized;
static bool nextGaussianIsValid;
static RealOpenMM nextGaussian;
public: public:
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008 Stanford University and the Authors. * * Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -86,9 +86,71 @@ void testTemperature() { ...@@ -86,9 +86,71 @@ void testTemperature() {
ASSERT_EQUAL_TOL(expected, ke, 3*expected/std::sqrt(1000.0)); ASSERT_EQUAL_TOL(expected, ke, 3*expected/std::sqrt(1000.0));
} }
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
ReferencePlatform platform;
System system(numParticles, 0);
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce(numParticles, 0);
for (int i = 0; i < numParticles; ++i) {
system.setParticleMass(i, 2.0);
forceField->setParticleParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
AndersenThermostat* thermostat = new AndersenThermostat(temp, collisionFreq);
system.addForce(thermostat);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
thermostat->setRandomNumberSeed(5);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
thermostat->setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() { int main() {
try { try {
testTemperature(); testTemperature();
testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -162,11 +162,71 @@ void testConstraints() { ...@@ -162,11 +162,71 @@ void testConstraints() {
} }
} }
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
ReferencePlatform platform;
System system(numParticles, 0);
BrownianIntegrator integrator(temp, 2.0, 0.001);
NonbondedForce* forceField = new NonbondedForce(numParticles, 0);
for (int i = 0; i < numParticles; ++i) {
system.setParticleMass(i, 2.0);
forceField->setParticleParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() { int main() {
try { try {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -169,11 +169,71 @@ void testConstraints() { ...@@ -169,11 +169,71 @@ void testConstraints() {
} }
} }
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double collisionFreq = 10.0;
ReferencePlatform platform;
System system(numParticles, 0);
LangevinIntegrator integrator(temp, 2.0, 0.01);
NonbondedForce* forceField = new NonbondedForce(numParticles, 0);
for (int i = 0; i < numParticles; ++i) {
system.setParticleMass(i, 2.0);
forceField->setParticleParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
int main() { int main() {
try { try {
testSingleBond(); testSingleBond();
testTemperature(); testTemperature();
testConstraints(); testConstraints();
testRandomSeed();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << 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