Commit 8df54762 authored by Lee-Ping Wang's avatar Lee-Ping Wang
Browse files

Merge branch 'master' of github.com:leeping/openmm

parents 3cb25ad8 59854c5e
/* Portions copyright (c) 2011 Stanford University and Simbios.
/* Portions copyright (c) 2011-2013 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -252,12 +252,12 @@ void ReferenceCustomDynamics::update(ContextImpl& context, int numberOfAtoms, ve
break;
}
case CustomIntegrator::ConstrainPositions: {
getReferenceConstraintAlgorithm()->apply(numberOfAtoms, oldPos, atomCoordinates, inverseMasses);
getReferenceConstraintAlgorithm()->apply(oldPos, atomCoordinates, inverseMasses);
oldPos = atomCoordinates;
break;
}
case CustomIntegrator::ConstrainVelocities: {
getReferenceConstraintAlgorithm()->applyToVelocities(numberOfAtoms, oldPos, velocities, inverseMasses);
getReferenceConstraintAlgorithm()->applyToVelocities(oldPos, velocities, inverseMasses);
break;
}
case CustomIntegrator::UpdateContextState: {
......
/* Portions copyright (c) 2009 Stanford University and Simbios.
/* Portions copyright (c) 2009-2013 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -40,18 +40,37 @@ using namespace OpenMM;
--------------------------------------------------------------------------------------- */
ReferenceCustomExternalIxn::ReferenceCustomExternalIxn(const Lepton::ExpressionProgram& energyExpression,
const Lepton::ExpressionProgram& forceExpressionX, const Lepton::ExpressionProgram& forceExpressionY,
const Lepton::ExpressionProgram& forceExpressionZ, const vector<string>& parameterNames, map<string, double> globalParameters) :
ReferenceCustomExternalIxn::ReferenceCustomExternalIxn(const Lepton::CompiledExpression& energyExpression,
const Lepton::CompiledExpression& forceExpressionX, const Lepton::CompiledExpression& forceExpressionY,
const Lepton::CompiledExpression& forceExpressionZ, const vector<string>& parameterNames, map<string, double> globalParameters) :
energyExpression(energyExpression), forceExpressionX(forceExpressionX), forceExpressionY(forceExpressionY),
forceExpressionZ(forceExpressionZ), paramNames(parameterNames), globalParameters(globalParameters) {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceCustomExternalIxn::ReferenceCustomExternalIxn";
// ---------------------------------------------------------------------------------------
forceExpressionZ(forceExpressionZ) {
energyX = ReferenceForce::getVariablePointer(this->energyExpression, "x");
energyY = ReferenceForce::getVariablePointer(this->energyExpression, "y");
energyZ = ReferenceForce::getVariablePointer(this->energyExpression, "z");
forceXX = ReferenceForce::getVariablePointer(this->forceExpressionX, "x");
forceXY = ReferenceForce::getVariablePointer(this->forceExpressionX, "y");
forceXZ = ReferenceForce::getVariablePointer(this->forceExpressionX, "z");
forceYX = ReferenceForce::getVariablePointer(this->forceExpressionY, "x");
forceYY = ReferenceForce::getVariablePointer(this->forceExpressionY, "y");
forceYZ = ReferenceForce::getVariablePointer(this->forceExpressionY, "z");
forceZX = ReferenceForce::getVariablePointer(this->forceExpressionZ, "x");
forceZY = ReferenceForce::getVariablePointer(this->forceExpressionZ, "y");
forceZZ = ReferenceForce::getVariablePointer(this->forceExpressionZ, "z");
numParameters = parameterNames.size();
for (int i = 0; i < (int) numParameters; i++) {
energyParams.push_back(ReferenceForce::getVariablePointer(this->energyExpression, parameterNames[i]));
forceXParams.push_back(ReferenceForce::getVariablePointer(this->forceExpressionX, parameterNames[i]));
forceYParams.push_back(ReferenceForce::getVariablePointer(this->forceExpressionY, parameterNames[i]));
forceZParams.push_back(ReferenceForce::getVariablePointer(this->forceExpressionZ, parameterNames[i]));
}
for (map<string, double>::const_iterator iter = globalParameters.begin(); iter != globalParameters.end(); ++iter) {
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(this->energyExpression, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(this->forceExpressionX, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(this->forceExpressionY, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(this->forceExpressionZ, iter->first), iter->second);
}
}
/**---------------------------------------------------------------------------------------
......@@ -90,18 +109,30 @@ void ReferenceCustomExternalIxn::calculateForce( int atomIndex,
static const std::string methodName = "\nReferenceCustomExternalIxn::calculateBondIxn";
map<string, double> variables = globalParameters;
for (int i = 0; i < (int) paramNames.size(); ++i)
variables[paramNames[i]] = parameters[i];
variables["x"] = atomCoordinates[atomIndex][0];
variables["y"] = atomCoordinates[atomIndex][1];
variables["z"] = atomCoordinates[atomIndex][2];
for (int i = 0; i < numParameters; i++) {
ReferenceForce::setVariable(energyParams[i], parameters[i]);
ReferenceForce::setVariable(forceXParams[i], parameters[i]);
ReferenceForce::setVariable(forceYParams[i], parameters[i]);
ReferenceForce::setVariable(forceZParams[i], parameters[i]);
}
ReferenceForce::setVariable(energyX, atomCoordinates[atomIndex][0]);
ReferenceForce::setVariable(energyY, atomCoordinates[atomIndex][1]);
ReferenceForce::setVariable(energyZ, atomCoordinates[atomIndex][2]);
ReferenceForce::setVariable(forceXX, atomCoordinates[atomIndex][0]);
ReferenceForce::setVariable(forceXY, atomCoordinates[atomIndex][1]);
ReferenceForce::setVariable(forceXZ, atomCoordinates[atomIndex][2]);
ReferenceForce::setVariable(forceYX, atomCoordinates[atomIndex][0]);
ReferenceForce::setVariable(forceYY, atomCoordinates[atomIndex][1]);
ReferenceForce::setVariable(forceYZ, atomCoordinates[atomIndex][2]);
ReferenceForce::setVariable(forceZX, atomCoordinates[atomIndex][0]);
ReferenceForce::setVariable(forceZY, atomCoordinates[atomIndex][1]);
ReferenceForce::setVariable(forceZZ, atomCoordinates[atomIndex][2]);
// ---------------------------------------------------------------------------------------
forces[atomIndex][0] -= (RealOpenMM) forceExpressionX.evaluate(variables);
forces[atomIndex][1] -= (RealOpenMM) forceExpressionY.evaluate(variables);
forces[atomIndex][2] -= (RealOpenMM) forceExpressionZ.evaluate(variables);
forces[atomIndex][0] -= (RealOpenMM) forceExpressionX.evaluate();
forces[atomIndex][1] -= (RealOpenMM) forceExpressionY.evaluate();
forces[atomIndex][2] -= (RealOpenMM) forceExpressionZ.evaluate();
if (energy != NULL)
*energy += (RealOpenMM) energyExpression.evaluate(variables);
*energy += (RealOpenMM) energyExpression.evaluate();
}
/* Portions copyright (c) 2009 Stanford University and Simbios.
/* Portions copyright (c) 2009-2013 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -45,8 +45,8 @@ using OpenMM::RealVec;
--------------------------------------------------------------------------------------- */
ReferenceCustomNonbondedIxn::ReferenceCustomNonbondedIxn(const Lepton::ExpressionProgram& energyExpression,
const Lepton::ExpressionProgram& forceExpression, const vector<string>& parameterNames) :
ReferenceCustomNonbondedIxn::ReferenceCustomNonbondedIxn(const Lepton::CompiledExpression& energyExpression,
const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames) :
cutoff(false), useSwitch(false), periodic(false), energyExpression(energyExpression), forceExpression(forceExpression), paramNames(parameterNames) {
// ---------------------------------------------------------------------------------------
......@@ -55,11 +55,14 @@ ReferenceCustomNonbondedIxn::ReferenceCustomNonbondedIxn(const Lepton::Expressio
// ---------------------------------------------------------------------------------------
energyR = ReferenceForce::getVariablePointer(this->energyExpression, "r");
forceR = ReferenceForce::getVariablePointer(this->forceExpression, "r");
for (int i = 0; i < (int) paramNames.size(); i++) {
for (int j = 1; j < 3; j++) {
stringstream name;
name << paramNames[i] << j;
particleParamNames.push_back(name.str());
energyParticleParams.push_back(ReferenceForce::getVariablePointer(this->energyExpression, name.str()));
forceParticleParams.push_back(ReferenceForce::getVariablePointer(this->forceExpression, name.str()));
}
}
}
......@@ -166,9 +169,12 @@ void ReferenceCustomNonbondedIxn::setUseSwitchingFunction( RealOpenMM distance )
void ReferenceCustomNonbondedIxn::calculatePairIxn( int numberOfAtoms, vector<RealVec>& atomCoordinates,
RealOpenMM** atomParameters, vector<set<int> >& exclusions,
RealOpenMM* fixedParameters, const map<string, double>& globalParameters, vector<RealVec>& forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const {
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) {
map<string, double> variables = globalParameters;
for (map<string, double>::const_iterator iter = globalParameters.begin(); iter != globalParameters.end(); ++iter) {
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(energyExpression, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(forceExpression, iter->first), iter->second);
}
if (interactionGroups.size() > 0) {
// The user has specified interaction groups, so compute only the requested interactions.
......@@ -182,10 +188,12 @@ void ReferenceCustomNonbondedIxn::calculatePairIxn( int numberOfAtoms, vector<Re
if (*atom1 > *atom2 && set1.find(*atom2) != set1.end() && set2.find(*atom1) != set2.end())
continue; // Both atoms are in both sets, so skip duplicate interactions.
for (int j = 0; j < (int) paramNames.size(); j++) {
variables[particleParamNames[j*2]] = atomParameters[*atom1][j];
variables[particleParamNames[j*2+1]] = atomParameters[*atom2][j];
ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[*atom1][j]);
ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[*atom2][j]);
ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[*atom1][j]);
ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[*atom2][j]);
}
calculateOneIxn(*atom1, *atom2, atomCoordinates, variables, forces, energyByAtom, totalEnergy);
calculateOneIxn(*atom1, *atom2, atomCoordinates, forces, energyByAtom, totalEnergy);
}
}
}
......@@ -196,10 +204,12 @@ void ReferenceCustomNonbondedIxn::calculatePairIxn( int numberOfAtoms, vector<Re
for (int i = 0; i < (int) neighborList->size(); i++) {
OpenMM::AtomPair pair = (*neighborList)[i];
for (int j = 0; j < (int) paramNames.size(); j++) {
variables[particleParamNames[j*2]] = atomParameters[pair.first][j];
variables[particleParamNames[j*2+1]] = atomParameters[pair.second][j];
ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[pair.first][j]);
ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[pair.second][j]);
ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[pair.first][j]);
ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[pair.second][j]);
}
calculateOneIxn(pair.first, pair.second, atomCoordinates, variables, forces, energyByAtom, totalEnergy);
calculateOneIxn(pair.first, pair.second, atomCoordinates, forces, energyByAtom, totalEnergy);
}
}
else {
......@@ -209,10 +219,12 @@ void ReferenceCustomNonbondedIxn::calculatePairIxn( int numberOfAtoms, vector<Re
for (int jj = ii+1; jj < numberOfAtoms; jj++) {
if (exclusions[jj].find(ii) == exclusions[jj].end()) {
for (int j = 0; j < (int) paramNames.size(); j++) {
variables[particleParamNames[j*2]] = atomParameters[ii][j];
variables[particleParamNames[j*2+1]] = atomParameters[jj][j];
ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[ii][j]);
ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[jj][j]);
ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[ii][j]);
ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[jj][j]);
}
calculateOneIxn(ii, jj, atomCoordinates, variables, forces, energyByAtom, totalEnergy);
calculateOneIxn(ii, jj, atomCoordinates, forces, energyByAtom, totalEnergy);
}
}
}
......@@ -233,9 +245,8 @@ void ReferenceCustomNonbondedIxn::calculatePairIxn( int numberOfAtoms, vector<Re
--------------------------------------------------------------------------------------- */
void ReferenceCustomNonbondedIxn::calculateOneIxn( int ii, int jj, vector<RealVec>& atomCoordinates,
map<string, double>& variables, vector<RealVec>& forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const {
void ReferenceCustomNonbondedIxn::calculateOneIxn( int ii, int jj, vector<RealVec>& atomCoordinates, vector<RealVec>& forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) {
// ---------------------------------------------------------------------------------------
......@@ -266,9 +277,10 @@ void ReferenceCustomNonbondedIxn::calculateOneIxn( int ii, int jj, vector<RealVe
// accumulate forces
variables["r"] = r;
RealOpenMM dEdR = (RealOpenMM) (forceExpression.evaluate(variables)/(deltaR[ReferenceForce::RIndex]));
RealOpenMM energy = (RealOpenMM) energyExpression.evaluate(variables);
ReferenceForce::setVariable(energyR, r);
ReferenceForce::setVariable(forceR, r);
RealOpenMM dEdR = (RealOpenMM) (forceExpression.evaluate()/(deltaR[ReferenceForce::RIndex]));
RealOpenMM energy = (RealOpenMM) energyExpression.evaluate();
if (useSwitch) {
if (r > switchingDistance) {
RealOpenMM t = (r-switchingDistance)/(cutoffDistance-switchingDistance);
......
/* Portions copyright (c) 2010 Stanford University and Simbios.
/* Portions copyright (c) 2010-2013 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -39,16 +39,21 @@ using namespace OpenMM;
--------------------------------------------------------------------------------------- */
ReferenceCustomTorsionIxn::ReferenceCustomTorsionIxn(const Lepton::ExpressionProgram& energyExpression,
const Lepton::ExpressionProgram& forceExpression, const vector<string>& parameterNames, map<string, double> globalParameters) :
energyExpression(energyExpression), forceExpression(forceExpression), paramNames(parameterNames), globalParameters(globalParameters) {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceCustomTorsionIxn::ReferenceCustomTorsionIxn";
// ---------------------------------------------------------------------------------------
ReferenceCustomTorsionIxn::ReferenceCustomTorsionIxn(const Lepton::CompiledExpression& energyExpression,
const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames, map<string, double> globalParameters) :
energyExpression(energyExpression), forceExpression(forceExpression) {
energyTheta = ReferenceForce::getVariablePointer(this->energyExpression, "theta");
forceTheta = ReferenceForce::getVariablePointer(this->forceExpression, "theta");
numParameters = parameterNames.size();
for (int i = 0; i < (int) numParameters; i++) {
energyParams.push_back(ReferenceForce::getVariablePointer(this->energyExpression, parameterNames[i]));
forceParams.push_back(ReferenceForce::getVariablePointer(this->forceExpression, parameterNames[i]));
}
for (map<string, double>::const_iterator iter = globalParameters.begin(); iter != globalParameters.end(); ++iter) {
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(this->energyExpression, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(this->forceExpression, iter->first), iter->second);
}
}
/**---------------------------------------------------------------------------------------
......@@ -91,9 +96,10 @@ void ReferenceCustomTorsionIxn::calculateBondIxn( int* atomIndices,
static const RealOpenMM one = 1.0;
RealOpenMM deltaR[3][ReferenceForce::LastDeltaRIndex];
map<string, double> variables = globalParameters;
for (int i = 0; i < (int) paramNames.size(); ++i)
variables[paramNames[i]] = parameters[i];
for (int i = 0; i < numParameters; i++) {
ReferenceForce::setVariable(energyParams[i], parameters[i]);
ReferenceForce::setVariable(forceParams[i], parameters[i]);
}
// ---------------------------------------------------------------------------------------
......@@ -118,13 +124,13 @@ void ReferenceCustomTorsionIxn::calculateBondIxn( int* atomIndices,
RealOpenMM dotDihedral;
RealOpenMM signOfAngle;
variables["theta"] = getDihedralAngleBetweenThreeVectors(deltaR[0], deltaR[1], deltaR[2],
crossProduct, &dotDihedral, deltaR[0],
&signOfAngle, 1);
RealOpenMM angle = getDihedralAngleBetweenThreeVectors(deltaR[0], deltaR[1], deltaR[2], crossProduct, &dotDihedral, deltaR[0], &signOfAngle, 1);
ReferenceForce::setVariable(energyTheta, angle);
ReferenceForce::setVariable(forceTheta, angle);
// evaluate delta angle, dE/d(angle)
RealOpenMM dEdAngle = (RealOpenMM) forceExpression.evaluate(variables);
RealOpenMM dEdAngle = (RealOpenMM) forceExpression.evaluate();
// compute force
......@@ -166,6 +172,6 @@ void ReferenceCustomTorsionIxn::calculateBondIxn( int* atomIndices,
// accumulate energies
if (totalEnergy != NULL)
*totalEnergy += (RealOpenMM) energyExpression.evaluate(variables);
*totalEnergy += (RealOpenMM) energyExpression.evaluate();
}
/* Portions copyright (c) 2006 Stanford University and Simbios.
/* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -161,3 +161,14 @@ void ReferenceForce::getDeltaROnly( const RealOpenMM* atomCoordinatesI,
deltaR[YIndex] = atomCoordinatesJ[1] - atomCoordinatesI[1];
deltaR[ZIndex] = atomCoordinatesJ[2] - atomCoordinatesI[2];
}
double* ReferenceForce::getVariablePointer(Lepton::CompiledExpression& expression, const std::string& name) {
if (expression.getVariables().find(name) == expression.getVariables().end())
return NULL;
return &expression.getVariableReference(name);
}
void ReferenceForce::setVariable(double* pointer, double value) {
if (pointer != NULL)
*pointer = value;
}
......@@ -31,7 +31,7 @@
#include "SimTKOpenMMUtilities.h"
#include "ReferenceLJCoulombIxn.h"
#include "ReferenceForce.h"
#include "PME.h"
#include "ReferencePME.h"
// In case we're using some primitive version of Visual Studio this will
// make sure that erf() and erfc() are defined.
......@@ -233,7 +233,10 @@ void ReferenceLJCoulombIxn::calculateEwaldIxn(int numberOfAtoms, vector<RealVec>
pme_init(&pmedata,alphaEwald,numberOfAtoms,meshDim,5,1);
pme_exec(pmedata,atomCoordinates,forces,atomParameters,periodicBoxSize,&recipEnergy,virial);
vector<RealOpenMM> charges(numberOfAtoms);
for (int i = 0; i < numberOfAtoms; i++)
charges[i] = atomParameters[i][QIndex];
pme_exec(pmedata,atomCoordinates,forces,charges,periodicBoxSize,&recipEnergy,virial);
if( totalEnergy )
*totalEnergy += recipEnergy;
......
......@@ -44,9 +44,7 @@ void OPENMM_EXPORT computeNeighborListNaive(
bool usePeriodic,
double maxDistance,
double minDistance,
bool reportSymmetricPairs
)
{
bool reportSymmetricPairs) {
neighborList.clear();
double maxDistanceSquared = maxDistance * maxDistance;
......@@ -102,15 +100,19 @@ public:
nx = (int) floor(periodicBoxSize[0]/voxelSizeX+0.5);
ny = (int) floor(periodicBoxSize[1]/voxelSizeY+0.5);
nz = (int) floor(periodicBoxSize[2]/voxelSizeZ+0.5);
voxelSizeX = periodicBoxSize[0]/nx;
voxelSizeY = periodicBoxSize[1]/ny;
voxelSizeZ = periodicBoxSize[2]/nz;
}
}
void insert(const AtomIndex& item, const RealVec& location)
{
VoxelIndex voxelIndex = getVoxelIndex(location);
if ( voxelMap.find(voxelIndex) == voxelMap.end() ) voxelMap[voxelIndex] = Voxel();
if (voxelMap.find(voxelIndex) == voxelMap.end())
voxelMap[voxelIndex] = Voxel();
Voxel& voxel = voxelMap.find(voxelIndex)->second;
voxel.push_back( VoxelItem(&location, item) );
voxel.push_back(VoxelItem(&location, item));
}
......@@ -180,8 +182,9 @@ public:
voxelIndex.y = (y+ny)%ny;
voxelIndex.z = (z+nz)%nz;
}
if (voxelMap.find(voxelIndex) == voxelMap.end()) continue; // no such voxel; skip
const Voxel& voxel = voxelMap.find(voxelIndex)->second;
const map<VoxelIndex, Voxel>::const_iterator voxelEntry = voxelMap.find(voxelIndex);
if (voxelEntry == voxelMap.end()) continue; // no such voxel; skip
const Voxel& voxel = voxelEntry->second;
for (Voxel::const_iterator itemIter = voxel.begin(); itemIter != voxel.end(); ++itemIter)
{
const AtomIndex atomJ = itemIter->second;
......@@ -190,13 +193,13 @@ public:
// Ignore self hits
if (atomI == atomJ) continue;
// Ignore exclusions.
if (exclusions[atomI].find(atomJ) != exclusions[atomI].end()) continue;
double dSquared = compPairDistanceSquared(locationI, locationJ, periodicBoxSize, usePeriodic);
if (dSquared > maxDistanceSquared) continue;
if (dSquared < minDistanceSquared) continue;
// Ignore exclusions.
if (exclusions[atomI].find(atomJ) != exclusions[atomI].end()) continue;
neighbors.push_back( AtomPair(atomI, atomJ) );
if (reportSymmetricPairs)
neighbors.push_back( AtomPair(atomJ, atomI) );
......@@ -234,9 +237,9 @@ void OPENMM_EXPORT computeNeighborListVoxelHash(
if (!usePeriodic)
edgeSizeX = edgeSizeY = edgeSizeZ = maxDistance; // TODO - adjust this as needed
else {
edgeSizeX = periodicBoxSize[0]/floor(periodicBoxSize[0]/maxDistance);
edgeSizeY = periodicBoxSize[1]/floor(periodicBoxSize[1]/maxDistance);
edgeSizeZ = periodicBoxSize[2]/floor(periodicBoxSize[2]/maxDistance);
edgeSizeX = 0.5*periodicBoxSize[0]/floor(periodicBoxSize[0]/maxDistance);
edgeSizeY = 0.5*periodicBoxSize[1]/floor(periodicBoxSize[1]/maxDistance);
edgeSizeZ = 0.5*periodicBoxSize[2]/floor(periodicBoxSize[2]/maxDistance);
}
VoxelHash voxelHash(edgeSizeX, edgeSizeY, edgeSizeZ, periodicBoxSize, usePeriodic);
for (AtomIndex atomJ = 0; atomJ < (AtomIndex) nAtoms; ++atomJ) // use "j", because j > i for pairs
......
......@@ -33,7 +33,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "PME.h"
#include "ReferencePME.h"
#include "fftpack.h"
using std::vector;
......@@ -195,7 +195,7 @@ pme_calculate_bsplines_moduli(pme_t pme)
static void
pme_update_grid_index_and_fraction(pme_t pme,
vector<RealVec>& atomCoordinates,
const vector<RealVec>& atomCoordinates,
const RealOpenMM periodicBoxSize[3])
{
int i;
......@@ -317,10 +317,8 @@ pme_update_bsplines(pme_t pme)
static void
pme_grid_spread_charge(pme_t pme,
RealOpenMM ** atomParameters)
pme_grid_spread_charge(pme_t pme, const vector<RealOpenMM>& charges)
{
static const int QIndex = 2; // atom charges are stored in atomParameters[atomID][2]
int order;
int i;
int ix,iy,iz;
......@@ -342,7 +340,7 @@ pme_grid_spread_charge(pme_t pme,
for(i=0;i<pme->natoms;i++)
{
q = atomParameters[i][QIndex];
q = charges[i];
/* Grid index for the actual atom position */
x0index = pme->particleindex[i][0];
......@@ -521,12 +519,11 @@ pme_reciprocal_convolution(pme_t pme,
static void
pme_grid_interpolate_force(pme_t pme,
const RealOpenMM periodicBoxSize[3],
RealOpenMM ** atomParameters,
vector<RealVec>& forces)
pme_grid_interpolate_force(pme_t pme,
const RealOpenMM periodicBoxSize[3],
const vector<RealOpenMM>& charges,
vector<RealVec>& forces)
{
static const int QIndex = 2; // atom charges are stored in atomParameters[atomID][2]
int i;
int ix,iy,iz;
int x0index,y0index,z0index;
......@@ -558,7 +555,7 @@ pme_grid_interpolate_force(pme_t pme,
{
fx = fy = fz = 0;
q = atomParameters[i][QIndex];
q = charges[i];
/* Grid index for the actual atom position */
x0index = pme->particleindex[i][0];
......@@ -669,12 +666,12 @@ pme_init(pme_t * ppme,
int pme_exec(pme_t pme,
vector<RealVec>& atomCoordinates,
vector<RealVec>& forces,
RealOpenMM ** atomParameters,
const RealOpenMM periodicBoxSize[3],
RealOpenMM * energy,
RealOpenMM pme_virial[3][3])
const vector<RealVec>& atomCoordinates,
vector<RealVec>& forces,
const vector<RealOpenMM>& charges,
const RealOpenMM periodicBoxSize[3],
RealOpenMM* energy,
RealOpenMM pme_virial[3][3])
{
/* Routine is called with coordinates in x, a box, and charges in q */
......@@ -692,7 +689,7 @@ int pme_exec(pme_t pme,
pme_update_bsplines(pme);
/* Spread the charges on grid (using newly calculated bsplines in the pme structure) */
pme_grid_spread_charge(pme,atomParameters);
pme_grid_spread_charge(pme, charges);
/* do 3d-fft */
fftpack_exec_3d(pme->fftplan,FFTPACK_FORWARD,pme->grid,pme->grid);
......@@ -704,7 +701,7 @@ int pme_exec(pme_t pme,
fftpack_exec_3d(pme->fftplan,FFTPACK_BACKWARD,pme->grid,pme->grid);
/* Get the particle forces from the grid and bsplines in the pme structure */
pme_grid_interpolate_force(pme,periodicBoxSize,atomParameters,forces);
pme_grid_interpolate_force(pme,periodicBoxSize,charges,forces);
return 0;
}
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "ReferenceSETTLEAlgorithm.h"
using namespace OpenMM;
using namespace std;
ReferenceSETTLEAlgorithm::ReferenceSETTLEAlgorithm(const vector<int>& atom1, const vector<int>& atom2, const vector<int>& atom3,
const vector<RealOpenMM>& distance1, const vector<RealOpenMM>& distance2, vector<RealOpenMM>& masses, RealOpenMM tolerance) :
atom1(atom1), atom2(atom2), atom3(atom3), distance1(distance1), distance2(distance2), masses(masses), tolerance(tolerance) {
}
RealOpenMM ReferenceSETTLEAlgorithm::getTolerance() const {
return tolerance;
}
void ReferenceSETTLEAlgorithm::setTolerance(RealOpenMM tolerance) {
this->tolerance = tolerance;
}
void ReferenceSETTLEAlgorithm::apply(vector<OpenMM::RealVec>& atomCoordinates, vector<OpenMM::RealVec>& atomCoordinatesP, vector<RealOpenMM>& inverseMasses) {
for (int index = 0; index < (int) atom1.size(); ++index) {
RealVec apos0 = atomCoordinates[atom1[index]];
RealVec xp0 = atomCoordinatesP[atom1[index]]-apos0;
RealVec apos1 = atomCoordinates[atom2[index]];
RealVec xp1 = atomCoordinatesP[atom2[index]]-apos1;
RealVec apos2 = atomCoordinates[atom3[index]];
RealVec xp2 = atomCoordinatesP[atom3[index]]-apos2;
RealOpenMM m0 = masses[atom1[index]];
RealOpenMM m1 = masses[atom2[index]];
RealOpenMM m2 = masses[atom3[index]];
// Apply the SETTLE algorithm.
RealOpenMM xb0 = apos1[0]-apos0[0];
RealOpenMM yb0 = apos1[1]-apos0[1];
RealOpenMM zb0 = apos1[2]-apos0[2];
RealOpenMM xc0 = apos2[0]-apos0[0];
RealOpenMM yc0 = apos2[1]-apos0[1];
RealOpenMM zc0 = apos2[2]-apos0[2];
RealOpenMM invTotalMass = 1/(m0+m1+m2);
RealOpenMM xcom = (xp0[0]*m0 + (xb0+xp1[0])*m1 + (xc0+xp2[0])*m2) * invTotalMass;
RealOpenMM ycom = (xp0[1]*m0 + (yb0+xp1[1])*m1 + (yc0+xp2[1])*m2) * invTotalMass;
RealOpenMM zcom = (xp0[2]*m0 + (zb0+xp1[2])*m1 + (zc0+xp2[2])*m2) * invTotalMass;
RealOpenMM xa1 = xp0[0] - xcom;
RealOpenMM ya1 = xp0[1] - ycom;
RealOpenMM za1 = xp0[2] - zcom;
RealOpenMM xb1 = xb0 + xp1[0] - xcom;
RealOpenMM yb1 = yb0 + xp1[1] - ycom;
RealOpenMM zb1 = zb0 + xp1[2] - zcom;
RealOpenMM xc1 = xc0 + xp2[0] - xcom;
RealOpenMM yc1 = yc0 + xp2[1] - ycom;
RealOpenMM zc1 = zc0 + xp2[2] - zcom;
RealOpenMM xaksZd = yb0*zc0 - zb0*yc0;
RealOpenMM yaksZd = zb0*xc0 - xb0*zc0;
RealOpenMM zaksZd = xb0*yc0 - yb0*xc0;
RealOpenMM xaksXd = ya1*zaksZd - za1*yaksZd;
RealOpenMM yaksXd = za1*xaksZd - xa1*zaksZd;
RealOpenMM zaksXd = xa1*yaksZd - ya1*xaksZd;
RealOpenMM xaksYd = yaksZd*zaksXd - zaksZd*yaksXd;
RealOpenMM yaksYd = zaksZd*xaksXd - xaksZd*zaksXd;
RealOpenMM zaksYd = xaksZd*yaksXd - yaksZd*xaksXd;
RealOpenMM axlng = sqrt(xaksXd*xaksXd + yaksXd*yaksXd + zaksXd*zaksXd);
RealOpenMM aylng = sqrt(xaksYd*xaksYd + yaksYd*yaksYd + zaksYd*zaksYd);
RealOpenMM azlng = sqrt(xaksZd*xaksZd + yaksZd*yaksZd + zaksZd*zaksZd);
RealOpenMM trns11 = xaksXd / axlng;
RealOpenMM trns21 = yaksXd / axlng;
RealOpenMM trns31 = zaksXd / axlng;
RealOpenMM trns12 = xaksYd / aylng;
RealOpenMM trns22 = yaksYd / aylng;
RealOpenMM trns32 = zaksYd / aylng;
RealOpenMM trns13 = xaksZd / azlng;
RealOpenMM trns23 = yaksZd / azlng;
RealOpenMM trns33 = zaksZd / azlng;
RealOpenMM xb0d = trns11*xb0 + trns21*yb0 + trns31*zb0;
RealOpenMM yb0d = trns12*xb0 + trns22*yb0 + trns32*zb0;
RealOpenMM xc0d = trns11*xc0 + trns21*yc0 + trns31*zc0;
RealOpenMM yc0d = trns12*xc0 + trns22*yc0 + trns32*zc0;
RealOpenMM za1d = trns13*xa1 + trns23*ya1 + trns33*za1;
RealOpenMM xb1d = trns11*xb1 + trns21*yb1 + trns31*zb1;
RealOpenMM yb1d = trns12*xb1 + trns22*yb1 + trns32*zb1;
RealOpenMM zb1d = trns13*xb1 + trns23*yb1 + trns33*zb1;
RealOpenMM xc1d = trns11*xc1 + trns21*yc1 + trns31*zc1;
RealOpenMM yc1d = trns12*xc1 + trns22*yc1 + trns32*zc1;
RealOpenMM zc1d = trns13*xc1 + trns23*yc1 + trns33*zc1;
// --- Step2 A2' ---
RealOpenMM rc = 0.5*distance2[index];
RealOpenMM rb = sqrt(distance1[index]*distance1[index]-rc*rc);
RealOpenMM ra = rb*(m1+m2)*invTotalMass;
rb -= ra;
RealOpenMM sinphi = za1d / ra;
RealOpenMM cosphi = sqrt(1 - sinphi*sinphi);
RealOpenMM sinpsi = (zb1d - zc1d) / (2*rc*cosphi);
RealOpenMM cospsi = sqrt(1 - sinpsi*sinpsi);
RealOpenMM ya2d = ra*cosphi;
RealOpenMM xb2d = - rc*cospsi;
RealOpenMM yb2d = - rb*cosphi - rc*sinpsi*sinphi;
RealOpenMM yc2d = - rb*cosphi + rc*sinpsi*sinphi;
RealOpenMM xb2d2 = xb2d*xb2d;
RealOpenMM hh2 = 4.0f*xb2d2 + (yb2d-yc2d)*(yb2d-yc2d) + (zb1d-zc1d)*(zb1d-zc1d);
RealOpenMM deltx = 2.0f*xb2d + sqrt(4.0f*xb2d2 - hh2 + distance2[index]*distance2[index]);
xb2d -= deltx*0.5;
// --- Step3 al,be,ga ---
RealOpenMM alpha = (xb2d*(xb0d-xc0d) + yb0d*yb2d + yc0d*yc2d);
RealOpenMM beta = (xb2d*(yc0d-yb0d) + xb0d*yb2d + xc0d*yc2d);
RealOpenMM gamma = xb0d*yb1d - xb1d*yb0d + xc0d*yc1d - xc1d*yc0d;
RealOpenMM al2be2 = alpha*alpha + beta*beta;
RealOpenMM sintheta = (alpha*gamma - beta*sqrt(al2be2 - gamma*gamma)) / al2be2;
// --- Step4 A3' ---
RealOpenMM costheta = sqrt(1 - sintheta*sintheta);
RealOpenMM xa3d = - ya2d*sintheta;
RealOpenMM ya3d = ya2d*costheta;
RealOpenMM za3d = za1d;
RealOpenMM xb3d = xb2d*costheta - yb2d*sintheta;
RealOpenMM yb3d = xb2d*sintheta + yb2d*costheta;
RealOpenMM zb3d = zb1d;
RealOpenMM xc3d = - xb2d*costheta - yc2d*sintheta;
RealOpenMM yc3d = - xb2d*sintheta + yc2d*costheta;
RealOpenMM zc3d = zc1d;
// --- Step5 A3 ---
RealOpenMM xa3 = trns11*xa3d + trns12*ya3d + trns13*za3d;
RealOpenMM ya3 = trns21*xa3d + trns22*ya3d + trns23*za3d;
RealOpenMM za3 = trns31*xa3d + trns32*ya3d + trns33*za3d;
RealOpenMM xb3 = trns11*xb3d + trns12*yb3d + trns13*zb3d;
RealOpenMM yb3 = trns21*xb3d + trns22*yb3d + trns23*zb3d;
RealOpenMM zb3 = trns31*xb3d + trns32*yb3d + trns33*zb3d;
RealOpenMM xc3 = trns11*xc3d + trns12*yc3d + trns13*zc3d;
RealOpenMM yc3 = trns21*xc3d + trns22*yc3d + trns23*zc3d;
RealOpenMM zc3 = trns31*xc3d + trns32*yc3d + trns33*zc3d;
xp0[0] = xcom + xa3;
xp0[1] = ycom + ya3;
xp0[2] = zcom + za3;
xp1[0] = xcom + xb3 - xb0;
xp1[1] = ycom + yb3 - yb0;
xp1[2] = zcom + zb3 - zb0;
xp2[0] = xcom + xc3 - xc0;
xp2[1] = ycom + yc3 - yc0;
xp2[2] = zcom + zc3 - zc0;
// Record the new positions.
atomCoordinatesP[atom1[index]] = xp0+apos0;
atomCoordinatesP[atom2[index]] = xp1+apos1;
atomCoordinatesP[atom3[index]] = xp2+apos2;
}
}
void ReferenceSETTLEAlgorithm::applyToVelocities(vector<OpenMM::RealVec>& atomCoordinates, vector<OpenMM::RealVec>& velocities, vector<RealOpenMM>& inverseMasses) {
for (int index = 0; index < (int) atom1.size(); ++index) {
RealVec apos0 = atomCoordinates[atom1[index]];
RealVec apos1 = atomCoordinates[atom2[index]];
RealVec apos2 = atomCoordinates[atom3[index]];
RealVec v0 = velocities[atom1[index]];
RealVec v1 = velocities[atom2[index]];
RealVec v2 = velocities[atom3[index]];
// Compute intermediate quantities: the atom masses, the bond directions, the relative velocities,
// and the angle cosines and sines.
RealOpenMM mA = masses[atom1[index]];
RealOpenMM mB = masses[atom2[index]];
RealOpenMM mC = masses[atom3[index]];
RealVec eAB = apos1-apos0;
RealVec eBC = apos2-apos1;
RealVec eCA = apos0-apos2;
eAB /= sqrt(eAB[0]*eAB[0] + eAB[1]*eAB[1] + eAB[2]*eAB[2]);
eBC /= sqrt(eBC[0]*eBC[0] + eBC[1]*eBC[1] + eBC[2]*eBC[2]);
eCA /= sqrt(eCA[0]*eCA[0] + eCA[1]*eCA[1] + eCA[2]*eCA[2]);
RealOpenMM vAB = (v1[0]-v0[0])*eAB[0] + (v1[1]-v0[1])*eAB[1] + (v1[2]-v0[2])*eAB[2];
RealOpenMM vBC = (v2[0]-v1[0])*eBC[0] + (v2[1]-v1[1])*eBC[1] + (v2[2]-v1[2])*eBC[2];
RealOpenMM vCA = (v0[0]-v2[0])*eCA[0] + (v0[1]-v2[1])*eCA[1] + (v0[2]-v2[2])*eCA[2];
RealOpenMM cA = -(eAB[0]*eCA[0] + eAB[1]*eCA[1] + eAB[2]*eCA[2]);
RealOpenMM cB = -(eAB[0]*eBC[0] + eAB[1]*eBC[1] + eAB[2]*eBC[2]);
RealOpenMM cC = -(eBC[0]*eCA[0] + eBC[1]*eCA[1] + eBC[2]*eCA[2]);
RealOpenMM s2A = 1-cA*cA;
RealOpenMM s2B = 1-cB*cB;
RealOpenMM s2C = 1-cC*cC;
// Solve the equations. These are different from those in the SETTLE paper (JCC 13(8), pp. 952-962, 1992), because
// in going from equations B1 to B2, they make the assumption that mB=mC (but don't bother to mention they're
// making that assumption). We allow all three atoms to have different masses.
RealOpenMM mABCinv = 1/(mA*mB*mC);
RealOpenMM denom = (((s2A*mB+s2B*mA)*mC+(s2A*mB*mB+2*(cA*cB*cC+1)*mA*mB+s2B*mA*mA))*mC+s2C*mA*mB*(mA+mB))*mABCinv;
RealOpenMM tab = ((cB*cC*mA-cA*mB-cA*mC)*vCA + (cA*cC*mB-cB*mC-cB*mA)*vBC + (s2C*mA*mA*mB*mB*mABCinv+(mA+mB+mC))*vAB)/denom;
RealOpenMM tbc = ((cA*cB*mC-cC*mB-cC*mA)*vCA + (s2A*mB*mB*mC*mC*mABCinv+(mA+mB+mC))*vBC + (cA*cC*mB-cB*mA-cB*mC)*vAB)/denom;
RealOpenMM tca = ((s2B*mA*mA*mC*mC*mABCinv+(mA+mB+mC))*vCA + (cA*cB*mC-cC*mB-cC*mA)*vBC + (cB*cC*mA-cA*mB-cA*mC)*vAB)/denom;
v0 += (eAB*tab - eCA*tca)*inverseMasses[atom1[index]];
v1 += (eBC*tbc - eAB*tab)*inverseMasses[atom2[index]];
v2 += (eCA*tca - eBC*tbc)*inverseMasses[atom3[index]];
velocities[atom1[index]] = v0;
velocities[atom2[index]] = v1;
velocities[atom3[index]] = v2;
}
}
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
* Contributors: Pande Group
*
* 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 "SimTKOpenMMCommon.h"
#include "SimTKOpenMMUtilities.h"
#include "SimTKOpenMMLog.h"
#include "ReferenceShakeAlgorithm.h"
#include "ReferenceDynamics.h"
#include "openmm/OpenMMException.h"
using std::vector;
using OpenMM::RealVec;
/**---------------------------------------------------------------------------------------
ReferenceShakeAlgorithm constructor
@param numberOfConstraints number of constraints
@param atomIndices block of atom indices
@param shakeParameters Shake parameters
@param tolerance constraint tolerance
--------------------------------------------------------------------------------------- */
ReferenceShakeAlgorithm::ReferenceShakeAlgorithm( int numberOfConstraints,
int** atomIndices,
RealOpenMM* distance,
RealOpenMM tolerance){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::ReferenceShakeAlgorithm";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static const RealOpenMM two = 2.0;
static const RealOpenMM three = 3.0;
static const RealOpenMM oneM = -1.0;
static const int threeI = 3;
// ---------------------------------------------------------------------------------------
_numberOfConstraints = numberOfConstraints;
_atomIndices = atomIndices;
_distance = distance;
_maximumNumberOfIterations = 150;
_tolerance = tolerance;
_hasInitializedMasses = false;
// work arrays
if (_numberOfConstraints > 0) {
_r_ij = SimTKOpenMMUtilities::allocateTwoDRealOpenMMArray( numberOfConstraints, threeI, NULL,
1, zero, "r_ij" );
_d_ij2 = SimTKOpenMMUtilities::allocateOneDRealOpenMMArray( numberOfConstraints, NULL, 1, zero, "dij_2" );
_distanceTolerance = SimTKOpenMMUtilities::allocateOneDRealOpenMMArray( numberOfConstraints, NULL, 1, zero, "distanceTolerance" );
_reducedMasses = SimTKOpenMMUtilities::allocateOneDRealOpenMMArray( numberOfConstraints, NULL, 1, zero, "reducedMasses" );
}
}
/**---------------------------------------------------------------------------------------
ReferenceShakeAlgorithm destructor
--------------------------------------------------------------------------------------- */
ReferenceShakeAlgorithm::~ReferenceShakeAlgorithm( ){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::~ReferenceShakeAlgorithm";
// ---------------------------------------------------------------------------------------
if (_numberOfConstraints > 0) {
SimTKOpenMMUtilities::freeTwoDRealOpenMMArray( _r_ij, "r_ij" );
SimTKOpenMMUtilities::freeOneDRealOpenMMArray( _d_ij2, "d_ij2" );
SimTKOpenMMUtilities::freeOneDRealOpenMMArray( _distanceTolerance, "distanceTolerance" );
SimTKOpenMMUtilities::freeOneDRealOpenMMArray( _reducedMasses, "reducedMasses" );
}
}
/**---------------------------------------------------------------------------------------
Get number of constraints
@return number of constraints
--------------------------------------------------------------------------------------- */
int ReferenceShakeAlgorithm::getNumberOfConstraints( void ) const {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::getNumberOfConstraints";
// ---------------------------------------------------------------------------------------
return _numberOfConstraints;
}
/**---------------------------------------------------------------------------------------
Get maximum number of iterations
@return maximum number of iterations
--------------------------------------------------------------------------------------- */
int ReferenceShakeAlgorithm::getMaximumNumberOfIterations( void ) const {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::getMaximumNumberOfIterations";
// ---------------------------------------------------------------------------------------
return _maximumNumberOfIterations;
}
/**---------------------------------------------------------------------------------------
Set maximum number of iterations
@param maximumNumberOfIterations new maximum number of iterations
--------------------------------------------------------------------------------------- */
void ReferenceShakeAlgorithm::setMaximumNumberOfIterations( int maximumNumberOfIterations ){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::setMaximumNumberOfIterations";
// ---------------------------------------------------------------------------------------
_maximumNumberOfIterations = maximumNumberOfIterations;
}
/**---------------------------------------------------------------------------------------
Get tolerance
@return tolerance
--------------------------------------------------------------------------------------- */
RealOpenMM ReferenceShakeAlgorithm::getTolerance( void ) const {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::getTolerance";
// ---------------------------------------------------------------------------------------
return _tolerance;
}
/**---------------------------------------------------------------------------------------
Set tolerance
@param tolerance new tolerance
--------------------------------------------------------------------------------------- */
void ReferenceShakeAlgorithm::setTolerance( RealOpenMM tolerance ){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceShakeAlgorithm::setTolerance";
// ---------------------------------------------------------------------------------------
_tolerance = tolerance;;
}
/**---------------------------------------------------------------------------------------
Apply Shake algorithm
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param atomCoordinatesP atom coordinates prime
@param inverseMasses 1/mass
@return SimTKOpenMMCommon::DefaultReturn if converge; else
return SimTKOpenMMCommon::ErrorReturn
--------------------------------------------------------------------------------------- */
int ReferenceShakeAlgorithm::apply( int numberOfAtoms, vector<RealVec>& atomCoordinates,
vector<RealVec>& atomCoordinatesP,
vector<RealOpenMM>& inverseMasses ){
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceShakeAlgorithm::apply";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static const RealOpenMM two = 2.0;
static const RealOpenMM three = 3.0;
static const RealOpenMM oneM = -1.0;
static const RealOpenMM half = 0.5;
static const RealOpenMM epsilon6 = (RealOpenMM) 1.0e-06;
// ---------------------------------------------------------------------------------------
int numberOfConstraints = getNumberOfConstraints();
// temp arrays
RealOpenMM** r_ij = _r_ij;
RealOpenMM* d_ij2 = _d_ij2;
RealOpenMM* distanceTolerance = _distanceTolerance;
RealOpenMM* reducedMasses = _reducedMasses;
// calculate reduced masses on 1st pass
if( !_hasInitializedMasses ){
_hasInitializedMasses = true;
for( int ii = 0; ii < _numberOfConstraints; ii++ ){
int atomI = _atomIndices[ii][0];
int atomJ = _atomIndices[ii][1];
reducedMasses[ii] = half/( inverseMasses[atomI] + inverseMasses[atomJ] );
}
}
// setup: r_ij for each (i,j) constraint
RealOpenMM tolerance = getTolerance();
tolerance *= two;
for( int ii = 0; ii < _numberOfConstraints; ii++ ){
int atomI = _atomIndices[ii][0];
int atomJ = _atomIndices[ii][1];
for( int jj = 0; jj < 3; jj++ ){
r_ij[ii][jj] = atomCoordinates[atomI][jj] - atomCoordinates[atomJ][jj];
}
d_ij2[ii] = DOT3( r_ij[ii], r_ij[ii] );
distanceTolerance[ii] = d_ij2[ii]*tolerance;
if( distanceTolerance[ii] > zero ){
distanceTolerance[ii] = one/distanceTolerance[ii];
}
}
// main loop
int done = 0;
int iterations = 0;
int numberConverged = 0;
while( !done && iterations++ < getMaximumNumberOfIterations() ){
numberConverged = 0;
for( int ii = 0; ii < _numberOfConstraints; ii++ ){
int atomI = _atomIndices[ii][0];
int atomJ = _atomIndices[ii][1];
RealOpenMM rp_ij[3];
for( int jj = 0; jj < 3; jj++ ){
rp_ij[jj] = atomCoordinatesP[atomI][jj] - atomCoordinatesP[atomJ][jj];
}
RealOpenMM rp2 = DOT3( rp_ij, rp_ij );
RealOpenMM dist2= _distance[ii]*_distance[ii];
RealOpenMM diff = dist2 - rp2;
int iconv = (int) ( FABS( diff )*distanceTolerance[ii] );
if( iconv ){
RealOpenMM rrpr = DOT3( rp_ij, r_ij[ii] );
RealOpenMM acor;
if( rrpr < d_ij2[ii]*epsilon6 ){
std::stringstream message;
message << iterations << " Error: sign of rrpr < 0?\n";
SimTKOpenMMLog::printMessage( message );
} else {
acor = reducedMasses[ii]*diff/rrpr;
for( int jj = 0; jj < 3; jj++ ){
RealOpenMM dr = acor*r_ij[ii][jj];
atomCoordinatesP[atomI][jj] += inverseMasses[atomI]*dr;
atomCoordinatesP[atomJ][jj] -= inverseMasses[atomJ]*dr;
}
}
} else {
numberConverged++;
}
}
if( numberConverged == _numberOfConstraints ){
done = true;
}
}
return (done ? SimTKOpenMMCommon::DefaultReturn : SimTKOpenMMCommon::ErrorReturn);
}
/**---------------------------------------------------------------------------------------
Apply constraint algorithm to velocities.
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities atom velocities
@param inverseMasses 1/mass
@return SimTKOpenMMCommon::DefaultReturn if converge; else
return SimTKOpenMMCommon::ErrorReturn
--------------------------------------------------------------------------------------- */
int ReferenceShakeAlgorithm::applyToVelocities(int numberOfAtoms, std::vector<OpenMM::RealVec>& atomCoordinates,
std::vector<OpenMM::RealVec>& velocities, std::vector<RealOpenMM>& inverseMasses) {
throw OpenMM::OpenMMException("applyToVelocities is not implemented");
}
/**---------------------------------------------------------------------------------------
Report any violated constriants
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param message report
@return number of violated constraints
--------------------------------------------------------------------------------------- */
int ReferenceShakeAlgorithm::reportShake( int numberOfAtoms, vector<RealVec>& atomCoordinates,
std::stringstream& message ){
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceShakeAlgorithm::reportShake";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static const RealOpenMM two = 2.0;
static const RealOpenMM three = 3.0;
static const RealOpenMM oneM = -1.0;
static const RealOpenMM half = 0.5;
// ---------------------------------------------------------------------------------------
int numberOfConstraints = getNumberOfConstraints();
// loop over constraints calculating distance and comparing to
// expected distance -- report any contraints that are violated
int numberConverged = 0;
RealOpenMM tolerance = getTolerance();
for( int ii = 0; ii < _numberOfConstraints; ii++ ){
int atomI = _atomIndices[ii][0];
int atomJ = _atomIndices[ii][1];
RealOpenMM rp2 = zero;
for( int jj = 0; jj < 3; jj++ ){
rp2 += (atomCoordinates[atomI][jj] - atomCoordinates[atomJ][jj])*(atomCoordinates[atomI][jj] - atomCoordinates[atomJ][jj]);
}
RealOpenMM diff = FABS( rp2 - (_distance[ii]*_distance[ii]) );
if( diff > tolerance ){
message << ii << " constraint violated: " << atomI << " " << atomJ << "] d=" << SQRT( rp2 ) << " " << rp2 << " d0=" << _distance[ii];
message << " diff=" << diff;
message << " [" << atomCoordinates[atomI][0] << " " << atomCoordinates[atomI][1] << " " << atomCoordinates[atomI][2] << "] ";
message << " [" << atomCoordinates[atomJ][0] << " " << atomCoordinates[atomJ][1] << " " << atomCoordinates[atomJ][2] << "] ";
message << "\n";
} else {
numberConverged++;
}
}
return (numberOfConstraints-numberConverged);
}
/* Portions copyright (c) 2006-2012 Stanford University and Simbios.
/* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -234,9 +234,8 @@ void ReferenceStochasticDynamics::update(const OpenMM::System& system, vector<Re
updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime );
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if( referenceConstraintAlgorithm ){
referenceConstraintAlgorithm->apply( numberOfAtoms, atomCoordinates, xPrime, inverseMasses );
}
if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
// copy xPrime -> atomCoordinates
......
/* Portions copyright (c) 2006-2012 Stanford University and Simbios.
/* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -278,10 +278,8 @@ void ReferenceVariableStochasticDynamics::update(const OpenMM::System& system, v
updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime );
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if( referenceConstraintAlgorithm ){
referenceConstraintAlgorithm->apply( numberOfAtoms, atomCoordinates, xPrime,
inverseMasses );
}
if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
// copy xPrime -> atomCoordinates
......
/* Portions copyright (c) 2006-2012 Stanford University and Simbios.
/* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -155,7 +155,7 @@ void ReferenceVariableVerletDynamics::update(const OpenMM::System& system, vecto
}
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply(numberOfAtoms, atomCoordinates, xPrime, inverseMasses);
referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
// Update the positions and velocities.
......
/* Portions copyright (c) 2006-2012 Stanford University and Simbios.
/* Portions copyright (c) 2006-2013 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -130,8 +130,8 @@ void ReferenceVerletDynamics::update(const OpenMM::System& system, vector<RealVe
}
}
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if( referenceConstraintAlgorithm )
referenceConstraintAlgorithm->apply( numberOfAtoms, atomCoordinates, xPrime, inverseMasses );
if (referenceConstraintAlgorithm)
referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses);
// Update the positions and velocities.
......
......@@ -308,23 +308,18 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
static const RealOpenMM fourth = static_cast<RealOpenMM>( 0.25 );
static const RealOpenMM eighth = static_cast<RealOpenMM>( 0.125 );
// ---------------------------------------------------------------------------------------
const ObcParameters* obcParameters = getObcParameters();
const int numberOfAtoms = obcParameters->getNumberOfAtoms();
// ---------------------------------------------------------------------------------------
// constants
const int numberOfAtoms = _obcParameters->getNumberOfAtoms();
const RealOpenMM dielectricOffset = _obcParameters->getDielectricOffset();
const RealOpenMM cutoffDistance = _obcParameters->getCutoffDistance();
const RealOpenMM soluteDielectric = _obcParameters->getSoluteDielectric();
const RealOpenMM solventDielectric = _obcParameters->getSolventDielectric();
RealOpenMM preFactor;
if( obcParameters->getSoluteDielectric() != zero && obcParameters->getSolventDielectric() != zero ){
preFactor = two*obcParameters->getElectricConstant()*( (one/obcParameters->getSoluteDielectric()) - (one/obcParameters->getSolventDielectric()) );
} else {
if (soluteDielectric != zero && solventDielectric != zero)
preFactor = two*_obcParameters->getElectricConstant()*((one/soluteDielectric) - (one/solventDielectric));
else
preFactor = zero;
}
const RealOpenMM dielectricOffset = obcParameters->getDielectricOffset();
// ---------------------------------------------------------------------------------------
......@@ -343,7 +338,7 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
// compute the nonpolar solvation via ACE approximation
if( includeAceApproximation() ){
computeAceNonPolarForce( obcParameters, bornRadii, &obcEnergy, bornForces );
computeAceNonPolarForce( _obcParameters, bornRadii, &obcEnergy, bornForces );
}
// ---------------------------------------------------------------------------------------
......@@ -360,7 +355,7 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
ReferenceForce::getDeltaRPeriodic( atomCoordinates[atomI], atomCoordinates[atomJ], _obcParameters->getPeriodicBox(), deltaR );
else
ReferenceForce::getDeltaR( atomCoordinates[atomI], atomCoordinates[atomJ], deltaR );
if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > _obcParameters->getCutoffDistance())
if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > cutoffDistance)
continue;
RealOpenMM r2 = deltaR[ReferenceForce::R2Index];
......@@ -379,9 +374,14 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
RealOpenMM dGpol_dr = -Gpol*( one - fourth*expTerm )/denominator2;
RealOpenMM dGpol_dalpha2_ij = -half*Gpol*expTerm*( one + D_ij )/denominator2;
RealOpenMM energy = Gpol;
if( atomI != atomJ ){
if (_obcParameters->getUseCutoff())
energy -= partialChargeI*partialCharges[atomJ]/cutoffDistance;
bornForces[atomJ] += dGpol_dalpha2_ij*bornRadii[atomI];
deltaX *= dGpol_dr;
......@@ -397,10 +397,10 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
inputForces[atomJ][2] -= deltaZ;
} else {
Gpol *= half;
energy *= half;
}
obcEnergy += Gpol;
obcEnergy += energy;
bornForces[atomI] += dGpol_dalpha2_ij*bornRadii[atomJ];
}
......@@ -411,12 +411,12 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
// second main loop
const RealOpenMMVector& obcChain = getObcChain();
const RealOpenMMVector& atomicRadii = obcParameters->getAtomicRadii();
const RealOpenMMVector& atomicRadii = _obcParameters->getAtomicRadii();
const RealOpenMM alphaObc = obcParameters->getAlphaObc();
const RealOpenMM betaObc = obcParameters->getBetaObc();
const RealOpenMM gammaObc = obcParameters->getGammaObc();
const RealOpenMMVector& scaledRadiusFactor = obcParameters->getScaledRadiusFactors();
const RealOpenMM alphaObc = _obcParameters->getAlphaObc();
const RealOpenMM betaObc = _obcParameters->getBetaObc();
const RealOpenMM gammaObc = _obcParameters->getGammaObc();
const RealOpenMMVector& scaledRadiusFactor = _obcParameters->getScaledRadiusFactors();
// compute factor that depends only on the outer loop index
......@@ -440,7 +440,7 @@ RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinat
ReferenceForce::getDeltaRPeriodic( atomCoordinates[atomI], atomCoordinates[atomJ], _obcParameters->getPeriodicBox(), deltaR );
else
ReferenceForce::getDeltaR( atomCoordinates[atomI], atomCoordinates[atomJ], deltaR );
if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > _obcParameters->getCutoffDistance())
if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > cutoffDistance)
continue;
RealOpenMM deltaX = deltaR[ReferenceForce::XIndex];
......
......@@ -351,7 +351,7 @@ void ObcParameters::setUseCutoff( RealOpenMM distance ) {
--------------------------------------------------------------------------------------- */
bool ObcParameters::getUseCutoff() {
bool ObcParameters::getUseCutoff() const {
return _cutoff;
}
......@@ -361,7 +361,7 @@ bool ObcParameters::getUseCutoff() {
--------------------------------------------------------------------------------------- */
RealOpenMM ObcParameters::getCutoffDistance() {
RealOpenMM ObcParameters::getCutoffDistance() const {
return _cutoffDistance;
}
......
......@@ -164,6 +164,38 @@ void testConstraints() {
}
}
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
BrownianIntegrator integrator(300.0, 2.0, 0.01);
bool failed = false;
try {
// This should throw an exception.
Context context(system, integrator, platform);
}
catch (exception& ex) {
failed = true;
}
ASSERT(failed);
// Now make both particles massless, which should work.
system.setParticleMass(1, 0.0);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(300.0);
integrator.step(1);
State state = context.getState(State::Velocities | State::Positions);
ASSERT_EQUAL(0.0, state.getVelocities()[0][0]);
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
......@@ -228,6 +260,7 @@ int main() {
testSingleBond();
testTemperature();
testConstraints();
testConstrainedMasslessParticles();
testRandomSeed();
}
catch(const exception& e) {
......
......@@ -57,6 +57,7 @@ void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMe
const int numMolecules = 70;
const int numParticles = numMolecules*2;
const double boxSize = 10.0;
const double cutoff = 2.0;
ReferencePlatform platform;
// Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction.
......@@ -71,8 +72,8 @@ void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMe
customSystem.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0.0, 0.0), Vec3(0.0, boxSize, 0.0), Vec3(0.0, 0.0, boxSize));
GBSAOBCForce* obc = new GBSAOBCForce();
CustomGBForce* custom = new CustomGBForce();
obc->setCutoffDistance(2.0);
custom->setCutoffDistance(2.0);
obc->setCutoffDistance(cutoff);
custom->setCutoffDistance(cutoff);
custom->addPerParticleParameter("q");
custom->addPerParticleParameter("radius");
custom->addPerParticleParameter("scale");
......@@ -88,7 +89,13 @@ void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMe
custom->addComputedValue("B", "1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);"
"psi=I*or; or=radius-0.009", CustomGBForce::SingleParticle);
custom->addEnergyTerm("28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935485*(1/soluteDielectric-1/solventDielectric)*q^2/B", CustomGBForce::SingleParticle);
custom->addEnergyTerm("-138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;"
string invCutoffString = "";
if (obcMethod != GBSAOBCForce::NoCutoff) {
stringstream s;
s<<(1.0/cutoff);
invCutoffString = s.str();
}
custom->addEnergyTerm("138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("+invCutoffString+"-1/f);"
"f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))", CustomGBForce::ParticlePairNoExclusions);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
......
......@@ -159,7 +159,7 @@ void testConstraints() {
* Test an integrator that applies constraints directly to velocities.
*/
void testVelocityConstraints() {
const int numParticles = 8;
const int numParticles = 10;
ReferencePlatform platform;
System system;
CustomIntegrator integrator(0.002);
......@@ -176,7 +176,21 @@ void testVelocityConstraints() {
system.addParticle(i%2 == 0 ? 5.0 : 10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
for (int i = 0; i < numParticles-1; ++i)
// Constrain the first three particles with SHAKE.
system.addConstraint(0, 1, 1.0);
system.addConstraint(1, 2, 1.0);
// Constrain the next three with SETTLE.
system.addConstraint(3, 4, 1.0);
system.addConstraint(5, 4, 1.0);
system.addConstraint(3, 5, sqrt(2.0));
// Constraint the rest with CCMA.
for (int i = 6; i < numParticles-1; ++i)
system.addConstraint(i, i+1, 1.0);
system.addForce(forceField);
Context context(system, integrator, platform);
......@@ -196,6 +210,7 @@ void testVelocityConstraints() {
double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) {
integrator.step(2);
State state = context.getState(State::Positions | State::Velocities | State::Energy);
for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2;
......@@ -213,14 +228,51 @@ void testVelocityConstraints() {
}
}
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
if (i == 1)
if (i == 0)
initialEnergy = energy;
else if (i > 1)
else if (i > 0)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(2);
}
}
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
CustomIntegrator integrator(0.002);
integrator.addPerDofVariable("oldx", 0);
integrator.addComputePerDof("v", "v+dt*f/m");
integrator.addComputePerDof("oldx", "x");
integrator.addComputePerDof("x", "x+dt*v");
integrator.addConstrainPositions();
integrator.addComputePerDof("v", "(x-oldx)/dt");
bool failed = false;
try {
// This should throw an exception.
Context context(system, integrator, platform);
}
catch (exception& ex) {
failed = true;
}
ASSERT(failed);
// Now make both particles massless, which should work.
system.setParticleMass(1, 0.0);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(300.0);
integrator.step(1);
State state = context.getState(State::Velocities | State::Positions);
ASSERT_EQUAL(0.0, state.getVelocities()[0][0]);
}
/**
* Test an integrator with an AndersenThermostat to see if updateContextState()
* is being handled correctly.
......@@ -651,6 +703,7 @@ int main() {
testSingleBond();
testConstraints();
testVelocityConstraints();
testConstrainedMasslessParticles();
testWithThermostat();
testMonteCarlo();
testSum();
......
......@@ -171,6 +171,38 @@ void testConstraints() {
}
}
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
LangevinIntegrator integrator(300.0, 2.0, 0.01);
bool failed = false;
try {
// This should throw an exception.
Context context(system, integrator, platform);
}
catch (exception& ex) {
failed = true;
}
ASSERT(failed);
// Now make both particles massless, which should work.
system.setParticleMass(1, 0.0);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(300.0);
integrator.step(1);
State state = context.getState(State::Velocities | State::Positions);
ASSERT_EQUAL(0.0, state.getVelocities()[0][0]);
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
......@@ -235,6 +267,7 @@ int main() {
testSingleBond();
testTemperature();
testConstraints();
testConstrainedMasslessParticles();
testRandomSeed();
}
catch(const exception& e) {
......
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