"...OpenDAS/text-generation-inference.git" did not exist on "e9cdf6225fa73484c0c09b7aaec1e8acbda729cc"
Unverified Commit c5c0348a authored by peastman's avatar peastman Committed by GitHub
Browse files

Merge pull request #2518 from andysim/inittemp

Modify temperature initialization mechanism
parents ef02e48d 58d2619e
...@@ -42,6 +42,7 @@ namespace OpenMM { ...@@ -42,6 +42,7 @@ namespace OpenMM {
class Context; class Context;
class ContextImpl; class ContextImpl;
class System;
/** /**
* An Integrator defines a method for simulating a System by integrating the equations of motion. * An Integrator defines a method for simulating a System by integrating the equations of motion.
...@@ -133,6 +134,16 @@ protected: ...@@ -133,6 +134,16 @@ protected:
virtual bool kineticEnergyRequiresForce() const { virtual bool kineticEnergyRequiresForce() const {
return true; return true;
} }
/**
* Return a list of velocities normally distributed around a target temperature. This may be
* overridden by Drude integrators to ensure that Drude pairs have their center of mass velocity
* assigned as a single entity, rather than treating both particles as being independent.
*
* @param system the system whose velocities are to be initialized.
* @param temperature the target temperature in Kelvin.
* @param randomSeed the random number seed to use when selecting velocities
*/
virtual std::vector<Vec3> getVelocitiesForTemperature(const System &system, double temperature, int randomSeed) const;
private: private:
double stepSize, constraintTol; double stepSize, constraintTol;
}; };
......
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/internal/ForceImpl.h" #include "openmm/internal/ForceImpl.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
...@@ -183,37 +181,9 @@ void Context::setVelocities(const vector<Vec3>& velocities) { ...@@ -183,37 +181,9 @@ void Context::setVelocities(const vector<Vec3>& velocities) {
} }
void Context::setVelocitiesToTemperature(double temperature, int randomSeed) { void Context::setVelocitiesToTemperature(double temperature, int randomSeed) {
const Integrator& integrator = impl->getIntegrator();
const System& system = impl->getSystem(); const System& system = impl->getSystem();
setVelocities(integrator.getVelocitiesForTemperature(system, temperature, randomSeed));
// Generate the list of Gaussian random numbers.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(randomSeed, sfmt);
vector<double> randoms;
while (randoms.size() < system.getNumParticles()*3) {
double x, y, r2;
do {
x = 2.0*genrand_real2(sfmt)-1.0;
y = 2.0*genrand_real2(sfmt)-1.0;
r2 = x*x + y*y;
} while (r2 >= 1.0 || r2 == 0.0);
double multiplier = sqrt((-2.0*log(r2))/r2);
randoms.push_back(x*multiplier);
randoms.push_back(y*multiplier);
}
// Assign the velocities.
vector<Vec3> velocities(system.getNumParticles(), Vec3());
int nextRandom = 0;
for (int i = 0; i < system.getNumParticles(); i++) {
double mass = system.getParticleMass(i);
if (mass != 0) {
double velocityScale = sqrt(BOLTZ*temperature/mass);
velocities[i] = Vec3(randoms[nextRandom++], randoms[nextRandom++], randoms[nextRandom++])*velocityScale;
}
}
setVelocities(velocities);
impl->applyVelocityConstraints(1e-5); impl->applyVelocityConstraints(1e-5);
} }
......
...@@ -29,9 +29,14 @@ ...@@ -29,9 +29,14 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "sfmt/SFMT.h"
#include "SimTKOpenMMRealType.h"
#include "openmm/Integrator.h" #include "openmm/Integrator.h"
#include "openmm/System.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include <cmath>
using namespace OpenMM; using namespace OpenMM;
Integrator::Integrator() : owner(NULL), context(NULL) { Integrator::Integrator() : owner(NULL), context(NULL) {
...@@ -63,3 +68,34 @@ double Integrator::getConstraintTolerance() const { ...@@ -63,3 +68,34 @@ double Integrator::getConstraintTolerance() const {
void Integrator::setConstraintTolerance(double tol) { void Integrator::setConstraintTolerance(double tol) {
constraintTol = tol; constraintTol = tol;
} }
std::vector<Vec3> Integrator::getVelocitiesForTemperature(const System &system, double temperature, int randomSeed) const {
// Generate the list of Gaussian random numbers.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(randomSeed, sfmt);
std::vector<double> randoms;
while (randoms.size() < system.getNumParticles()*3) {
double x, y, r2;
do {
x = 2.0*genrand_real2(sfmt)-1.0;
y = 2.0*genrand_real2(sfmt)-1.0;
r2 = x*x + y*y;
} while (r2 >= 1.0 || r2 == 0.0);
double multiplier = sqrt((-2.0*std::log(r2))/r2);
randoms.push_back(x*multiplier);
randoms.push_back(y*multiplier);
}
// Assign the velocities.
std::vector<Vec3> velocities(system.getNumParticles(), Vec3());
int nextRandom = 0;
for (int i = 0; i < system.getNumParticles(); i++) {
double mass = system.getParticleMass(i);
if (mass != 0) {
double velocityScale = sqrt(BOLTZ*temperature/mass);
velocities[i] = Vec3(randoms[nextRandom++], randoms[nextRandom++], randoms[nextRandom++])*velocityScale;
}
}
return velocities;
}
#ifndef OPENMM_DRUDEINTEGRATOR_H_
#define OPENMM_DRUDEINTEGRATOR_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-2013 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 "openmm/Integrator.h"
#include "openmm/Kernel.h"
#include "openmm/internal/windowsExportDrude.h"
namespace OpenMM {
/**
* A base class to encapsulate features common to Drude integrators.
*/
class OPENMM_EXPORT_DRUDE DrudeIntegrator : public Integrator {
public:
/**
* Create a DrudeSCFIntegrator.
*
* @param stepSize the step size with which to integrator the system (in picoseconds)
*/
DrudeIntegrator(double stepSize) {};
/**
* Advance a simulation through time by taking a series of time steps.
*
* @param steps the number of time steps to take
*/
virtual void step(int steps) override {};
/**
* Get the temperature of the heat bath applied to internal coordinates of Drude particles (in Kelvin).
*
* @return the temperature of the heat bath, measured in Kelvin
*/
double getDrudeTemperature() const {
return drudeTemperature;
}
/**
* Set the temperature of the heat bath applied to internal coordinates of Drude particles (in Kelvin).
*
* @param temp the temperature of the heat bath, measured in Kelvin
*/
void setDrudeTemperature(double temp) {
drudeTemperature = temp;
}
/**
* Get the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
*/
double getMaxDrudeDistance() const;
/**
* Set the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
*/
void setMaxDrudeDistance(double distance);
/**
* 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.
*
* If seed is set to 0 (which is the default value assigned), a unique seed is chosen when a Context
* is created from this Force. This is done to ensure that each Context receives unique random seeds
* without you needing to set them explicitly.
*/
void setRandomNumberSeed(int seed) {
randomNumberSeed = seed;
}
/**
* Get the random number seed. See setRandomNumberSeed() for details.
*/
int getRandomNumberSeed() const {
return randomNumberSeed;
}
protected:
/**
* This will be called by the Context when it is created. It informs the Integrator
* of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the Context.
*/
virtual void initialize(ContextImpl& context) override {};
/**
* This will be called by the Context when it is destroyed to let the Integrator do any necessary
* cleanup. It will also get called again if the application calls reinitialize() on the Context.
*/
virtual void cleanup() override {};
/**
* Get the names of all Kernels used by this Integrator.
*/
virtual std::vector<std::string> getKernelNames() override { return std::vector<std::string>(); }
/**
* Compute the kinetic energy of the system at the current time.
*/
virtual double computeKineticEnergy() override { return 0; }
/**
* Return a list of velocities normally distributed around a target temperature, with the Drude
* temperatures assigned according to the Drude temperature assigned to the integrator.
*
* @param system the system whose velocities are to be initialized.
* @param temperature the target temperature in Kelvin.
* @param randomSeed the random number seed to use when selecting velocities
*/
virtual std::vector<Vec3> getVelocitiesForTemperature(const System &system, double temperature,
int randomSeed) const override;
int randomNumberSeed;
double drudeTemperature, maxDrudeDistance;
};
} // namespace OpenMM
#endif /*OPENMM_DRUDEINTEGRATOR_H_*/
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "openmm/Integrator.h" #include "openmm/DrudeIntegrator.h"
#include "openmm/Kernel.h" #include "openmm/Kernel.h"
#include "openmm/internal/windowsExportDrude.h" #include "openmm/internal/windowsExportDrude.h"
...@@ -53,7 +53,7 @@ namespace OpenMM { ...@@ -53,7 +53,7 @@ namespace OpenMM {
* particles. * particles.
*/ */
class OPENMM_EXPORT_DRUDE DrudeLangevinIntegrator : public Integrator { class OPENMM_EXPORT_DRUDE DrudeLangevinIntegrator : public DrudeIntegrator {
public: public:
/** /**
* Create a DrudeLangevinIntegrator. * Create a DrudeLangevinIntegrator.
...@@ -99,22 +99,6 @@ public: ...@@ -99,22 +99,6 @@ public:
void setFriction(double coeff) { void setFriction(double coeff) {
friction = coeff; friction = coeff;
} }
/**
* Get the temperature of the heat bath applied to internal coordinates of Drude particles (in Kelvin).
*
* @return the temperature of the heat bath, measured in Kelvin
*/
double getDrudeTemperature() const {
return drudeTemperature;
}
/**
* Set the temperature of the heat bath applied to internal coordinates of Drude particles (in Kelvin).
*
* @param temp the temperature of the heat bath, measured in Kelvin
*/
void setDrudeTemperature(double temp) {
drudeTemperature = temp;
}
/** /**
* Get the friction coefficient which determines how strongly the internal coordinates of Drude particles * Get the friction coefficient which determines how strongly the internal coordinates of Drude particles
* are coupled to the heat bath (in inverse ps). * are coupled to the heat bath (in inverse ps).
...@@ -133,70 +117,34 @@ public: ...@@ -133,70 +117,34 @@ public:
void setDrudeFriction(double coeff) { void setDrudeFriction(double coeff) {
drudeFriction = coeff; drudeFriction = coeff;
} }
/**
* Get the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
*/
double getMaxDrudeDistance() const;
/**
* Set the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
*/
void setMaxDrudeDistance(double distance);
/**
* 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.
*
* If seed is set to 0 (which is the default value assigned), a unique seed is chosen when a Context
* is created from this Force. This is done to ensure that each Context receives unique random seeds
* without you needing to set them explicitly.
*/
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.
* *
* @param steps the number of time steps to take * @param steps the number of time steps to take
*/ */
void step(int steps); void step(int steps) override;
protected: protected:
/** /**
* This will be called by the Context when it is created. It informs the Integrator * This will be called by the Context when it is created. It informs the Integrator
* of what context it will be integrating, and gives it a chance to do any necessary initialization. * of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the Context. * It will also get called again if the application calls reinitialize() on the Context.
*/ */
void initialize(ContextImpl& context); void initialize(ContextImpl& context) override;
/** /**
* This will be called by the Context when it is destroyed to let the Integrator do any necessary * This will be called by the Context when it is destroyed to let the Integrator do any necessary
* cleanup. It will also get called again if the application calls reinitialize() on the Context. * cleanup. It will also get called again if the application calls reinitialize() on the Context.
*/ */
void cleanup(); void cleanup() override;
/**
* When the user modifies the state, we need to mark that the forces need to be recalculated.
*/
void stateChanged(State::DataType changed);
/** /**
* Get the names of all Kernels used by this Integrator. * Get the names of all Kernels used by this Integrator.
*/ */
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames() override;
/** /**
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
*/ */
double computeKineticEnergy(); double computeKineticEnergy() override;
private: private:
double temperature, friction, drudeTemperature, drudeFriction, maxDrudeDistance; double temperature, friction, drudeFriction;
int randomNumberSeed;
Kernel kernel; Kernel kernel;
}; };
......
...@@ -74,7 +74,7 @@ public: ...@@ -74,7 +74,7 @@ public:
* of what context it will be integrating, and gives it a chance to do any necessary initialization. * of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the Context. * It will also get called again if the application calls reinitialize() on the Context.
*/ */
void initialize(ContextImpl& context); void initialize(ContextImpl& context) override;
/** /**
* Get the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented * Get the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted. * with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
...@@ -93,6 +93,18 @@ public: ...@@ -93,6 +93,18 @@ public:
* Compute the kinetic energy of all (real and drude) particles at the current time. * Compute the kinetic energy of all (real and drude) particles at the current time.
*/ */
double computeTotalKineticEnergy(); double computeTotalKineticEnergy();
/**
* Return a list of velocities normally distributed around a target temperature, with the Drude
* temperatures assigned according to the Drude temperature assigned to the integrator.
*
* @param system the system whose velocities are to be initialized.
* @param temperature the target temperature in Kelvin.
* @param randomSeed the random number seed to use when selecting velocities
*/
virtual std::vector<Vec3> getVelocitiesForTemperature(const System &system, double temperature,
int randomSeed) const override;
protected:
double drudeTemperature;
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "openmm/Integrator.h" #include "openmm/DrudeIntegrator.h"
#include "openmm/Kernel.h" #include "openmm/Kernel.h"
#include "openmm/internal/windowsExportDrude.h" #include "openmm/internal/windowsExportDrude.h"
...@@ -47,7 +47,7 @@ namespace OpenMM { ...@@ -47,7 +47,7 @@ namespace OpenMM {
* particles. * particles.
*/ */
class OPENMM_EXPORT_DRUDE DrudeSCFIntegrator : public Integrator { class OPENMM_EXPORT_DRUDE DrudeSCFIntegrator : public DrudeIntegrator {
public: public:
/** /**
* Create a DrudeSCFIntegrator. * Create a DrudeSCFIntegrator.
...@@ -78,31 +78,27 @@ public: ...@@ -78,31 +78,27 @@ public:
* *
* @param steps the number of time steps to take * @param steps the number of time steps to take
*/ */
void step(int steps); void step(int steps) override;
protected: protected:
/** /**
* This will be called by the Context when it is created. It informs the Integrator * This will be called by the Context when it is created. It informs the Integrator
* of what context it will be integrating, and gives it a chance to do any necessary initialization. * of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the Context. * It will also get called again if the application calls reinitialize() on the Context.
*/ */
void initialize(ContextImpl& context); void initialize(ContextImpl& context) override;
/** /**
* This will be called by the Context when it is destroyed to let the Integrator do any necessary * This will be called by the Context when it is destroyed to let the Integrator do any necessary
* cleanup. It will also get called again if the application calls reinitialize() on the Context. * cleanup. It will also get called again if the application calls reinitialize() on the Context.
*/ */
void cleanup(); void cleanup() override;
/**
* When the user modifies the state, we need to mark that the forces need to be recalculated.
*/
void stateChanged(State::DataType changed);
/** /**
* Get the names of all Kernels used by this Integrator. * Get the names of all Kernels used by this Integrator.
*/ */
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames() override;
/** /**
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
*/ */
double computeKineticEnergy(); double computeKineticEnergy() override;
private: private:
double tolerance; double tolerance;
Kernel kernel; Kernel kernel;
......
/* -------------------------------------------------------------------------- *
* 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-2015 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 "sfmt/SFMT.h"
#include "SimTKOpenMMRealType.h"
#include "openmm/DrudeForce.h"
#include "openmm/DrudeLangevinIntegrator.h"
#include "openmm/Context.h"
#include "openmm/System.h"
#include "openmm/OpenMMException.h"
#include <set>
namespace OpenMM {
std::vector<Vec3> assignDrudeVelocities(const System &system, double temperature, double drudeTemperature, int randomSeed) {
// Find the underlying Drude force object
const DrudeForce* drudeForce = NULL;
for (int i = 0; i < system.getNumForces(); i++)
if (dynamic_cast<const DrudeForce*>(&system.getForce(i)) != NULL) {
if (drudeForce == NULL)
drudeForce = dynamic_cast<const DrudeForce*>(&system.getForce(i));
else
throw OpenMMException("The System contains multiple DrudeForces");
}
if (drudeForce == NULL)
throw OpenMMException("The System does not contain a DrudeForce");
// Figure out which particles are individual and which are Drude pairs
std::set<int> particles;
std::vector<std::pair<int, int>> pairParticles;
for (int i = 0; i < system.getNumParticles(); i++) {
particles.insert(i);
}
for (int i = 0; i < drudeForce->getNumParticles(); i++) {
int p, p1, p2, p3, p4;
double charge, polarizability, aniso12, aniso34;
drudeForce->getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34);
particles.erase(p);
particles.erase(p1);
pairParticles.emplace_back(p, p1);
}
std::vector<int> normalParticles(particles.begin(), particles.end());
// Generate the list of Gaussian random numbers.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(randomSeed, sfmt);
std::vector<double> randoms;
while (randoms.size() < system.getNumParticles()*3) {
double x, y, r2;
do {
x = 2.0*genrand_real2(sfmt)-1.0;
y = 2.0*genrand_real2(sfmt)-1.0;
r2 = x*x + y*y;
} while (r2 >= 1.0 || r2 == 0.0);
double multiplier = sqrt((-2.0*std::log(r2))/r2);
randoms.push_back(x*multiplier);
randoms.push_back(y*multiplier);
}
// Assign the velocities.
std::vector<Vec3> velocities(system.getNumParticles(), Vec3());
int nextRandom = 0;
// First the indivitual atoms
for (const auto &atom : normalParticles ) {
double mass = system.getParticleMass(atom);
if (mass != 0) {
double velocityScale = sqrt(BOLTZ*temperature/mass);
velocities[atom] = Vec3(randoms[nextRandom++], randoms[nextRandom++], randoms[nextRandom++])*velocityScale;
}
}
// Now the particle-Drude pairs
for (const auto &pair : pairParticles ) {
const auto atom1 = pair.first;
const auto atom2 = pair.second;
double mass1 = system.getParticleMass(atom1);
double mass2 = system.getParticleMass(atom2);
if (mass1 != 0 && mass2 != 0) {
double invMass = 1.0 / (mass1 + mass2);
double redMass = mass1 * mass2 * invMass;
double fracM1 = mass1 * invMass;
double fracM2 = mass2 * invMass;
Vec3 comVelocity = Vec3(randoms[nextRandom++], randoms[nextRandom++], randoms[nextRandom++])*sqrt(BOLTZ*temperature*invMass);
Vec3 relVelocity = Vec3(randoms[nextRandom++], randoms[nextRandom++], randoms[nextRandom++])*sqrt(BOLTZ*drudeTemperature/redMass);
velocities[atom1] = comVelocity - fracM2 * relVelocity;
velocities[atom2] = comVelocity + fracM1 * relVelocity;
}
}
return velocities;
}
}
/* -------------------------------------------------------------------------- *
* 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-2015 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 "SimTKOpenMMRealType.h"
#include "openmm/DrudeForce.h"
#include "openmm/DrudeIntegrator.h"
#include "openmm/OpenMMException.h"
#include "openmm/System.h"
#include <set>
using namespace OpenMM;
namespace OpenMM {
extern std::vector<Vec3> assignDrudeVelocities(const System &system, double temperature, double drudeTemperature, int randomSeed);
}
std::vector<Vec3> DrudeIntegrator::getVelocitiesForTemperature(const System &system, double temperature, int randomSeedIn) const {
return assignDrudeVelocities(system, temperature, drudeTemperature, randomSeedIn);
}
double DrudeIntegrator::getMaxDrudeDistance() const {
return maxDrudeDistance;
}
void DrudeIntegrator::setMaxDrudeDistance(double distance) {
if (distance < 0)
throw OpenMMException("setMaxDrudeDistance: Distance cannot be negative");
maxDrudeDistance = distance;
}
...@@ -34,14 +34,16 @@ ...@@ -34,14 +34,16 @@
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/DrudeKernels.h" #include "openmm/DrudeKernels.h"
#include <cmath>
#include <ctime> #include <ctime>
#include <set>
#include <string> #include <string>
using namespace OpenMM; using namespace OpenMM;
using std::string; using std::string;
using std::vector; using std::vector;
DrudeLangevinIntegrator::DrudeLangevinIntegrator(double temperature, double frictionCoeff, double drudeTemperature, double drudeFrictionCoeff, double stepSize) { DrudeLangevinIntegrator::DrudeLangevinIntegrator(double temperature, double frictionCoeff, double drudeTemperature, double drudeFrictionCoeff, double stepSize) : DrudeIntegrator(stepSize) {
setTemperature(temperature); setTemperature(temperature);
setFriction(frictionCoeff); setFriction(frictionCoeff);
setDrudeTemperature(drudeTemperature); setDrudeTemperature(drudeTemperature);
...@@ -52,16 +54,6 @@ DrudeLangevinIntegrator::DrudeLangevinIntegrator(double temperature, double fric ...@@ -52,16 +54,6 @@ DrudeLangevinIntegrator::DrudeLangevinIntegrator(double temperature, double fric
setRandomNumberSeed(0); setRandomNumberSeed(0);
} }
double DrudeLangevinIntegrator::getMaxDrudeDistance() const {
return maxDrudeDistance;
}
void DrudeLangevinIntegrator::setMaxDrudeDistance(double distance) {
if (distance < 0)
throw OpenMMException("setMaxDrudeDistance: Distance cannot be negative");
maxDrudeDistance = distance;
}
void DrudeLangevinIntegrator::initialize(ContextImpl& contextRef) { void DrudeLangevinIntegrator::initialize(ContextImpl& contextRef) {
if (owner != NULL && &contextRef.getOwner() != owner) if (owner != NULL && &contextRef.getOwner() != owner)
throw OpenMMException("This Integrator is already bound to a context"); throw OpenMMException("This Integrator is already bound to a context");
...@@ -86,9 +78,6 @@ void DrudeLangevinIntegrator::cleanup() { ...@@ -86,9 +78,6 @@ void DrudeLangevinIntegrator::cleanup() {
kernel = Kernel(); kernel = Kernel();
} }
void DrudeLangevinIntegrator::stateChanged(State::DataType changed) {
}
vector<string> DrudeLangevinIntegrator::getKernelNames() { vector<string> DrudeLangevinIntegrator::getKernelNames() {
std::vector<std::string> names; std::vector<std::string> names;
names.push_back(IntegrateDrudeLangevinStepKernel::Name()); names.push_back(IntegrateDrudeLangevinStepKernel::Name());
......
...@@ -46,11 +46,16 @@ using namespace OpenMM; ...@@ -46,11 +46,16 @@ using namespace OpenMM;
using std::string; using std::string;
using std::vector; using std::vector;
namespace OpenMM {
extern std::vector<Vec3> assignDrudeVelocities(const System &system, double temperature, double drudeTemperature, int randomSeed);
}
DrudeNoseHooverIntegrator::DrudeNoseHooverIntegrator(double temperature, double collisionFrequency, DrudeNoseHooverIntegrator::DrudeNoseHooverIntegrator(double temperature, double collisionFrequency,
double drudeTemperature, double drudeCollisionFrequency, double drudeTemperature, double drudeCollisionFrequency,
double stepSize, int chainLength, int numMTS, int numYoshidaSuzuki) : double stepSize, int chainLength, int numMTS, int numYoshidaSuzuki) :
NoseHooverIntegrator(stepSize) { NoseHooverIntegrator(stepSize),
drudeTemperature(drudeTemperature)
{
setMaxDrudeDistance(0); setMaxDrudeDistance(0);
hasSubsystemThermostats_ = false; hasSubsystemThermostats_ = false;
addSubsystemThermostat(std::vector<int>(), std::vector<std::pair<int, int>>(), temperature, addSubsystemThermostat(std::vector<int>(), std::vector<std::pair<int, int>>(), temperature,
...@@ -143,3 +148,8 @@ double DrudeNoseHooverIntegrator::computeTotalKineticEnergy() { ...@@ -143,3 +148,8 @@ double DrudeNoseHooverIntegrator::computeTotalKineticEnergy() {
return vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this); return vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this);
} }
std::vector<Vec3> DrudeNoseHooverIntegrator::getVelocitiesForTemperature(const System &system, double temperature,
int randomSeedIn) const {
return assignDrudeVelocities(system, temperature, drudeTemperature, randomSeedIn);
}
...@@ -42,7 +42,9 @@ using namespace OpenMM; ...@@ -42,7 +42,9 @@ using namespace OpenMM;
using std::string; using std::string;
using std::vector; using std::vector;
DrudeSCFIntegrator::DrudeSCFIntegrator(double stepSize) { DrudeSCFIntegrator::DrudeSCFIntegrator(double stepSize) : DrudeIntegrator(stepSize)
{
setDrudeTemperature(0.0); // This is only used to initialize velocities for this integrator
setStepSize(stepSize); setStepSize(stepSize);
setMinimizationErrorTolerance(0.1); setMinimizationErrorTolerance(0.1);
setConstraintTolerance(1e-5); setConstraintTolerance(1e-5);
...@@ -72,9 +74,6 @@ void DrudeSCFIntegrator::cleanup() { ...@@ -72,9 +74,6 @@ void DrudeSCFIntegrator::cleanup() {
kernel = Kernel(); kernel = Kernel();
} }
void DrudeSCFIntegrator::stateChanged(State::DataType changed) {
}
vector<string> DrudeSCFIntegrator::getKernelNames() { vector<string> DrudeSCFIntegrator::getKernelNames() {
std::vector<std::string> names; std::vector<std::string> names;
names.push_back(IntegrateDrudeSCFStepKernel::Name()); names.push_back(IntegrateDrudeSCFStepKernel::Name());
......
...@@ -6,6 +6,7 @@ ENABLE_TESTING() ...@@ -6,6 +6,7 @@ ENABLE_TESTING()
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests) INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/cuda/tests)
# Automatically create tests using files named "Test*.cpp" # Automatically create tests using files named "Test*.cpp"
FILE(GLOB TEST_PROGS "*Test*.cpp") FILE(GLOB TEST_PROGS "*Test*.cpp")
......
/* -------------------------------------------------------------------------- *
* 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) 2013 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 "CudaTests.h"
extern "C" void registerDrudeCudaKernelFactories();
using namespace OpenMM;
void setupKernels (int argc, char* argv[]) {
registerDrudeCudaKernelFactories();
platform = dynamic_cast<CudaPlatform&>(Platform::getPlatformByName("CUDA"));
initializeTests(argc, argv);
}
...@@ -29,185 +29,7 @@ ...@@ -29,185 +29,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
/** #include "CudaDrudeTests.h"
* This tests the CUDA implementation of DrudeForce. #include "TestDrudeForce.h"
*/
#include "openmm/internal/AssertionUtilities.h" void runPlatformTests() {}
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/DrudeForce.h"
#include "SimTKOpenMMUtilities.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" void registerDrudeCudaKernelFactories();
void validateForce(System& system, vector<Vec3>& positions, double expectedEnergy) {
// Given a System containing a Drude force, check that its energy has the expected value.
VerletIntegrator integ(1.0);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
context.setPositions(positions);
State state = context.getState(State::Energy | State::Forces);
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5);
// Try moving each particle along each axis, and see if the energy changes by the correct amount.
double offset = 1e-2;
for (int i = 0; i < system.getNumParticles(); i++)
for (int j = 0; j < 3; j++) {
vector<Vec3> offsetPos = positions;
offsetPos[i][j] = positions[i][j]-offset;
context.setPositions(offsetPos);
double e1 = context.getState(State::Energy | State::Forces).getPotentialEnergy();
offsetPos[i][j] = positions[i][j]+offset;
context.setPositions(offsetPos);
double e2 = context.getState(State::Energy | State::Forces).getPotentialEnergy();
ASSERT_EQUAL_TOL(state.getForces()[i][j], (e1-e2)/(2*offset), 1e-3);
}
}
void testSingleParticle() {
const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1;
const double alpha = ONE_4PI_EPS0*charge*charge/k;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
DrudeForce* drude = new DrudeForce();
drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1);
system.addForce(drude);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(2, 0, 0);
validateForce(system, positions, 0.5*k*3*3);
}
void testAnisotropicParticle() {
const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1;
const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double a1 = 0.8;
const double a2 = 1.1;
const double k1 = k/a1;
const double k2 = k/a2;
const double k3 = k/(3-a1-a2);
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
DrudeForce* drude = new DrudeForce();
drude->addParticle(1, 0, 2, 3, 4, charge, alpha, a1, a2);
system.addForce(drude);
vector<Vec3> positions(5);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0.1, -0.5, 0.8);
positions[2] = Vec3(0, 2, 0);
positions[3] = Vec3(1, 2, 0);
positions[4] = Vec3(1, 2, 3);
validateForce(system, positions, 0.5*k1*0.5*0.5 + 0.5*k2*0.8*0.8 + 0.5*k3*0.1*0.1);
}
double computeScreening(double r, double thole, double alpha1, double alpha2) {
double u = r*thole/pow(alpha1*alpha2, 1.0/6.0);
return 1.0-(1.0+u/2)*exp(-u);
}
void testThole() {
const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1;
const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double thole = 2.5;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
DrudeForce* drude = new DrudeForce();
drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1);
drude->addParticle(3, 2, -1, -1, -1, charge, alpha, 1, 1);
drude->addScreenedPair(0, 1, thole);
system.addForce(drude);
vector<Vec3> positions(4);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, -0.5, 0);
positions[2] = Vec3(1, 0, 0);
positions[3] = Vec3(1, 0, 0.3);
double energySpring1 = 0.5*k*0.5*0.5;
double energySpring2 = 0.5*k*0.3*0.3;
double energyDipole = 0.0;
double q[] = {-charge, charge, -charge, charge};
for (int i = 0; i < 2; i++)
for (int j = 2; j < 4; j++) {
Vec3 delta = positions[i]-positions[j];
double r = sqrt(delta.dot(delta));
energyDipole += ONE_4PI_EPS0*q[i]*q[j]*computeScreening(r, thole, alpha, alpha)/r;
}
validateForce(system, positions, energySpring1+energySpring2+energyDipole);
}
void testChangingParameters() {
const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1;
const double alpha = ONE_4PI_EPS0*charge*charge/k;
Platform& platform = Platform::getPlatformByName("CUDA");
// Create the system.
System system;
system.addParticle(1.0);
system.addParticle(1.0);
DrudeForce* drude = new DrudeForce();
drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1);
system.addForce(drude);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(2, 0, 0);
// Check the energy.
VerletIntegrator integ(1.0);
Context context(system, integ, platform);
context.setPositions(positions);
State state = context.getState(State::Energy);
ASSERT_EQUAL_TOL(0.5*k*3*3, state.getPotentialEnergy(), 1e-5);
// Modify the parameters.
const double k2 = ONE_4PI_EPS0*2.2;
const double charge2 = 0.3;
const double alpha2 = ONE_4PI_EPS0*charge2*charge2/k2;
drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1);
drude->updateParametersInContext(context);
state = context.getState(State::Energy);
ASSERT_EQUAL_TOL(0.5*k2*3*3, state.getPotentialEnergy(), 1e-5);
}
int main(int argc, char* argv[]) {
try {
registerDrudeCudaKernelFactories();
if (argc > 1)
Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", std::string(argv[1]));
testSingleParticle();
testAnisotropicParticle();
testThole();
testChangingParameters();
}
catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl;
std::cout << "FAIL - ERROR. Test failed." << std::endl;
return 1;
}
std::cout << "Done" << std::endl;
return 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) 2013-2016 Stanford University and the Authors. * * Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -29,230 +29,7 @@ ...@@ -29,230 +29,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
/** #include "CudaDrudeTests.h"
* This tests the CUDA implementation of DrudeLangevinIntegrator. #include "TestDrudeLangevinIntegrator.h"
*/
#include "openmm/internal/AssertionUtilities.h" void runPlatformTests() {}
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/VirtualSite.h"
#include "openmm/DrudeForce.h"
#include "openmm/DrudeLangevinIntegrator.h"
#include "SimTKOpenMMUtilities.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeCudaKernelFactories();
void testSinglePair() {
const double temperature = 300.0;
const double temperatureDrude = 10.0;
const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1;
const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double mass1 = 1.0;
const double mass2 = 0.1;
const double totalMass = mass1+mass2;
const double reducedMass = (mass1*mass2)/(mass1+mass2);
const double maxDistance = 0.05;
System system;
system.addParticle(mass1);
system.addParticle(mass2);
DrudeForce* drude = new DrudeForce();
drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1);
system.addForce(drude);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 0, 0);
DrudeLangevinIntegrator integ(temperature, 20.0, temperatureDrude, 20.0, 0.003);
integ.setMaxDrudeDistance(maxDistance);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
context.setPositions(positions);
// Equilibrate.
integ.step(1000);
// Compute the internal and center of mass temperatures.
double keCM = 0, keInternal = 0;
int numSteps = 10000;
for (int i = 0; i < numSteps; i++) {
integ.step(10);
State state = context.getState(State::Velocities | State::Positions);
const vector<Vec3>& vel = state.getVelocities();
Vec3 velCM = vel[0]*(mass1/totalMass) + vel[1]*(mass2/totalMass);
keCM += 0.5*totalMass*velCM.dot(velCM);
Vec3 velInternal = vel[0]-vel[1];
keInternal += 0.5*reducedMass*velInternal.dot(velInternal);
Vec3 delta = state.getPositions()[0]-state.getPositions()[1];
double distance = sqrt(delta.dot(delta));
ASSERT(distance <= maxDistance*(1+1e-6));
}
ASSERT_USUALLY_EQUAL_TOL(3*0.5*BOLTZ*temperature, keCM/numSteps, 0.1);
ASSERT_USUALLY_EQUAL_TOL(3*0.5*BOLTZ*temperatureDrude, keInternal/numSteps, 0.01);
}
void testWater() {
// Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites,
// and Drude particles.
const int gridSize = 4;
const int numMolecules = gridSize*gridSize*gridSize;
const double spacing = 0.6;
const double boxSize = spacing*(gridSize+1);
const double temperature = 300.0;
const double temperatureDrude = 10.0;
System system;
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nonbonded->setCutoffDistance(1.0);
for (int i = 0; i < numMolecules; i++) {
int startIndex = system.getNumParticles();
system.addParticle(15.6); // O
system.addParticle(0.4); // D
system.addParticle(1.0); // H1
system.addParticle(1.0); // H2
system.addParticle(0.0); // M
nonbonded->addParticle(1.71636, 0.318395, 0.21094*4.184);
nonbonded->addParticle(-1.71636, 1, 0);
nonbonded->addParticle(0.55733, 1, 0);
nonbonded->addParticle(0.55733, 1, 0);
nonbonded->addParticle(-1.11466, 1, 0);
for (int j = 0; j < 5; j++)
for (int k = 0; k < j; k++)
nonbonded->addException(startIndex+j, startIndex+k, 0, 1, 0);
system.addConstraint(startIndex, startIndex+2, 0.09572);
system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
}
vector<Vec3> positions;
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
positions.push_back(pos+Vec3(0.09572, 0, 0));
positions.push_back(pos+Vec3(-0.023999, 0.092663, 0));
positions.push_back(pos);
}
// Simulate it and check the temperature.
DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.0005);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
context.setPositions(positions);
context.applyConstraints(1e-5);
// Equilibrate.
integ.step(1000);
// Compute the internal and center of mass temperatures.
double ke = 0;
int numSteps = 10000;
for (int i = 0; i < numSteps; i++) {
integ.step(1);
ke += context.getState(State::Energy).getKineticEnergy();
}
ke /= numSteps;
int numStandardDof = 3*3*numMolecules-system.getNumConstraints();
int numDrudeDof = 3*numMolecules;
int numDof = numStandardDof+numDrudeDof;
double expectedTemp = (numStandardDof*temperature+numDrudeDof*temperatureDrude)/numDof;
ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.02);
}
void testForceEnergyConsistency() {
// Create a box of polarizable particles.
const int gridSize = 3;
const int numAtoms = gridSize*gridSize*gridSize;
const double spacing = 0.6;
const double boxSize = spacing*(gridSize+1);
const double temperature = 300.0;
const double temperatureDrude = 10.0;
System system;
vector<Vec3> positions;
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::PME);
nonbonded->setCutoffDistance(1.0);
nonbonded->setUseSwitchingFunction(true);
nonbonded->setSwitchingDistance(0.9);
nonbonded->setEwaldErrorTolerance(5e-5);
for (int i = 0; i < numAtoms; i++) {
int startIndex = system.getNumParticles();
system.addParticle(1.0);
system.addParticle(1.0);
nonbonded->addParticle(1.0, 0.3, 1.0);
nonbonded->addParticle(-1.0, 0.3, 1.0);
nonbonded->addException(startIndex, startIndex+1, 0, 1, 0);
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.0, 0.001, 1, 1);
}
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
}
// Simulate it and check that force and energy remain consistent.
DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.001);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
context.setPositions(positions);
State prevState;
for (int i = 0; i < 100; i++) {
State state = context.getState(State::Energy | State::Forces | State::Positions);
if (i > 0) {
double expectedEnergyChange = 0;
for (int j = 0; j < system.getNumParticles(); j++) {
Vec3 delta = state.getPositions()[j]-prevState.getPositions()[j];
expectedEnergyChange -= 0.5*(state.getForces()[j]+prevState.getForces()[j]).dot(delta);
}
ASSERT_EQUAL_TOL(expectedEnergyChange, state.getPotentialEnergy()-prevState.getPotentialEnergy(), 0.05);
}
prevState = state;
integ.step(1);
}
}
int main(int argc, char* argv[]) {
try {
registerDrudeCudaKernelFactories();
if (argc > 1)
Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", string(argv[1]));
testSinglePair();
testWater();
testForceEnergyConsistency();
}
catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl;
std::cout << "FAIL - ERROR. Test failed." << std::endl;
return 1;
}
std::cout << "Done" << std::endl;
return 0;
}
...@@ -29,33 +29,7 @@ ...@@ -29,33 +29,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
//#include "ReferenceTests.h" #include "CudaDrudeTests.h"
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/DrudeForce.h"
#include "CudaPlatform.h"
#include "SimTKOpenMMUtilities.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeCudaKernelFactories();
void runPlatformTests() { }
#include "TestDrudeNoseHoover.h" #include "TestDrudeNoseHoover.h"
Platform& initializePlatform(int argc, char* argv[]) { void runPlatformTests() {}
registerDrudeCudaKernelFactories();
if (argc > 1) Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", std::string(argv[1]));
return Platform::getPlatformByName("CUDA");
}
...@@ -29,116 +29,7 @@ ...@@ -29,116 +29,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
/** #include "CudaDrudeTests.h"
* This tests the CUDA implementation of DrudeSCFIntegrator. #include "TestDrudeSCFIntegrator.h"
*/
#include "openmm/internal/AssertionUtilities.h" void runPlatformTests() {}
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/VirtualSite.h"
#include "openmm/DrudeForce.h"
#include "openmm/DrudeSCFIntegrator.h"
#include "SimTKOpenMMUtilities.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeCudaKernelFactories();
void testWater() {
// Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites,
// and Drude particles.
const int gridSize = 4;
const int numMolecules = gridSize*gridSize*gridSize;
const double spacing = 0.6;
const double boxSize = spacing*(gridSize+1);
System system;
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nonbonded->setCutoffDistance(1.0);
for (int i = 0; i < numMolecules; i++) {
int startIndex = system.getNumParticles();
system.addParticle(15.6); // O
system.addParticle(0.4); // D
system.addParticle(1.0); // H1
system.addParticle(1.0); // H2
system.addParticle(0.0); // M
nonbonded->addParticle(1.71636, 0.318395, 0.21094*4.184);
nonbonded->addParticle(-1.71636, 1, 0);
nonbonded->addParticle(0.55733, 1, 0);
nonbonded->addParticle(0.55733, 1, 0);
nonbonded->addParticle(-1.11466, 1, 0);
for (int j = 0; j < 5; j++)
for (int k = 0; k < j; k++)
nonbonded->addException(startIndex+j, startIndex+k, 0, 1, 0);
system.addConstraint(startIndex, startIndex+2, 0.09572);
system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
}
vector<Vec3> positions;
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
positions.push_back(pos+Vec3(0.09572, 0, 0));
positions.push_back(pos+Vec3(-0.023999, 0.092663, 0));
positions.push_back(pos);
}
// Simulate it and check energy conservation and the total force on the Drude particles.
DrudeSCFIntegrator integ(0.0005);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
context.setPositions(positions);
context.applyConstraints(1e-5);
context.setVelocitiesToTemperature(300.0);
State state = context.getState(State::Energy);
double initialEnergy;
int numSteps = 1000;
double maxNorm = (platform.getPropertyValue(context, "Precision") == "double" ? 1.0 : 5.0);
for (int i = 0; i < numSteps; i++) {
integ.step(1);
state = context.getState(State::Energy | State::Forces);
if (i == 0)
initialEnergy = state.getPotentialEnergy()+state.getKineticEnergy();
else
ASSERT_EQUAL_TOL(initialEnergy, state.getPotentialEnergy()+state.getKineticEnergy(), 0.01);
const vector<Vec3>& force = state.getForces();
double norm = 0.0;
for (int j = 1; j < (int) force.size(); j += 5)
norm += sqrt(force[j].dot(force[j]));
norm = (norm/numMolecules);
ASSERT(norm < maxNorm);
}
}
int main(int argc, char* argv[]) {
try {
registerDrudeCudaKernelFactories();
if (argc > 1)
Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", string(argv[1]));
testWater();
}
catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl;
std::cout << "FAIL - ERROR. Test failed." << std::endl;
return 1;
}
std::cout << "Done" << std::endl;
return 0;
}
...@@ -6,6 +6,7 @@ ENABLE_TESTING() ...@@ -6,6 +6,7 @@ ENABLE_TESTING()
INCLUDE_DIRECTORIES(${OPENCL_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${OPENCL_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests) INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/opencl/tests)
# Automatically create tests using files named "Test*.cpp" # Automatically create tests using files named "Test*.cpp"
FILE(GLOB TEST_PROGS "*Test*.cpp") FILE(GLOB TEST_PROGS "*Test*.cpp")
......
/* -------------------------------------------------------------------------- *
* 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) 2013 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 "OpenCLTests.h"
extern "C" void registerDrudeOpenCLKernelFactories();
using namespace OpenMM;
void setupKernels (int argc, char* argv[]) {
registerDrudeOpenCLKernelFactories();
platform = dynamic_cast<OpenCLPlatform&>(Platform::getPlatformByName("OpenCL"));
initializeTests(argc, argv);
}
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