Unverified Commit f5df1076 authored by Andy Simmonett's avatar Andy Simmonett
Browse files

Add Drude Nose-Hoover capability, with tests

parent 182f7f15
...@@ -1365,8 +1365,9 @@ public: ...@@ -1365,8 +1365,9 @@ public:
* *
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined. * @param noseHooverChain the chain whose energy is to be determined.
* @param downloadValue whether the computed value should be downloaded and returned.
*/ */
virtual double computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain) = 0; virtual double computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain, bool downloadValue) = 0;
/** /**
* Execute the kernel that scales the velocities of particles associated with a nose hoover chain * Execute the kernel that scales the velocities of particles associated with a nose hoover chain
* *
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "Integrator.h" #include "Integrator.h"
#include "openmm/State.h"
#include "openmm/Kernel.h" #include "openmm/Kernel.h"
#include "openmm/NoseHooverChain.h" #include "openmm/NoseHooverChain.h"
#include "internal/windowsExport.h" #include "internal/windowsExport.h"
...@@ -174,10 +175,10 @@ protected: ...@@ -174,10 +175,10 @@ protected:
/** /**
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
*/ */
double computeKineticEnergy(); virtual double computeKineticEnergy();
std::vector<NoseHooverChain> noseHooverChains; std::vector<NoseHooverChain> noseHooverChains;
bool forcesAreValid; bool forcesAreValid;
private:
Kernel vvKernel, nhcKernel; Kernel vvKernel, nhcKernel;
}; };
......
...@@ -38,9 +38,9 @@ ...@@ -38,9 +38,9 @@
#include "openmm/CMMotionRemover.h" #include "openmm/CMMotionRemover.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/kernels.h" #include "openmm/kernels.h"
#include <iostream>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <iostream>
using namespace OpenMM; using namespace OpenMM;
using std::string; using std::string;
...@@ -95,8 +95,8 @@ int VelocityVerletIntegrator::addMaskedNoseHooverChainThermostat(System& system, ...@@ -95,8 +95,8 @@ int VelocityVerletIntegrator::addMaskedNoseHooverChainThermostat(System& system,
int particle1, particle2; int particle1, particle2;
double distance; double distance;
system.getConstraintParameters(constraintNum, particle1, particle2, distance); system.getConstraintParameters(constraintNum, particle1, particle2, distance);
bool particle1_in_mask = (std::find(mask.begin(), mask.end(), particle1) == mask.end()); bool particle1_in_mask = (std::find(mask.begin(), mask.end(), particle1) != mask.end());
bool particle2_in_mask = (std::find(mask.begin(), mask.end(), particle2) == mask.end()); bool particle2_in_mask = (std::find(mask.begin(), mask.end(), particle2) != mask.end());
if ((system.getParticleMass(particle1) > 0) && (system.getParticleMass(particle2) > 0)){ if ((system.getParticleMass(particle1) > 0) && (system.getParticleMass(particle2) > 0)){
if ((particle1_in_mask && !particle2_in_mask) || (!particle1_in_mask && particle2_in_mask)){ if ((particle1_in_mask && !particle2_in_mask) || (!particle1_in_mask && particle2_in_mask)){
throw OpenMMException("Cannot add only one of particles " + std::to_string(particle1) + " and " + std::to_string(particle2) throw OpenMMException("Cannot add only one of particles " + std::to_string(particle1) + " and " + std::to_string(particle2)
...@@ -173,8 +173,17 @@ void VelocityVerletIntegrator::setCollisionFrequency(double frequency, int chain ...@@ -173,8 +173,17 @@ void VelocityVerletIntegrator::setCollisionFrequency(double frequency, int chain
} }
double VelocityVerletIntegrator::computeKineticEnergy() { double VelocityVerletIntegrator::computeKineticEnergy() {
return vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this); double kE = 0.0;
if(noseHooverChains.size()) {
for (const auto &nhc: noseHooverChains){
if (nhc.getParentAtoms().size() == 0) {
kE += nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc, true);
}
}
} else {
kE = vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this);
}
return kE;
} }
double VelocityVerletIntegrator::computeHeatBathEnergy() { double VelocityVerletIntegrator::computeHeatBathEnergy() {
...@@ -216,13 +225,13 @@ void VelocityVerletIntegrator::step(int steps) { ...@@ -216,13 +225,13 @@ void VelocityVerletIntegrator::step(int steps) {
for (int i = 0; i < steps; ++i) { for (int i = 0; i < steps; ++i) {
context->updateContextState(); context->updateContextState();
for(auto &nhc : noseHooverChains) { for(auto &nhc : noseHooverChains) {
kineticEnergy = nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc); kineticEnergy = nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc, false);
scale = nhcKernel.getAs<NoseHooverChainKernel>().propagateChain(*context, nhc, kineticEnergy, getStepSize()); scale = nhcKernel.getAs<NoseHooverChainKernel>().propagateChain(*context, nhc, kineticEnergy, getStepSize());
nhcKernel.getAs<NoseHooverChainKernel>().scaleVelocities(*context, nhc, scale); nhcKernel.getAs<NoseHooverChainKernel>().scaleVelocities(*context, nhc, scale);
} }
vvKernel.getAs<IntegrateVelocityVerletStepKernel>().execute(*context, *this, forcesAreValid); vvKernel.getAs<IntegrateVelocityVerletStepKernel>().execute(*context, *this, forcesAreValid);
for(auto &nhc : noseHooverChains) { for(auto &nhc : noseHooverChains) {
kineticEnergy = nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc); kineticEnergy = nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc, false);
scale = nhcKernel.getAs<NoseHooverChainKernel>().propagateChain(*context, nhc, kineticEnergy, getStepSize()); scale = nhcKernel.getAs<NoseHooverChainKernel>().propagateChain(*context, nhc, kineticEnergy, getStepSize());
nhcKernel.getAs<NoseHooverChainKernel>().scaleVelocities(*context, nhc, scale); nhcKernel.getAs<NoseHooverChainKernel>().scaleVelocities(*context, nhc, scale);
} }
......
...@@ -71,10 +71,6 @@ public: ...@@ -71,10 +71,6 @@ public:
* @param name the name of the array * @param name the name of the array
*/ */
CudaArray(CudaContext& context, int size, int elementSize, const std::string& name); CudaArray(CudaContext& context, int size, int elementSize, const std::string& name);
CudaArray(const CudaArray &other) noexcept;
CudaArray& operator=(CudaArray &&other) noexcept;
CudaArray& operator=(const CudaArray& other) noexcept;
CudaArray(CudaArray &&other) noexcept ;
~CudaArray(); ~CudaArray();
/** /**
* Initialize this object. * Initialize this object.
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "openmm/System.h" #include "openmm/System.h"
#include "CudaContext.h" #include "CudaContext.h"
#include "windowsExportCuda.h" #include "windowsExportCuda.h"
#include <map>
#include <iosfwd> #include <iosfwd>
namespace OpenMM { namespace OpenMM {
...@@ -125,7 +126,7 @@ public: ...@@ -125,7 +126,7 @@ public:
* *
* @return vector of chain states * @return vector of chain states
*/ */
std::vector<CudaArray>& getNoseHooverChainState(); std::map<int, CudaArray>& getNoseHooverChainState();
private: private:
void applyConstraints(bool constrainVelocities, double tol); void applyConstraints(bool constrainVelocities, double tol);
CudaContext& context; CudaContext& context;
...@@ -174,7 +175,7 @@ private: ...@@ -174,7 +175,7 @@ private:
double2 lastStepSize; double2 lastStepSize;
struct ShakeCluster; struct ShakeCluster;
struct ConstraintOrderer; struct ConstraintOrderer;
std::vector<CudaArray> noseHooverChainState; std::map<int, CudaArray> noseHooverChainState;
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -1750,8 +1750,10 @@ public: ...@@ -1750,8 +1750,10 @@ public:
* *
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined. * @param noseHooverChain the chain whose energy is to be determined.
* @param downloadValue whether the computed value should be downloaded and returned.
*
*/ */
virtual double computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain); virtual double computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain, bool downloadValue);
/** /**
* Execute the kernel that scales the velocities of particles associated with a nose hoover chain * Execute the kernel that scales the velocities of particles associated with a nose hoover chain
...@@ -1765,13 +1767,12 @@ public: ...@@ -1765,13 +1767,12 @@ public:
private: private:
CudaContext& cu; CudaContext& cu;
CudaArray scaleFactorBuffer, kineticEnergyBuffer, chainMasses, chainForces, heatBathEnergy; CudaArray scaleFactorBuffer, kineticEnergyBuffer, chainMasses, chainForces, heatBathEnergy;
std::vector<CudaArray> masks; std::map<int, CudaArray> masks;
std::map<int, CUfunction> propagateKernels; std::map<int, CUfunction> propagateKernels;
CUfunction reduceEnergyKernel; CUfunction reduceEnergyKernel;
CUfunction computeHeatBathEnergyKernel; CUfunction computeHeatBathEnergyKernel;
CUfunction computeMaskedKineticEnergyKernel; CUfunction computeMaskedKineticEnergyKernel;
CUfunction scaleVelocitiesKernel; CUfunction scaleVelocitiesKernel;
CUfunction zeroEnergyBuffersKernel;
}; };
/** /**
......
...@@ -35,47 +35,6 @@ using namespace OpenMM; ...@@ -35,47 +35,6 @@ using namespace OpenMM;
CudaArray::CudaArray() : pointer(0), ownsMemory(false) { CudaArray::CudaArray() : pointer(0), ownsMemory(false) {
} }
CudaArray::CudaArray(const CudaArray &other) noexcept {
context = other.context;
pointer = other.pointer;
size = other.size;
elementSize = other.elementSize;
ownsMemory = false;
name = other.name;
}
CudaArray::CudaArray(CudaArray &&other) noexcept :
context(std::move(other.context)),
pointer(std::move(other.pointer)),
size(std::move(other.size)),
elementSize(std::move(other.elementSize)),
ownsMemory(false),
name(std::move(other.name)) { }
CudaArray& CudaArray::operator =(const CudaArray& other) noexcept{
if(this != &other) {
context = other.context;
pointer = other.pointer;
size = other.size;
elementSize = other.elementSize;
ownsMemory = false;
name = other.name;
}
return *this;
}
CudaArray& CudaArray::operator =(CudaArray &&other) noexcept{
if(this != &other) {
context = other.context;
pointer = other.pointer;
size = other.size;
elementSize = other.elementSize;
ownsMemory = false;
name = other.name;
}
return *this;
}
CudaArray::CudaArray(CudaContext& context, int size, int elementSize, const std::string& name) : pointer(0) { CudaArray::CudaArray(CudaContext& context, int size, int elementSize, const std::string& name) : pointer(0) {
initialize(context, size, elementSize, name); initialize(context, size, elementSize, name);
} }
......
...@@ -707,6 +707,24 @@ int CudaIntegrationUtilities::prepareRandomNumbers(int numValues) { ...@@ -707,6 +707,24 @@ int CudaIntegrationUtilities::prepareRandomNumbers(int numValues) {
} }
void CudaIntegrationUtilities::createCheckpoint(ostream& stream) { void CudaIntegrationUtilities::createCheckpoint(ostream& stream) {
size_t numChains = noseHooverChainState.size();
bool useDouble = context.getUseDoublePrecision() || context.getUseMixedPrecision();
stream.write((char*) &numChains, sizeof(size_t));
for (auto &chainState: noseHooverChainState){
int chainID = chainState.first;
size_t chainLength = chainState.second.getSize();
stream.write((char*) &chainID, sizeof(int));
stream.write((char*) &chainLength, sizeof(size_t));
if (useDouble) {
vector<double2> stateVec;
chainState.second.download(stateVec);
stream.write((char*) stateVec.data(), sizeof(double2)*chainLength);
} else {
vector<float2> stateVec;
chainState.second.download(stateVec);
stream.write((char*) stateVec.data(), sizeof(float2)*chainLength);
}
}
if (!random.isInitialized()) if (!random.isInitialized())
return; return;
stream.write((char*) &randomPos, sizeof(int)); stream.write((char*) &randomPos, sizeof(int));
...@@ -716,18 +734,31 @@ void CudaIntegrationUtilities::createCheckpoint(ostream& stream) { ...@@ -716,18 +734,31 @@ void CudaIntegrationUtilities::createCheckpoint(ostream& stream) {
vector<int4> randomSeedVec; vector<int4> randomSeedVec;
randomSeed.download(randomSeedVec); randomSeed.download(randomSeedVec);
stream.write((char*) &randomSeedVec[0], sizeof(int4)*randomSeed.getSize()); stream.write((char*) &randomSeedVec[0], sizeof(int4)*randomSeed.getSize());
size_t numChains = noseHooverChainState.size();
stream.write((char*) &numChains, sizeof(size_t));
for (auto &chainState: noseHooverChainState){
vector<float2> stateVec;
chainState.download(stateVec);
size_t vecLength = stateVec.size();
stream.write((char*) &vecLength, sizeof(size_t));
stream.write((char*) stateVec.data(), sizeof(float2)*stateVec.size());
}
} }
void CudaIntegrationUtilities::loadCheckpoint(istream& stream) { void CudaIntegrationUtilities::loadCheckpoint(istream& stream) {
size_t numChains, chainLength;
bool useDouble = context.getUseDoublePrecision() || context.getUseMixedPrecision();
stream.read((char*) &numChains, sizeof(size_t));
noseHooverChainState.clear();
for (size_t i=0; i<numChains; i++){
int chainID;
stream.read((char*) &chainID, sizeof(int));
stream.read((char*) &chainLength, sizeof(size_t));
if (useDouble) {
noseHooverChainState[chainID] = CudaArray();
noseHooverChainState[chainID].initialize<double2>(context, chainLength, "chainState" + std::to_string(chainID));
std::vector<double2> stateVec(chainLength);
stream.read((char*) &stateVec[0], sizeof(double2)*chainLength);
noseHooverChainState[chainID].upload(stateVec);
} else {
noseHooverChainState[chainID] = CudaArray();
noseHooverChainState[chainID].initialize<float2>(context, chainLength, "chainState" + std::to_string(chainID));
std::vector<float2> stateVec(chainLength);
stream.read((char*) &stateVec[0], sizeof(float2)*chainLength);
noseHooverChainState[chainID].upload(stateVec);
}
}
if (!random.isInitialized()) if (!random.isInitialized())
return; return;
stream.read((char*) &randomPos, sizeof(int)); stream.read((char*) &randomPos, sizeof(int));
...@@ -737,17 +768,6 @@ void CudaIntegrationUtilities::loadCheckpoint(istream& stream) { ...@@ -737,17 +768,6 @@ void CudaIntegrationUtilities::loadCheckpoint(istream& stream) {
vector<int4> randomSeedVec(randomSeed.getSize()); vector<int4> randomSeedVec(randomSeed.getSize());
stream.read((char*) &randomSeedVec[0], sizeof(int4)*randomSeed.getSize()); stream.read((char*) &randomSeedVec[0], sizeof(int4)*randomSeed.getSize());
randomSeed.upload(randomSeedVec); randomSeed.upload(randomSeedVec);
size_t numChains, chainLength;
stream.read((char*) &numChains, sizeof(size_t));
noseHooverChainState.clear();
for (size_t i=0; i<numChains; i++){
stream.read((char*) &chainLength, sizeof(size_t));
std::vector<float2> stateVec(chainLength);
stream.read((char*) &stateVec[0], sizeof(float2)*chainLength);
CudaArray state;
state.upload(stateVec);
noseHooverChainState.push_back(state);
}
} }
double CudaIntegrationUtilities::computeKineticEnergy(double timeShift) { double CudaIntegrationUtilities::computeKineticEnergy(double timeShift) {
...@@ -796,6 +816,6 @@ double CudaIntegrationUtilities::computeKineticEnergy(double timeShift) { ...@@ -796,6 +816,6 @@ double CudaIntegrationUtilities::computeKineticEnergy(double timeShift) {
return 0.5*energy; return 0.5*energy;
} }
std::vector<CudaArray>& CudaIntegrationUtilities::getNoseHooverChainState(){ std::map<int, CudaArray>& CudaIntegrationUtilities::getNoseHooverChainState(){
return noseHooverChainState; return noseHooverChainState;
}; };
...@@ -8391,8 +8391,10 @@ double CudaNoseHooverChainKernel::propagateChain(ContextImpl& context, const Nos ...@@ -8391,8 +8391,10 @@ double CudaNoseHooverChainKernel::propagateChain(ContextImpl& context, const Nos
double frequency = nhc.getDefaultCollisionFrequency(); double frequency = nhc.getDefaultCollisionFrequency();
auto & chainState = cu.getIntegrationUtilities().getNoseHooverChainState(); auto & chainState = cu.getIntegrationUtilities().getNoseHooverChainState();
if (chainID >= chainState.size()) chainState.resize(chainID+1); if (!chainState.count(chainID)) {
if (!chainState.at(chainID).isInitialized() || chainState.at(chainID).getSize() != chainLength) { chainState[chainID] = CudaArray();
}
if (chainState.at(chainID).getSize() != chainLength) {
// We need to upload the CUDA array // We need to upload the CUDA array
if(useDouble){ if(useDouble){
chainState.at(chainID).initialize<double2>(cu, chainLength, "chainState" + std::to_string(chainID)); chainState.at(chainID).initialize<double2>(cu, chainLength, "chainState" + std::to_string(chainID));
...@@ -8504,7 +8506,7 @@ double CudaNoseHooverChainKernel::computeHeatBathEnergy(ContextImpl& context, co ...@@ -8504,7 +8506,7 @@ double CudaNoseHooverChainKernel::computeHeatBathEnergy(ContextImpl& context, co
} }
} }
double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &nhc) { double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &nhc, bool downloadValue) {
cu.setAsCurrent(); cu.setAsCurrent();
bool useDouble = cu.getUseDoublePrecision() || cu.getUseMixedPrecision(); bool useDouble = cu.getUseDoublePrecision() || cu.getUseMixedPrecision();
...@@ -8512,9 +8514,8 @@ double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& contex ...@@ -8512,9 +8514,8 @@ double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& contex
int chainID = nhc.getDefaultChainID(); int chainID = nhc.getDefaultChainID();
const auto & parents = nhc.getParentAtoms(); const auto & parents = nhc.getParentAtoms();
const auto & thermostatedAtoms = nhc.getThermostatedAtoms(); const auto & thermostatedAtoms = nhc.getThermostatedAtoms();
if (chainID >= masks.size()) masks.resize(chainID+1);
auto nAtoms = cu.getPaddedNumAtoms(); auto nAtoms = cu.getPaddedNumAtoms();
if (!masks.at(chainID).isInitialized()) { if (!masks.count(chainID)) {
// We need to upload the CUDA array // We need to upload the CUDA array
std::vector<int> maskVec(nAtoms); std::vector<int> maskVec(nAtoms);
for (int i = 0; i < nAtoms; ++i) maskVec[i] = i; for (int i = 0; i < nAtoms; ++i) maskVec[i] = i;
...@@ -8530,12 +8531,9 @@ double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& contex ...@@ -8530,12 +8531,9 @@ double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& contex
maskVec[atom] = -1L; maskVec[atom] = -1L;
} }
} }
// Account for padding in the paddedNumAtoms loops masks[chainID] = CudaArray();
for(int i = thermostatedAtoms.size(); i < nAtoms; ++i){ masks[chainID].initialize<int>(cu, nAtoms, "mask" + std::to_string(chainID));
maskVec[i] = i; masks[chainID].upload(maskVec);
}
masks.at(chainID).initialize<int>(cu, nAtoms, "mask" + std::to_string(chainID));
masks.at(chainID).upload(maskVec);
} }
if (masks[chainID].getSize() != nAtoms) { if (masks[chainID].getSize() != nAtoms) {
throw OpenMMException("Number of atoms changed. Cannot be handled by the same Nose-Hoover thermostat."); throw OpenMMException("Number of atoms changed. Cannot be handled by the same Nose-Hoover thermostat.");
...@@ -8561,7 +8559,13 @@ double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& contex ...@@ -8561,7 +8559,13 @@ double CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& contex
void* args2[] = {&cu.getEnergyBuffer().getDevicePointer(), &kineticEnergyBuffer.getDevicePointer(), &bufferSize, &workGroupSize}; void* args2[] = {&cu.getEnergyBuffer().getDevicePointer(), &kineticEnergyBuffer.getDevicePointer(), &bufferSize, &workGroupSize};
cu.executeKernel(reduceEnergyKernel, args2, workGroupSize, workGroupSize, workGroupSize*cu.getEnergyBuffer().getElementSize()); cu.executeKernel(reduceEnergyKernel, args2, workGroupSize, workGroupSize, workGroupSize*cu.getEnergyBuffer().getElementSize());
return 0; double value = 0;
if (downloadValue) {
void * pinnedBuffer = cu.getPinnedBuffer();
kineticEnergyBuffer.download(pinnedBuffer);
value = useDouble ? *((double*) pinnedBuffer) : *((float*) pinnedBuffer);
}
return value;
} }
void CudaNoseHooverChainKernel::scaleVelocities(ContextImpl& context, const NoseHooverChain &nhc, double scaleFactor) { void CudaNoseHooverChainKernel::scaleVelocities(ContextImpl& context, const NoseHooverChain &nhc, double scaleFactor) {
......
...@@ -1465,8 +1465,10 @@ public: ...@@ -1465,8 +1465,10 @@ public:
* *
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined. * @param noseHooverChain the chain whose energy is to be determined.
* @param downloadValue whether the computed value should be downloaded and returned.
*
*/ */
virtual double computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain); virtual double computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain, bool downloadValue);
/** /**
* Execute the kernel that scales the velocities of particles associated with a nose hoover chain * Execute the kernel that scales the velocities of particles associated with a nose hoover chain
......
...@@ -2527,7 +2527,7 @@ double ReferenceNoseHooverChainKernel::computeHeatBathEnergy(ContextImpl& contex ...@@ -2527,7 +2527,7 @@ double ReferenceNoseHooverChainKernel::computeHeatBathEnergy(ContextImpl& contex
return kineticEnergy + potentialEnergy; return kineticEnergy + potentialEnergy;
} }
double ReferenceNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain) { double ReferenceNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &noseHooverChain, bool downloadValue) {
const std::vector<int>& mask = noseHooverChain.getThermostatedAtoms(); const std::vector<int>& mask = noseHooverChain.getThermostatedAtoms();
const std::vector<int>& parents = noseHooverChain.getParentAtoms(); const std::vector<int>& parents = noseHooverChain.getParentAtoms();
std::vector<Vec3>& velocities = extractVelocities(context); std::vector<Vec3>& velocities = extractVelocities(context);
...@@ -2554,6 +2554,7 @@ double ReferenceNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& c ...@@ -2554,6 +2554,7 @@ double ReferenceNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& c
ke += 0.5 * mass * velocity.dot(velocity); ke += 0.5 * mass * velocity.dot(velocity);
} }
} }
// We ignore the downloadValue argument here and always return the correct value
return ke; return ke;
} }
......
...@@ -76,13 +76,6 @@ public: ...@@ -76,13 +76,6 @@ public:
int addDrudeNoseHooverChainThermostat(System& system, double temperature, double collisionFrequency, int addDrudeNoseHooverChainThermostat(System& system, double temperature, double collisionFrequency,
double drudeTemperature, double drudeCollisionFrequency, double drudeTemperature, double drudeCollisionFrequency,
int chainLength, int numMTS, int numYoshidaSuzuki); int chainLength, int numMTS, int numYoshidaSuzuki);
/**
* Advance a simulation through time by taking a series of time steps.
*
* @param steps the number of time steps to take
*/
//void step(int steps);
//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.
...@@ -90,9 +83,13 @@ public: ...@@ -90,9 +83,13 @@ public:
*/ */
void initialize(ContextImpl& context); void initialize(ContextImpl& context);
/** /**
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the drude particles at the current time.
*/
double computeDrudeKineticEnergy();
/**
* Compute the kinetic energy of all (real and drude) particles at the current time.
*/ */
//double computeKineticEnergy(); double computeTotalKineticEnergy();
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -35,7 +35,10 @@ ...@@ -35,7 +35,10 @@
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/DrudeKernels.h" #include "openmm/DrudeKernels.h"
#include "openmm/DrudeForce.h" #include "openmm/DrudeForce.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/kernels.h"
#include <ctime> #include <ctime>
#include <iostream>
#include <string> #include <string>
#include <set> #include <set>
...@@ -63,19 +66,18 @@ int DrudeVelocityVerletIntegrator::addDrudeNoseHooverChainThermostat(System& sys ...@@ -63,19 +66,18 @@ int DrudeVelocityVerletIntegrator::addDrudeNoseHooverChainThermostat(System& sys
std::set<int> realParticlesSet; std::set<int> realParticlesSet;
vector<int> realParticles, drudeParticles, drudeParents; vector<int> realParticles, drudeParticles, drudeParents;
for (int i = 0; i < system.getNumParticles(); i++) { for (int i = 0; i < system.getNumParticles(); i++) {
realParticlesSet.insert(i); if (system.getParticleMass(i) > 0.0) realParticlesSet.insert(i);
} }
for (int i = 0; i < drudeForce->getNumParticles(); i++) { for (int i = 0; i < drudeForce->getNumParticles(); i++) {
int p, p1, p2, p3, p4; int p, p1, p2, p3, p4;
double charge, polarizability, aniso12, aniso34; double charge, polarizability, aniso12, aniso34;
drudeForce->getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); drudeForce->getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34);
realParticlesSet.erase(p); realParticlesSet.erase(p);
realParticlesSet.erase(p1);
drudeParticles.push_back(p); drudeParticles.push_back(p);
drudeParents.push_back(p1); drudeParents.push_back(p1);
} }
for(const auto &p : realParticlesSet) realParticles.push_back(p); for(const auto &p : realParticlesSet) realParticles.push_back(p);
addMaskedNoseHooverChainThermostat(system, realParticles, vector<int>(), temperature, collisionFrequency, addMaskedNoseHooverChainThermostat(system, realParticles, vector<int>(), temperature, collisionFrequency,
chainLength, numMTS, numYoshidaSuzuki); chainLength, numMTS, numYoshidaSuzuki);
addMaskedNoseHooverChainThermostat(system, drudeParticles, drudeParents, drudeTemperature, drudeCollisionFrequency, addMaskedNoseHooverChainThermostat(system, drudeParticles, drudeParents, drudeTemperature, drudeCollisionFrequency,
...@@ -84,19 +86,44 @@ int DrudeVelocityVerletIntegrator::addDrudeNoseHooverChainThermostat(System& sys ...@@ -84,19 +86,44 @@ int DrudeVelocityVerletIntegrator::addDrudeNoseHooverChainThermostat(System& sys
} }
void DrudeVelocityVerletIntegrator::initialize(ContextImpl& contextRef) { void DrudeVelocityVerletIntegrator::initialize(ContextImpl& contextRef) {
VelocityVerletIntegrator::initialize(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");
const DrudeForce* drudeForce = NULL; const DrudeForce* drudeForce = NULL;
const System& system = contextRef.getSystem(); const System& system = contextRef.getSystem();
for (int i = 0; i < system.getNumForces(); i++) bool hasCMMotionRemover = false;
for (int i = 0; i < system.getNumForces(); i++){
if (dynamic_cast<const DrudeForce*>(&system.getForce(i)) != NULL) { if (dynamic_cast<const DrudeForce*>(&system.getForce(i)) != NULL) {
if (drudeForce == NULL) if (drudeForce == NULL)
drudeForce = dynamic_cast<const DrudeForce*>(&system.getForce(i)); drudeForce = dynamic_cast<const DrudeForce*>(&system.getForce(i));
else else
throw OpenMMException("The System contains multiple DrudeForces"); throw OpenMMException("The System contains multiple DrudeForces");
} }
if (dynamic_cast<const CMMotionRemover*>(&system.getForce(i))) {
hasCMMotionRemover = true;
}
}
if (drudeForce == NULL) if (drudeForce == NULL)
throw OpenMMException("The System does not contain a DrudeForce"); throw OpenMMException("The System does not contain a DrudeForce");
if (!hasCMMotionRemover) {
std::cout << "Warning: Did not find a center-of-mass motion remover in the system. "
"This is problematic when using Drude." << std::endl;
}
context = &contextRef; context = &contextRef;
owner = &contextRef.getOwner(); owner = &contextRef.getOwner();
} }
double DrudeVelocityVerletIntegrator::computeDrudeKineticEnergy() {
double kE = 0.0;
for (const auto &nhc: noseHooverChains){
if (nhc.getParentAtoms().size() != 0) {
kE += nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc, true);
}
}
return kE;
}
double DrudeVelocityVerletIntegrator::computeTotalKineticEnergy() {
return vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this);
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
ENABLE_TESTING() ENABLE_TESTING()
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/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 "ReferenceTests.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();
//OpenMM::CudaPlatform platform;
Platform& initializePlatform(int argc, char* argv[]) {
registerDrudeCudaKernelFactories();
if (argc > 1) Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", std::string(argv[1]));
return Platform::getPlatformByName("CUDA");
}
#include "TestDrudeNoseHoover.h"
void runPlatformTests() { }
...@@ -5,6 +5,7 @@ ENABLE_TESTING() ...@@ -5,6 +5,7 @@ ENABLE_TESTING()
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/reference/include) INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/reference/include)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/openmmapi/include/openmm) INCLUDE_DIRECTORIES(${OPENMM_DIR}/openmmapi/include/openmm)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/reference/src) INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/reference/src)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests)
SET(SHARED_OPENMM_DRUDE_TARGET OpenMMDrude) SET(SHARED_OPENMM_DRUDE_TARGET OpenMMDrude)
......
/* -------------------------------------------------------------------------- *
* 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 "ReferenceTests.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 "SimTKOpenMMUtilities.h"
#include "ReferencePlatform.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeReferenceKernelFactories();
Platform& initializePlatform(int argc, char* argv[]) {
registerDrudeReferenceKernelFactories();
return Platform::getPlatformByName("Reference");
}
#include "TestDrudeNoseHoover.h"
void runPlatformTests() { }
...@@ -265,7 +265,8 @@ void testPropagateChainConsistentWithPythonReference() { ...@@ -265,7 +265,8 @@ void testPropagateChainConsistentWithPythonReference() {
void testCheckpoints() { void testCheckpoints() {
VelocityVerletIntegrator integrator(0.001); double timeStep = 0.001;
VelocityVerletIntegrator integrator(timeStep), newIntegrator(timeStep);
System system; System system;
double mass = 1; double mass = 1;
system.addParticle(mass); system.addParticle(mass);
...@@ -278,11 +279,17 @@ void testCheckpoints() { ...@@ -278,11 +279,17 @@ void testCheckpoints() {
double temperature=300, collisionFrequency=1, chainLength=3, numMTS=3, numYS=3; double temperature=300, collisionFrequency=1, chainLength=3, numMTS=3, numYS=3;
integrator.addMaskedNoseHooverChainThermostat(system, std::vector<int>(1,0), std::vector<int>(), temperature, collisionFrequency, integrator.addMaskedNoseHooverChainThermostat(system, std::vector<int>(1,0), std::vector<int>(), temperature, collisionFrequency,
chainLength, numMTS, numYS); chainLength, numMTS, numYS);
newIntegrator.addMaskedNoseHooverChainThermostat(system, std::vector<int>(1,0), std::vector<int>(), temperature, collisionFrequency,
chainLength, numMTS, numYS);
chainLength = 10; chainLength = 10;
integrator.addMaskedNoseHooverChainThermostat(system, std::vector<int>(1,1), std::vector<int>(1,0), integrator.addMaskedNoseHooverChainThermostat(system, std::vector<int>(1,1), std::vector<int>(1,0),
temperature, collisionFrequency, temperature, collisionFrequency,
chainLength, numMTS, numYS); chainLength, numMTS, numYS);
newIntegrator.addMaskedNoseHooverChainThermostat(system, std::vector<int>(1,1), std::vector<int>(1,0),
temperature, collisionFrequency,
chainLength, numMTS, numYS);
Context context(system, integrator, platform); Context context(system, integrator, platform);
Context newContext(system, newIntegrator, platform);
std::vector<Vec3> positions(2); std::vector<Vec3> positions(2);
positions[1] = {0.1,0.1,0.1}; positions[1] = {0.1,0.1,0.1};
context.setPositions(positions); context.setPositions(positions);
...@@ -304,16 +311,16 @@ void testCheckpoints() { ...@@ -304,16 +311,16 @@ void testCheckpoints() {
#if DEBUG #if DEBUG
std::cout << std::endl << std::endl << "loading checkpoint" << std::endl; std::cout << std::endl << std::endl << "loading checkpoint" << std::endl;
#endif #endif
context.loadCheckpoint(checkpoint); newContext.loadCheckpoint(checkpoint);
State state2 = context.getState(State::Positions | State::Velocities); State state2 = context.getState(State::Positions | State::Velocities);
for (size_t i=0; i<100; i++){ for (size_t i=0; i<100; i++){
state2 = context.getState(State::Positions | State::Velocities); state2 = newContext.getState(State::Positions | State::Velocities);
#if DEBUG #if DEBUG
std::cout << "posvel" << state2.getPositions()[0] << " " << state2.getVelocities()[0] << std::endl; std::cout << "posvel" << state2.getPositions()[0] << " " << state2.getVelocities()[0] << std::endl;
#endif #endif
integrator.step(1); newIntegrator.step(1);
} }
for (int i=0; i<3;i++){ for (int i=0; i<3;i++){
......
...@@ -78,6 +78,7 @@ class WrapperGenerator: ...@@ -78,6 +78,7 @@ class WrapperGenerator:
'Vec3 OpenMM::LocalCoordinatesSite::getXWeights', 'Vec3 OpenMM::LocalCoordinatesSite::getXWeights',
'Vec3 OpenMM::LocalCoordinatesSite::getYWeights', 'Vec3 OpenMM::LocalCoordinatesSite::getYWeights',
'std::vector<double> OpenMM::NoseHooverChain::getDefaultYoshidaSuzukiWeights', 'std::vector<double> OpenMM::NoseHooverChain::getDefaultYoshidaSuzukiWeights',
'virtual void OpenMM::VelocityVerletIntegrator::stateChanged',
] ]
self.hideClasses = ['Kernel', 'KernelImpl', 'KernelFactory', 'ContextImpl', 'SerializationNode', 'SerializationProxy'] self.hideClasses = ['Kernel', 'KernelImpl', 'KernelFactory', 'ContextImpl', 'SerializationNode', 'SerializationProxy']
self.nodeByID={} self.nodeByID={}
......
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