Commit 18295108 authored by peastman's avatar peastman
Browse files

Merge changes from main branch

parents e6101f68 8d7234e5
...@@ -53,7 +53,7 @@ public: ...@@ -53,7 +53,7 @@ public:
const PeriodicTorsionForce& getOwner() const { const PeriodicTorsionForce& getOwner() const {
return owner; return owner;
} }
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context, bool& forcesInvalid) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
......
...@@ -53,7 +53,7 @@ public: ...@@ -53,7 +53,7 @@ public:
const RBTorsionForce& getOwner() const { const RBTorsionForce& getOwner() const {
return owner; return owner;
} }
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context, bool& forcesInvalid) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
......
...@@ -47,7 +47,7 @@ void AndersenThermostatImpl::initialize(ContextImpl& context) { ...@@ -47,7 +47,7 @@ void AndersenThermostatImpl::initialize(ContextImpl& context) {
kernel.getAs<ApplyAndersenThermostatKernel>().initialize(context.getSystem(), owner); kernel.getAs<ApplyAndersenThermostatKernel>().initialize(context.getSystem(), owner);
} }
void AndersenThermostatImpl::updateContextState(ContextImpl& context) { void AndersenThermostatImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
kernel.getAs<ApplyAndersenThermostatKernel>().execute(context); kernel.getAs<ApplyAndersenThermostatKernel>().execute(context);
} }
......
...@@ -48,7 +48,7 @@ void CMMotionRemoverImpl::initialize(ContextImpl& context) { ...@@ -48,7 +48,7 @@ void CMMotionRemoverImpl::initialize(ContextImpl& context) {
kernel.getAs<RemoveCMMotionKernel>().initialize(system, owner); kernel.getAs<RemoveCMMotionKernel>().initialize(system, owner);
} }
void CMMotionRemoverImpl::updateContextState(ContextImpl& context) { void CMMotionRemoverImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
kernel.getAs<RemoveCMMotionKernel>().execute(context); kernel.getAs<RemoveCMMotionKernel>().execute(context);
} }
......
...@@ -40,16 +40,25 @@ ...@@ -40,16 +40,25 @@
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
Context::Context(const System& system, Integrator& integrator, ContextImpl& linked) : properties(linked.getOwner().properties) {
// This is used by ContextImpl::createLinkedContext().
impl = new ContextImpl(*this, system, integrator, &linked.getPlatform(), properties, &linked);
impl->initialize();
}
Context::Context(const System& system, Integrator& integrator) : properties(map<string, string>()) { Context::Context(const System& system, Integrator& integrator) : properties(map<string, string>()) {
impl = new ContextImpl(*this, system, integrator, 0, properties); impl = new ContextImpl(*this, system, integrator, 0, properties);
impl->initialize();
} }
Context::Context(const System& system, Integrator& integrator, Platform& platform) : properties(map<string, string>()) { Context::Context(const System& system, Integrator& integrator, Platform& platform) : properties(map<string, string>()) {
impl = new ContextImpl(*this, system, integrator, &platform, properties); impl = new ContextImpl(*this, system, integrator, &platform, properties);
impl->initialize();
} }
Context::Context(const System& system, Integrator& integrator, Platform& platform, const map<string, string>& properties) : properties(properties) { Context::Context(const System& system, Integrator& integrator, Platform& platform, const map<string, string>& properties) : properties(properties) {
impl = new ContextImpl(*this, system, integrator, &platform, properties); impl = new ContextImpl(*this, system, integrator, &platform, properties);
impl->initialize();
} }
Context::~Context() { Context::~Context() {
...@@ -240,6 +249,7 @@ void Context::reinitialize() { ...@@ -240,6 +249,7 @@ void Context::reinitialize() {
integrator.cleanup(); integrator.cleanup();
delete impl; delete impl;
impl = new ContextImpl(*this, system, integrator, &platform, properties); impl = new ContextImpl(*this, system, integrator, &platform, properties);
impl->initialize();
} }
void Context::createCheckpoint(ostream& stream) { void Context::createCheckpoint(ostream& stream) {
......
...@@ -53,7 +53,7 @@ using namespace std; ...@@ -53,7 +53,7 @@ using namespace std;
const static char CHECKPOINT_MAGIC_BYTES[] = "OpenMM Binary Checkpoint\n"; const static char CHECKPOINT_MAGIC_BYTES[] = "OpenMM Binary Checkpoint\n";
ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integrator, Platform* platform, const map<string, string>& properties) : ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integrator, Platform* platform, const map<string, string>& properties, ContextImpl* originalContext) :
owner(owner), system(system), integrator(integrator), hasInitializedForces(false), hasSetPositions(false), integratorIsDeleted(false), owner(owner), system(system), integrator(integrator), hasInitializedForces(false), hasSetPositions(false), integratorIsDeleted(false),
lastForceGroups(-1), platform(platform), platformData(NULL) { lastForceGroups(-1), platform(platform), platformData(NULL) {
int numParticles = system.getNumParticles(); int numParticles = system.getNumParticles();
...@@ -119,8 +119,6 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ ...@@ -119,8 +119,6 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
kernelNames.push_back(VirtualSitesKernel::Name()); kernelNames.push_back(VirtualSitesKernel::Name());
for (int i = 0; i < system.getNumForces(); ++i) { for (int i = 0; i < system.getNumForces(); ++i) {
forceImpls.push_back(system.getForce(i).createImpl()); forceImpls.push_back(system.getForce(i).createImpl());
map<string, double> forceParameters = forceImpls[forceImpls.size()-1]->getDefaultParameters();
parameters.insert(forceParameters.begin(), forceParameters.end());
vector<string> forceKernels = forceImpls[forceImpls.size()-1]->getKernelNames(); vector<string> forceKernels = forceImpls[forceImpls.size()-1]->getKernelNames();
kernelNames.insert(kernelNames.begin(), forceKernels.begin(), forceKernels.end()); kernelNames.insert(kernelNames.begin(), forceKernels.begin(), forceKernels.end());
} }
...@@ -154,7 +152,10 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ ...@@ -154,7 +152,10 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
for (int i = candidatePlatforms.size()-1; i >= 0; i--) { for (int i = candidatePlatforms.size()-1; i >= 0; i--) {
try { try {
this->platform = platform = candidatePlatforms[i].second; this->platform = platform = candidatePlatforms[i].second;
if (originalContext == NULL)
platform->contextCreated(*this, validatedProperties); platform->contextCreated(*this, validatedProperties);
else
platform->linkedContextCreated(*this, *originalContext);
break; break;
} }
catch (...) { catch (...) {
...@@ -163,7 +164,9 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ ...@@ -163,7 +164,9 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
throw; throw;
} }
} }
}
void ContextImpl::initialize() {
// Create and initialize kernels and other objects. // Create and initialize kernels and other objects.
initializeForcesKernel = platform->createKernel(CalcForcesAndEnergyKernel::Name(), *this); initializeForcesKernel = platform->createKernel(CalcForcesAndEnergyKernel::Name(), *this);
...@@ -177,10 +180,13 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ ...@@ -177,10 +180,13 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
Vec3 periodicBoxVectors[3]; Vec3 periodicBoxVectors[3];
system.getDefaultPeriodicBoxVectors(periodicBoxVectors[0], periodicBoxVectors[1], periodicBoxVectors[2]); system.getDefaultPeriodicBoxVectors(periodicBoxVectors[0], periodicBoxVectors[1], periodicBoxVectors[2]);
updateStateDataKernel.getAs<UpdateStateDataKernel>().setPeriodicBoxVectors(*this, periodicBoxVectors[0], periodicBoxVectors[1], periodicBoxVectors[2]); updateStateDataKernel.getAs<UpdateStateDataKernel>().setPeriodicBoxVectors(*this, periodicBoxVectors[0], periodicBoxVectors[1], periodicBoxVectors[2]);
for (size_t i = 0; i < forceImpls.size(); ++i) for (size_t i = 0; i < forceImpls.size(); ++i) {
forceImpls[i]->initialize(*this); forceImpls[i]->initialize(*this);
map<string, double> forceParameters = forceImpls[i]->getDefaultParameters();
parameters.insert(forceParameters.begin(), forceParameters.end());
}
integrator.initialize(*this); integrator.initialize(*this);
updateStateDataKernel.getAs<UpdateStateDataKernel>().setVelocities(*this, vector<Vec3>(numParticles)); updateStateDataKernel.getAs<UpdateStateDataKernel>().setVelocities(*this, vector<Vec3>(system.getNumParticles()));
} }
ContextImpl::~ContextImpl() { ContextImpl::~ContextImpl() {
...@@ -301,7 +307,7 @@ double ContextImpl::calcForcesAndEnergy(bool includeForces, bool includeEnergy, ...@@ -301,7 +307,7 @@ double ContextImpl::calcForcesAndEnergy(bool includeForces, bool includeEnergy,
} }
} }
int ContextImpl::getLastForceGroups() const { int& ContextImpl::getLastForceGroups() {
return lastForceGroups; return lastForceGroups;
} }
...@@ -309,9 +315,11 @@ double ContextImpl::calcKineticEnergy() { ...@@ -309,9 +315,11 @@ double ContextImpl::calcKineticEnergy() {
return integrator.computeKineticEnergy(); return integrator.computeKineticEnergy();
} }
void ContextImpl::updateContextState() { bool ContextImpl::updateContextState() {
bool forcesInvalid = false;
for (auto force : forceImpls) for (auto force : forceImpls)
force->updateContextState(*this); force->updateContextState(*this, forcesInvalid);
return forcesInvalid;
} }
const vector<ForceImpl*>& ContextImpl::getForceImpls() const { const vector<ForceImpl*>& ContextImpl::getForceImpls() const {
...@@ -478,3 +486,7 @@ void ContextImpl::loadCheckpoint(istream& stream) { ...@@ -478,3 +486,7 @@ void ContextImpl::loadCheckpoint(istream& stream) {
void ContextImpl::systemChanged() { void ContextImpl::systemChanged() {
integrator.stateChanged(State::Energy); integrator.stateChanged(State::Energy);
} }
Context* ContextImpl::createLinkedContext(const System& system, Integrator& integrator) {
return new Context(system, integrator, *this);
}
/* -------------------------------------------------------------------------- *
* 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-2017 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/OpenMMException.h"
#include "openmm/CustomCVForce.h"
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/internal/CustomCVForceImpl.h"
#include <cmath>
#include <map>
#include <set>
#include <utility>
using namespace OpenMM;
using namespace std;
CustomCVForce::CustomCVForce(const string& energy) : energyExpression(energy) {
}
CustomCVForce::~CustomCVForce() {
for (auto variable : variables)
delete variable.variable;
for (auto function : functions)
delete function.function;
}
const string& CustomCVForce::getEnergyFunction() const {
return energyExpression;
}
void CustomCVForce::setEnergyFunction(const std::string& energy) {
energyExpression = energy;
}
int CustomCVForce::addCollectiveVariable(const std::string& name, Force* variable) {
if (variables.size() >= 32)
throw OpenMMException("CustomCVForce cannot have more than 32 collective variables");
variables.push_back(VariableInfo(name, variable));
return variables.size()-1;
}
const string& CustomCVForce::getCollectiveVariableName(int index) const {
ASSERT_VALID_INDEX(index, variables);
return variables[index].name;
}
Force& CustomCVForce::getCollectiveVariable(int index) {
ASSERT_VALID_INDEX(index, variables);
return *variables[index].variable;
}
const Force& CustomCVForce::getCollectiveVariable(int index) const {
ASSERT_VALID_INDEX(index, variables);
return *variables[index].variable;
}
int CustomCVForce::addGlobalParameter(const string& name, double defaultValue) {
globalParameters.push_back(GlobalParameterInfo(name, defaultValue));
return globalParameters.size()-1;
}
const string& CustomCVForce::getGlobalParameterName(int index) const {
ASSERT_VALID_INDEX(index, globalParameters);
return globalParameters[index].name;
}
void CustomCVForce::setGlobalParameterName(int index, const string& name) {
ASSERT_VALID_INDEX(index, globalParameters);
globalParameters[index].name = name;
}
double CustomCVForce::getGlobalParameterDefaultValue(int index) const {
ASSERT_VALID_INDEX(index, globalParameters);
return globalParameters[index].defaultValue;
}
void CustomCVForce::setGlobalParameterDefaultValue(int index, double defaultValue) {
ASSERT_VALID_INDEX(index, globalParameters);
globalParameters[index].defaultValue = defaultValue;
}
void CustomCVForce::addEnergyParameterDerivative(const string& name) {
for (int i = 0; i < globalParameters.size(); i++)
if (name == globalParameters[i].name) {
energyParameterDerivatives.push_back(i);
return;
}
throw OpenMMException(string("addEnergyParameterDerivative: Unknown global parameter '"+name+"'"));
}
const string& CustomCVForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomCVForce::addTabulatedFunction(const std::string& name, TabulatedFunction* function) {
functions.push_back(FunctionInfo(name, function));
return functions.size()-1;
}
const TabulatedFunction& CustomCVForce::getTabulatedFunction(int index) const {
ASSERT_VALID_INDEX(index, functions);
return *functions[index].function;
}
TabulatedFunction& CustomCVForce::getTabulatedFunction(int index) {
ASSERT_VALID_INDEX(index, functions);
return *functions[index].function;
}
const string& CustomCVForce::getTabulatedFunctionName(int index) const {
ASSERT_VALID_INDEX(index, functions);
return functions[index].name;
}
void CustomCVForce::getCollectiveVariableValues(Context& context, vector<double>& values) {
dynamic_cast<CustomCVForceImpl&>(getImplInContext(context)).getCollectiveVariableValues(getContextImpl(context), values);
}
ForceImpl* CustomCVForce::createImpl() const {
return new CustomCVForceImpl(*this);
}
Context& CustomCVForce::getInnerContext(Context& context) {
return dynamic_cast<CustomCVForceImpl&>(getImplInContext(context)).getInnerContext();
}
bool CustomCVForce::usesPeriodicBoundaryConditions() const {
for (auto& variable : variables)
if (variable.variable->usesPeriodicBoundaryConditions())
return true;
return false;
}
/* -------------------------------------------------------------------------- *
* 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-2017 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/NonbondedForce.h"
#include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/internal/CustomCVForceImpl.h"
#include "openmm/kernels.h"
#include "openmm/serialization/XmlSerializer.h"
#include <map>
using namespace OpenMM;
using namespace std;
CustomCVForceImpl::CustomCVForceImpl(const CustomCVForce& owner) : owner(owner), innerIntegrator(1.0),
innerContext(NULL) {
}
CustomCVForceImpl::~CustomCVForceImpl() {
if (innerContext != NULL)
delete innerContext;
}
void CustomCVForceImpl::initialize(ContextImpl& context) {
// Construct the inner system used to evaluate collective variables.
const System& system = context.getSystem();
Vec3 a, b, c;
system.getDefaultPeriodicBoxVectors(a, b, c);
innerSystem.setDefaultPeriodicBoxVectors(a, b, c);
for (int i = 0; i < system.getNumParticles(); i++)
innerSystem.addParticle(system.getParticleMass(i));
for (int i = 0; i < owner.getNumCollectiveVariables(); i++) {
Force* variable = XmlSerializer::clone<Force>(owner.getCollectiveVariable(i));
variable->setForceGroup(i);
NonbondedForce* nonbonded = dynamic_cast<NonbondedForce*>(variable);
if (nonbonded != NULL)
nonbonded->setReciprocalSpaceForceGroup(-1);
innerSystem.addForce(variable);
}
// Create the inner context.
innerContext = context.createLinkedContext(innerSystem, innerIntegrator);
vector<Vec3> positions(system.getNumParticles(), Vec3());
innerContext->setPositions(positions);
// Create the kernel.
kernel = context.getPlatform().createKernel(CalcCustomCVForceKernel::Name(), context);
kernel.getAs<CalcCustomCVForceKernel>().initialize(context.getSystem(), owner, getContextImpl(*innerContext));
}
double CustomCVForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
if ((groups&(1<<owner.getForceGroup())) != 0)
return kernel.getAs<CalcCustomCVForceKernel>().execute(context, getContextImpl(*innerContext), includeForces, includeEnergy);
return 0.0;
}
vector<string> CustomCVForceImpl::getKernelNames() {
vector<string> names;
names.push_back(CalcCustomCVForceKernel::Name());
return names;
}
map<string, double> CustomCVForceImpl::getDefaultParameters() {
map<string, double> parameters;
parameters.insert(innerContext->getParameters().begin(), innerContext->getParameters().end());
for (int i = 0; i < owner.getNumGlobalParameters(); i++)
parameters[owner.getGlobalParameterName(i)] = owner.getGlobalParameterDefaultValue(i);
return parameters;
}
void CustomCVForceImpl::getCollectiveVariableValues(ContextImpl& context, vector<double>& values) {
kernel.getAs<CalcCustomCVForceKernel>().copyState(context, getContextImpl(*innerContext));
values.clear();
for (int i = 0; i < innerSystem.getNumForces(); i++) {
double value = innerContext->getState(State::Energy, false, 1<<i).getPotentialEnergy();
values.push_back(value);
}
}
Context& CustomCVForceImpl::getInnerContext() {
return *innerContext;
}
...@@ -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) 2011-2016 Stanford University and the Authors. * * Portions copyright (c) 2011-2017 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -48,6 +48,11 @@ CustomIntegrator::CustomIntegrator(double stepSize) : globalsAreCurrent(true), f ...@@ -48,6 +48,11 @@ CustomIntegrator::CustomIntegrator(double stepSize) : globalsAreCurrent(true), f
kineticEnergy = "m*v*v/2"; kineticEnergy = "m*v*v/2";
} }
CustomIntegrator::~CustomIntegrator() {
for (auto function : functions)
delete function.function;
}
void CustomIntegrator::initialize(ContextImpl& contextRef) { void CustomIntegrator::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");
...@@ -281,6 +286,26 @@ void CustomIntegrator::getComputationStep(int index, ComputationType& type, stri ...@@ -281,6 +286,26 @@ void CustomIntegrator::getComputationStep(int index, ComputationType& type, stri
expression = computations[index].expression; expression = computations[index].expression;
} }
int CustomIntegrator::addTabulatedFunction(const std::string& name, TabulatedFunction* function) {
functions.push_back(FunctionInfo(name, function));
return functions.size()-1;
}
const TabulatedFunction& CustomIntegrator::getTabulatedFunction(int index) const {
ASSERT_VALID_INDEX(index, functions);
return *functions[index].function;
}
TabulatedFunction& CustomIntegrator::getTabulatedFunction(int index) {
ASSERT_VALID_INDEX(index, functions);
return *functions[index].function;
}
const string& CustomIntegrator::getTabulatedFunctionName(int index) const {
ASSERT_VALID_INDEX(index, functions);
return functions[index].name;
}
const string& CustomIntegrator::getKineticEnergyExpression() const { const string& CustomIntegrator::getKineticEnergyExpression() const {
return kineticEnergy; return kineticEnergy;
} }
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <algorithm> #include <algorithm>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <utility>
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
...@@ -71,7 +72,7 @@ bool CustomIntegratorUtilities::usesVariable(const Lepton::ParsedExpression& exp ...@@ -71,7 +72,7 @@ bool CustomIntegratorUtilities::usesVariable(const Lepton::ParsedExpression& exp
void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context, const CustomIntegrator& integrator, vector<vector<Lepton::ParsedExpression> >& expressions, void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context, const CustomIntegrator& integrator, vector<vector<Lepton::ParsedExpression> >& expressions,
vector<Comparison>& comparisons, vector<int>& blockEnd, vector<bool>& invalidatesForces, vector<bool>& needsForces, vector<bool>& needsEnergy, vector<Comparison>& comparisons, vector<int>& blockEnd, vector<bool>& invalidatesForces, vector<bool>& needsForces, vector<bool>& needsEnergy,
vector<bool>& computeBoth, vector<int>& forceGroup) { vector<bool>& computeBoth, vector<int>& forceGroup, const map<string, Lepton::CustomFunction*>& functions) {
int numSteps = integrator.getNumComputations(); int numSteps = integrator.getNumComputations();
expressions.resize(numSteps); expressions.resize(numSteps);
comparisons.resize(numSteps); comparisons.resize(numSteps);
...@@ -82,7 +83,7 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context, ...@@ -82,7 +83,7 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
forceGroup.resize(numSteps, -2); forceGroup.resize(numSteps, -2);
vector<CustomIntegrator::ComputationType> stepType(numSteps); vector<CustomIntegrator::ComputationType> stepType(numSteps);
vector<string> stepVariable(numSteps); vector<string> stepVariable(numSteps);
map<string, Lepton::CustomFunction*> customFunctions; map<string, Lepton::CustomFunction*> customFunctions = functions;
DerivFunction derivFunction; DerivFunction derivFunction;
customFunctions["deriv"] = &derivFunction; customFunctions["deriv"] = &derivFunction;
...@@ -111,7 +112,8 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context, ...@@ -111,7 +112,8 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
for (auto& param : force->getDefaultParameters()) for (auto& param : force->getDefaultParameters())
affectsForce.insert(param.first); affectsForce.insert(param.first);
for (int i = 0; i < numSteps; i++) for (int i = 0; i < numSteps; i++)
invalidatesForces[i] = (stepType[i] == CustomIntegrator::ConstrainPositions || affectsForce.find(stepVariable[i]) != affectsForce.end()); invalidatesForces[i] = (stepType[i] == CustomIntegrator::ConstrainPositions || stepType[i] == CustomIntegrator::UpdateContextState ||
affectsForce.find(stepVariable[i]) != affectsForce.end());
// Make a list of which steps require valid forces or energy to be known. // Make a list of which steps require valid forces or energy to be known.
...@@ -249,26 +251,23 @@ void CustomIntegratorUtilities::enumeratePaths(int firstStep, vector<int> steps, ...@@ -249,26 +251,23 @@ void CustomIntegratorUtilities::enumeratePaths(int firstStep, vector<int> steps,
void CustomIntegratorUtilities::analyzeForceComputationsForPath(vector<int>& steps, const vector<bool>& needsForces, const vector<bool>& needsEnergy, void CustomIntegratorUtilities::analyzeForceComputationsForPath(vector<int>& steps, const vector<bool>& needsForces, const vector<bool>& needsEnergy,
const vector<bool>& invalidatesForces, const vector<int>& forceGroup, vector<bool>& computeBoth) { const vector<bool>& invalidatesForces, const vector<int>& forceGroup, vector<bool>& computeBoth) {
vector<int> candidatePoints; vector<pair<int, int> > candidatePoints;
int currentGroup = -1;
for (int step : steps) { for (int step : steps) {
if (invalidatesForces[step] || ((needsForces[step] || needsEnergy[step]) && forceGroup[step] != currentGroup)) { if (invalidatesForces[step]) {
// Forces and energies are invalidated at this step, or it changes to a different force group, // Forces and energies are invalidated at this step, so anything from this point on won't affect what we do at earlier steps.
// so anything from this point on won't affect what we do at earlier steps.
candidatePoints.clear(); candidatePoints.clear();
} }
if (needsForces[step] || needsEnergy[step]) { if (needsForces[step] || needsEnergy[step]) {
// See if this step affects what we do at earlier points. // See if this step affects what we do at earlier points.
for (int candidate : candidatePoints) for (auto candidate : candidatePoints)
if ((needsForces[candidate] && needsEnergy[step]) || (needsEnergy[candidate] && needsForces[step])) if (candidate.second == forceGroup[step] && ((needsForces[candidate.first] && needsEnergy[step]) || (needsEnergy[candidate.first] && needsForces[step])))
computeBoth[candidate] = true; computeBoth[candidate.first] = true;
// Add this to the list of candidates that might be affected by later steps. // Add this to the list of candidates that might be affected by later steps.
candidatePoints.push_back(step); candidatePoints.push_back(make_pair(step, forceGroup[step]));
currentGroup = forceGroup[step];
} }
} }
} }
......
...@@ -170,14 +170,17 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc ...@@ -170,14 +170,17 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc
vector<vector<double> > classes; vector<vector<double> > classes;
map<vector<double>, int> classIndex; map<vector<double>, int> classIndex;
vector<int> atomClass(numParticles); vector<int> atomClass(numParticles);
for (int i = 0; i < numParticles; i++) {
vector<double> parameters; vector<double> parameters;
for (int i = 0; i < numParticles; i++) {
force.getParticleParameters(i, parameters); force.getParticleParameters(i, parameters);
if (classIndex.find(parameters) == classIndex.end()) { map<vector<double>, int>::iterator entry = classIndex.find(parameters);
if (entry == classIndex.end()) {
classIndex[parameters] = classes.size(); classIndex[parameters] = classes.size();
atomClass[i] = classes.size();
classes.push_back(parameters); classes.push_back(parameters);
} }
atomClass[i] = classIndex[parameters]; else
atomClass[i] = entry->second;
} }
int numClasses = classes.size(); int numClasses = classes.size();
...@@ -228,10 +231,18 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc ...@@ -228,10 +231,18 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc
double nPart = (double) numParticles; double nPart = (double) numParticles;
double numInteractions = (nPart*(nPart+1))/2; double numInteractions = (nPart*(nPart+1))/2;
Lepton::CompiledExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).createCompiledExpression(); Lepton::CompiledExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).createCompiledExpression();
vector<string> paramNames;
for (int i = 0; i < force.getNumPerParticleParameters(); i++) {
stringstream name1, name2;
name1 << force.getPerParticleParameterName(i) << 1;
name2 << force.getPerParticleParameterName(i) << 2;
paramNames.push_back(name1.str());
paramNames.push_back(name2.str());
}
double sum = 0; double sum = 0;
for (int i = 0; i < numClasses; i++) for (int i = 0; i < numClasses; i++)
for (int j = i; j < numClasses; j++) for (int j = i; j < numClasses; j++)
sum += interactionCount[make_pair(i, j)]*integrateInteraction(expression, classes[i], classes[j], force, context); sum += interactionCount[make_pair(i, j)]*integrateInteraction(expression, classes[i], classes[j], force, context, paramNames);
sum /= numInteractions; sum /= numInteractions;
coefficient = 2*M_PI*nPart*nPart*sum; coefficient = 2*M_PI*nPart*nPart*sum;
...@@ -244,23 +255,20 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc ...@@ -244,23 +255,20 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc
sum = 0; sum = 0;
for (int i = 0; i < numClasses; i++) for (int i = 0; i < numClasses; i++)
for (int j = i; j < numClasses; j++) for (int j = i; j < numClasses; j++)
sum += interactionCount[make_pair(i, j)]*integrateInteraction(expression, classes[i], classes[j], force, context); sum += interactionCount[make_pair(i, j)]*integrateInteraction(expression, classes[i], classes[j], force, context, paramNames);
sum /= numInteractions; sum /= numInteractions;
derivatives[k] = 2*M_PI*nPart*nPart*sum; derivatives[k] = 2*M_PI*nPart*nPart*sum;
} }
} }
double CustomNonbondedForceImpl::integrateInteraction(Lepton::CompiledExpression& expression, const vector<double>& params1, const vector<double>& params2, double CustomNonbondedForceImpl::integrateInteraction(Lepton::CompiledExpression& expression, const vector<double>& params1, const vector<double>& params2,
const CustomNonbondedForce& force, const Context& context) { const CustomNonbondedForce& force, const Context& context, const vector<string>& paramNames) {
const set<string>& variables = expression.getVariables(); const set<string>& variables = expression.getVariables();
for (int i = 0; i < force.getNumPerParticleParameters(); i++) { for (int i = 0; i < force.getNumPerParticleParameters(); i++) {
stringstream name1, name2; if (variables.find(paramNames[2*i]) != variables.end())
name1 << force.getPerParticleParameterName(i) << 1; expression.getVariableReference(paramNames[2*i]) = params1[i];
name2 << force.getPerParticleParameterName(i) << 2; if (variables.find(paramNames[2*i+1]) != variables.end())
if (variables.find(name1.str()) != variables.end()) expression.getVariableReference(paramNames[2*i+1]) = params2[i];
expression.getVariableReference(name1.str()) = params1[i];
if (variables.find(name2.str()) != variables.end())
expression.getVariableReference(name2.str()) = params2[i];
} }
for (int i = 0; i < force.getNumGlobalParameters(); i++) { for (int i = 0; i < force.getNumGlobalParameters(); i++) {
const string& name = force.getGlobalParameterName(i); const string& name = force.getGlobalParameterName(i);
......
/* -------------------------------------------------------------------------- *
* 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) 2017 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/internal/ForceImpl.h"
using namespace OpenMM;
using namespace std;
void ForceImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
// Usually subclasses will override this. If they don't, call the old
// (single argument) version instead, and just assume they invalidate forces.
updateContextState(context);
forcesInvalid = true;
}
void ForceImpl::updateContextState(ContextImpl& context) {
}
...@@ -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) 2010-2016 Stanford University and the Authors. * * Portions copyright (c) 2010-2017 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -68,7 +68,7 @@ void MonteCarloBarostatImpl::initialize(ContextImpl& context) { ...@@ -68,7 +68,7 @@ void MonteCarloBarostatImpl::initialize(ContextImpl& context) {
init_gen_rand(randSeed, random); init_gen_rand(randSeed, random);
} }
void MonteCarloBarostatImpl::updateContextState(ContextImpl& context) { void MonteCarloBarostatImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
if (++step < owner.getFrequency() || owner.getFrequency() == 0) if (++step < owner.getFrequency() || owner.getFrequency() == 0)
return; return;
step = 0; step = 0;
...@@ -101,8 +101,10 @@ void MonteCarloBarostatImpl::updateContextState(ContextImpl& context) { ...@@ -101,8 +101,10 @@ void MonteCarloBarostatImpl::updateContextState(ContextImpl& context) {
context.getOwner().setPeriodicBoxVectors(box[0], box[1], box[2]); context.getOwner().setPeriodicBoxVectors(box[0], box[1], box[2]);
volume = newVolume; volume = newVolume;
} }
else else {
numAccepted++; numAccepted++;
forcesInvalid = true;
}
numAttempted++; numAttempted++;
if (numAttempted >= 10) { if (numAttempted >= 10) {
if (numAccepted < 0.25*numAttempted) { if (numAccepted < 0.25*numAttempted) {
......
...@@ -568,7 +568,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -568,7 +568,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
int nextk = k+1; int nextk = k+1;
double deltax = x[nexti]-x[i]; double deltax = x[nexti]-x[i];
double deltay = y[nextj]-y[j]; double deltay = y[nextj]-y[j];
double deltaz = z[nextj]-z[j]; double deltaz = z[nextk]-z[k];
double e[] = {values[i+j*xsize+k*xysize], values[nexti+j*xsize+k*xysize], values[i+nextj*xsize+k*xysize], values[nexti+nextj*xsize+k*xysize], values[i+j*xsize+nextk*xysize], values[nexti+j*xsize+nextk*xysize], values[i+nextj*xsize+nextk*xysize], values[nexti+nextj*xsize+nextk*xysize]}; double e[] = {values[i+j*xsize+k*xysize], values[nexti+j*xsize+k*xysize], values[i+nextj*xsize+k*xysize], values[nexti+nextj*xsize+k*xysize], values[i+j*xsize+nextk*xysize], values[nexti+j*xsize+nextk*xysize], values[i+nextj*xsize+nextk*xysize], values[nexti+nextj*xsize+nextk*xysize]};
double e1[] = {d1[i+j*xsize+k*xysize], d1[nexti+j*xsize+k*xysize], d1[i+nextj*xsize+k*xysize], d1[nexti+nextj*xsize+k*xysize], d1[i+j*xsize+nextk*xysize], d1[nexti+j*xsize+nextk*xysize], d1[i+nextj*xsize+nextk*xysize], d1[nexti+nextj*xsize+nextk*xysize]}; double e1[] = {d1[i+j*xsize+k*xysize], d1[nexti+j*xsize+k*xysize], d1[i+nextj*xsize+k*xysize], d1[nexti+nextj*xsize+k*xysize], d1[i+j*xsize+nextk*xysize], d1[nexti+j*xsize+nextk*xysize], d1[i+nextj*xsize+nextk*xysize], d1[nexti+nextj*xsize+nextk*xysize]};
double e2[] = {d2[i+j*xsize+k*xysize], d2[nexti+j*xsize+k*xysize], d2[i+nextj*xsize+k*xysize], d2[nexti+nextj*xsize+k*xysize], d2[i+j*xsize+nextk*xysize], d2[nexti+j*xsize+nextk*xysize], d2[i+nextj*xsize+nextk*xysize], d2[nexti+nextj*xsize+nextk*xysize]}; double e2[] = {d2[i+j*xsize+k*xysize], d2[nexti+j*xsize+k*xysize], d2[i+nextj*xsize+k*xysize], d2[nexti+nextj*xsize+k*xysize], d2[i+j*xsize+nextk*xysize], d2[nexti+j*xsize+nextk*xysize], d2[i+nextj*xsize+nextk*xysize], d2[nexti+nextj*xsize+nextk*xysize]};
......
...@@ -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) 2012-2014 Stanford University and the Authors. * * Portions copyright (c) 2012-2017 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -105,8 +105,30 @@ double OutOfPlaneSite::getWeightCross() const { ...@@ -105,8 +105,30 @@ double OutOfPlaneSite::getWeightCross() const {
return weightCross; return weightCross;
} }
LocalCoordinatesSite::LocalCoordinatesSite(int particle1, int particle2, int particle3, const Vec3& originWeights, const Vec3& xWeights, const Vec3& yWeights, const Vec3& localPosition) : LocalCoordinatesSite::LocalCoordinatesSite(const vector<int>& particles, const vector<double>& originWeights, const vector<double>& xWeights, const vector<double>& yWeights, const Vec3& localPosition) :
originWeights(originWeights), xWeights(xWeights), yWeights(yWeights), localPosition(localPosition) { originWeights(originWeights), xWeights(xWeights), yWeights(yWeights), localPosition(localPosition) {
int numParticles = particles.size();
if (numParticles < 2)
throw OpenMMException("LocalCoordinatesSite: Must depend on at least two other particles");
if (originWeights.size() != numParticles || xWeights.size() != numParticles || yWeights.size() != numParticles)
throw OpenMMException("LocalCoordinatesSite: Number of weights does not match number of particles");
double originSum = 0, xSum = 0, ySum = 0;
for (int i = 0; i < numParticles; i++) {
originSum += originWeights[i];
xSum += xWeights[i];
ySum += yWeights[i];
}
if (fabs(originSum-1.0) > 1e-6)
throw OpenMMException("LocalCoordinatesSite: Weights for computing origin must add to 1");
if (fabs(xSum) > 1e-6)
throw OpenMMException("LocalCoordinatesSite: Weights for computing x axis must add to 0");
if (fabs(ySum) > 1e-6)
throw OpenMMException("LocalCoordinatesSite: Weights for computing y axis must add to 0");
setParticles(particles);
}
LocalCoordinatesSite::LocalCoordinatesSite(int particle1, int particle2, int particle3, const Vec3& originWeights, const Vec3& xWeights, const Vec3& yWeights, const Vec3& localPosition) :
localPosition(localPosition) {
if (fabs(originWeights[0]+originWeights[1]+originWeights[2]-1.0) > 1e-6) if (fabs(originWeights[0]+originWeights[1]+originWeights[2]-1.0) > 1e-6)
throw OpenMMException("LocalCoordinatesSite: Weights for computing origin must add to 1"); throw OpenMMException("LocalCoordinatesSite: Weights for computing origin must add to 1");
if (fabs(xWeights[0]+xWeights[1]+xWeights[2]) > 1e-6) if (fabs(xWeights[0]+xWeights[1]+xWeights[2]) > 1e-6)
...@@ -118,18 +140,45 @@ LocalCoordinatesSite::LocalCoordinatesSite(int particle1, int particle2, int par ...@@ -118,18 +140,45 @@ LocalCoordinatesSite::LocalCoordinatesSite(int particle1, int particle2, int par
particles[1] = particle2; particles[1] = particle2;
particles[2] = particle3; particles[2] = particle3;
setParticles(particles); setParticles(particles);
this->originWeights.push_back(originWeights[0]);
this->originWeights.push_back(originWeights[1]);
this->originWeights.push_back(originWeights[2]);
this->xWeights.push_back(xWeights[0]);
this->xWeights.push_back(xWeights[1]);
this->xWeights.push_back(xWeights[2]);
this->yWeights.push_back(yWeights[0]);
this->yWeights.push_back(yWeights[1]);
this->yWeights.push_back(yWeights[2]);
}
void LocalCoordinatesSite::getOriginWeights(vector<double>& weights) const {
weights = originWeights;
}
Vec3 LocalCoordinatesSite::getOriginWeights() const {
if (originWeights.size() != 3)
throw OpenMMException("LocalCoordinatesSite: This version of getOriginWeights() requires the site to depend on three particles");
return Vec3(originWeights[0], originWeights[1], originWeights[2]);
}
void LocalCoordinatesSite::getXWeights(vector<double>& weights) const {
weights = xWeights;
} }
const Vec3& LocalCoordinatesSite::getOriginWeights() const { Vec3 LocalCoordinatesSite::getXWeights() const {
return originWeights; if (xWeights.size() != 3)
throw OpenMMException("LocalCoordinatesSite: This version of getXWeights() requires the site to depend on three particles");
return Vec3(xWeights[0], xWeights[1], xWeights[2]);
} }
const Vec3& LocalCoordinatesSite::getXWeights() const { void LocalCoordinatesSite::getYWeights(vector<double>& weights) const {
return xWeights; weights = yWeights;
} }
const Vec3& LocalCoordinatesSite::getYWeights() const { Vec3 LocalCoordinatesSite::getYWeights() const {
return yWeights; if (yWeights.size() != 3)
throw OpenMMException("LocalCoordinatesSite: This version of getYWeights() requires the site to depend on three particles");
return Vec3(yWeights[0], yWeights[1], yWeights[2]);
} }
const Vec3& LocalCoordinatesSite::getLocalPosition() const { const Vec3& LocalCoordinatesSite::getLocalPosition() const {
......
...@@ -373,7 +373,7 @@ private: ...@@ -373,7 +373,7 @@ private:
class CpuCalcCustomGBForceKernel : public CalcCustomGBForceKernel { class CpuCalcCustomGBForceKernel : public CalcCustomGBForceKernel {
public: public:
CpuCalcCustomGBForceKernel(std::string name, const Platform& platform, CpuPlatform::PlatformData& data) : CpuCalcCustomGBForceKernel(std::string name, const Platform& platform, CpuPlatform::PlatformData& data) :
CalcCustomGBForceKernel(name, platform), data(data) { CalcCustomGBForceKernel(name, platform), data(data), ixn(NULL), neighborList(NULL) {
} }
~CpuCalcCustomGBForceKernel(); ~CpuCalcCustomGBForceKernel();
/** /**
...@@ -406,6 +406,7 @@ private: ...@@ -406,6 +406,7 @@ private:
double **particleParamArray; double **particleParamArray;
double nonbondedCutoff; double nonbondedCutoff;
CpuCustomGBForce* ixn; CpuCustomGBForce* ixn;
CpuNeighborList* neighborList;
std::vector<std::set<int> > exclusions; std::vector<std::set<int> > exclusions;
std::vector<std::string> particleParameterNames, globalParameterNames, energyParamDerivNames, valueNames; std::vector<std::string> particleParameterNames, globalParameterNames, energyParamDerivNames, valueNames;
std::vector<OpenMM::CustomGBForce::ComputationType> valueTypes; std::vector<OpenMM::CustomGBForce::ComputationType> valueTypes;
......
...@@ -68,6 +68,15 @@ public: ...@@ -68,6 +68,15 @@ public:
static const std::string key = "Threads"; static const std::string key = "Threads";
return key; return key;
} }
/**
* This is the name of the parameter for requesting that force computations be deterministic. Setting
* this to "true" DOES NOT GUARANTEE that the forces will actually be fully deterministic, but it does
* try to reduce the variation in them at the cost of a small loss in performance.
*/
static const std::string& CpuDeterministicForces() {
static const std::string key = "DeterministicForces";
return key;
}
/** /**
* We cannot use the standard mechanism for platform data, because that is already used by the superclass. * We cannot use the standard mechanism for platform data, because that is already used by the superclass.
* Instead, we maintain a table of ContextImpls to PlatformDatas. * Instead, we maintain a table of ContextImpls to PlatformDatas.
...@@ -80,7 +89,7 @@ private: ...@@ -80,7 +89,7 @@ private:
class CpuPlatform::PlatformData { class CpuPlatform::PlatformData {
public: public:
PlatformData(int numParticles, int numThreads); PlatformData(int numParticles, int numThreads, bool deterministicForces);
~PlatformData(); ~PlatformData();
void requestNeighborList(double cutoffDistance, double padding, bool useExclusions, const std::vector<std::set<int> >& exclusionList); void requestNeighborList(double cutoffDistance, double padding, bool useExclusions, const std::vector<std::set<int> >& exclusionList);
AlignedArray<float> posq; AlignedArray<float> posq;
...@@ -91,7 +100,7 @@ public: ...@@ -91,7 +100,7 @@ public:
std::map<std::string, std::string> propertyValues; std::map<std::string, std::string> propertyValues;
CpuNeighborList* neighborList; CpuNeighborList* neighborList;
double cutoff, paddedCutoff; double cutoff, paddedCutoff;
bool anyExclusions; bool anyExclusions, deterministicForces;
std::vector<std::set<int> > exclusions; std::vector<std::set<int> > exclusions;
}; };
......
...@@ -642,7 +642,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo ...@@ -642,7 +642,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
useOptimizedPme = getPlatform().supportsKernels(kernelNames); useOptimizedPme = getPlatform().supportsKernels(kernelNames);
if (useOptimizedPme) { if (useOptimizedPme) {
optimizedPme = getPlatform().createKernel(CalcPmeReciprocalForceKernel::Name(), context); optimizedPme = getPlatform().createKernel(CalcPmeReciprocalForceKernel::Name(), context);
optimizedPme.getAs<CalcPmeReciprocalForceKernel>().initialize(gridSize[0], gridSize[1], gridSize[2], numParticles, ewaldAlpha); optimizedPme.getAs<CalcPmeReciprocalForceKernel>().initialize(gridSize[0], gridSize[1], gridSize[2], numParticles, ewaldAlpha, data.deterministicForces);
} }
} }
if (nonbondedMethod == LJPME) { if (nonbondedMethod == LJPME) {
...@@ -653,10 +653,10 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo ...@@ -653,10 +653,10 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
useOptimizedPme = getPlatform().supportsKernels(kernelNames); useOptimizedPme = getPlatform().supportsKernels(kernelNames);
if (useOptimizedPme) { if (useOptimizedPme) {
optimizedPme = getPlatform().createKernel(CalcPmeReciprocalForceKernel::Name(), context); optimizedPme = getPlatform().createKernel(CalcPmeReciprocalForceKernel::Name(), context);
optimizedPme.getAs<CalcPmeReciprocalForceKernel>().initialize(gridSize[0], gridSize[1], gridSize[2], numParticles, ewaldAlpha); optimizedPme.getAs<CalcPmeReciprocalForceKernel>().initialize(gridSize[0], gridSize[1], gridSize[2], numParticles, ewaldAlpha, data.deterministicForces);
optimizedDispersionPme = getPlatform().createKernel(CalcDispersionPmeReciprocalForceKernel::Name(), context); optimizedDispersionPme = getPlatform().createKernel(CalcDispersionPmeReciprocalForceKernel::Name(), context);
optimizedDispersionPme.getAs<CalcDispersionPmeReciprocalForceKernel>().initialize(dispersionGridSize[0], dispersionGridSize[1], optimizedDispersionPme.getAs<CalcDispersionPmeReciprocalForceKernel>().initialize(dispersionGridSize[0], dispersionGridSize[1],
dispersionGridSize[2], numParticles, ewaldDispersionAlpha); dispersionGridSize[2], numParticles, ewaldDispersionAlpha, data.deterministicForces);
} }
} }
} }
...@@ -1018,6 +1018,8 @@ CpuCalcCustomGBForceKernel::~CpuCalcCustomGBForceKernel() { ...@@ -1018,6 +1018,8 @@ CpuCalcCustomGBForceKernel::~CpuCalcCustomGBForceKernel() {
} }
if (ixn != NULL) if (ixn != NULL)
delete ixn; delete ixn;
if (neighborList != NULL)
delete neighborList;
} }
void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGBForce& force) { void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGBForce& force) {
...@@ -1064,7 +1066,7 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB ...@@ -1064,7 +1066,7 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
nonbondedMethod = CalcCustomGBForceKernel::NonbondedMethod(force.getNonbondedMethod()); nonbondedMethod = CalcCustomGBForceKernel::NonbondedMethod(force.getNonbondedMethod());
nonbondedCutoff = force.getCutoffDistance(); nonbondedCutoff = force.getCutoffDistance();
if (nonbondedMethod != NoCutoff) if (nonbondedMethod != NoCutoff)
data.requestNeighborList(nonbondedCutoff, 0.25*nonbondedCutoff, force.getNumExclusions() > 0, exclusions); neighborList = new CpuNeighborList(4);
// Create custom functions for the tabulated functions. // Create custom functions for the tabulated functions.
...@@ -1171,7 +1173,8 @@ double CpuCalcCustomGBForceKernel::execute(ContextImpl& context, bool includeFor ...@@ -1171,7 +1173,8 @@ double CpuCalcCustomGBForceKernel::execute(ContextImpl& context, bool includeFor
ixn->setPeriodic(extractBoxSize(context)); ixn->setPeriodic(extractBoxSize(context));
if (nonbondedMethod != NoCutoff) { if (nonbondedMethod != NoCutoff) {
vector<set<int> > noExclusions(numParticles); vector<set<int> > noExclusions(numParticles);
ixn->setUseCutoff(nonbondedCutoff, *data.neighborList); neighborList->computeNeighborList(numParticles, data.posq, noExclusions, boxVectors, data.isPeriodic, nonbondedCutoff, data.threads);
ixn->setUseCutoff(nonbondedCutoff, *neighborList);
} }
map<string, double> globalParameters; map<string, double> globalParameters;
for (auto& name : globalParameterNames) for (auto& name : globalParameterNames)
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/internal/hardware.h" #include "openmm/internal/hardware.h"
#include "openmm/internal/vectorize.h" #include "openmm/internal/vectorize.h"
#include <algorithm>
#include <sstream> #include <sstream>
#include <stdlib.h> #include <stdlib.h>
...@@ -74,6 +75,7 @@ CpuPlatform::CpuPlatform() { ...@@ -74,6 +75,7 @@ CpuPlatform::CpuPlatform() {
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory); registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory); registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory);
platformProperties.push_back(CpuThreads()); platformProperties.push_back(CpuThreads());
platformProperties.push_back(CpuDeterministicForces());
int threads = getNumProcessors(); int threads = getNumProcessors();
char* threadsEnv = getenv("OPENMM_CPU_THREADS"); char* threadsEnv = getenv("OPENMM_CPU_THREADS");
if (threadsEnv != NULL) if (threadsEnv != NULL)
...@@ -81,6 +83,7 @@ CpuPlatform::CpuPlatform() { ...@@ -81,6 +83,7 @@ CpuPlatform::CpuPlatform() {
stringstream defaultThreads; stringstream defaultThreads;
defaultThreads << threads; defaultThreads << threads;
setPropertyDefaultValue(CpuThreads(), defaultThreads.str()); setPropertyDefaultValue(CpuThreads(), defaultThreads.str());
setPropertyDefaultValue(CpuDeterministicForces(), "false");
} }
const string& CpuPlatform::getPropertyValue(const Context& context, const string& property) const { const string& CpuPlatform::getPropertyValue(const Context& context, const string& property) const {
...@@ -111,9 +114,13 @@ void CpuPlatform::contextCreated(ContextImpl& context, const map<string, string> ...@@ -111,9 +114,13 @@ void CpuPlatform::contextCreated(ContextImpl& context, const map<string, string>
ReferencePlatform::contextCreated(context, properties); ReferencePlatform::contextCreated(context, properties);
const string& threadsPropValue = (properties.find(CpuThreads()) == properties.end() ? const string& threadsPropValue = (properties.find(CpuThreads()) == properties.end() ?
getPropertyDefaultValue(CpuThreads()) : properties.find(CpuThreads())->second); getPropertyDefaultValue(CpuThreads()) : properties.find(CpuThreads())->second);
string deterministicForcesValue = (properties.find(CpuDeterministicForces()) == properties.end() ?
getPropertyDefaultValue(CpuDeterministicForces()) : properties.find(CpuDeterministicForces())->second);
int numThreads; int numThreads;
stringstream(threadsPropValue) >> numThreads; stringstream(threadsPropValue) >> numThreads;
PlatformData* data = new PlatformData(context.getSystem().getNumParticles(), numThreads); transform(deterministicForcesValue.begin(), deterministicForcesValue.end(), deterministicForcesValue.begin(), ::tolower);
bool deterministicForces = (deterministicForcesValue == "true");
PlatformData* data = new PlatformData(context.getSystem().getNumParticles(), numThreads, deterministicForces);
contextData[&context] = data; contextData[&context] = data;
ReferenceConstraints& constraints = *(ReferenceConstraints*) reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData())->constraints; ReferenceConstraints& constraints = *(ReferenceConstraints*) reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData())->constraints;
if (constraints.settle != NULL) { if (constraints.settle != NULL) {
...@@ -139,8 +146,8 @@ const CpuPlatform::PlatformData& CpuPlatform::getPlatformData(const ContextImpl& ...@@ -139,8 +146,8 @@ const CpuPlatform::PlatformData& CpuPlatform::getPlatformData(const ContextImpl&
return *contextData[&context]; return *contextData[&context];
} }
CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads) : posq(4*numParticles), threads(numThreads), CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads, bool deterministicForces) : posq(4*numParticles), threads(numThreads),
neighborList(NULL), cutoff(0.0), paddedCutoff(0.0), anyExclusions(false) { deterministicForces(deterministicForces), neighborList(NULL), cutoff(0.0), paddedCutoff(0.0), anyExclusions(false) {
numThreads = threads.getNumThreads(); numThreads = threads.getNumThreads();
threadForce.resize(numThreads); threadForce.resize(numThreads);
for (int i = 0; i < numThreads; i++) for (int i = 0; i < numThreads; i++)
...@@ -149,6 +156,7 @@ CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads) : posq ...@@ -149,6 +156,7 @@ CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads) : posq
stringstream threadsProperty; stringstream threadsProperty;
threadsProperty << numThreads; threadsProperty << numThreads;
propertyValues[CpuThreads()] = threadsProperty.str(); propertyValues[CpuThreads()] = threadsProperty.str();
propertyValues[CpuDeterministicForces()] = deterministicForces ? "true" : "false";
} }
CpuPlatform::PlatformData::~PlatformData() { CpuPlatform::PlatformData::~PlatformData() {
......
...@@ -77,7 +77,8 @@ public: ...@@ -77,7 +77,8 @@ public:
static const int ThreadBlockSize; static const int ThreadBlockSize;
static const int TileSize; static const int TileSize;
CudaContext(const System& system, int deviceIndex, bool useBlockingSync, const std::string& precision, CudaContext(const System& system, int deviceIndex, bool useBlockingSync, const std::string& precision,
const std::string& compiler, const std::string& tempDir, const std::string& hostCompiler, CudaPlatform::PlatformData& platformData); const std::string& compiler, const std::string& tempDir, const std::string& hostCompiler, CudaPlatform::PlatformData& platformData,
CudaContext* originalContext);
~CudaContext(); ~CudaContext();
/** /**
* This is called to initialize internal data structures after all Forces in the system * This is called to initialize internal data structures after all Forces in the system
...@@ -284,6 +285,10 @@ public: ...@@ -284,6 +285,10 @@ public:
* Clear all buffers that have been registered with addAutoclearBuffer(). * Clear all buffers that have been registered with addAutoclearBuffer().
*/ */
void clearAutoclearBuffers(); void clearAutoclearBuffers();
/**
* Sum the buffer containing energy.
*/
double reduceEnergy();
/** /**
* Get the current simulation time. * Get the current simulation time.
*/ */
...@@ -622,6 +627,7 @@ private: ...@@ -622,6 +627,7 @@ private:
int numAtomBlocks; int numAtomBlocks;
int numThreadBlocks; int numThreadBlocks;
bool useBlockingSync, useDoublePrecision, useMixedPrecision, contextIsValid, atomsWereReordered, boxIsTriclinic, hasCompilerKernel, isNvccAvailable, forcesValid; bool useBlockingSync, useDoublePrecision, useMixedPrecision, contextIsValid, atomsWereReordered, boxIsTriclinic, hasCompilerKernel, isNvccAvailable, forcesValid;
bool isLinkedContext;
std::string compiler, tempDir, cacheDir, gpuArchitecture; std::string compiler, tempDir, cacheDir, gpuArchitecture;
float4 periodicBoxVecXFloat, periodicBoxVecYFloat, periodicBoxVecZFloat, periodicBoxSizeFloat, invPeriodicBoxSizeFloat; float4 periodicBoxVecXFloat, periodicBoxVecYFloat, periodicBoxVecZFloat, periodicBoxSizeFloat, invPeriodicBoxSizeFloat;
double4 periodicBoxVecX, periodicBoxVecY, periodicBoxVecZ, periodicBoxSize, invPeriodicBoxSize; double4 periodicBoxVecX, periodicBoxVecY, periodicBoxVecZ, periodicBoxSize, invPeriodicBoxSize;
...@@ -636,6 +642,7 @@ private: ...@@ -636,6 +642,7 @@ private:
CUfunction clearFourBuffersKernel; CUfunction clearFourBuffersKernel;
CUfunction clearFiveBuffersKernel; CUfunction clearFiveBuffersKernel;
CUfunction clearSixBuffersKernel; CUfunction clearSixBuffersKernel;
CUfunction reduceEnergyKernel;
CUfunction setChargesKernel; CUfunction setChargesKernel;
std::vector<CudaForceInfo*> forces; std::vector<CudaForceInfo*> forces;
std::vector<Molecule> molecules; std::vector<Molecule> molecules;
...@@ -647,6 +654,7 @@ private: ...@@ -647,6 +654,7 @@ private:
CudaArray* velm; CudaArray* velm;
CudaArray* force; CudaArray* force;
CudaArray* energyBuffer; CudaArray* energyBuffer;
CudaArray* energySum;
CudaArray* energyParamDerivBuffer; CudaArray* energyParamDerivBuffer;
CudaArray* atomIndexDevice; CudaArray* atomIndexDevice;
CudaArray* chargeBuffer; CudaArray* chargeBuffer;
......
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