Commit 83ed602e authored by peastman's avatar peastman
Browse files

Merge pull request #797 from peastman/triclinic

C++ libraries support triclinic boxes
parents b51e05a8 050e1262
...@@ -1261,6 +1261,61 @@ Other Features ...@@ -1261,6 +1261,61 @@ Other Features
############## ##############
Periodic Boundary Conditions
****************************
Many Force objects support periodic boundary conditions. They act as if space
were tiled with infinitely repeating copies of the system, then compute the
forces acting on a single copy based on the infinite periodic copies. In most
(but not all) cases, they apply a cutoff so that each particle only interacts
with a single copy of each other particle.
OpenMM supports triclinic periodic boxes. This means the periodicity is defined
by three vectors, :math:`\mathbf{a}`\ , :math:`\mathbf{b}`\ , and
:math:`\mathbf{c}`\ . Given a particle position, the infinite periodic copies
of that particle are generated by adding vectors of the form
:math:`i \mathbf{a}+j \mathbf{b}+k \mathbf{c}`\ , where :math:`i`\ ,
:math:`j`\ , and :math:`k` are arbitrary integers.
The periodic box vectors must be chosen to satisfy certain requirements.
Roughly speaking, :math:`\mathbf{a}`\ , :math:`\mathbf{b}`\ , and
:math:`\mathbf{c}` need to "mostly" correspond to the x, y, and z axes. They
must have the form
.. math::
\mathbf{a} = (a_x, 0, 0)
\mathbf{b} = (b_x, b_y, 0)
\mathbf{c} = (c_x, c_y, c_z)
It is always possible to put the box vectors into this form by rotating the
system until :math:`\mathbf{a}` is parallel to x and :math:`\mathbf{b}` lies in
the xy plane.
Furthermore, they must obey the following constraints:
.. math::
a_x > 0, b_y > 0, c_z > 0
a_x \ge 2 |b_x|
a_x \ge 2 |c_x|
b_y \ge 2 |c_y|
This effectively requires the box vectors to be specified in a particular
reduced form. By forming combinations of box vectors (a process known as
"lattice reduction"), it is always possible to put them in this form without
changing the periodic system they represent.
These requirements have an important consequence: the periodic unit cell can
always be treated as an axis-aligned rectangular box of size
:math:`(a_x, b_y, c_z)`\ . The remaining non-zero elements of the box vectors
cause the repeating copies of the system to be staggered relative to each other,
but they do not affect the shape or size of each copy. The volume of the unit
cell is simply given by :math:`a_x b_y c_z`\ .
LocalEnergyMinimizer LocalEnergyMinimizer
******************** ********************
......
...@@ -1223,12 +1223,12 @@ public: ...@@ -1223,12 +1223,12 @@ public:
virtual void initialize(int gridx, int gridy, int gridz, int numParticles, double alpha) = 0; virtual void initialize(int gridx, int gridy, int gridz, int numParticles, double alpha) = 0;
/** /**
* Begin computing the force and energy. * Begin computing the force and energy.
* *
* @param io an object that coordinates data transfer * @param io an object that coordinates data transfer
* @param periodicBoxSize the size of the periodic box (measured in nm) * @param periodicBoxVectors the vectors defining the periodic box (measured in nm)
* @param includeEnergy true if potential energy should be computed * @param includeEnergy true if potential energy should be computed
*/ */
virtual void beginComputation(IO& io, Vec3 periodicBoxSize, bool includeEnergy) = 0; virtual void beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy) = 0;
/** /**
* Finish computing the force and energy. * Finish computing the force and energy.
* *
......
...@@ -182,8 +182,9 @@ public: ...@@ -182,8 +182,9 @@ public:
* Set the vectors defining the axes of the periodic box (measured in nm). They will affect * Set the vectors defining the axes of the periodic box (measured in nm). They will affect
* any Force that uses periodic boundary conditions. * any Force that uses periodic boundary conditions.
* *
* Currently, only rectangular boxes are supported. This means that a, b, and c must be aligned with the * Triclinic boxes are supported, but the vectors must satisfy certain requirements. In particular,
* x, y, and z axes respectively. Future releases may support arbitrary triclinic boxes. * a must point in the x direction, b must point "mostly" in the y direction, and c must point "mostly"
* in the z direction. See the documentation for details.
* *
* @param a the vector defining the first edge of the periodic box * @param a the vector defining the first edge of the periodic box
* @param b the vector defining the second edge of the periodic box * @param b the vector defining the second edge of the periodic box
......
...@@ -203,9 +203,6 @@ public: ...@@ -203,9 +203,6 @@ public:
* created Context will have its box vectors set to these. They will affect * created Context will have its box vectors set to these. They will affect
* any Force added to the System that uses periodic boundary conditions. * any Force added to the System that uses periodic boundary conditions.
* *
* Currently, only rectangular boxes are supported. This means that a, b, and c must be aligned with the
* x, y, and z axes respectively. Future releases may support arbitrary triclinic boxes.
*
* @param a on exit, this contains the vector defining the first edge of the periodic box * @param a on exit, this contains the vector defining the first edge of the periodic box
* @param b on exit, this contains the vector defining the second edge of the periodic box * @param b on exit, this contains the vector defining the second edge of the periodic box
* @param c on exit, this contains the vector defining the third edge of the periodic box * @param c on exit, this contains the vector defining the third edge of the periodic box
...@@ -216,8 +213,9 @@ public: ...@@ -216,8 +213,9 @@ public:
* created Context will have its box vectors set to these. They will affect * created Context will have its box vectors set to these. They will affect
* any Force added to the System that uses periodic boundary conditions. * any Force added to the System that uses periodic boundary conditions.
* *
* Currently, only rectangular boxes are supported. This means that a, b, and c must be aligned with the * Triclinic boxes are supported, but the vectors must satisfy certain requirements. In particular,
* x, y, and z axes respectively. Future releases may support arbitrary triclinic boxes. * a must point in the x direction, b must point "mostly" in the y direction, and c must point "mostly"
* in the z direction. See the documentation for details.
* *
* @param a the vector defining the first edge of the periodic box * @param a the vector defining the first edge of the periodic box
* @param b the vector defining the second edge of the periodic box * @param b the vector defining the second edge of the periodic box
......
...@@ -142,9 +142,6 @@ public: ...@@ -142,9 +142,6 @@ public:
* Get the vectors defining the axes of the periodic box (measured in nm). They will affect * Get the vectors defining the axes of the periodic box (measured in nm). They will affect
* any Force that uses periodic boundary conditions. * any Force that uses periodic boundary conditions.
* *
* Currently, only rectangular boxes are supported. This means that a, b, and c must be aligned with the
* x, y, and z axes respectively. Future releases may support arbitrary triclinic boxes.
*
* @param a the vector defining the first edge of the periodic box * @param a the vector defining the first edge of the periodic box
* @param b the vector defining the second edge of the periodic box * @param b the vector defining the second edge of the periodic box
* @param c the vector defining the third edge of the periodic box * @param c the vector defining the third edge of the periodic box
...@@ -154,8 +151,9 @@ public: ...@@ -154,8 +151,9 @@ public:
* Set the vectors defining the axes of the periodic box (measured in nm). They will affect * Set the vectors defining the axes of the periodic box (measured in nm). They will affect
* any Force that uses periodic boundary conditions. * any Force that uses periodic boundary conditions.
* *
* Currently, only rectangular boxes are supported. This means that a, b, and c must be aligned with the * Triclinic boxes are supported, but the vectors must satisfy certain requirements. In particular,
* x, y, and z axes respectively. Future releases may support arbitrary triclinic boxes. * a must point in the x direction, b must point "mostly" in the y direction, and c must point "mostly"
* in the z direction. See the documentation for details.
* *
* @param a the vector defining the first edge of the periodic box * @param a the vector defining the first edge of the periodic box
* @param b the vector defining the second edge of the periodic box * @param b the vector defining the second edge of the periodic box
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "openmm/VirtualSite.h" #include "openmm/VirtualSite.h"
#include "openmm/Context.h" #include "openmm/Context.h"
#include <algorithm> #include <algorithm>
#include <cmath>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <utility> #include <utility>
...@@ -235,10 +236,10 @@ void ContextImpl::getPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) { ...@@ -235,10 +236,10 @@ void ContextImpl::getPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) {
void ContextImpl::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) { void ContextImpl::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) {
if (a[1] != 0.0 || a[2] != 0.0) if (a[1] != 0.0 || a[2] != 0.0)
throw OpenMMException("First periodic box vector must be parallel to x."); throw OpenMMException("First periodic box vector must be parallel to x.");
if (b[0] != 0.0 || b[2] != 0.0) if (b[2] != 0.0)
throw OpenMMException("Second periodic box vector must be parallel to y."); throw OpenMMException("Second periodic box vector must be in the x-y plane.");
if (c[0] != 0.0 || c[1] != 0.0) if (a[0] <= 0.0 || b[1] <= 0.0 || c[2] <= 0.0 || a[0] < 2*fabs(b[0]) || a[0] < 2*fabs(c[0]) || b[1] < 2*fabs(c[1]))
throw OpenMMException("Third periodic box vector must be parallel to z."); throw OpenMMException("Periodic box vectors must be in reduced form.");
updateStateDataKernel.getAs<UpdateStateDataKernel>().setPeriodicBoxVectors(*this, a, b, c); updateStateDataKernel.getAs<UpdateStateDataKernel>().setPeriodicBoxVectors(*this, a, b, c);
} }
......
...@@ -112,7 +112,9 @@ void MonteCarloAnisotropicBarostatImpl::updateContextState(ContextImpl& context) ...@@ -112,7 +112,9 @@ void MonteCarloAnisotropicBarostatImpl::updateContextState(ContextImpl& context)
Vec3 lengthScale(1.0, 1.0, 1.0); Vec3 lengthScale(1.0, 1.0, 1.0);
lengthScale[axis] = newVolume/volume; lengthScale[axis] = newVolume/volume;
kernel.getAs<ApplyMonteCarloBarostatKernel>().scaleCoordinates(context, lengthScale[0], lengthScale[1], lengthScale[2]); kernel.getAs<ApplyMonteCarloBarostatKernel>().scaleCoordinates(context, lengthScale[0], lengthScale[1], lengthScale[2]);
context.getOwner().setPeriodicBoxVectors(box[0]*lengthScale[0], box[1]*lengthScale[1], box[2]*lengthScale[2]); context.getOwner().setPeriodicBoxVectors(Vec3(box[0][0]*lengthScale[0], box[0][1]*lengthScale[1], box[0][2]*lengthScale[2]),
Vec3(box[1][0]*lengthScale[0], box[1][1]*lengthScale[1], box[1][2]*lengthScale[2]),
Vec3(box[2][0]*lengthScale[0], box[2][1]*lengthScale[1], box[2][2]*lengthScale[2]));
// Compute the energy of the modified system. // Compute the energy of the modified system.
......
...@@ -113,7 +113,9 @@ void MonteCarloMembraneBarostatImpl::updateContextState(ContextImpl& context) { ...@@ -113,7 +113,9 @@ void MonteCarloMembraneBarostatImpl::updateContextState(ContextImpl& context) {
} }
double deltaArea = box[0][0]*lengthScale[0]*box[1][1]*lengthScale[1] - box[0][0]*box[1][1]; double deltaArea = box[0][0]*lengthScale[0]*box[1][1]*lengthScale[1] - box[0][0]*box[1][1];
kernel.getAs<ApplyMonteCarloBarostatKernel>().scaleCoordinates(context, lengthScale[0], lengthScale[1], lengthScale[2]); kernel.getAs<ApplyMonteCarloBarostatKernel>().scaleCoordinates(context, lengthScale[0], lengthScale[1], lengthScale[2]);
context.getOwner().setPeriodicBoxVectors(box[0]*lengthScale[0], box[1]*lengthScale[1], box[2]*lengthScale[2]); context.getOwner().setPeriodicBoxVectors(Vec3(box[0][0]*lengthScale[0], box[0][1]*lengthScale[1], box[0][2]*lengthScale[2]),
Vec3(box[1][0]*lengthScale[0], box[1][1]*lengthScale[1], box[1][2]*lengthScale[2]),
Vec3(box[2][0]*lengthScale[0], box[2][1]*lengthScale[1], box[2][2]*lengthScale[2]));
// Compute the energy of the modified system. // Compute the energy of the modified system.
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008-2014 Stanford University and the Authors. * * Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -98,6 +98,8 @@ void NonbondedForceImpl::initialize(ContextImpl& context) { ...@@ -98,6 +98,8 @@ void NonbondedForceImpl::initialize(ContextImpl& context) {
double cutoff = owner.getCutoffDistance(); double cutoff = owner.getCutoffDistance();
if (cutoff > 0.5*boxVectors[0][0] || cutoff > 0.5*boxVectors[1][1] || cutoff > 0.5*boxVectors[2][2]) if (cutoff > 0.5*boxVectors[0][0] || cutoff > 0.5*boxVectors[1][1] || cutoff > 0.5*boxVectors[2][2])
throw OpenMMException("NonbondedForce: The cutoff distance cannot be greater than half the periodic box size."); throw OpenMMException("NonbondedForce: The cutoff distance cannot be greater than half the periodic box size.");
if (owner.getNonbondedMethod() == NonbondedForce::Ewald && (boxVectors[1][0] != 0.0 || boxVectors[2][0] != 0.0 || boxVectors[2][1] != 0))
throw OpenMMException("NonbondedForce: Ewald is not supported with non-rectangular boxes. Use PME instead.");
} }
kernel.getAs<CalcNonbondedForceKernel>().initialize(context.getSystem(), owner); kernel.getAs<CalcNonbondedForceKernel>().initialize(context.getSystem(), owner);
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "openmm/System.h" #include "openmm/System.h"
#include "openmm/VirtualSite.h" #include "openmm/VirtualSite.h"
#include "openmm/internal/AssertionUtilities.h" #include "openmm/internal/AssertionUtilities.h"
#include <cmath>
using namespace OpenMM; using namespace OpenMM;
...@@ -111,10 +112,10 @@ void System::getDefaultPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) const { ...@@ -111,10 +112,10 @@ void System::getDefaultPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) const {
void System::setDefaultPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) { void System::setDefaultPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) {
if (a[1] != 0.0 || a[2] != 0.0) if (a[1] != 0.0 || a[2] != 0.0)
throw OpenMMException("First periodic box vector must be parallel to x."); throw OpenMMException("First periodic box vector must be parallel to x.");
if (b[0] != 0.0 || b[2] != 0.0) if (b[2] != 0.0)
throw OpenMMException("Second periodic box vector must be parallel to y."); throw OpenMMException("Second periodic box vector must be in the x-y plane.");
if (c[0] != 0.0 || c[1] != 0.0) if (a[0] <= 0.0 || b[1] <= 0.0 || c[2] <= 0.0 || a[0] < 2*fabs(b[0]) || a[0] < 2*fabs(c[0]) || b[1] < 2*fabs(c[1]))
throw OpenMMException("Third periodic box vector must be parallel to z."); throw OpenMMException("Periodic box vectors must be in reduced form.");
periodicBoxVectors[0] = a; periodicBoxVectors[0] = a;
periodicBoxVectors[1] = b; periodicBoxVectors[1] = b;
periodicBoxVectors[2] = c; periodicBoxVectors[2] = c;
......
...@@ -51,9 +51,11 @@ private: ...@@ -51,9 +51,11 @@ private:
class ComputeForceTask; class ComputeForceTask;
class ThreadData; class ThreadData;
int numParticles, numParticlesPerSet, numPerParticleParameters, numTypes; int numParticles, numParticlesPerSet, numPerParticleParameters, numTypes;
bool useCutoff, usePeriodic, centralParticleMode; bool useCutoff, usePeriodic, triclinic, centralParticleMode;
RealOpenMM cutoffDistance; RealOpenMM cutoffDistance;
RealOpenMM periodicBoxSize[3]; float recipBoxSize[3];
RealVec periodicBoxVectors[3];
AlignedArray<fvec4> periodicBoxVec4;
CpuNeighborList* neighborList; CpuNeighborList* neighborList;
ThreadPool& threads; ThreadPool& threads;
std::vector<std::set<int> > exclusions; std::vector<std::set<int> > exclusions;
...@@ -138,9 +140,9 @@ public: ...@@ -138,9 +140,9 @@ public:
* already been set, and the smallest side of the periodic box is at least twice the cutoff * already been set, and the smallest side of the periodic box is at least twice the cutoff
* distance. * distance.
* *
* @param boxSize the X, Y, and Z widths of the periodic box * @param periodicBoxVectors the vectors defining the periodic box
*/ */
void setPeriodic(OpenMM::RealVec& boxSize); void setPeriodic(RealVec* periodicBoxVectors);
/** /**
* Calculate the interaction. * Calculate the interaction.
......
...@@ -95,11 +95,11 @@ class CpuCustomNonbondedForce { ...@@ -95,11 +95,11 @@ class CpuCustomNonbondedForce {
already been set, and the smallest side of the periodic box is at least twice the cutoff already been set, and the smallest side of the periodic box is at least twice the cutoff
distance. distance.
@param boxSize the X, Y, and Z widths of the periodic box @param periodicBoxVectors the vectors defining the periodic box
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void setPeriodic(OpenMM::RealVec& boxSize); void setPeriodic(RealVec* periodicBoxVectors);
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -127,8 +127,11 @@ private: ...@@ -127,8 +127,11 @@ private:
bool cutoff; bool cutoff;
bool useSwitch; bool useSwitch;
bool periodic; bool periodic;
bool triclinic;
const CpuNeighborList* neighborList; const CpuNeighborList* neighborList;
RealOpenMM periodicBoxSize[3]; float recipBoxSize[3];
RealVec periodicBoxVectors[3];
AlignedArray<fvec4> periodicBoxVec4;
RealOpenMM cutoffDistance, switchingDistance; RealOpenMM cutoffDistance, switchingDistance;
ThreadPool& threads; ThreadPool& threads;
const std::vector<std::set<int> > exclusions; const std::vector<std::set<int> > exclusions;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "AlignedArray.h" #include "AlignedArray.h"
#include "RealVec.h"
#include "windowsExportCpu.h" #include "windowsExportCpu.h"
#include "openmm/internal/ThreadPool.h" #include "openmm/internal/ThreadPool.h"
#include <set> #include <set>
...@@ -40,14 +41,14 @@ ...@@ -40,14 +41,14 @@
#include <vector> #include <vector>
namespace OpenMM { namespace OpenMM {
class OPENMM_EXPORT_CPU CpuNeighborList { class OPENMM_EXPORT_CPU CpuNeighborList {
public: public:
class ThreadTask; class ThreadTask;
class Voxels; class Voxels;
CpuNeighborList(int blockSize); CpuNeighborList(int blockSize);
void computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const std::vector<std::set<int> >& exclusions, void computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const std::vector<std::set<int> >& exclusions,
const float* periodicBoxSize, bool usePeriodic, float maxDistance, ThreadPool& threads); const RealVec* periodicBoxVectors, bool usePeriodic, float maxDistance, ThreadPool& threads);
int getNumBlocks() const; int getNumBlocks() const;
const std::vector<int>& getSortedAtoms() const; const std::vector<int>& getSortedAtoms() const;
const std::vector<int>& getBlockNeighbors(int blockIndex) const; const std::vector<int>& getBlockNeighbors(int blockIndex) const;
...@@ -68,7 +69,7 @@ private: ...@@ -68,7 +69,7 @@ private:
Voxels* voxels; Voxels* voxels;
const std::vector<std::set<int> >* exclusions; const std::vector<std::set<int> >* exclusions;
const float* atomLocations; const float* atomLocations;
const float* periodicBoxSize; RealVec periodicBoxVectors[3];
int numAtoms; int numAtoms;
bool usePeriodic; bool usePeriodic;
float maxDistance; float maxDistance;
......
...@@ -83,11 +83,11 @@ class CpuNonbondedForce { ...@@ -83,11 +83,11 @@ class CpuNonbondedForce {
already been set, and the smallest side of the periodic box is at least twice the cutoff already been set, and the smallest side of the periodic box is at least twice the cutoff
distance. distance.
@param boxSize the X, Y, and Z widths of the periodic box @param periodicBoxVectors the vectors defining the periodic box
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void setPeriodic(float* periodicBoxSize); void setPeriodic(RealVec* periodicBoxVectors);
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -161,11 +161,14 @@ protected: ...@@ -161,11 +161,14 @@ protected:
bool cutoff; bool cutoff;
bool useSwitch; bool useSwitch;
bool periodic; bool periodic;
bool triclinic;
bool ewald; bool ewald;
bool pme; bool pme;
bool tableIsValid; bool tableIsValid;
const CpuNeighborList* neighborList; const CpuNeighborList* neighborList;
float periodicBoxSize[3]; float recipBoxSize[3];
RealVec periodicBoxVectors[3];
AlignedArray<fvec4> periodicBoxVec4;
float cutoffDistance, switchingDistance; float cutoffDistance, switchingDistance;
float krf, crf; float krf, crf;
float alphaEwald; float alphaEwald;
......
/* Portions copyright (c) 2006-2013 Stanford University and Simbios. /* Portions copyright (c) 2006-2014 Stanford University and Simbios.
* Contributors: Pande Group * Contributors: Pande Group
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
...@@ -52,6 +52,12 @@ protected: ...@@ -52,6 +52,12 @@ protected:
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void calculateBlockIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize); void calculateBlockIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/**
* Templatized implementation of calculateBlockIxn.
*/
template <bool TRICLINIC>
void calculateBlockIxnImpl(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -65,10 +71,17 @@ protected: ...@@ -65,10 +71,17 @@ protected:
void calculateBlockEwaldIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize); void calculateBlockEwaldIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/**
* Templatized implementation of calculateBlockEwaldIxn.
*/
template <bool TRICLINIC>
void calculateBlockEwaldIxnImpl(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/** /**
* Compute the displacement and squared distance between a collection of points, optionally using * Compute the displacement and squared distance between a collection of points, optionally using
* periodic boundary conditions. * periodic boundary conditions.
*/ */
template <bool TRICLINIC>
void getDeltaR(const float* posI, const fvec4& x, const fvec4& y, const fvec4& z, fvec4& dx, fvec4& dy, fvec4& dz, fvec4& r2, bool periodic, const fvec4& boxSize, const fvec4& invBoxSize) const; void getDeltaR(const float* posI, const fvec4& x, const fvec4& y, const fvec4& z, fvec4& dx, fvec4& dy, fvec4& dz, fvec4& r2, bool periodic, const fvec4& boxSize, const fvec4& invBoxSize) const;
/** /**
......
/* Portions copyright (c) 2006-2013 Stanford University and Simbios. /* Portions copyright (c) 2006-2014 Stanford University and Simbios.
* Contributors: Pande Group * Contributors: Pande Group
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
...@@ -51,6 +51,12 @@ protected: ...@@ -51,6 +51,12 @@ protected:
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void calculateBlockIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize); void calculateBlockIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/**
* Templatized implementation of calculateBlockIxn.
*/
template <bool TRICLINIC>
void calculateBlockIxnImpl(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -64,10 +70,17 @@ protected: ...@@ -64,10 +70,17 @@ protected:
void calculateBlockEwaldIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize); void calculateBlockEwaldIxn(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/**
* Templatized implementation of calculateBlockEwaldIxn.
*/
template <bool TRICLINIC>
void calculateBlockEwaldIxnImpl(int blockIndex, float* forces, double* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
/** /**
* Compute the displacement and squared distance between a collection of points, optionally using * Compute the displacement and squared distance between a collection of points, optionally using
* periodic boundary conditions. * periodic boundary conditions.
*/ */
template <bool TRICLINIC>
void getDeltaR(const float* posI, const fvec8& x, const fvec8& y, const fvec8& z, fvec8& dx, fvec8& dy, fvec8& dz, fvec8& r2, bool periodic, const fvec4& boxSize, const fvec4& invBoxSize) const; void getDeltaR(const float* posI, const fvec8& x, const fvec8& y, const fvec8& z, fvec8& dx, fvec8& dy, fvec8& dz, fvec8& r2, bool periodic, const fvec4& boxSize, const fvec4& invBoxSize) const;
/** /**
......
...@@ -122,8 +122,7 @@ void CpuCustomManyParticleForce::calculateIxn(AlignedArray<float>& posq, RealOpe ...@@ -122,8 +122,7 @@ void CpuCustomManyParticleForce::calculateIxn(AlignedArray<float>& posq, RealOpe
particleNeighbors.resize(numParticles); particleNeighbors.resize(numParticles);
for (int i = 0; i < numParticles; i++) for (int i = 0; i < numParticles; i++)
particleNeighbors[i].clear(); particleNeighbors[i].clear();
float boxSizeFloat[] = {(float) periodicBoxSize[0], (float) periodicBoxSize[1], (float) periodicBoxSize[2]}; neighborList->computeNeighborList(numParticles, posq, exclusions, periodicBoxVectors, usePeriodic, cutoffDistance, threads);
neighborList->computeNeighborList(numParticles, posq, exclusions, boxSizeFloat, usePeriodic, cutoffDistance, threads);
for (int blockIndex = 0; blockIndex < neighborList->getNumBlocks(); blockIndex++) { for (int blockIndex = 0; blockIndex < neighborList->getNumBlocks(); blockIndex++) {
const vector<int>& neighbors = neighborList->getBlockNeighbors(blockIndex); const vector<int>& neighbors = neighborList->getBlockNeighbors(blockIndex);
const vector<char>& exclusions = neighborList->getBlockExclusions(blockIndex); const vector<char>& exclusions = neighborList->getBlockExclusions(blockIndex);
...@@ -159,8 +158,8 @@ void CpuCustomManyParticleForce::calculateIxn(AlignedArray<float>& posq, RealOpe ...@@ -159,8 +158,8 @@ void CpuCustomManyParticleForce::calculateIxn(AlignedArray<float>& posq, RealOpe
void CpuCustomManyParticleForce::threadComputeForce(ThreadPool& threads, int threadIndex) { void CpuCustomManyParticleForce::threadComputeForce(ThreadPool& threads, int threadIndex) {
vector<int> particleIndices(numParticlesPerSet); vector<int> particleIndices(numParticlesPerSet);
fvec4 boxSize(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2], 0); fvec4 boxSize(periodicBoxVectors[0][0], periodicBoxVectors[1][1], periodicBoxVectors[2][2], 0);
fvec4 invBoxSize((1/periodicBoxSize[0]), (1/periodicBoxSize[1]), (1/periodicBoxSize[2]), 0); fvec4 invBoxSize(recipBoxSize[0], recipBoxSize[1], recipBoxSize[2], 0);
float* forces = &(*threadForce)[threadIndex][0]; float* forces = &(*threadForce)[threadIndex][0];
ThreadData& data = *threadData[threadIndex]; ThreadData& data = *threadData[threadIndex];
data.energy = 0; data.energy = 0;
...@@ -201,15 +200,25 @@ void CpuCustomManyParticleForce::setUseCutoff(RealOpenMM distance) { ...@@ -201,15 +200,25 @@ void CpuCustomManyParticleForce::setUseCutoff(RealOpenMM distance) {
neighborList = new CpuNeighborList(4); neighborList = new CpuNeighborList(4);
} }
void CpuCustomManyParticleForce::setPeriodic(RealVec& boxSize) { void CpuCustomManyParticleForce::setPeriodic(RealVec* periodicBoxVectors) {
assert(useCutoff); assert(cutoff);
assert(boxSize[0] >= 2.0*cutoffDistance); assert(periodicBoxVectors[0][0] >= 2.0*cutoffDistance);
assert(boxSize[1] >= 2.0*cutoffDistance); assert(periodicBoxVectors[1][1] >= 2.0*cutoffDistance);
assert(boxSize[2] >= 2.0*cutoffDistance); assert(periodicBoxVectors[2][2] >= 2.0*cutoffDistance);
usePeriodic = true; usePeriodic = true;
periodicBoxSize[0] = boxSize[0]; this->periodicBoxVectors[0] = periodicBoxVectors[0];
periodicBoxSize[1] = boxSize[1]; this->periodicBoxVectors[1] = periodicBoxVectors[1];
periodicBoxSize[2] = boxSize[2]; this->periodicBoxVectors[2] = periodicBoxVectors[2];
recipBoxSize[0] = (float) (1.0/periodicBoxVectors[0][0]);
recipBoxSize[1] = (float) (1.0/periodicBoxVectors[1][1]);
recipBoxSize[2] = (float) (1.0/periodicBoxVectors[2][2]);
periodicBoxVec4.resize(3);
periodicBoxVec4[0] = fvec4(periodicBoxVectors[0][0], periodicBoxVectors[0][1], periodicBoxVectors[0][2], 0);
periodicBoxVec4[1] = fvec4(periodicBoxVectors[1][0], periodicBoxVectors[1][1], periodicBoxVectors[1][2], 0);
periodicBoxVec4[2] = fvec4(periodicBoxVectors[2][0], periodicBoxVectors[2][1], periodicBoxVectors[2][2], 0);
triclinic = (periodicBoxVectors[0][1] != 0.0 || periodicBoxVectors[0][2] != 0.0 ||
periodicBoxVectors[1][0] != 0.0 || periodicBoxVectors[1][2] != 0.0 ||
periodicBoxVectors[2][0] != 0.0 || periodicBoxVectors[2][1] != 0.0);
} }
void CpuCustomManyParticleForce::loopOverInteractions(vector<int>& availableParticles, vector<int>& particleSet, int loopIndex, int startIndex, void CpuCustomManyParticleForce::loopOverInteractions(vector<int>& availableParticles, vector<int>& particleSet, int loopIndex, int startIndex,
...@@ -394,8 +403,15 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO ...@@ -394,8 +403,15 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO
void CpuCustomManyParticleForce::computeDelta(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const { void CpuCustomManyParticleForce::computeDelta(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const {
deltaR = posJ-posI; deltaR = posJ-posI;
if (usePeriodic) { if (usePeriodic) {
fvec4 base = round(deltaR*invBoxSize)*boxSize; if (triclinic) {
deltaR = deltaR-base; deltaR -= periodicBoxVec4[2]*floorf(deltaR[2]*recipBoxSize[2]+0.5f);
deltaR -= periodicBoxVec4[1]*floorf(deltaR[1]*recipBoxSize[1]+0.5f);
deltaR -= periodicBoxVec4[0]*floorf(deltaR[0]*recipBoxSize[0]+0.5f);
}
else {
fvec4 base = round(deltaR*invBoxSize)*boxSize;
deltaR = deltaR-base;
}
} }
r2 = dot3(deltaR, deltaR); r2 = dot3(deltaR, deltaR);
} }
......
...@@ -98,15 +98,25 @@ void CpuCustomNonbondedForce::setUseSwitchingFunction(RealOpenMM distance) { ...@@ -98,15 +98,25 @@ void CpuCustomNonbondedForce::setUseSwitchingFunction(RealOpenMM distance) {
switchingDistance = distance; switchingDistance = distance;
} }
void CpuCustomNonbondedForce::setPeriodic(RealVec& boxSize) { void CpuCustomNonbondedForce::setPeriodic(RealVec* periodicBoxVectors) {
assert(cutoff); assert(cutoff);
assert(boxSize[0] >= 2.0*cutoffDistance); assert(periodicBoxVectors[0][0] >= 2.0*cutoffDistance);
assert(boxSize[1] >= 2.0*cutoffDistance); assert(periodicBoxVectors[1][1] >= 2.0*cutoffDistance);
assert(boxSize[2] >= 2.0*cutoffDistance); assert(periodicBoxVectors[2][2] >= 2.0*cutoffDistance);
periodic = true; periodic = true;
periodicBoxSize[0] = boxSize[0]; this->periodicBoxVectors[0] = periodicBoxVectors[0];
periodicBoxSize[1] = boxSize[1]; this->periodicBoxVectors[1] = periodicBoxVectors[1];
periodicBoxSize[2] = boxSize[2]; this->periodicBoxVectors[2] = periodicBoxVectors[2];
recipBoxSize[0] = (float) (1.0/periodicBoxVectors[0][0]);
recipBoxSize[1] = (float) (1.0/periodicBoxVectors[1][1]);
recipBoxSize[2] = (float) (1.0/periodicBoxVectors[2][2]);
periodicBoxVec4.resize(3);
periodicBoxVec4[0] = fvec4(periodicBoxVectors[0][0], periodicBoxVectors[0][1], periodicBoxVectors[0][2], 0);
periodicBoxVec4[1] = fvec4(periodicBoxVectors[1][0], periodicBoxVectors[1][1], periodicBoxVectors[1][2], 0);
periodicBoxVec4[2] = fvec4(periodicBoxVectors[2][0], periodicBoxVectors[2][1], periodicBoxVectors[2][2], 0);
triclinic = (periodicBoxVectors[0][1] != 0.0 || periodicBoxVectors[0][2] != 0.0 ||
periodicBoxVectors[1][0] != 0.0 || periodicBoxVectors[1][2] != 0.0 ||
periodicBoxVectors[2][0] != 0.0 || periodicBoxVectors[2][1] != 0.0);
} }
...@@ -155,8 +165,8 @@ void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int thread ...@@ -155,8 +165,8 @@ void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int thread
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(data.energyExpression, iter->first), iter->second); ReferenceForce::setVariable(ReferenceForce::getVariablePointer(data.energyExpression, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(data.forceExpression, iter->first), iter->second); ReferenceForce::setVariable(ReferenceForce::getVariablePointer(data.forceExpression, iter->first), iter->second);
} }
fvec4 boxSize(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2], 0); fvec4 boxSize(periodicBoxVectors[0][0], periodicBoxVectors[1][1], periodicBoxVectors[2][2], 0);
fvec4 invBoxSize((1/periodicBoxSize[0]), (1/periodicBoxSize[1]), (1/periodicBoxSize[2]), 0); fvec4 invBoxSize(recipBoxSize[0], recipBoxSize[1], recipBoxSize[2], 0);
if (groupInteractions.size() > 0) { if (groupInteractions.size() > 0) {
// The user has specified interaction groups, so compute only the requested interactions. // The user has specified interaction groups, so compute only the requested interactions.
...@@ -266,8 +276,15 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, ThreadData& data, ...@@ -266,8 +276,15 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, ThreadData& data,
void CpuCustomNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const { void CpuCustomNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const {
deltaR = posJ-posI; deltaR = posJ-posI;
if (periodic) { if (periodic) {
fvec4 base = round(deltaR*invBoxSize)*boxSize; if (triclinic) {
deltaR = deltaR-base; deltaR -= periodicBoxVec4[2]*floorf(deltaR[2]*recipBoxSize[2]+0.5f);
deltaR -= periodicBoxVec4[1]*floorf(deltaR[1]*recipBoxSize[1]+0.5f);
deltaR -= periodicBoxVec4[0]*floorf(deltaR[0]*recipBoxSize[0]+0.5f);
}
else {
fvec4 base = round(deltaR*invBoxSize)*boxSize;
deltaR = deltaR-base;
}
} }
r2 = dot3(deltaR, deltaR); r2 = dot3(deltaR, deltaR);
} }
...@@ -73,6 +73,11 @@ static RealVec& extractBoxSize(ContextImpl& context) { ...@@ -73,6 +73,11 @@ static RealVec& extractBoxSize(ContextImpl& context) {
return *(RealVec*) data->periodicBoxSize; return *(RealVec*) data->periodicBoxSize;
} }
static RealVec* extractBoxVectors(ContextImpl& context) {
ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
return (RealVec*) data->periodicBoxVectors;
}
static ReferenceConstraints& extractConstraints(ContextImpl& context) { static ReferenceConstraints& extractConstraints(ContextImpl& context) {
ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData()); ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
return *(ReferenceConstraints*) data->constraints; return *(ReferenceConstraints*) data->constraints;
...@@ -147,19 +152,36 @@ public: ...@@ -147,19 +152,36 @@ public:
AlignedArray<float>& posq = data.posq; AlignedArray<float>& posq = data.posq;
vector<RealVec>& posData = extractPositions(context); vector<RealVec>& posData = extractPositions(context);
RealVec boxSize = extractBoxSize(context); RealVec* boxVectors = extractBoxVectors(context);
double invBoxSize[3] = {1/boxSize[0], 1/boxSize[1], 1/boxSize[2]}; double boxSize[3] = {boxVectors[0][0], boxVectors[1][1], boxVectors[2][2]};
double invBoxSize[3] = {1/boxVectors[0][0], 1/boxVectors[1][1], 1/boxVectors[2][2]};
bool triclinic = (boxVectors[0][1] != 0 || boxVectors[0][2] != 0 || boxVectors[1][0] != 0 || boxVectors[1][2] != 0 || boxVectors[2][0] != 0 || boxVectors[2][1] != 0);
int numParticles = context.getSystem().getNumParticles(); int numParticles = context.getSystem().getNumParticles();
int numThreads = threads.getNumThreads(); int numThreads = threads.getNumThreads();
int start = threadIndex*numParticles/numThreads; int start = threadIndex*numParticles/numThreads;
int end = (threadIndex+1)*numParticles/numThreads; int end = (threadIndex+1)*numParticles/numThreads;
if (data.isPeriodic) if (data.isPeriodic) {
for (int i = start; i < end; i++) if (triclinic) {
for (int j = 0; j < 3; j++) { for (int i = start; i < end; i++) {
RealOpenMM x = posData[i][j]; RealVec pos = posData[i];
double base = floor(x*invBoxSize[j])*boxSize[j]; pos -= boxVectors[2]*floor(pos[2]*invBoxSize[2]);
posq[4*i+j] = (float) (x-base); pos -= boxVectors[1]*floor(pos[1]*invBoxSize[1]);
pos -= boxVectors[0]*floor(pos[0]*invBoxSize[0]);
posq[4*i] = (float) pos[0];
posq[4*i+1] = (float) pos[1];
posq[4*i+2] = (float) pos[2];
} }
}
else {
for (int i = start; i < end; i++) {
for (int j = 0; j < 3; j++) {
RealOpenMM x = posData[i][j];
double base = floor(x*invBoxSize[j])*boxSize[j];
posq[4*i+j] = (float) (x-base);
}
}
}
}
else else
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
posq[4*i] = (float) posData[i][0]; posq[4*i] = (float) posData[i][0];
...@@ -201,7 +223,7 @@ void CpuCalcForcesAndEnergyKernel::beginComputation(ContextImpl& context, bool i ...@@ -201,7 +223,7 @@ void CpuCalcForcesAndEnergyKernel::beginComputation(ContextImpl& context, bool i
referenceKernel.getAs<ReferenceCalcForcesAndEnergyKernel>().beginComputation(context, includeForce, includeEnergy, groups); referenceKernel.getAs<ReferenceCalcForcesAndEnergyKernel>().beginComputation(context, includeForce, includeEnergy, groups);
// Convert positions to single precision and clear the forces. // Convert positions to single precision and clear the forces.
InitForceTask task(context.getSystem().getNumParticles(), context, data); InitForceTask task(context.getSystem().getNumParticles(), context, data);
data.threads.execute(task); data.threads.execute(task);
data.threads.waitForThreads(); data.threads.waitForThreads();
...@@ -499,8 +521,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo ...@@ -499,8 +521,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
AlignedArray<float>& posq = data.posq; AlignedArray<float>& posq = data.posq;
vector<RealVec>& posData = extractPositions(context); vector<RealVec>& posData = extractPositions(context);
vector<RealVec>& forceData = extractForces(context); vector<RealVec>& forceData = extractForces(context);
RealVec boxSize = extractBoxSize(context); RealVec* boxVectors = extractBoxVectors(context);
float floatBoxSize[3] = {(float) boxSize[0], (float) boxSize[1], (float) boxSize[2]};
double energy = (includeReciprocal ? ewaldSelfEnergy : 0.0); double energy = (includeReciprocal ? ewaldSelfEnergy : 0.0);
bool ewald = (nonbondedMethod == Ewald); bool ewald = (nonbondedMethod == Ewald);
bool pme = (nonbondedMethod == PME); bool pme = (nonbondedMethod == PME);
...@@ -546,16 +567,17 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo ...@@ -546,16 +567,17 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
} }
} }
if (needRecompute) { if (needRecompute) {
neighborList->computeNeighborList(numParticles, posq, exclusions, floatBoxSize, data.isPeriodic, nonbondedCutoff+padding, data.threads); neighborList->computeNeighborList(numParticles, posq, exclusions, boxVectors, data.isPeriodic, nonbondedCutoff+padding, data.threads);
lastPositions = posData; lastPositions = posData;
} }
nonbonded->setUseCutoff(nonbondedCutoff, *neighborList, rfDielectric); nonbonded->setUseCutoff(nonbondedCutoff, *neighborList, rfDielectric);
} }
if (data.isPeriodic) { if (data.isPeriodic) {
RealVec* boxVectors = extractBoxVectors(context);
double minAllowedSize = 1.999999*nonbondedCutoff; double minAllowedSize = 1.999999*nonbondedCutoff;
if (boxSize[0] < minAllowedSize || boxSize[1] < minAllowedSize || boxSize[2] < minAllowedSize) if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize)
throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff."); throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff.");
nonbonded->setPeriodic(floatBoxSize); nonbonded->setPeriodic(boxVectors);
} }
if (ewald) if (ewald)
nonbonded->setUseEwald(ewaldAlpha, kmax[0], kmax[1], kmax[2]); nonbonded->setUseEwald(ewaldAlpha, kmax[0], kmax[1], kmax[2]);
...@@ -569,8 +591,8 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo ...@@ -569,8 +591,8 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
if (includeReciprocal) { if (includeReciprocal) {
if (useOptimizedPme) { if (useOptimizedPme) {
PmeIO io(&posq[0], &data.threadForce[0][0], numParticles); PmeIO io(&posq[0], &data.threadForce[0][0], numParticles);
Vec3 periodicBoxSize(boxSize[0], boxSize[1], boxSize[2]); Vec3 periodicBoxVectors[3] = {boxVectors[0], boxVectors[1], boxVectors[2]};
optimizedPme.getAs<CalcPmeReciprocalForceKernel>().beginComputation(io, periodicBoxSize, includeEnergy); optimizedPme.getAs<CalcPmeReciprocalForceKernel>().beginComputation(io, periodicBoxVectors, includeEnergy);
nonbondedEnergy += optimizedPme.getAs<CalcPmeReciprocalForceKernel>().finishComputation(io); nonbondedEnergy += optimizedPme.getAs<CalcPmeReciprocalForceKernel>().finishComputation(io);
} }
else else
...@@ -582,7 +604,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo ...@@ -582,7 +604,7 @@ double CpuCalcNonbondedForceKernel::execute(ContextImpl& context, bool includeFo
ReferenceLJCoulomb14 nonbonded14; ReferenceLJCoulomb14 nonbonded14;
refBondForce.calculateForce(num14, bonded14IndexArray, posData, bonded14ParamArray, forceData, includeEnergy ? &energy : NULL, nonbonded14); refBondForce.calculateForce(num14, bonded14IndexArray, posData, bonded14ParamArray, forceData, includeEnergy ? &energy : NULL, nonbonded14);
if (data.isPeriodic) if (data.isPeriodic)
energy += dispersionCoefficient/(boxSize[0]*boxSize[1]*boxSize[2]); energy += dispersionCoefficient/(boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2]);
} }
return energy; return energy;
} }
...@@ -736,19 +758,18 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C ...@@ -736,19 +758,18 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C
double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
vector<RealVec>& posData = extractPositions(context); vector<RealVec>& posData = extractPositions(context);
vector<RealVec>& forceData = extractForces(context); vector<RealVec>& forceData = extractForces(context);
RealVec& box = extractBoxSize(context); RealVec* boxVectors = extractBoxVectors(context);
float floatBoxSize[3] = {(float) box[0], (float) box[1], (float) box[2]};
double energy = 0; double energy = 0;
bool periodic = (nonbondedMethod == CutoffPeriodic); bool periodic = (nonbondedMethod == CutoffPeriodic);
if (nonbondedMethod != NoCutoff) { if (nonbondedMethod != NoCutoff) {
neighborList->computeNeighborList(numParticles, data.posq, exclusions, floatBoxSize, data.isPeriodic, nonbondedCutoff, data.threads); neighborList->computeNeighborList(numParticles, data.posq, exclusions, boxVectors, data.isPeriodic, nonbondedCutoff, data.threads);
nonbonded->setUseCutoff(nonbondedCutoff, *neighborList); nonbonded->setUseCutoff(nonbondedCutoff, *neighborList);
} }
if (periodic) { if (periodic) {
double minAllowedSize = 2*nonbondedCutoff; double minAllowedSize = 2*nonbondedCutoff;
if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize) if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize)
throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff."); throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff.");
nonbonded->setPeriodic(box); nonbonded->setPeriodic(boxVectors);
} }
bool globalParamsChanged = false; bool globalParamsChanged = false;
for (int i = 0; i < (int) globalParameterNames.size(); i++) { for (int i = 0; i < (int) globalParameterNames.size(); i++) {
...@@ -767,7 +788,7 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc ...@@ -767,7 +788,7 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc
longRangeCoefficient = CustomNonbondedForceImpl::calcLongRangeCorrection(*forceCopy, context.getOwner()); longRangeCoefficient = CustomNonbondedForceImpl::calcLongRangeCorrection(*forceCopy, context.getOwner());
hasInitializedLongRangeCorrection = true; hasInitializedLongRangeCorrection = true;
} }
energy += longRangeCoefficient/(box[0]*box[1]*box[2]); energy += longRangeCoefficient/(boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2]);
return energy; return energy;
} }
...@@ -975,13 +996,12 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB ...@@ -975,13 +996,12 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
double CpuCalcCustomGBForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CpuCalcCustomGBForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
vector<RealVec>& forceData = extractForces(context); vector<RealVec>& forceData = extractForces(context);
RealOpenMM energy = 0; RealOpenMM energy = 0;
RealVec& box = extractBoxSize(context); RealVec* boxVectors = extractBoxVectors(context);
float floatBoxSize[3] = {(float) box[0], (float) box[1], (float) box[2]};
if (data.isPeriodic) if (data.isPeriodic)
ixn->setPeriodic(extractBoxSize(context)); ixn->setPeriodic(extractBoxSize(context));
if (nonbondedMethod != NoCutoff) { if (nonbondedMethod != NoCutoff) {
vector<set<int> > noExclusions(numParticles); vector<set<int> > noExclusions(numParticles);
neighborList->computeNeighborList(numParticles, data.posq, exclusions, floatBoxSize, data.isPeriodic, nonbondedCutoff, data.threads); neighborList->computeNeighborList(numParticles, data.posq, exclusions, boxVectors, data.isPeriodic, nonbondedCutoff, data.threads);
ixn->setUseCutoff(nonbondedCutoff, *neighborList); ixn->setUseCutoff(nonbondedCutoff, *neighborList);
} }
map<string, double> globalParameters; map<string, double> globalParameters;
...@@ -1038,6 +1058,7 @@ void CpuCalcCustomManyParticleForceKernel::initialize(const System& system, cons ...@@ -1038,6 +1058,7 @@ void CpuCalcCustomManyParticleForceKernel::initialize(const System& system, cons
ixn = new CpuCustomManyParticleForce(force, data.threads); ixn = new CpuCustomManyParticleForce(force, data.threads);
nonbondedMethod = CalcCustomManyParticleForceKernel::NonbondedMethod(force.getNonbondedMethod()); nonbondedMethod = CalcCustomManyParticleForceKernel::NonbondedMethod(force.getNonbondedMethod());
cutoffDistance = force.getCutoffDistance(); cutoffDistance = force.getCutoffDistance();
data.isPeriodic = (nonbondedMethod == CutoffPeriodic);
} }
double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -1045,11 +1066,11 @@ double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool ...@@ -1045,11 +1066,11 @@ double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool
for (int i = 0; i < (int) globalParameterNames.size(); i++) for (int i = 0; i < (int) globalParameterNames.size(); i++)
globalParameters[globalParameterNames[i]] = context.getParameter(globalParameterNames[i]); globalParameters[globalParameterNames[i]] = context.getParameter(globalParameterNames[i]);
if (nonbondedMethod == CutoffPeriodic) { if (nonbondedMethod == CutoffPeriodic) {
RealVec& box = extractBoxSize(context); RealVec* boxVectors = extractBoxVectors(context);
double minAllowedSize = 2*cutoffDistance; double minAllowedSize = 2*cutoffDistance;
if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize) if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize)
throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff."); throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff.");
ixn->setPeriodic(box); ixn->setPeriodic(boxVectors);
} }
double energy = 0; double energy = 0;
ixn->calculateIxn(data.posq, particleParamArray, globalParameters, data.threadForce, includeForces, includeEnergy, energy); ixn->calculateIxn(data.posq, particleParamArray, globalParameters, data.threadForce, includeForces, includeEnergy, energy);
......
This diff is collapsed.
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