Commit 604881dc authored by peastman's avatar peastman
Browse files

Merge pull request #604 from peastman/many

Created CustomManyParticleForce
parents f2eb95d0 1515e2bc
...@@ -105,7 +105,7 @@ ReferenceBondIxn::~ReferenceBondIxn( ){ ...@@ -105,7 +105,7 @@ ReferenceBondIxn::~ReferenceBondIxn( ){
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
RealOpenMM ReferenceBondIxn::getNormedDotProduct( RealOpenMM* vector1, RealOpenMM* vector2, RealOpenMM ReferenceBondIxn::getNormedDotProduct( RealOpenMM* vector1, RealOpenMM* vector2,
int hasREntry = 0 ) const { int hasREntry = 0 ) {
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
...@@ -187,7 +187,7 @@ RealOpenMM ReferenceBondIxn::getNormedDotProduct( RealOpenMM* vector1, RealOpenM ...@@ -187,7 +187,7 @@ RealOpenMM ReferenceBondIxn::getNormedDotProduct( RealOpenMM* vector1, RealOpenM
RealOpenMM ReferenceBondIxn::getAngleBetweenTwoVectors( RealOpenMM* vector1, RealOpenMM* vector2, RealOpenMM ReferenceBondIxn::getAngleBetweenTwoVectors( RealOpenMM* vector1, RealOpenMM* vector2,
RealOpenMM* outputDotProduct = NULL, RealOpenMM* outputDotProduct = NULL,
int hasREntry = 0 ) const { int hasREntry = 0 ) {
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
...@@ -249,7 +249,7 @@ RealOpenMM ReferenceBondIxn::getDihedralAngleBetweenThreeVectors( RealOpenMM* v ...@@ -249,7 +249,7 @@ RealOpenMM ReferenceBondIxn::getDihedralAngleBetweenThreeVectors( RealOpenMM* v
RealOpenMM* cosineOfAngle = NULL, RealOpenMM* cosineOfAngle = NULL,
RealOpenMM* signVector = NULL, RealOpenMM* signVector = NULL,
RealOpenMM* signOfAngle = NULL, RealOpenMM* signOfAngle = NULL,
int hasREntry = 0 ) const { int hasREntry = 0 ) {
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
......
/* Portions copyright (c) 2009-2014 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* 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 <string.h>
#include <sstream>
#include <utility>
#include "SimTKOpenMMCommon.h"
#include "SimTKOpenMMLog.h"
#include "SimTKOpenMMUtilities.h"
#include "ReferenceForce.h"
#include "ReferenceCustomManyParticleIxn.h"
#include "ReferenceTabulatedFunction.h"
#include "openmm/internal/CustomManyParticleForceImpl.h"
#include "lepton/CustomFunction.h"
using namespace OpenMM;
using namespace std;
ReferenceCustomManyParticleIxn::ReferenceCustomManyParticleIxn(const CustomManyParticleForce& force) : useCutoff(false), usePeriodic(false) {
numParticlesPerSet = force.getNumParticlesPerSet();
numPerParticleParameters = force.getNumPerParticleParameters();
centralParticleMode = (force.getPermutationMode() == CustomManyParticleForce::UniqueCentralParticle);
// Create custom functions for the tabulated functions.
map<string, Lepton::CustomFunction*> functions;
for (int i = 0; i < (int) force.getNumTabulatedFunctions(); i++)
functions[force.getTabulatedFunctionName(i)] = createReferenceTabulatedFunction(force.getTabulatedFunction(i));
// Parse the expression and create the object used to calculate the interaction.
map<string, vector<int> > distances;
map<string, vector<int> > angles;
map<string, vector<int> > dihedrals;
Lepton::ParsedExpression energyExpr = CustomManyParticleForceImpl::prepareExpression(force, functions, distances, angles, dihedrals);
energyExpression = energyExpr.createProgram();
vector<string> particleParameterNames;
if (force.getNonbondedMethod() != CustomManyParticleForce::NoCutoff)
setUseCutoff(force.getCutoffDistance());
// Delete the custom functions.
for (map<string, Lepton::CustomFunction*>::iterator iter = functions.begin(); iter != functions.end(); iter++)
delete iter->second;
// Differentiate the energy to get expressions for the force.
particleParamNames.resize(numParticlesPerSet);
for (int i = 0; i < numParticlesPerSet; i++) {
stringstream xname, yname, zname;
xname << 'x' << (i+1);
yname << 'y' << (i+1);
zname << 'z' << (i+1);
particleTerms.push_back(ReferenceCustomManyParticleIxn::ParticleTermInfo(xname.str(), i, 0, energyExpr.differentiate(xname.str()).optimize().createProgram()));
particleTerms.push_back(ReferenceCustomManyParticleIxn::ParticleTermInfo(yname.str(), i, 1, energyExpr.differentiate(yname.str()).optimize().createProgram()));
particleTerms.push_back(ReferenceCustomManyParticleIxn::ParticleTermInfo(zname.str(), i, 2, energyExpr.differentiate(zname.str()).optimize().createProgram()));
for (int j = 0; j < numPerParticleParameters; j++) {
stringstream paramname;
paramname << force.getPerParticleParameterName(j) << (i+1);
particleParamNames[i].push_back(paramname.str());
}
}
for (map<string, vector<int> >::const_iterator iter = distances.begin(); iter != distances.end(); ++iter)
distanceTerms.push_back(ReferenceCustomManyParticleIxn::DistanceTermInfo(iter->first, iter->second, energyExpr.differentiate(iter->first).optimize().createProgram()));
for (map<string, vector<int> >::const_iterator iter = angles.begin(); iter != angles.end(); ++iter)
angleTerms.push_back(ReferenceCustomManyParticleIxn::AngleTermInfo(iter->first, iter->second, energyExpr.differentiate(iter->first).optimize().createProgram()));
for (map<string, vector<int> >::const_iterator iter = dihedrals.begin(); iter != dihedrals.end(); ++iter)
dihedralTerms.push_back(ReferenceCustomManyParticleIxn::DihedralTermInfo(iter->first, iter->second, energyExpr.differentiate(iter->first).optimize().createProgram()));
// Record exclusions.
exclusions.resize(force.getNumParticles());
for (int i = 0; i < (int) force.getNumExclusions(); i++) {
int p1, p2;
force.getExclusionParticles(i, p1, p2);
exclusions[p1].insert(p2);
exclusions[p2].insert(p1);
}
// Record information about type filters.
CustomManyParticleForceImpl::buildFilterArrays(force, numTypes, particleTypes, orderIndex, particleOrder);
}
ReferenceCustomManyParticleIxn::~ReferenceCustomManyParticleIxn( ){
}
void ReferenceCustomManyParticleIxn::calculateIxn(vector<RealVec>& atomCoordinates, RealOpenMM** particleParameters,
const map<string, double>& globalParameters, vector<RealVec>& forces,
RealOpenMM* totalEnergy) const {
map<string, double> variables = globalParameters;
vector<int> particles(numParticlesPerSet);
loopOverInteractions(particles, 0, atomCoordinates, particleParameters, variables, forces, totalEnergy);
}
void ReferenceCustomManyParticleIxn::setUseCutoff(RealOpenMM distance) {
useCutoff = true;
cutoffDistance = distance;
}
void ReferenceCustomManyParticleIxn::setPeriodic(RealVec& boxSize) {
assert(useCutoff);
assert(boxSize[0] >= 2.0*cutoffDistance);
assert(boxSize[1] >= 2.0*cutoffDistance);
assert(boxSize[2] >= 2.0*cutoffDistance);
usePeriodic = true;
periodicBoxSize[0] = boxSize[0];
periodicBoxSize[1] = boxSize[1];
periodicBoxSize[2] = boxSize[2];
}
void ReferenceCustomManyParticleIxn::loopOverInteractions(vector<int>& particles, int loopIndex, vector<OpenMM::RealVec>& atomCoordinates,
RealOpenMM** particleParameters, map<string, double>& variables, vector<OpenMM::RealVec>& forces,
RealOpenMM* totalEnergy) const {
int numParticles = atomCoordinates.size();
int firstPartialLoop = (centralParticleMode ? 2 : 1);
int start = (loopIndex < firstPartialLoop ? 0 : particles[loopIndex-1]+1);
for (int i = start; i < numParticles; i++) {
if (loopIndex > 0 && i == particles[0])
continue;
particles[loopIndex] = i;
if (loopIndex == numParticlesPerSet-1)
calculateOneIxn(particles, atomCoordinates, particleParameters, variables, forces, totalEnergy);
else
loopOverInteractions(particles, loopIndex+1, atomCoordinates, particleParameters, variables, forces, totalEnergy);
}
}
void ReferenceCustomManyParticleIxn::calculateOneIxn(const vector<int>& particles, vector<RealVec>& atomCoordinates,
RealOpenMM** particleParameters, map<string, double>& variables, vector<RealVec>& forces, RealOpenMM* totalEnergy) const {
// Select the ordering to use for the particles.
vector<int> permutedParticles(numParticlesPerSet);
if (particleOrder.size() == 1) {
// There are no filters, so we don't need to worry about ordering.
permutedParticles = particles;
}
else {
int index = 0;
for (int i = numParticlesPerSet-1; i >= 0; i--)
index = particleTypes[particles[i]]+numTypes*index;
int order = orderIndex[index];
if (order == -1)
return;
for (int i = 0; i < numParticlesPerSet; i++)
permutedParticles[i] = particles[particleOrder[order][i]];
}
// Decide whether to include this interaction.
for (int i = 0; i < numParticlesPerSet; i++) {
int p1 = permutedParticles[i];
for (int j = i+1; j < numParticlesPerSet; j++) {
int p2 = permutedParticles[j];
if (exclusions[p1].find(p2) != exclusions[p1].end())
return;
if (useCutoff && (i == 0 || !centralParticleMode)) {
RealOpenMM delta[ReferenceForce::LastDeltaRIndex];
computeDelta(p1, p2, delta, atomCoordinates);
if (delta[ReferenceForce::RIndex] >= cutoffDistance)
return;
}
}
}
// Record per-particle parameters.
for (int i = 0; i < numParticlesPerSet; i++)
for (int j = 0; j < numPerParticleParameters; j++)
variables[particleParamNames[i][j]] = particleParameters[permutedParticles[i]][j];
// Compute all of the variables the energy can depend on.
for (int i = 0; i < (int) particleTerms.size(); i++) {
const ParticleTermInfo& term = particleTerms[i];
variables[term.name] = atomCoordinates[permutedParticles[term.atom]][term.component];
}
for (int i = 0; i < (int) distanceTerms.size(); i++) {
const DistanceTermInfo& term = distanceTerms[i];
computeDelta(permutedParticles[term.p1], permutedParticles[term.p2], term.delta, atomCoordinates);
variables[term.name] = term.delta[ReferenceForce::RIndex];
}
for (int i = 0; i < (int) angleTerms.size(); i++) {
const AngleTermInfo& term = angleTerms[i];
computeDelta(permutedParticles[term.p1], permutedParticles[term.p2], term.delta1, atomCoordinates);
computeDelta(permutedParticles[term.p3], permutedParticles[term.p2], term.delta2, atomCoordinates);
variables[term.name] = computeAngle(term.delta1, term.delta2);
}
for (int i = 0; i < (int) dihedralTerms.size(); i++) {
const DihedralTermInfo& term = dihedralTerms[i];
computeDelta(permutedParticles[term.p2], permutedParticles[term.p1], term.delta1, atomCoordinates);
computeDelta(permutedParticles[term.p2], permutedParticles[term.p3], term.delta2, atomCoordinates);
computeDelta(permutedParticles[term.p4], permutedParticles[term.p3], term.delta3, atomCoordinates);
RealOpenMM dotDihedral, signOfDihedral;
RealOpenMM* crossProduct[] = {term.cross1, term.cross2};
variables[term.name] = ReferenceBondIxn::getDihedralAngleBetweenThreeVectors(term.delta1, term.delta2, term.delta3, crossProduct, &dotDihedral, term.delta1, &signOfDihedral, 1);
}
// Apply forces based on individual particle coordinates.
for (int i = 0; i < (int) particleTerms.size(); i++) {
const ParticleTermInfo& term = particleTerms[i];
forces[permutedParticles[term.atom]][term.component] -= term.forceExpression.evaluate(variables);
}
// Apply forces based on distances.
for (int i = 0; i < (int) distanceTerms.size(); i++) {
const DistanceTermInfo& term = distanceTerms[i];
RealOpenMM dEdR = (RealOpenMM) (term.forceExpression.evaluate(variables)/(term.delta[ReferenceForce::RIndex]));
for (int i = 0; i < 3; i++) {
RealOpenMM force = -dEdR*term.delta[i];
forces[permutedParticles[term.p1]][i] -= force;
forces[permutedParticles[term.p2]][i] += force;
}
}
// Apply forces based on angles.
for (int i = 0; i < (int) angleTerms.size(); i++) {
const AngleTermInfo& term = angleTerms[i];
RealOpenMM dEdTheta = (RealOpenMM) term.forceExpression.evaluate(variables);
RealOpenMM thetaCross[ReferenceForce::LastDeltaRIndex];
SimTKOpenMMUtilities::crossProductVector3(term.delta1, term.delta2, thetaCross);
RealOpenMM lengthThetaCross = SQRT(DOT3(thetaCross, thetaCross));
if (lengthThetaCross < 1.0e-06)
lengthThetaCross = (RealOpenMM) 1.0e-06;
RealOpenMM termA = dEdTheta/(term.delta1[ReferenceForce::R2Index]*lengthThetaCross);
RealOpenMM termC = -dEdTheta/(term.delta2[ReferenceForce::R2Index]*lengthThetaCross);
RealOpenMM deltaCrossP[3][3];
SimTKOpenMMUtilities::crossProductVector3(term.delta1, thetaCross, deltaCrossP[0]);
SimTKOpenMMUtilities::crossProductVector3(term.delta2, thetaCross, deltaCrossP[2]);
for (int i = 0; i < 3; i++) {
deltaCrossP[0][i] *= termA;
deltaCrossP[2][i] *= termC;
deltaCrossP[1][i] = -(deltaCrossP[0][i]+deltaCrossP[2][i]);
}
for (int i = 0; i < 3; i++) {
forces[permutedParticles[term.p1]][i] += deltaCrossP[0][i];
forces[permutedParticles[term.p2]][i] += deltaCrossP[1][i];
forces[permutedParticles[term.p3]][i] += deltaCrossP[2][i];
}
}
// Apply forces based on dihedrals.
for (int i = 0; i < (int) dihedralTerms.size(); i++) {
const DihedralTermInfo& term = dihedralTerms[i];
RealOpenMM dEdTheta = (RealOpenMM) term.forceExpression.evaluate(variables);
RealOpenMM internalF[4][3];
RealOpenMM forceFactors[4];
RealOpenMM normCross1 = DOT3(term.cross1, term.cross1);
RealOpenMM normBC = term.delta2[ReferenceForce::RIndex];
forceFactors[0] = (-dEdTheta*normBC)/normCross1;
RealOpenMM normCross2 = DOT3(term.cross2, term.cross2);
forceFactors[3] = (dEdTheta*normBC)/normCross2;
forceFactors[1] = DOT3(term.delta1, term.delta2);
forceFactors[1] /= term.delta2[ReferenceForce::R2Index];
forceFactors[2] = DOT3(term.delta3, term.delta2);
forceFactors[2] /= term.delta2[ReferenceForce::R2Index];
for (int i = 0; i < 3; i++) {
internalF[0][i] = forceFactors[0]*term.cross1[i];
internalF[3][i] = forceFactors[3]*term.cross2[i];
RealOpenMM s = forceFactors[1]*internalF[0][i] - forceFactors[2]*internalF[3][i];
internalF[1][i] = internalF[0][i] - s;
internalF[2][i] = internalF[3][i] + s;
}
for (int i = 0; i < 3; i++) {
forces[permutedParticles[term.p1]][i] += internalF[0][i];
forces[permutedParticles[term.p2]][i] -= internalF[1][i];
forces[permutedParticles[term.p3]][i] -= internalF[2][i];
forces[permutedParticles[term.p4]][i] += internalF[3][i];
}
}
// Add the energy
if (totalEnergy)
*totalEnergy += (RealOpenMM) energyExpression.evaluate(variables);
}
void ReferenceCustomManyParticleIxn::computeDelta(int atom1, int atom2, RealOpenMM* delta, vector<RealVec>& atomCoordinates) const {
if (usePeriodic)
ReferenceForce::getDeltaRPeriodic(atomCoordinates[atom1], atomCoordinates[atom2], periodicBoxSize, delta);
else
ReferenceForce::getDeltaR(atomCoordinates[atom1], atomCoordinates[atom2], delta);
}
RealOpenMM ReferenceCustomManyParticleIxn::computeAngle(RealOpenMM* vec1, RealOpenMM* vec2) {
RealOpenMM dot = DOT3(vec1, vec2);
RealOpenMM cosine = dot/SQRT((vec1[ReferenceForce::R2Index]*vec2[ReferenceForce::R2Index]));
RealOpenMM angle;
if (cosine >= 1)
angle = 0;
else if (cosine <= -1)
angle = PI_M;
else
angle = ACOS(cosine);
return angle;
}
/* -------------------------------------------------------------------------- *
* 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) 2014 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. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of CustomManyParticleForce.
*/
#ifdef WIN32
#define _USE_MATH_DEFINES // Needed to get M_PI
#endif
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "openmm/CustomCompoundBondForce.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/System.h"
#include "openmm/TabulatedFunction.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void validateAxilrodTeller(CustomManyParticleForce* force, const vector<Vec3>& positions, const vector<const int*>& expectedSets, double boxSize) {
// Create a System and Context.
int numParticles = force->getNumParticles();
CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod();
System system;
for (int i = 0; i < numParticles; i++)
system.addParticle(1.0);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(force);
VerletIntegrator integrator(0.001);
ReferencePlatform platform;
Context context(system, integrator, platform);
context.setPositions(positions);
State state1 = context.getState(State::Forces | State::Energy);
double c = context.getParameter("C");
// See if the energy matches the expected value.
double expectedEnergy = 0;
for (int i = 0; i < (int) expectedSets.size(); i++) {
int p1 = expectedSets[i][0];
int p2 = expectedSets[i][1];
int p3 = expectedSets[i][2];
Vec3 d12 = positions[p2]-positions[p1];
Vec3 d13 = positions[p3]-positions[p1];
Vec3 d23 = positions[p3]-positions[p2];
if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) {
for (int j = 0; j < 3; j++) {
d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize;
d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize;
d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize;
}
}
double r12 = sqrt(d12.dot(d12));
double r13 = sqrt(d13.dot(d13));
double r23 = sqrt(d23.dot(d23));
double ctheta1 = d12.dot(d13)/(r12*r13);
double ctheta2 = -d12.dot(d23)/(r12*r23);
double ctheta3 = d13.dot(d23)/(r13*r23);
double rprod = r12*r13*r23;
expectedEnergy += c*(1+3*ctheta1*ctheta2*ctheta3)/(rprod*rprod*rprod);
}
ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5);
// Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount.
const vector<Vec3>& forces = state1.getForces();
double norm = 0.0;
for (int i = 0; i < (int) forces.size(); ++i)
norm += forces[i].dot(forces[i]);
norm = std::sqrt(norm);
const double stepSize = 1e-3;
double step = 0.5*stepSize/norm;
vector<Vec3> positions2(numParticles), positions3(numParticles);
for (int i = 0; i < (int) positions.size(); ++i) {
Vec3 p = positions[i];
Vec3 f = forces[i];
positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step);
}
context.setPositions(positions2);
State state2 = context.getState(State::Energy);
context.setPositions(positions3);
State state3 = context.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4);
}
void validateStillingerWeber(CustomManyParticleForce* force, const vector<Vec3>& positions, const vector<const int*>& expectedSets, double boxSize) {
// Create a System and Context.
int numParticles = force->getNumParticles();
CustomManyParticleForce::NonbondedMethod nonbondedMethod = force->getNonbondedMethod();
System system;
for (int i = 0; i < numParticles; i++)
system.addParticle(1.0);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(force);
VerletIntegrator integrator(0.001);
ReferencePlatform platform;
Context context(system, integrator, platform);
context.setPositions(positions);
State state1 = context.getState(State::Forces | State::Energy);
double L = context.getParameter("L");
double eps = context.getParameter("eps");
double a = context.getParameter("a");
double gamma = context.getParameter("gamma");
double sigma = context.getParameter("sigma");
// See if the energy matches the expected value.
double expectedEnergy = 0;
for (int i = 0; i < (int) expectedSets.size(); i++) {
int p1 = expectedSets[i][0];
int p2 = expectedSets[i][1];
int p3 = expectedSets[i][2];
Vec3 d12 = positions[p2]-positions[p1];
Vec3 d13 = positions[p3]-positions[p1];
Vec3 d23 = positions[p3]-positions[p2];
if (nonbondedMethod == CustomManyParticleForce::CutoffPeriodic) {
for (int j = 0; j < 3; j++) {
d12[j] -= floor(d12[j]/boxSize+0.5f)*boxSize;
d13[j] -= floor(d13[j]/boxSize+0.5f)*boxSize;
d23[j] -= floor(d23[j]/boxSize+0.5f)*boxSize;
}
}
double r12 = sqrt(d12.dot(d12));
double r13 = sqrt(d13.dot(d13));
double r23 = sqrt(d23.dot(d23));
double ctheta1 = d12.dot(d13)/(r12*r13);
double ctheta2 = -d12.dot(d23)/(r12*r23);
double ctheta3 = d13.dot(d23)/(r13*r23);
expectedEnergy += L*eps*(ctheta1+1.0/3.0)*(ctheta1+1.0/3.0)*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));
}
ASSERT_EQUAL_TOL(expectedEnergy, state1.getPotentialEnergy(), 1e-5);
// Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount.
const vector<Vec3>& forces = state1.getForces();
double norm = 0.0;
for (int i = 0; i < (int) forces.size(); ++i)
norm += forces[i].dot(forces[i]);
norm = std::sqrt(norm);
const double stepSize = 1e-3;
double step = 0.5*stepSize/norm;
vector<Vec3> positions2(numParticles), positions3(numParticles);
for (int i = 0; i < (int) positions.size(); ++i) {
Vec3 p = positions[i];
Vec3 f = forces[i];
positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step);
}
context.setPositions(positions2);
State state2 = context.getState(State::Energy);
context.setPositions(positions3);
State state3 = context.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/stepSize, 1e-4);
}
void testNoCutoff() {
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;"
"theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);"
"r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)");
force->addGlobalParameter("C", 1.5);
vector<double> params;
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(1, 0, 0));
positions.push_back(Vec3(0, 1.1, 0.3));
positions.push_back(Vec3(0.4, 0, -0.8));
int sets[4][3] = {{0,1,2}, {1,2,3}, {2,3,0}, {3,0,1}};
vector<const int*> expectedSets(&sets[0], &sets[4]);
validateAxilrodTeller(force, positions, expectedSets, 2.0);
}
void testCutoff() {
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;"
"theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);"
"r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)");
force->addGlobalParameter("C", 1.5);
force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic);
force->setCutoffDistance(1.55);
vector<double> params;
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(1, 0, 0));
positions.push_back(Vec3(0, 1.1, 0.3));
positions.push_back(Vec3(0.4, 0, -0.8));
positions.push_back(Vec3(0.2, 0.5, -0.1));
int sets[7][3] = {{0,1,2}, {0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,2,4}, {1,3,4}};
vector<const int*> expectedSets(&sets[0], &sets[7]);
validateAxilrodTeller(force, positions, expectedSets, 2.0);
}
void testPeriodic() {
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;"
"theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);"
"r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)");
force->addGlobalParameter("C", 1.5);
force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic);
force->setCutoffDistance(1.05);
vector<double> params;
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(1, 0, 0));
positions.push_back(Vec3(0, 1.1, 0.3));
positions.push_back(Vec3(0.4, 0, -0.8));
positions.push_back(Vec3(0.2, 0.5, -0.1));
double boxSize = 2.1;
int sets[5][3] = {{0,1,3}, {0,1,4}, {0,2,4}, {0,3,4}, {1,3,4}};
vector<const int*> expectedSets(&sets[0], &sets[5]);
validateAxilrodTeller(force, positions, expectedSets, boxSize);
}
void testExclusions() {
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;"
"theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);"
"r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)");
force->addGlobalParameter("C", 1.5);
vector<double> params;
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(1, 0, 0));
positions.push_back(Vec3(0, 1.1, 0.3));
positions.push_back(Vec3(0.4, 0, -0.8));
positions.push_back(Vec3(0.2, 0.5, -0.1));
force->addExclusion(0, 2);
force->addExclusion(0, 3);
int sets[5][3] = {{0,1,4}, {1,2,3}, {1,2,4}, {1,3,4}, {2,3,4}};
vector<const int*> expectedSets(&sets[0], &sets[5]);
validateAxilrodTeller(force, positions, expectedSets, 2.0);
}
void testAllTerms() {
int numParticles = 4;
ReferencePlatform platform;
// Create a system with a CustomManyParticleForce.
System system1;
CustomManyParticleForce* force1 = new CustomManyParticleForce(4,
"distance(p1,p2)+angle(p1,p4,p3)+dihedral(p1,p3,p2,p4)+x1+y4+z3");
system1.addForce(force1);
vector<double> params;
for (int i = 0; i < numParticles; i++) {
system1.addParticle(1.0);
force1->addParticle(params, i);
}
set<int> filter;
filter.insert(0);
force1->setTypeFilter(0, filter);
filter.clear();
filter.insert(1);
force1->setTypeFilter(1, filter);
filter.clear();
filter.insert(3);
force1->setTypeFilter(2, filter);
filter.clear();
filter.insert(2);
force1->setTypeFilter(3, filter);
// Create a system that use a CustomCompoundBondForce to compute exactly the same interactions.
System system2;
CustomCompoundBondForce* force2 = new CustomCompoundBondForce(4,
"distance(p1,p2)+angle(p1,p3,p4)+dihedral(p1,p4,p2,p3)+x1+y3+z4");
system2.addForce(force2);
vector<int> particles;
particles.push_back(0);
particles.push_back(1);
particles.push_back(2);
particles.push_back(3);
force2->addBond(particles, params);
for (int i = 0; i < numParticles; i++)
system2.addParticle(1.0);
// Create contexts for both of them.
vector<Vec3> positions;
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++)
positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)));
VerletIntegrator integrator1(0.001);
VerletIntegrator integrator2(0.001);
Context context1(system1, integrator1, platform);
Context context2(system2, integrator2, platform);
context1.setPositions(positions);
context2.setPositions(positions);
// See if they produce identical forces and energies.
State state1 = context1.getState(State::Forces | State::Energy);
State state2 = context2.getState(State::Forces | State::Energy);
ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), 1e-4);
for (int i = 0; i < numParticles; i++)
ASSERT_EQUAL_VEC(state2.getForces()[i], state1.getForces()[i], 1e-4);
}
void testParameters() {
// Create a system.
int numParticles = 5;
System system;
CustomManyParticleForce* force = new CustomManyParticleForce(3, "C*scale1*scale2*scale3*(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))");
force->addGlobalParameter("C", 2.0);
force->addPerParticleParameter("scale");
vector<double> params(1);
vector<Vec3> positions;
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
params[0] = i+1;
force->addParticle(params);
positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)));
system.addParticle(1.0);
}
system.addForce(force);
VerletIntegrator integrator(0.001);
ReferencePlatform platform;
Context context(system, integrator, platform);
context.setPositions(positions);
// See if the energy is correct.
State state = context.getState(State::Energy);
double expectedEnergy = 0;
for (int i = 0; i < numParticles; i++)
for (int j = i+1; j < numParticles; j++)
for (int k = j+1; k < numParticles; k++) {
Vec3 d12 = positions[j]-positions[i];
Vec3 d13 = positions[k]-positions[i];
Vec3 d23 = positions[k]-positions[j];
double r12 = sqrt(d12.dot(d12));
double r13 = sqrt(d13.dot(d13));
double r23 = sqrt(d23.dot(d23));
expectedEnergy += 2.0*(i+1)*(j+1)*(k+1)*(r12+r13+r23);
}
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5);
// Modify the parameters.
context.setParameter("C", 3.5);
for (int i = 0; i < numParticles; i++) {
params[0] = 0.5*i-0.1;
force->setParticleParameters(i, params, 0);
}
force->updateParametersInContext(context);
// See if the energy is still correct.
state = context.getState(State::Energy);
expectedEnergy = 0;
for (int i = 0; i < numParticles; i++)
for (int j = i+1; j < numParticles; j++)
for (int k = j+1; k < numParticles; k++) {
Vec3 d12 = positions[j]-positions[i];
Vec3 d13 = positions[k]-positions[i];
Vec3 d23 = positions[k]-positions[j];
double r12 = sqrt(d12.dot(d12));
double r13 = sqrt(d13.dot(d13));
double r23 = sqrt(d23.dot(d23));
expectedEnergy += 3.5*(0.5*i-0.1)*(0.5*j-0.1)*(0.5*k-0.1)*(r12+r13+r23);
}
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5);
}
void testTabulatedFunctions() {
int numParticles = 5;
// Create two tabulated functions.
vector<double> values;
values.push_back(0.0);
values.push_back(50.0);
Continuous1DFunction* f1 = new Continuous1DFunction(values, 0, 100);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<double> c(numParticles);
for (int i = 0; i < numParticles; i++)
c[i] = genrand_real2(sfmt);
values.resize(numParticles*numParticles*numParticles);
for (int i = 0; i < numParticles; i++)
for (int j = 0; j < numParticles; j++)
for (int k = 0; k < numParticles; k++)
values[i+numParticles*j+numParticles*numParticles*k] = c[i]+c[j]+c[k];
Discrete3DFunction* f2 = new Discrete3DFunction(numParticles, numParticles, numParticles, values);
// Create a system.
System system;
CustomManyParticleForce* force = new CustomManyParticleForce(3, "f1(distance(p1,p2)+distance(p2,p3)+distance(p1,p3))*f2(atom1, atom2, atom3)");
force->addPerParticleParameter("atom");
force->addTabulatedFunction("f1", f1);
force->addTabulatedFunction("f2", f2);
vector<double> params(1);
vector<Vec3> positions;
for (int i = 0; i < numParticles; i++) {
params[0] = i;
force->addParticle(params);
positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)));
system.addParticle(1.0);
}
system.addForce(force);
VerletIntegrator integrator(0.001);
ReferencePlatform platform;
Context context(system, integrator, platform);
context.setPositions(positions);
// See if the energy is correct.
State state = context.getState(State::Energy);
double expectedEnergy = 0;
for (int i = 0; i < numParticles; i++)
for (int j = i+1; j < numParticles; j++)
for (int k = j+1; k < numParticles; k++) {
Vec3 d12 = positions[j]-positions[i];
Vec3 d13 = positions[k]-positions[i];
Vec3 d23 = positions[k]-positions[j];
double r12 = sqrt(d12.dot(d12));
double r13 = sqrt(d13.dot(d13));
double r23 = sqrt(d23.dot(d23));
expectedEnergy += 0.5*(r12+r13+r23)*(c[i]+c[j]+c[k]);
}
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5);
}
void testTypeFilters() {
// Create a system.
System system;
for (int i = 0; i < 5; i++)
system.addParticle(1.0);
CustomManyParticleForce* force = new CustomManyParticleForce(3, "c1*(distance(p1,p2)+distance(p1,p3))");
force->addPerParticleParameter("c");
double c[] = {1.0, 2.0, 1.3, 1.5, -2.1};
int type[] = {0, 1, 0, 1, 5};
vector<double> params(1);
for (int i = 0; i < 5; i++) {
params[0] = c[i];
force->addParticle(params, type[i]);
}
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(1, 0, 0));
positions.push_back(Vec3(0, 1.1, 0.3));
positions.push_back(Vec3(0.4, 0, -0.8));
positions.push_back(Vec3(0.2, 0.5, -0.1));
set<int> f1, f2;
f1.insert(0);
f2.insert(1);
f2.insert(5);
force->setTypeFilter(0, f1);
force->setTypeFilter(1, f2);
force->setTypeFilter(2, f2);
system.addForce(force);
VerletIntegrator integrator(0.001);
ReferencePlatform platform;
Context context(system, integrator, platform);
context.setPositions(positions);
// See if the energy is correct.
State state = context.getState(State::Energy);
double expectedEnergy = 0;
int sets[6][3] = {{0,1,3}, {0,1,4}, {0,3,4}, {2,1,3}, {2,1,4}, {2,3,4}};
for (int i = 0; i < 6; i++) {
int p1 = sets[i][0];
int p2 = sets[i][1];
int p3 = sets[i][2];
Vec3 d12 = positions[p2]-positions[p1];
Vec3 d13 = positions[p3]-positions[p1];
double r12 = sqrt(d12.dot(d12));
double r13 = sqrt(d13.dot(d13));
expectedEnergy += c[p1]*(r12+r13);
}
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5);
}
void testCentralParticleModeNoCutoff() {
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));"
"r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)");
force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle);
force->addGlobalParameter("L", 23.13);
force->addGlobalParameter("eps", 25.894776);
force->addGlobalParameter("a", 1.8);
force->addGlobalParameter("sigma", 0.23925);
force->addGlobalParameter("gamma", 1.2);
vector<double> params;
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(0.1, 0, 0));
positions.push_back(Vec3(0, 0.11, 0.03));
positions.push_back(Vec3(0.04, 0, -0.08));
int sets[12][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {2,0,3}, {2, 1, 3}, {3,0,1}, {3,0,2}, {3,1,2}};
vector<const int*> expectedSets(&sets[0], &sets[12]);
validateStillingerWeber(force, positions, expectedSets, 2.0);
}
void testCentralParticleModeCutoff() {
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));"
"r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)");
force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle);
force->addGlobalParameter("L", 23.13);
force->addGlobalParameter("eps", 25.894776);
force->addGlobalParameter("a", 1.8);
force->addGlobalParameter("sigma", 0.23925);
force->addGlobalParameter("gamma", 1.2);
force->setNonbondedMethod(CustomManyParticleForce::CutoffNonPeriodic);
force->setCutoffDistance(0.155);
vector<double> params;
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
force->addParticle(params);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(0.1, 0, 0));
positions.push_back(Vec3(0, 0.11, 0.03));
positions.push_back(Vec3(0.04, 0, -0.08));
int sets[8][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,0,2}, {1,0,3}, {1, 2, 3}, {2,0,1}, {3,0,1}};
vector<const int*> expectedSets(&sets[0], &sets[8]);
validateStillingerWeber(force, positions, expectedSets, 2.0);
}
int main() {
try {
testNoCutoff();
testCutoff();
testPeriodic();
testExclusions();
testAllTerms();
testParameters();
testTabulatedFunctions();
testTypeFilters();
testCentralParticleModeNoCutoff();
testCentralParticleModeCutoff();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
#ifndef OPENMM_CUSTOMMANYPARTICLEFORCE_PROXY_H_
#define OPENMM_CUSTOMMANYPARTICLEFORCE_PROXY_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2014 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/windowsExport.h"
#include "openmm/serialization/SerializationProxy.h"
namespace OpenMM {
/**
* This is a proxy for serializing CustomManyParticleForce objects.
*/
class OPENMM_EXPORT CustomManyParticleForceProxy : public SerializationProxy {
public:
CustomManyParticleForceProxy();
void serialize(const void* object, SerializationNode& node) const;
void* deserialize(const SerializationNode& node) const;
};
} // namespace OpenMM
#endif /*OPENMM_CUSTOMMANYPARTICLEFORCE_PROXY_H_*/
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-2014 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/serialization/CustomManyParticleForceProxy.h"
#include "openmm/serialization/SerializationNode.h"
#include "openmm/Force.h"
#include "openmm/CustomManyParticleForce.h"
#include <sstream>
using namespace OpenMM;
using namespace std;
CustomManyParticleForceProxy::CustomManyParticleForceProxy() : SerializationProxy("CustomManyParticleForce") {
}
void CustomManyParticleForceProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 1);
const CustomManyParticleForce& force = *reinterpret_cast<const CustomManyParticleForce*>(object);
node.setIntProperty("forceGroup", force.getForceGroup());
node.setIntProperty("particlesPerSet", force.getNumParticlesPerSet());
node.setStringProperty("energy", force.getEnergyFunction());
node.setIntProperty("method", (int) force.getNonbondedMethod());
node.setIntProperty("permutationMode", (int) force.getPermutationMode());
node.setDoubleProperty("cutoff", force.getCutoffDistance());
SerializationNode& perParticleParams = node.createChildNode("PerParticleParameters");
for (int i = 0; i < force.getNumPerParticleParameters(); i++) {
perParticleParams.createChildNode("Parameter").setStringProperty("name", force.getPerParticleParameterName(i));
}
SerializationNode& globalParams = node.createChildNode("GlobalParameters");
for (int i = 0; i < force.getNumGlobalParameters(); i++) {
globalParams.createChildNode("Parameter").setStringProperty("name", force.getGlobalParameterName(i)).setDoubleProperty("default", force.getGlobalParameterDefaultValue(i));
}
SerializationNode& particles = node.createChildNode("Particles");
for (int i = 0; i < force.getNumParticles(); i++) {
vector<double> params;
int type;
force.getParticleParameters(i, params, type);
SerializationNode& node = particles.createChildNode("Particle");
node.setIntProperty("type", type);
for (int j = 0; j < (int) params.size(); j++) {
stringstream key;
key << "param";
key << j+1;
node.setDoubleProperty(key.str(), params[j]);
}
}
SerializationNode& exclusions = node.createChildNode("Exclusions");
for (int i = 0; i < force.getNumExclusions(); i++) {
int particle1, particle2;
force.getExclusionParticles(i, particle1, particle2);
exclusions.createChildNode("Exclusion").setIntProperty("p1", particle1).setIntProperty("p2", particle2);
}
SerializationNode& filters = node.createChildNode("TypeFilters");
for (int i = 0; i < force.getNumParticlesPerSet(); i++) {
set<int> types;
force.getTypeFilter(i, types);
stringstream list;
bool first = true;
for (set<int>::const_iterator iter = types.begin(); iter != types.end(); ++iter) {
if (!first)
list << ",";
list << *iter;
first = false;
}
filters.createChildNode("Filter").setIntProperty("index", i).setStringProperty("types", list.str());
}
SerializationNode& functions = node.createChildNode("Functions");
for (int i = 0; i < force.getNumTabulatedFunctions(); i++)
functions.createChildNode("Function", &force.getTabulatedFunction(i)).setStringProperty("name", force.getTabulatedFunctionName(i));
}
void* CustomManyParticleForceProxy::deserialize(const SerializationNode& node) const {
if (node.getIntProperty("version") != 1)
throw OpenMMException("Unsupported version number");
CustomManyParticleForce* force = NULL;
try {
CustomManyParticleForce* force = new CustomManyParticleForce(node.getIntProperty("particlesPerSet"), node.getStringProperty("energy"));
force->setForceGroup(node.getIntProperty("forceGroup", 0));
force->setNonbondedMethod((CustomManyParticleForce::NonbondedMethod) node.getIntProperty("method"));
force->setPermutationMode((CustomManyParticleForce::PermutationMode) node.getIntProperty("permutationMode"));
force->setCutoffDistance(node.getDoubleProperty("cutoff"));
const SerializationNode& perParticleParams = node.getChildNode("PerParticleParameters");
for (int i = 0; i < (int) perParticleParams.getChildren().size(); i++) {
const SerializationNode& parameter = perParticleParams.getChildren()[i];
force->addPerParticleParameter(parameter.getStringProperty("name"));
}
const SerializationNode& globalParams = node.getChildNode("GlobalParameters");
for (int i = 0; i < (int) globalParams.getChildren().size(); i++) {
const SerializationNode& parameter = globalParams.getChildren()[i];
force->addGlobalParameter(parameter.getStringProperty("name"), parameter.getDoubleProperty("default"));
}
const SerializationNode& particles = node.getChildNode("Particles");
vector<double> params(force->getNumPerParticleParameters());
for (int i = 0; i < (int) particles.getChildren().size(); i++) {
const SerializationNode& particle = particles.getChildren()[i];
for (int j = 0; j < (int) params.size(); j++) {
stringstream key;
key << "param";
key << j+1;
params[j] = particle.getDoubleProperty(key.str());
}
force->addParticle(params, particle.getIntProperty("type"));
}
const SerializationNode& exclusions = node.getChildNode("Exclusions");
for (int i = 0; i < (int) exclusions.getChildren().size(); i++) {
const SerializationNode& exclusion = exclusions.getChildren()[i];
force->addExclusion(exclusion.getIntProperty("p1"), exclusion.getIntProperty("p2"));
}
const SerializationNode& filters = node.getChildNode("TypeFilters");
for (int i = 0; i < (int) filters.getChildren().size(); i++) {
const SerializationNode& filter = filters.getChildren()[i];
string typesString = filter.getStringProperty("types");
vector<string> splitTypes;
size_t searchPos = 0, nextPos;
while ((nextPos = typesString.find_first_of(", ", searchPos)) != string::npos) {
splitTypes.push_back(typesString.substr(searchPos, nextPos-searchPos));
searchPos = nextPos+1;
}
splitTypes.push_back(typesString.substr(searchPos));
set<int> types;
for (int j = 0; j < (int) splitTypes.size(); j++) {
if (splitTypes[j].size() > 0) {
int type;
stringstream(splitTypes[j]) >> type;
types.insert(type);
}
}
force->setTypeFilter(filter.getIntProperty("index"), types);
}
const SerializationNode& functions = node.getChildNode("Functions");
for (int i = 0; i < (int) functions.getChildren().size(); i++) {
const SerializationNode& function = functions.getChildren()[i];
force->addTabulatedFunction(function.getStringProperty("name"), function.decodeObject<TabulatedFunction>());
}
return force;
}
catch (...) {
if (force != NULL)
delete force;
throw;
}
}
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "openmm/CustomGBForce.h" #include "openmm/CustomGBForce.h"
#include "openmm/CustomHbondForce.h" #include "openmm/CustomHbondForce.h"
#include "openmm/CustomIntegrator.h" #include "openmm/CustomIntegrator.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/CustomNonbondedForce.h" #include "openmm/CustomNonbondedForce.h"
#include "openmm/CustomTorsionForce.h" #include "openmm/CustomTorsionForce.h"
#include "openmm/GBSAOBCForce.h" #include "openmm/GBSAOBCForce.h"
...@@ -69,6 +70,7 @@ ...@@ -69,6 +70,7 @@
#include "openmm/serialization/CustomGBForceProxy.h" #include "openmm/serialization/CustomGBForceProxy.h"
#include "openmm/serialization/CustomHbondForceProxy.h" #include "openmm/serialization/CustomHbondForceProxy.h"
#include "openmm/serialization/CustomIntegratorProxy.h" #include "openmm/serialization/CustomIntegratorProxy.h"
#include "openmm/serialization/CustomManyParticleForceProxy.h"
#include "openmm/serialization/CustomNonbondedForceProxy.h" #include "openmm/serialization/CustomNonbondedForceProxy.h"
#include "openmm/serialization/CustomTorsionForceProxy.h" #include "openmm/serialization/CustomTorsionForceProxy.h"
#include "openmm/serialization/GBSAOBCForceProxy.h" #include "openmm/serialization/GBSAOBCForceProxy.h"
...@@ -116,6 +118,7 @@ extern "C" void registerSerializationProxies() { ...@@ -116,6 +118,7 @@ extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(CustomGBForce), new CustomGBForceProxy()); SerializationProxy::registerProxy(typeid(CustomGBForce), new CustomGBForceProxy());
SerializationProxy::registerProxy(typeid(CustomHbondForce), new CustomHbondForceProxy()); SerializationProxy::registerProxy(typeid(CustomHbondForce), new CustomHbondForceProxy());
SerializationProxy::registerProxy(typeid(CustomIntegrator), new CustomIntegratorProxy()); SerializationProxy::registerProxy(typeid(CustomIntegrator), new CustomIntegratorProxy());
SerializationProxy::registerProxy(typeid(CustomManyParticleForce), new CustomManyParticleForceProxy());
SerializationProxy::registerProxy(typeid(CustomNonbondedForce), new CustomNonbondedForceProxy()); SerializationProxy::registerProxy(typeid(CustomNonbondedForce), new CustomNonbondedForceProxy());
SerializationProxy::registerProxy(typeid(CustomTorsionForce), new CustomTorsionForceProxy()); SerializationProxy::registerProxy(typeid(CustomTorsionForce), new CustomTorsionForceProxy());
SerializationProxy::registerProxy(typeid(Discrete1DFunction), new Discrete1DFunctionProxy()); SerializationProxy::registerProxy(typeid(Discrete1DFunction), new Discrete1DFunctionProxy());
......
/* -------------------------------------------------------------------------- *
* 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) 2010-2014 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/AssertionUtilities.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/serialization/XmlSerializer.h"
#include <iostream>
#include <sstream>
using namespace OpenMM;
using namespace std;
void testSerialization() {
// Create a Force.
CustomManyParticleForce force(3, "C*(a1+a2+a3)*(distance(p1,p2)+distance(p1,p3))");
force.setForceGroup(3);
force.setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic);
force.setPermutationMode(CustomManyParticleForce::UniqueCentralParticle);
force.setCutoffDistance(2.1);
force.addGlobalParameter("C", 1.3);
force.addPerParticleParameter("a");
vector<double> params(1);
params[0] = 1.0;
force.addParticle(params, 0);
params[0] = -3.3;
force.addParticle(params, 2);
params[0] = 2.1;
force.addParticle(params, 3);
set<int> types1, types2;
types1.insert(0);
types2.insert(2);
types2.insert(3);
force.setTypeFilter(0, types1);
force.setTypeFilter(2, types2);
force.addExclusion(0, 1);
force.addExclusion(1, 2);
vector<double> values(10);
for (int i = 0; i < 10; i++)
values[i] = sin((double) i);
force.addTabulatedFunction("f", new Continuous1DFunction(values, 0.5, 1.5));
// Serialize and then deserialize it.
stringstream buffer;
XmlSerializer::serialize<CustomManyParticleForce>(&force, "Force", buffer);
CustomManyParticleForce* copy = XmlSerializer::deserialize<CustomManyParticleForce>(buffer);
// Compare the two forces to see if they are identical.
CustomManyParticleForce& force2 = *copy;
ASSERT_EQUAL(force.getForceGroup(), force2.getForceGroup());
ASSERT_EQUAL(force.getNumParticlesPerSet(), force2.getNumParticlesPerSet());
ASSERT_EQUAL(force.getEnergyFunction(), force2.getEnergyFunction());
ASSERT_EQUAL(force.getNonbondedMethod(), force2.getNonbondedMethod());
ASSERT_EQUAL(force.getCutoffDistance(), force2.getCutoffDistance());
ASSERT_EQUAL(force.getNumPerParticleParameters(), force2.getNumPerParticleParameters());
for (int i = 0; i < force.getNumPerParticleParameters(); i++)
ASSERT_EQUAL(force.getPerParticleParameterName(i), force2.getPerParticleParameterName(i));
ASSERT_EQUAL(force.getNumGlobalParameters(), force2.getNumGlobalParameters());
for (int i = 0; i < force.getNumGlobalParameters(); i++) {
ASSERT_EQUAL(force.getGlobalParameterName(i), force2.getGlobalParameterName(i));
ASSERT_EQUAL(force.getGlobalParameterDefaultValue(i), force2.getGlobalParameterDefaultValue(i));
}
ASSERT_EQUAL(force.getNumParticles(), force2.getNumParticles());
for (int i = 0; i < force.getNumParticles(); i++) {
vector<double> params1, params2;
int type1, type2;
force.getParticleParameters(i, params1, type1);
force2.getParticleParameters(i, params2, type2);
ASSERT_EQUAL(type1, type2);
ASSERT_EQUAL(params1.size(), params2.size());
for (int j = 0; j < (int) params1.size(); j++)
ASSERT_EQUAL(params1[j], params2[j]);
}
ASSERT_EQUAL(force.getNumExclusions(), force2.getNumExclusions());
for (int i = 0; i < force.getNumExclusions(); i++) {
int a1, a2, b1, b2;
force.getExclusionParticles(i, a1, b1);
force2.getExclusionParticles(i, a2, b2);
ASSERT_EQUAL(a1, a2);
ASSERT_EQUAL(b1, b2);
}
for (int i = 0; i < force.getNumParticlesPerSet(); i++) {
set<int> set1, set2;
force.getTypeFilter(i, set1);
force2.getTypeFilter(i, set2);
ASSERT_EQUAL_CONTAINERS(set1, set2);
}
ASSERT_EQUAL(force.getNumTabulatedFunctions(), force2.getNumTabulatedFunctions());
for (int i = 0; i < force.getNumTabulatedFunctions(); i++) {
double min1, min2, max1, max2;
vector<double> val1, val2;
dynamic_cast<Continuous1DFunction&>(force.getTabulatedFunction(i)).getFunctionParameters(val1, min1, max1);
dynamic_cast<Continuous1DFunction&>(force2.getTabulatedFunction(i)).getFunctionParameters(val2, min2, max2);
ASSERT_EQUAL(force.getTabulatedFunctionName(i), force2.getTabulatedFunctionName(i));
ASSERT_EQUAL(min1, min2);
ASSERT_EQUAL(max1, max2);
ASSERT_EQUAL(val1.size(), val2.size());
for (int j = 0; j < (int) val1.size(); j++)
ASSERT_EQUAL(val1[j], val2[j]);
}
}
int main() {
try {
testSerialization();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -153,6 +153,7 @@ void testMathFunctions() { ...@@ -153,6 +153,7 @@ void testMathFunctions() {
ASSERT(any(f1 > 0.5)); ASSERT(any(f1 > 0.5));
ASSERT(!any(f1 > 2.0)); ASSERT(!any(f1 > 2.0));
ASSERT_VEC4_EQUAL(blend(f1, f2, ivec4(-1, 0, -1, 0)), 1.1, 1.9, 1.3, -3.8); ASSERT_VEC4_EQUAL(blend(f1, f2, ivec4(-1, 0, -1, 0)), 1.1, 1.9, 1.3, -3.8);
ASSERT_VEC4_EQUAL(cross(f1, f2), 3.91, -1.84, -1.61, 0.0);
} }
void testTranspose() { void testTranspose() {
......
...@@ -1620,7 +1620,6 @@ class CustomNonbondedGenerator: ...@@ -1620,7 +1620,6 @@ class CustomNonbondedGenerator:
for atom in data.atoms: for atom in data.atoms:
t = data.atomType[atom] t = data.atomType[atom]
if t in self.typeMap: if t in self.typeMap:
values = self.typeMap[t]
force.addParticle(self.typeMap[t]) force.addParticle(self.typeMap[t])
else: else:
raise ValueError('No CustomNonbonded parameters defined for atom type '+t) raise ValueError('No CustomNonbonded parameters defined for atom type '+t)
...@@ -1629,35 +1628,33 @@ class CustomNonbondedGenerator: ...@@ -1629,35 +1628,33 @@ class CustomNonbondedGenerator:
sys.addForce(force) sys.addForce(force)
def postprocessSystem(self, sys, data, args): def postprocessSystem(self, sys, data, args):
# Create exceptions based on bonds, virtual sites, and Drude particles. # Create exclusions based on bonds.
if self.bondCutoff == 0:
return
bondIndices = [] bondIndices = []
for bond in data.bonds: for bond in data.bonds:
bondIndices.append((bond.atom1, bond.atom2)) bondIndices.append((bond.atom1, bond.atom2))
# If a virtual site does *not* share exclusions with another atom, add a bond between it and its first parent atom.
for i in range(sys.getNumParticles()): for i in range(sys.getNumParticles()):
if sys.isVirtualSite(i): if sys.isVirtualSite(i):
site = sys.getVirtualSite(i) (site, atoms, excludeWith) = data.virtualSites[data.atoms[i]]
for j in range(site.getNumParticles()): if excludeWith is None:
bondIndices.append((i, site.getParticle(j))) bondIndices.append((i, site.getParticle(0)))
drude = [f for f in sys.getForces() if isinstance(f, mm.DrudeForce)]
if len(drude) > 0: # Certain particles, such as lone pairs and Drude particles, share exclusions with a parent atom.
drude = drude[0] # If the parent atom does not interact with an atom, the child particle does not either.
# For purposes of creating exceptions, a Drude particle is "bonded" to anything
# its parent atom is bonded to. for atom1, atom2 in bondIndices:
drudeMap = {} for child1 in data.excludeAtomWith[atom1]:
for i in range(drude.getNumParticles()): bondIndices.append((child1, atom2))
params = drude.getParticleParameters(i) for child2 in data.excludeAtomWith[atom2]:
drudeMap[params[1]] = params[0] bondIndices.append((child1, child2))
for atom1, atom2 in bondIndices: for child2 in data.excludeAtomWith[atom2]:
drude1 = drudeMap[atom1] if atom1 in drudeMap else None bondIndices.append((atom1, child2))
drude2 = drudeMap[atom2] if atom2 in drudeMap else None
if drude1 is not None: # Create the exclusions.
bondIndices.append((drude1, atom2))
if drude2 is not None:
bondIndices.append((drude1, drude2))
if drude2 is not None:
bondIndices.append((atom1, drude2))
nonbonded = [f for f in sys.getForces() if isinstance(f, mm.CustomNonbondedForce)][0] nonbonded = [f for f in sys.getForces() if isinstance(f, mm.CustomNonbondedForce)][0]
nonbonded.createExclusionsFromBonds(bondIndices, self.bondCutoff) nonbonded.createExclusionsFromBonds(bondIndices, self.bondCutoff)
...@@ -1743,7 +1740,6 @@ class CustomGBGenerator: ...@@ -1743,7 +1740,6 @@ class CustomGBGenerator:
for atom in data.atoms: for atom in data.atoms:
t = data.atomType[atom] t = data.atomType[atom]
if t in self.typeMap: if t in self.typeMap:
values = self.typeMap[t]
force.addParticle(self.typeMap[t]) force.addParticle(self.typeMap[t])
else: else:
raise ValueError('No CustomGB parameters defined for atom type '+t) raise ValueError('No CustomGB parameters defined for atom type '+t)
...@@ -1753,6 +1749,113 @@ class CustomGBGenerator: ...@@ -1753,6 +1749,113 @@ class CustomGBGenerator:
parsers["CustomGBForce"] = CustomGBGenerator.parseElement parsers["CustomGBForce"] = CustomGBGenerator.parseElement
## @private
class CustomManyParticleGenerator:
"""A CustomManyParticleGenerator constructs a CustomManyParticleForce."""
def __init__(self, forcefield, particlesPerSet, energy, permutationMode, bondCutoff):
self.ff = forcefield
self.particlesPerSet = particlesPerSet
self.energy = energy
self.permutationMode = permutationMode
self.bondCutoff = bondCutoff
self.typeMap = {}
self.globalParams = {}
self.perParticleParams = []
self.functions = []
self.typeFilters = []
@staticmethod
def parseElement(element, ff):
permutationMap = {"SinglePermutation" : mm.CustomManyParticleForce.SinglePermutation,
"UniqueCentralParticle" : mm.CustomManyParticleForce.UniqueCentralParticle}
generator = CustomManyParticleGenerator(ff, int(element.attrib['particlesPerSet']), element.attrib['energy'], permutationMap[element.attrib['permutationMode']], int(element.attrib['bondCutoff']))
ff.registerGenerator(generator)
for param in element.findall('GlobalParameter'):
generator.globalParams[param.attrib['name']] = float(param.attrib['defaultValue'])
for param in element.findall('PerParticleParameter'):
generator.perParticleParams.append(param.attrib['name'])
for param in element.findall('TypeFilter'):
generator.typeFilters.append((int(param.attrib['index']), [int(x) for x in param.attrib['types'].split(',')]))
for atom in element.findall('Atom'):
types = ff._findAtomTypes(atom.attrib, 1)
if None not in types:
values = [float(atom.attrib[param]) for param in generator.perParticleParams]
for t in types[0]:
generator.typeMap[t] = (values, int(atom.attrib['filterType']))
def createForce(self, sys, data, nonbondedMethod, nonbondedCutoff, args):
methodMap = {NoCutoff:mm.CustomManyParticleForce.NoCutoff,
CutoffNonPeriodic:mm.CustomManyParticleForce.CutoffNonPeriodic,
CutoffPeriodic:mm.CustomManyParticleForce.CutoffPeriodic}
if nonbondedMethod not in methodMap:
raise ValueError('Illegal nonbonded method for CustomManyParticleForce')
force = mm.CustomManyParticleForce(self.particlesPerSet, self.energy)
force.setPermutationMode(self.permutationMode)
for param in self.globalParams:
force.addGlobalParameter(param, self.globalParams[param])
for param in self.perParticleParams:
force.addPerParticleParameter(param)
for index, types in self.typeFilters:
force.setTypeFilter(index, types)
for (name, type, values, params) in self.functions:
if type == 'Continuous1D':
force.addTabulatedFunction(name, mm.Continuous1DFunction(values, params['min'], params['max']))
elif type == 'Continuous2D':
force.addTabulatedFunction(name, mm.Continuous2DFunction(params['xsize'], params['ysize'], values, params['xmin'], params['xmax'], params['ymin'], params['ymax']))
elif type == 'Continuous3D':
force.addTabulatedFunction(name, mm.Continuous2DFunction(params['xsize'], params['ysize'], params['zsize'], values, params['xmin'], params['xmax'], params['ymin'], params['ymax'], params['zmin'], params['zmax']))
elif type == 'Discrete1D':
force.addTabulatedFunction(name, mm.Discrete1DFunction(values))
elif type == 'Discrete2D':
force.addTabulatedFunction(name, mm.Discrete2DFunction(params['xsize'], params['ysize'], values))
elif type == 'Discrete3D':
force.addTabulatedFunction(name, mm.Discrete2DFunction(params['xsize'], params['ysize'], params['zsize'], values))
for atom in data.atoms:
t = data.atomType[atom]
if t in self.typeMap:
values = self.typeMap[t]
force.addParticle(values[0], values[1])
else:
raise ValueError('No CustomManyParticle parameters defined for atom type '+t)
force.setNonbondedMethod(methodMap[nonbondedMethod])
force.setCutoffDistance(nonbondedCutoff)
sys.addForce(force)
def postprocessSystem(self, sys, data, args):
# Create exclusions based on bonds.
bondIndices = []
for bond in data.bonds:
bondIndices.append((bond.atom1, bond.atom2))
# If a virtual site does *not* share exclusions with another atom, add a bond between it and its first parent atom.
for i in range(sys.getNumParticles()):
if sys.isVirtualSite(i):
(site, atoms, excludeWith) = data.virtualSites[data.atoms[i]]
if excludeWith is None:
bondIndices.append((i, site.getParticle(0)))
# Certain particles, such as lone pairs and Drude particles, share exclusions with a parent atom.
# If the parent atom does not interact with an atom, the child particle does not either.
for atom1, atom2 in bondIndices:
for child1 in data.excludeAtomWith[atom1]:
bondIndices.append((child1, atom2))
for child2 in data.excludeAtomWith[atom2]:
bondIndices.append((child1, child2))
for child2 in data.excludeAtomWith[atom2]:
bondIndices.append((atom1, child2))
# Create the exclusions.
nonbonded = [f for f in sys.getForces() if isinstance(f, mm.CustomManyParticleForce)][0]
nonbonded.createExclusionsFromBonds(bondIndices, self.bondCutoff)
parsers["CustomManyParticleForce"] = CustomManyParticleGenerator.parseElement
def getAtomPrint(data, atomIndex): def getAtomPrint(data, atomIndex):
if (atomIndex < len(data.atoms)): if (atomIndex < len(data.atoms)):
......
...@@ -140,6 +140,7 @@ STEAL_OWNERSHIP = {("Platform", "registerPlatform") : [0], ...@@ -140,6 +140,7 @@ STEAL_OWNERSHIP = {("Platform", "registerPlatform") : [0],
("CustomGBForce", "addTabulatedFunction") : [1], ("CustomGBForce", "addTabulatedFunction") : [1],
("CustomHbondForce", "addTabulatedFunction") : [1], ("CustomHbondForce", "addTabulatedFunction") : [1],
("CustomCompoundBondForce", "addTabulatedFunction") : [1], ("CustomCompoundBondForce", "addTabulatedFunction") : [1],
("CustomManyParticleForce", "addTabulatedFunction") : [1],
} }
# This is a list of units to attach to return values and method args. # This is a list of units to attach to return values and method args.
...@@ -191,6 +192,9 @@ UNITS = { ...@@ -191,6 +192,9 @@ UNITS = {
("*", "getWeight12") : (None, ()), ("*", "getWeight12") : (None, ()),
("*", "getWeight13") : (None, ()), ("*", "getWeight13") : (None, ()),
("*", "getWeightCross") : (None, ()), ("*", "getWeightCross") : (None, ()),
("*", "getNonbondedMethod") : (None, ()),
("*", "getGlobalParameterDefaultValue") : (None, ()),
("*", "getPermutationMode") : (None, ()),
("LocalCoordinatesSite", "getOriginWeights") : (None, ()), ("LocalCoordinatesSite", "getOriginWeights") : (None, ()),
("LocalCoordinatesSite", "getXWeights") : (None, ()), ("LocalCoordinatesSite", "getXWeights") : (None, ()),
("LocalCoordinatesSite", "getYWeights") : (None, ()), ("LocalCoordinatesSite", "getYWeights") : (None, ()),
...@@ -228,7 +232,6 @@ UNITS = { ...@@ -228,7 +232,6 @@ UNITS = {
("AmoebaInPlaneAngleForce", "getAngleParameters") : ( None, (None, None, None, None, 'unit.radian', 'unit.kilojoule_per_mole/(unit.radian*unit.radian)')), ("AmoebaInPlaneAngleForce", "getAngleParameters") : ( None, (None, None, None, None, 'unit.radian', 'unit.kilojoule_per_mole/(unit.radian*unit.radian)')),
("AmoebaMultipoleForce", "getNumMultipoles") : ( None,()), ("AmoebaMultipoleForce", "getNumMultipoles") : ( None,()),
("AmoebaMultipoleForce", "getNonbondedMethod") : ( None,()),
("AmoebaMultipoleForce", "getPolarizationType") : ( None,()), ("AmoebaMultipoleForce", "getPolarizationType") : ( None,()),
("AmoebaMultipoleForce", "getCutoffDistance") : ( 'unit.nanometer',()), ("AmoebaMultipoleForce", "getCutoffDistance") : ( 'unit.nanometer',()),
("AmoebaMultipoleForce", "getAEwald") : ( '1/unit.nanometer',()), ("AmoebaMultipoleForce", "getAEwald") : ( '1/unit.nanometer',()),
...@@ -285,7 +288,6 @@ UNITS = { ...@@ -285,7 +288,6 @@ UNITS = {
("AmoebaVdwForce", "getEpsilonCombiningRule") : ( None, ()), ("AmoebaVdwForce", "getEpsilonCombiningRule") : ( None, ()),
("AmoebaVdwForce", "getParticleExclusions") : ( None, ()), ("AmoebaVdwForce", "getParticleExclusions") : ( None, ()),
("AmoebaVdwForce", "getCutoff") : ( 'unit.nanometer', ()), ("AmoebaVdwForce", "getCutoff") : ( 'unit.nanometer', ()),
("AmoebaVdwForce", "getNonbondedMethod") : ( None, ()),
# LPW 2012-10 Modified because it no longer returns ivIndex and classIndex. # LPW 2012-10 Modified because it no longer returns ivIndex and classIndex.
# ("AmoebaVdwForce", "getParticleParameters") : ( None, (None, None, 'unit.nanometer', 'unit.kilojoule_per_mole', None)), # ("AmoebaVdwForce", "getParticleParameters") : ( None, (None, None, 'unit.nanometer', 'unit.kilojoule_per_mole', None)),
("AmoebaVdwForce", "getParticleParameters") : ( None, (None, 'unit.nanometer', 'unit.kilojoule_per_mole', None)), ("AmoebaVdwForce", "getParticleParameters") : ( None, (None, 'unit.nanometer', 'unit.kilojoule_per_mole', None)),
...@@ -310,22 +312,18 @@ UNITS = { ...@@ -310,22 +312,18 @@ UNITS = {
("CustomAngleForce", "getEnergyFunction") : (None, ()), ("CustomAngleForce", "getEnergyFunction") : (None, ()),
("CustomAngleForce", "getPerAngleParameterName") : (None, ()), ("CustomAngleForce", "getPerAngleParameterName") : (None, ()),
("CustomAngleForce", "getGlobalParameterName") : (None, ()), ("CustomAngleForce", "getGlobalParameterName") : (None, ()),
("CustomAngleForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomAngleForce", "getAngleParameters") : (None, ()), ("CustomAngleForce", "getAngleParameters") : (None, ()),
("CustomBondForce", "getNumPerBondParameters") : (None, ()), ("CustomBondForce", "getNumPerBondParameters") : (None, ()),
("CustomBondForce", "getNumGlobalParameters") : (None, ()), ("CustomBondForce", "getNumGlobalParameters") : (None, ()),
("CustomBondForce", "getEnergyFunction") : (None, ()), ("CustomBondForce", "getEnergyFunction") : (None, ()),
("CustomBondForce", "getPerBondParameterName") : (None, ()), ("CustomBondForce", "getPerBondParameterName") : (None, ()),
("CustomBondForce", "getGlobalParameterName") : (None, ()), ("CustomBondForce", "getGlobalParameterName") : (None, ()),
("CustomBondForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomBondForce", "getBondParameters") : (None, ()), ("CustomBondForce", "getBondParameters") : (None, ()),
("CustomCompoundBondForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomExternalForce", "getNumPerParticleParameters") : (None, ()), ("CustomExternalForce", "getNumPerParticleParameters") : (None, ()),
("CustomExternalForce", "getNumGlobalParameters") : (None, ()), ("CustomExternalForce", "getNumGlobalParameters") : (None, ()),
("CustomExternalForce", "getEnergyFunction") : (None, ()), ("CustomExternalForce", "getEnergyFunction") : (None, ()),
("CustomExternalForce", "getPerParticleParameterName") : (None, ()), ("CustomExternalForce", "getPerParticleParameterName") : (None, ()),
("CustomExternalForce", "getGlobalParameterName") : (None, ()), ("CustomExternalForce", "getGlobalParameterName") : (None, ()),
("CustomExternalForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomExternalForce", "getParticleParameters") : (None, ()), ("CustomExternalForce", "getParticleParameters") : (None, ()),
("CustomGBForce", "getNumExclusions") : (None, ()), ("CustomGBForce", "getNumExclusions") : (None, ()),
("CustomGBForce", "getNumPerParticleParameters") : (None, ()), ("CustomGBForce", "getNumPerParticleParameters") : (None, ()),
...@@ -333,10 +331,8 @@ UNITS = { ...@@ -333,10 +331,8 @@ UNITS = {
("CustomGBForce", "getNumFunctions") : (None, ()), ("CustomGBForce", "getNumFunctions") : (None, ()),
("CustomGBForce", "getNumComputedValues") : (None, ()), ("CustomGBForce", "getNumComputedValues") : (None, ()),
("CustomGBForce", "getNumEnergyTerms") : (None, ()), ("CustomGBForce", "getNumEnergyTerms") : (None, ()),
("CustomGBForce", "getNonbondedMethod") : (None, ()),
("CustomGBForce", "getPerParticleParameterName") : (None, ()), ("CustomGBForce", "getPerParticleParameterName") : (None, ()),
("CustomGBForce", "getGlobalParameterName") : (None, ()), ("CustomGBForce", "getGlobalParameterName") : (None, ()),
("CustomGBForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomGBForce", "getParticleParameters") : (None, ()), ("CustomGBForce", "getParticleParameters") : (None, ()),
("CustomGBForce", "getComputedValueParameters") : (None, ()), ("CustomGBForce", "getComputedValueParameters") : (None, ()),
("CustomGBForce", "getEnergyTermParameters") : (None, ()), ("CustomGBForce", "getEnergyTermParameters") : (None, ()),
...@@ -347,7 +343,6 @@ UNITS = { ...@@ -347,7 +343,6 @@ UNITS = {
("CustomHbondForce", "getEnergyFunction") : (None, ()), ("CustomHbondForce", "getEnergyFunction") : (None, ()),
("CustomHbondForce", "getExclusionParticles") : (None, ()), ("CustomHbondForce", "getExclusionParticles") : (None, ()),
("CustomHbondForce", "getFunctionParameters") : (None, ()), ("CustomHbondForce", "getFunctionParameters") : (None, ()),
("CustomHbondForce", "getNonbondedMethod") : (None, ()),
("CustomHbondForce", "getNumAcceptors") : (None, ()), ("CustomHbondForce", "getNumAcceptors") : (None, ()),
("CustomHbondForce", "getNumDonors") : (None, ()), ("CustomHbondForce", "getNumDonors") : (None, ()),
("CustomHbondForce", "getNumExclusions") : (None, ()), ("CustomHbondForce", "getNumExclusions") : (None, ()),
...@@ -355,7 +350,6 @@ UNITS = { ...@@ -355,7 +350,6 @@ UNITS = {
("CustomHbondForce", "getNumGlobalParameters") : (None, ()), ("CustomHbondForce", "getNumGlobalParameters") : (None, ()),
("CustomHbondForce", "getNumPerAcceptorParameters") : (None, ()), ("CustomHbondForce", "getNumPerAcceptorParameters") : (None, ()),
("CustomHbondForce", "getNumPerDonorParameters") : (None, ()), ("CustomHbondForce", "getNumPerDonorParameters") : (None, ()),
("CustomHbondForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomHbondForce", "getGlobalParameterName") : (None, ()), ("CustomHbondForce", "getGlobalParameterName") : (None, ()),
("CustomHbondForce", "getPerAcceptorParameterName") : (None, ()), ("CustomHbondForce", "getPerAcceptorParameterName") : (None, ()),
("CustomHbondForce", "getPerDonorParameterName") : (None, ()), ("CustomHbondForce", "getPerDonorParameterName") : (None, ()),
...@@ -363,9 +357,7 @@ UNITS = { ...@@ -363,9 +357,7 @@ UNITS = {
("CustomNonbondedForce", "getExceptionParameters") : (None, ()), ("CustomNonbondedForce", "getExceptionParameters") : (None, ()),
("CustomNonbondedForce", "getExclusionParticles") : (None, ()), ("CustomNonbondedForce", "getExclusionParticles") : (None, ()),
("CustomNonbondedForce", "getFunctionParameters") : (None, ()), ("CustomNonbondedForce", "getFunctionParameters") : (None, ()),
("CustomNonbondedForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomNonbondedForce", "getGlobalParameterName") : (None, ()), ("CustomNonbondedForce", "getGlobalParameterName") : (None, ()),
("CustomNonbondedForce", "getNonbondedMethod") : (None, ()),
("CustomNonbondedForce", "getNumExclusions") : (None, ()), ("CustomNonbondedForce", "getNumExclusions") : (None, ()),
("CustomNonbondedForce", "getNumFunctions") : (None, ()), ("CustomNonbondedForce", "getNumFunctions") : (None, ()),
("CustomNonbondedForce", "getNumPerParticleParameters") : (None, ()), ("CustomNonbondedForce", "getNumPerParticleParameters") : (None, ()),
...@@ -380,13 +372,10 @@ UNITS = { ...@@ -380,13 +372,10 @@ UNITS = {
("CustomTorsionForce", "getEnergyFunction") : (None, ()), ("CustomTorsionForce", "getEnergyFunction") : (None, ()),
("CustomTorsionForce", "getPerTorsionParameterName") : (None, ()), ("CustomTorsionForce", "getPerTorsionParameterName") : (None, ()),
("CustomTorsionForce", "getGlobalParameterName") : (None, ()), ("CustomTorsionForce", "getGlobalParameterName") : (None, ()),
("CustomTorsionForce", "getGlobalParameterDefaultValue") : (None, ()),
("CustomTorsionForce", "getTorsionParameters") : (None, ()), ("CustomTorsionForce", "getTorsionParameters") : (None, ()),
("GBSAOBCForce", "getNonbondedMethod") : (None, ()),
("GBSAOBCForce", "getParticleParameters") ("GBSAOBCForce", "getParticleParameters")
: (None, ('unit.elementary_charge', : (None, ('unit.elementary_charge',
'unit.nanometer', None)), 'unit.nanometer', None)),
("GBVIForce", "getNonbondedMethod") : (None, ()),
("GBVIForce", "getBornRadiusScalingMethod") : (None, ()), ("GBVIForce", "getBornRadiusScalingMethod") : (None, ()),
("GBVIForce", "getQuinticLowerLimitFactor") : (None, ()), ("GBVIForce", "getQuinticLowerLimitFactor") : (None, ()),
("GBVIForce", "getQuinticUpperBornRadiusLimit") : ('unit.nanometer', ()), ("GBVIForce", "getQuinticUpperBornRadiusLimit") : ('unit.nanometer', ()),
...@@ -408,7 +397,6 @@ UNITS = { ...@@ -408,7 +397,6 @@ UNITS = {
: (None, (None, None, : (None, (None, None,
'unit.elementary_charge*unit.elementary_charge', 'unit.elementary_charge*unit.elementary_charge',
'unit.nanometer', 'unit.kilojoule_per_mole')), 'unit.nanometer', 'unit.kilojoule_per_mole')),
("NonbondedForce", "getNonbondedMethod") : (None, ()),
("NonbondedForce", "getParticleParameters") ("NonbondedForce", "getParticleParameters")
: (None, ('unit.elementary_charge', : (None, ('unit.elementary_charge',
'unit.nanometer', 'unit.kilojoule_per_mole')), 'unit.nanometer', 'unit.kilojoule_per_mole')),
......
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