Commit 18295108 authored by peastman's avatar peastman
Browse files

Merge changes from main branch

parents e6101f68 8d7234e5
......@@ -53,7 +53,7 @@ public:
const PeriodicTorsionForce& getOwner() const {
return owner;
}
void updateContextState(ContextImpl& context) {
void updateContextState(ContextImpl& context, bool& forcesInvalid) {
// This force field doesn't update the state directly.
}
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
......
......@@ -53,7 +53,7 @@ public:
const RBTorsionForce& getOwner() const {
return owner;
}
void updateContextState(ContextImpl& context) {
void updateContextState(ContextImpl& context, bool& forcesInvalid) {
// This force field doesn't update the state directly.
}
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
......
......@@ -47,7 +47,7 @@ void AndersenThermostatImpl::initialize(ContextImpl& context) {
kernel.getAs<ApplyAndersenThermostatKernel>().initialize(context.getSystem(), owner);
}
void AndersenThermostatImpl::updateContextState(ContextImpl& context) {
void AndersenThermostatImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
kernel.getAs<ApplyAndersenThermostatKernel>().execute(context);
}
......
......@@ -48,7 +48,7 @@ void CMMotionRemoverImpl::initialize(ContextImpl& context) {
kernel.getAs<RemoveCMMotionKernel>().initialize(system, owner);
}
void CMMotionRemoverImpl::updateContextState(ContextImpl& context) {
void CMMotionRemoverImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
kernel.getAs<RemoveCMMotionKernel>().execute(context);
}
......
......@@ -40,16 +40,25 @@
using namespace OpenMM;
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>()) {
impl = new ContextImpl(*this, system, integrator, 0, properties);
impl->initialize();
}
Context::Context(const System& system, Integrator& integrator, Platform& platform) : properties(map<string, string>()) {
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) {
impl = new ContextImpl(*this, system, integrator, &platform, properties);
impl->initialize();
}
Context::~Context() {
......@@ -240,6 +249,7 @@ void Context::reinitialize() {
integrator.cleanup();
delete impl;
impl = new ContextImpl(*this, system, integrator, &platform, properties);
impl->initialize();
}
void Context::createCheckpoint(ostream& stream) {
......
......@@ -53,7 +53,7 @@ using namespace std;
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),
lastForceGroups(-1), platform(platform), platformData(NULL) {
int numParticles = system.getNumParticles();
......@@ -119,8 +119,6 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
kernelNames.push_back(VirtualSitesKernel::Name());
for (int i = 0; i < system.getNumForces(); ++i) {
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();
kernelNames.insert(kernelNames.begin(), forceKernels.begin(), forceKernels.end());
}
......@@ -154,7 +152,10 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
for (int i = candidatePlatforms.size()-1; i >= 0; i--) {
try {
this->platform = platform = candidatePlatforms[i].second;
if (originalContext == NULL)
platform->contextCreated(*this, validatedProperties);
else
platform->linkedContextCreated(*this, *originalContext);
break;
}
catch (...) {
......@@ -163,7 +164,9 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
throw;
}
}
}
void ContextImpl::initialize() {
// Create and initialize kernels and other objects.
initializeForcesKernel = platform->createKernel(CalcForcesAndEnergyKernel::Name(), *this);
......@@ -177,10 +180,13 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
Vec3 periodicBoxVectors[3];
system.getDefaultPeriodicBoxVectors(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);
map<string, double> forceParameters = forceImpls[i]->getDefaultParameters();
parameters.insert(forceParameters.begin(), forceParameters.end());
}
integrator.initialize(*this);
updateStateDataKernel.getAs<UpdateStateDataKernel>().setVelocities(*this, vector<Vec3>(numParticles));
updateStateDataKernel.getAs<UpdateStateDataKernel>().setVelocities(*this, vector<Vec3>(system.getNumParticles()));
}
ContextImpl::~ContextImpl() {
......@@ -301,7 +307,7 @@ double ContextImpl::calcForcesAndEnergy(bool includeForces, bool includeEnergy,
}
}
int ContextImpl::getLastForceGroups() const {
int& ContextImpl::getLastForceGroups() {
return lastForceGroups;
}
......@@ -309,9 +315,11 @@ double ContextImpl::calcKineticEnergy() {
return integrator.computeKineticEnergy();
}
void ContextImpl::updateContextState() {
bool ContextImpl::updateContextState() {
bool forcesInvalid = false;
for (auto force : forceImpls)
force->updateContextState(*this);
force->updateContextState(*this, forcesInvalid);
return forcesInvalid;
}
const vector<ForceImpl*>& ContextImpl::getForceImpls() const {
......@@ -478,3 +486,7 @@ void ContextImpl::loadCheckpoint(istream& stream) {
void ContextImpl::systemChanged() {
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 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* 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 *
* Contributors: *
* *
......@@ -48,6 +48,11 @@ CustomIntegrator::CustomIntegrator(double stepSize) : globalsAreCurrent(true), f
kineticEnergy = "m*v*v/2";
}
CustomIntegrator::~CustomIntegrator() {
for (auto function : functions)
delete function.function;
}
void CustomIntegrator::initialize(ContextImpl& contextRef) {
if (owner != NULL && &contextRef.getOwner() != owner)
throw OpenMMException("This Integrator is already bound to a context");
......@@ -281,6 +286,26 @@ void CustomIntegrator::getComputationStep(int index, ComputationType& type, stri
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 {
return kineticEnergy;
}
......
......@@ -37,6 +37,7 @@
#include <algorithm>
#include <set>
#include <sstream>
#include <utility>
using namespace OpenMM;
using namespace std;
......@@ -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,
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();
expressions.resize(numSteps);
comparisons.resize(numSteps);
......@@ -82,7 +83,7 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
forceGroup.resize(numSteps, -2);
vector<CustomIntegrator::ComputationType> stepType(numSteps);
vector<string> stepVariable(numSteps);
map<string, Lepton::CustomFunction*> customFunctions;
map<string, Lepton::CustomFunction*> customFunctions = functions;
DerivFunction derivFunction;
customFunctions["deriv"] = &derivFunction;
......@@ -111,7 +112,8 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
for (auto& param : force->getDefaultParameters())
affectsForce.insert(param.first);
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.
......@@ -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,
const vector<bool>& invalidatesForces, const vector<int>& forceGroup, vector<bool>& computeBoth) {
vector<int> candidatePoints;
int currentGroup = -1;
vector<pair<int, int> > candidatePoints;
for (int step : steps) {
if (invalidatesForces[step] || ((needsForces[step] || needsEnergy[step]) && forceGroup[step] != currentGroup)) {
// Forces and energies are invalidated at this step, or it changes to a different force group,
// so anything from this point on won't affect what we do at earlier steps.
if (invalidatesForces[step]) {
// Forces and energies are invalidated at this step, so anything from this point on won't affect what we do at earlier steps.
candidatePoints.clear();
}
if (needsForces[step] || needsEnergy[step]) {
// See if this step affects what we do at earlier points.
for (int candidate : candidatePoints)
if ((needsForces[candidate] && needsEnergy[step]) || (needsEnergy[candidate] && needsForces[step]))
computeBoth[candidate] = true;
for (auto candidate : candidatePoints)
if (candidate.second == forceGroup[step] && ((needsForces[candidate.first] && needsEnergy[step]) || (needsEnergy[candidate.first] && needsForces[step])))
computeBoth[candidate.first] = true;
// Add this to the list of candidates that might be affected by later steps.
candidatePoints.push_back(step);
currentGroup = forceGroup[step];
candidatePoints.push_back(make_pair(step, forceGroup[step]));
}
}
}
......
......@@ -170,14 +170,17 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc
vector<vector<double> > classes;
map<vector<double>, int> classIndex;
vector<int> atomClass(numParticles);
for (int i = 0; i < numParticles; i++) {
vector<double> parameters;
for (int i = 0; i < numParticles; i++) {
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();
atomClass[i] = classes.size();
classes.push_back(parameters);
}
atomClass[i] = classIndex[parameters];
else
atomClass[i] = entry->second;
}
int numClasses = classes.size();
......@@ -228,10 +231,18 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc
double nPart = (double) numParticles;
double numInteractions = (nPart*(nPart+1))/2;
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;
for (int i = 0; i < numClasses; i++)
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;
coefficient = 2*M_PI*nPart*nPart*sum;
......@@ -244,23 +255,20 @@ void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForc
sum = 0;
for (int i = 0; i < numClasses; i++)
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;
derivatives[k] = 2*M_PI*nPart*nPart*sum;
}
}
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();
for (int i = 0; i < force.getNumPerParticleParameters(); i++) {
stringstream name1, name2;
name1 << force.getPerParticleParameterName(i) << 1;
name2 << force.getPerParticleParameterName(i) << 2;
if (variables.find(name1.str()) != variables.end())
expression.getVariableReference(name1.str()) = params1[i];
if (variables.find(name2.str()) != variables.end())
expression.getVariableReference(name2.str()) = params2[i];
if (variables.find(paramNames[2*i]) != variables.end())
expression.getVariableReference(paramNames[2*i]) = params1[i];
if (variables.find(paramNames[2*i+1]) != variables.end())
expression.getVariableReference(paramNames[2*i+1]) = params2[i];
}
for (int i = 0; i < force.getNumGlobalParameters(); 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 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* 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 *
* Contributors: *
* *
......@@ -68,7 +68,7 @@ void MonteCarloBarostatImpl::initialize(ContextImpl& context) {
init_gen_rand(randSeed, random);
}
void MonteCarloBarostatImpl::updateContextState(ContextImpl& context) {
void MonteCarloBarostatImpl::updateContextState(ContextImpl& context, bool& forcesInvalid) {
if (++step < owner.getFrequency() || owner.getFrequency() == 0)
return;
step = 0;
......@@ -101,8 +101,10 @@ void MonteCarloBarostatImpl::updateContextState(ContextImpl& context) {
context.getOwner().setPeriodicBoxVectors(box[0], box[1], box[2]);
volume = newVolume;
}
else
else {
numAccepted++;
forcesInvalid = true;
}
numAttempted++;
if (numAttempted >= 10) {
if (numAccepted < 0.25*numAttempted) {
......
......@@ -568,7 +568,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
int nextk = k+1;
double deltax = x[nexti]-x[i];
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 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]};
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* 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 *
* Contributors: *
* *
......@@ -105,8 +105,30 @@ double OutOfPlaneSite::getWeightCross() const {
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) {
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)
throw OpenMMException("LocalCoordinatesSite: Weights for computing origin must add to 1");
if (fabs(xWeights[0]+xWeights[1]+xWeights[2]) > 1e-6)
......@@ -118,18 +140,45 @@ LocalCoordinatesSite::LocalCoordinatesSite(int particle1, int particle2, int par
particles[1] = particle2;
particles[2] = particle3;
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 {
return originWeights;
Vec3 LocalCoordinatesSite::getXWeights() const {
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 {
return xWeights;
void LocalCoordinatesSite::getYWeights(vector<double>& weights) const {
weights = yWeights;
}
const Vec3& LocalCoordinatesSite::getYWeights() const {
return yWeights;
Vec3 LocalCoordinatesSite::getYWeights() const {
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 {
......
......@@ -373,7 +373,7 @@ private:
class CpuCalcCustomGBForceKernel : public CalcCustomGBForceKernel {
public:
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();
/**
......@@ -406,6 +406,7 @@ private:
double **particleParamArray;
double nonbondedCutoff;
CpuCustomGBForce* ixn;
CpuNeighborList* neighborList;
std::vector<std::set<int> > exclusions;
std::vector<std::string> particleParameterNames, globalParameterNames, energyParamDerivNames, valueNames;
std::vector<OpenMM::CustomGBForce::ComputationType> valueTypes;
......
......@@ -68,6 +68,15 @@ public:
static const std::string key = "Threads";
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.
* Instead, we maintain a table of ContextImpls to PlatformDatas.
......@@ -80,7 +89,7 @@ private:
class CpuPlatform::PlatformData {
public:
PlatformData(int numParticles, int numThreads);
PlatformData(int numParticles, int numThreads, bool deterministicForces);
~PlatformData();
void requestNeighborList(double cutoffDistance, double padding, bool useExclusions, const std::vector<std::set<int> >& exclusionList);
AlignedArray<float> posq;
......@@ -91,7 +100,7 @@ public:
std::map<std::string, std::string> propertyValues;
CpuNeighborList* neighborList;
double cutoff, paddedCutoff;
bool anyExclusions;
bool anyExclusions, deterministicForces;
std::vector<std::set<int> > exclusions;
};
......
......@@ -642,7 +642,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
useOptimizedPme = getPlatform().supportsKernels(kernelNames);
if (useOptimizedPme) {
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) {
......@@ -653,10 +653,10 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
useOptimizedPme = getPlatform().supportsKernels(kernelNames);
if (useOptimizedPme) {
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.getAs<CalcDispersionPmeReciprocalForceKernel>().initialize(dispersionGridSize[0], dispersionGridSize[1],
dispersionGridSize[2], numParticles, ewaldDispersionAlpha);
dispersionGridSize[2], numParticles, ewaldDispersionAlpha, data.deterministicForces);
}
}
}
......@@ -1018,6 +1018,8 @@ CpuCalcCustomGBForceKernel::~CpuCalcCustomGBForceKernel() {
}
if (ixn != NULL)
delete ixn;
if (neighborList != NULL)
delete neighborList;
}
void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGBForce& force) {
......@@ -1064,7 +1066,7 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
nonbondedMethod = CalcCustomGBForceKernel::NonbondedMethod(force.getNonbondedMethod());
nonbondedCutoff = force.getCutoffDistance();
if (nonbondedMethod != NoCutoff)
data.requestNeighborList(nonbondedCutoff, 0.25*nonbondedCutoff, force.getNumExclusions() > 0, exclusions);
neighborList = new CpuNeighborList(4);
// Create custom functions for the tabulated functions.
......@@ -1171,7 +1173,8 @@ double CpuCalcCustomGBForceKernel::execute(ContextImpl& context, bool includeFor
ixn->setPeriodic(extractBoxSize(context));
if (nonbondedMethod != NoCutoff) {
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;
for (auto& name : globalParameterNames)
......
......@@ -37,6 +37,7 @@
#include "openmm/OpenMMException.h"
#include "openmm/internal/hardware.h"
#include "openmm/internal/vectorize.h"
#include <algorithm>
#include <sstream>
#include <stdlib.h>
......@@ -74,6 +75,7 @@ CpuPlatform::CpuPlatform() {
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory);
platformProperties.push_back(CpuThreads());
platformProperties.push_back(CpuDeterministicForces());
int threads = getNumProcessors();
char* threadsEnv = getenv("OPENMM_CPU_THREADS");
if (threadsEnv != NULL)
......@@ -81,6 +83,7 @@ CpuPlatform::CpuPlatform() {
stringstream defaultThreads;
defaultThreads << threads;
setPropertyDefaultValue(CpuThreads(), defaultThreads.str());
setPropertyDefaultValue(CpuDeterministicForces(), "false");
}
const string& CpuPlatform::getPropertyValue(const Context& context, const string& property) const {
......@@ -111,9 +114,13 @@ void CpuPlatform::contextCreated(ContextImpl& context, const map<string, string>
ReferencePlatform::contextCreated(context, properties);
const string& threadsPropValue = (properties.find(CpuThreads()) == properties.end() ?
getPropertyDefaultValue(CpuThreads()) : properties.find(CpuThreads())->second);
string deterministicForcesValue = (properties.find(CpuDeterministicForces()) == properties.end() ?
getPropertyDefaultValue(CpuDeterministicForces()) : properties.find(CpuDeterministicForces())->second);
int 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;
ReferenceConstraints& constraints = *(ReferenceConstraints*) reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData())->constraints;
if (constraints.settle != NULL) {
......@@ -139,8 +146,8 @@ const CpuPlatform::PlatformData& CpuPlatform::getPlatformData(const ContextImpl&
return *contextData[&context];
}
CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads) : posq(4*numParticles), threads(numThreads),
neighborList(NULL), cutoff(0.0), paddedCutoff(0.0), anyExclusions(false) {
CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads, bool deterministicForces) : posq(4*numParticles), threads(numThreads),
deterministicForces(deterministicForces), neighborList(NULL), cutoff(0.0), paddedCutoff(0.0), anyExclusions(false) {
numThreads = threads.getNumThreads();
threadForce.resize(numThreads);
for (int i = 0; i < numThreads; i++)
......@@ -149,6 +156,7 @@ CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads) : posq
stringstream threadsProperty;
threadsProperty << numThreads;
propertyValues[CpuThreads()] = threadsProperty.str();
propertyValues[CpuDeterministicForces()] = deterministicForces ? "true" : "false";
}
CpuPlatform::PlatformData::~PlatformData() {
......
......@@ -77,7 +77,8 @@ public:
static const int ThreadBlockSize;
static const int TileSize;
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();
/**
* This is called to initialize internal data structures after all Forces in the system
......@@ -284,6 +285,10 @@ public:
* Clear all buffers that have been registered with addAutoclearBuffer().
*/
void clearAutoclearBuffers();
/**
* Sum the buffer containing energy.
*/
double reduceEnergy();
/**
* Get the current simulation time.
*/
......@@ -622,6 +627,7 @@ private:
int numAtomBlocks;
int numThreadBlocks;
bool useBlockingSync, useDoublePrecision, useMixedPrecision, contextIsValid, atomsWereReordered, boxIsTriclinic, hasCompilerKernel, isNvccAvailable, forcesValid;
bool isLinkedContext;
std::string compiler, tempDir, cacheDir, gpuArchitecture;
float4 periodicBoxVecXFloat, periodicBoxVecYFloat, periodicBoxVecZFloat, periodicBoxSizeFloat, invPeriodicBoxSizeFloat;
double4 periodicBoxVecX, periodicBoxVecY, periodicBoxVecZ, periodicBoxSize, invPeriodicBoxSize;
......@@ -636,6 +642,7 @@ private:
CUfunction clearFourBuffersKernel;
CUfunction clearFiveBuffersKernel;
CUfunction clearSixBuffersKernel;
CUfunction reduceEnergyKernel;
CUfunction setChargesKernel;
std::vector<CudaForceInfo*> forces;
std::vector<Molecule> molecules;
......@@ -647,6 +654,7 @@ private:
CudaArray* velm;
CudaArray* force;
CudaArray* energyBuffer;
CudaArray* energySum;
CudaArray* energyParamDerivBuffer;
CudaArray* atomIndexDevice;
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