Commit 4193a416 authored by peastman's avatar peastman
Browse files

CpuNeighborList correctly handles triclinic boxes

parent 34ddae96
...@@ -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>
...@@ -46,6 +47,8 @@ public: ...@@ -46,6 +47,8 @@ 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,
const RealVec* periodicBoxVectors, bool usePeriodic, float maxDistance, ThreadPool& threads);
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 float* periodicBoxSize, bool usePeriodic, float maxDistance, ThreadPool& threads);
int getNumBlocks() const; int getNumBlocks() const;
...@@ -68,7 +71,7 @@ private: ...@@ -68,7 +71,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;
......
...@@ -45,12 +45,12 @@ namespace OpenMM { ...@@ -45,12 +45,12 @@ namespace OpenMM {
class VoxelIndex class VoxelIndex
{ {
public: public:
VoxelIndex() : x(0), y(0) { VoxelIndex() : y(0), z(0) {
} }
VoxelIndex(int x, int y) : x(x), y(y) { VoxelIndex(int y, int z) : y(y), z(z) {
} }
int x;
int y; int y;
int z;
}; };
/** /**
...@@ -59,26 +59,35 @@ public: ...@@ -59,26 +59,35 @@ public:
*/ */
class CpuNeighborList::Voxels { class CpuNeighborList::Voxels {
public: public:
Voxels(int blockSize, float vsx, float vsy, float minx, float maxx, float miny, float maxy, const float* periodicBoxSize, bool usePeriodic) : Voxels(int blockSize, float vsy, float vsz, float miny, float maxy, float minz, float maxz, const RealVec* periodicBoxVectors, bool usePeriodic) :
blockSize(blockSize), voxelSizeX(vsx), voxelSizeY(vsy), minx(minx), maxx(maxx), miny(miny), maxy(maxy), periodicBoxSize(periodicBoxSize), usePeriodic(usePeriodic) { blockSize(blockSize), voxelSizeY(vsy), voxelSizeZ(vsz), miny(miny), maxy(maxy), minz(minz), maxz(maxz), periodicBoxVectors(periodicBoxVectors), usePeriodic(usePeriodic) {
periodicBoxSize[0] = (float) periodicBoxVectors[0][0];
periodicBoxSize[1] = (float) periodicBoxVectors[1][1];
periodicBoxSize[2] = (float) periodicBoxVectors[2][2];
recipBoxSize[0] = (float) (1/periodicBoxVectors[0][0]);
recipBoxSize[1] = (float) (1/periodicBoxVectors[1][1]);
recipBoxSize[2] = (float) (1/periodicBoxVectors[2][2]);
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);
if (usePeriodic) { if (usePeriodic) {
nx = (int) floorf(periodicBoxSize[0]/voxelSizeX+0.5f); ny = (int) floorf(periodicBoxVectors[1][1]/voxelSizeY+0.5f);
ny = (int) floorf(periodicBoxSize[1]/voxelSizeY+0.5f); nz = (int) floorf(periodicBoxVectors[2][2]/voxelSizeZ+0.5f);
voxelSizeX = periodicBoxSize[0]/nx; voxelSizeY = periodicBoxVectors[1][1]/ny;
voxelSizeY = periodicBoxSize[1]/ny; voxelSizeZ = periodicBoxVectors[2][2]/nz;
} }
else { else {
nx = max(1, (int) floorf((maxx-minx)/voxelSizeX+0.5f));
ny = max(1, (int) floorf((maxy-miny)/voxelSizeY+0.5f)); ny = max(1, (int) floorf((maxy-miny)/voxelSizeY+0.5f));
if (maxx > minx) nz = max(1, (int) floorf((maxz-minz)/voxelSizeZ+0.5f));
voxelSizeX = (maxx-minx)/nx;
if (maxy > miny) if (maxy > miny)
voxelSizeY = (maxy-miny)/ny; voxelSizeY = (maxy-miny)/ny;
if (maxz > minz)
voxelSizeZ = (maxz-minz)/nz;
} }
bins.resize(nx); bins.resize(ny);
for (int i = 0; i < nx; i++) { for (int i = 0; i < ny; i++) {
bins[i].resize(ny); bins[i].resize(nz);
for (int j = 0; j < ny; j++) for (int j = 0; j < nz; j++)
bins[i][j].resize(0); bins[i][j].resize(0);
} }
} }
...@@ -88,28 +97,28 @@ public: ...@@ -88,28 +97,28 @@ public:
*/ */
void insert(const int& atom, const float* location) { void insert(const int& atom, const float* location) {
VoxelIndex voxelIndex = getVoxelIndex(location); VoxelIndex voxelIndex = getVoxelIndex(location);
bins[voxelIndex.x][voxelIndex.y].push_back(make_pair(location[2], atom)); bins[voxelIndex.y][voxelIndex.z].push_back(make_pair(location[0], atom));
} }
/** /**
* Sort the particles in each voxel by z coordinate. * Sort the particles in each voxel by x coordinate.
*/ */
void sortItems() { void sortItems() {
for (int i = 0; i < nx; i++) for (int i = 0; i < ny; i++)
for (int j = 0; j < ny; j++) for (int j = 0; j < nz; j++)
sort(bins[i][j].begin(), bins[i][j].end()); sort(bins[i][j].begin(), bins[i][j].end());
} }
/** /**
* Find the index of the first particle in voxel (x,y) whose z coordinate in >= the specified value. * Find the index of the first particle in voxel (y,z) whose x coordinate in >= the specified value.
*/ */
int findLowerBound(int x, int y, double z) const { int findLowerBound(int y, int z, double x) const {
const vector<pair<float, int> >& bin = bins[x][y]; const vector<pair<float, int> >& bin = bins[y][z];
int lower = 0; int lower = 0;
int upper = bin.size(); int upper = bin.size();
while (lower < upper) { while (lower < upper) {
int middle = (lower+upper)/2; int middle = (lower+upper)/2;
if (bin[middle].first < z) if (bin[middle].first < x)
lower = middle+1; lower = middle+1;
else else
upper = middle; upper = middle;
...@@ -118,15 +127,15 @@ public: ...@@ -118,15 +127,15 @@ public:
} }
/** /**
* Find the index of the first particle in voxel (x,y) whose z coordinate in greater than the specified value. * Find the index of the first particle in voxel (y,z) whose x coordinate in greater than the specified value.
*/ */
int findUpperBound(int x, int y, double z) const { int findUpperBound(int y, int z, double x) const {
const vector<pair<float, int> >& bin = bins[x][y]; const vector<pair<float, int> >& bin = bins[y][z];
int lower = 0; int lower = 0;
int upper = bin.size(); int upper = bin.size();
while (lower < upper) { while (lower < upper) {
int middle = (lower+upper)/2; int middle = (lower+upper)/2;
if (bin[middle].first > z) if (bin[middle].first > x)
upper = middle; upper = middle;
else else
lower = middle+1; lower = middle+1;
...@@ -138,121 +147,144 @@ public: ...@@ -138,121 +147,144 @@ public:
* Get the voxel index containing a particular location. * Get the voxel index containing a particular location.
*/ */
VoxelIndex getVoxelIndex(const float* location) const { VoxelIndex getVoxelIndex(const float* location) const {
float xperiodic, yperiodic; float yperiodic, zperiodic;
if (!usePeriodic) { if (!usePeriodic) {
xperiodic = location[0]-minx;
yperiodic = location[1]-miny; yperiodic = location[1]-miny;
zperiodic = location[2]-minz;
} }
else { else {
xperiodic = location[0]-periodicBoxSize[0]*floorf(location[0]/periodicBoxSize[0]); float scale2 = floorf(location[2]*recipBoxSize[2]);
yperiodic = location[1]-periodicBoxSize[1]*floorf(location[1]/periodicBoxSize[1]); yperiodic = location[1]-periodicBoxVectors[2][1]*scale2;
zperiodic = location[2]-periodicBoxVectors[2][2]*scale2;
float scale1 = floorf(yperiodic*recipBoxSize[1]);
yperiodic -= periodicBoxVectors[1][0]*scale1;
} }
int x = min(nx-1, int(floorf(xperiodic / voxelSizeX)));
int y = min(ny-1, int(floorf(yperiodic / voxelSizeY))); int y = min(ny-1, int(floorf(yperiodic / voxelSizeY)));
int z = min(nz-1, int(floorf(zperiodic / voxelSizeZ)));
return VoxelIndex(x, y); return VoxelIndex(y, z);
} }
void getNeighbors(vector<int>& neighbors, int blockIndex, const fvec4& blockCenter, const fvec4& blockWidth, const vector<int>& sortedAtoms, vector<char>& exclusions, float maxDistance, const vector<int>& blockAtoms, const float* atomLocations, const vector<VoxelIndex>& atomVoxelIndex) const { void getNeighbors(vector<int>& neighbors, int blockIndex, const fvec4& blockCenter, const fvec4& blockWidth, const vector<int>& sortedAtoms, vector<char>& exclusions, float maxDistance, const vector<int>& blockAtoms, const float* atomLocations, const vector<VoxelIndex>& atomVoxelIndex) const {
neighbors.resize(0); neighbors.resize(0);
exclusions.resize(0); exclusions.resize(0);
fvec4 boxSize(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2], 0); fvec4 boxSize(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2], 0);
fvec4 invBoxSize(1/periodicBoxSize[0], 1/periodicBoxSize[1], 1/periodicBoxSize[2], 0); fvec4 invBoxSize(recipBoxSize[0], recipBoxSize[1], recipBoxSize[2], 0);
fvec4 periodicBoxVec4[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);
float maxDistanceSquared = maxDistance * maxDistance; float maxDistanceSquared = maxDistance * maxDistance;
float refineCutoff = maxDistance-max(max(blockWidth[0], blockWidth[1]), blockWidth[2]); float refineCutoff = maxDistance-max(max(blockWidth[0], blockWidth[1]), blockWidth[2]);
float refineCutoffSquared = refineCutoff*refineCutoff; float refineCutoffSquared = refineCutoff*refineCutoff;
int dIndexX = int((maxDistance+blockWidth[0])/voxelSizeX)+1; // How may voxels away do we have to look? int dIndexY = int((maxDistance+blockWidth[1])/voxelSizeY)+1; // How may voxels away do we have to look?
int dIndexY = int((maxDistance+blockWidth[1])/voxelSizeY)+1; int dIndexZ = int((maxDistance+blockWidth[2])/voxelSizeZ)+1;
if (usePeriodic) { if (usePeriodic) {
dIndexX = min(nx/2, dIndexX);
dIndexY = min(ny/2, dIndexY); dIndexY = min(ny/2, dIndexY);
dIndexZ = min(nz/2, dIndexZ);
} }
float centerPos[4]; float centerPos[4];
blockCenter.store(centerPos); blockCenter.store(centerPos);
VoxelIndex centerVoxelIndex = getVoxelIndex(centerPos); VoxelIndex centerVoxelIndex = getVoxelIndex(centerPos);
int startx = centerVoxelIndex.x-dIndexX;
// Loop over voxels along the z axis.
int startz = centerVoxelIndex.z-dIndexZ;
int endz = centerVoxelIndex.z+dIndexZ;
if (usePeriodic)
endz = min(endz, startz+nz-1);
else {
startz = max(startz, 0);
endz = min(endz, nz-1);
}
int lastSortedIndex = blockSize*(blockIndex+1);
VoxelIndex voxelIndex(0, 0);
for (int z = startz; z <= endz; ++z) {
voxelIndex.z = z;
if (usePeriodic)
voxelIndex.z = (z < 0 ? z+nz : (z >= nz ? z-nz : z));
// Loop over voxels along the y axis.
int boxz = (int) floor((float) z/nz);
int starty = centerVoxelIndex.y-dIndexY; int starty = centerVoxelIndex.y-dIndexY;
int endx = centerVoxelIndex.x+dIndexX;
int endy = centerVoxelIndex.y+dIndexY; int endy = centerVoxelIndex.y+dIndexY;
int numRanges; float yoffset = (float) (usePeriodic ? boxz*periodicBoxVectors[2][1] : 0);
if (usePeriodic) { if (usePeriodic) {
endx = min(endx, centerVoxelIndex.x-dIndexX+nx-1); starty -= (int) ceil(yoffset/voxelSizeY);
endy = min(endy, centerVoxelIndex.y-dIndexY+ny-1); endy -= (int) floor(yoffset/voxelSizeY);
endy = min(endy, starty+ny-1);
} }
else { else {
startx = max(startx, 0);
starty = max(starty, 0); starty = max(starty, 0);
endx = min(endx, nx-1);
endy = min(endy, ny-1); endy = min(endy, ny-1);
} }
int lastSortedIndex = blockSize*(blockIndex+1);
VoxelIndex voxelIndex(0, 0);
for (int x = startx; x <= endx; ++x) {
voxelIndex.x = x;
if (usePeriodic)
voxelIndex.x = (x < 0 ? x+nx : (x >= nx ? x-nx : x));
for (int y = starty; y <= endy; ++y) { for (int y = starty; y <= endy; ++y) {
voxelIndex.y = y; voxelIndex.y = y;
if (usePeriodic) if (usePeriodic)
voxelIndex.y = (y < 0 ? y+ny : (y >= ny ? y-ny : y)); voxelIndex.y = (y < 0 ? y+ny : (y >= ny ? y-ny : y));
int boxy = (int) floor((float) y/ny);
float xoffset = (float) (usePeriodic ? boxy*periodicBoxVectors[1][0]+boxz*periodicBoxVectors[2][0] : 0);
// Identify the range of atoms within this bin we need to search. When using periodic boundary // Identify the range of atoms within this bin we need to search. When using periodic boundary
// conditions, there may be two separate ranges. // conditions, there may be two separate ranges.
float minz = centerPos[2]; float minx = centerPos[0];
float maxz = centerPos[2]; float maxx = centerPos[0];
fvec4 offset(voxelSizeX*x+(usePeriodic ? 0.0f : minx), voxelSizeY*y+(usePeriodic ? 0.0f : miny), 0, 0); fvec4 offset(-xoffset, -yoffset+voxelSizeY*y+(usePeriodic ? 0.0f : miny), voxelSizeZ*z+(usePeriodic ? 0.0f : minz), 0);
for (int k = 0; k < (int) blockAtoms.size(); k++) { for (int k = 0; k < (int) blockAtoms.size(); k++) {
const float* atomPos = &atomLocations[4*blockAtoms[k]]; const float* atomPos = &atomLocations[4*blockAtoms[k]];
fvec4 posVec(atomPos); fvec4 posVec(atomPos);
fvec4 delta1 = offset-posVec; fvec4 delta1 = offset-posVec;
fvec4 delta2 = delta1+fvec4(voxelSizeX, voxelSizeY, 0, 0); fvec4 delta2 = delta1+fvec4(0, voxelSizeY, voxelSizeZ, 0);
if (usePeriodic) { if (usePeriodic) {
delta1 -= round(delta1*invBoxSize)*boxSize; delta1 -= round(delta1*invBoxSize)*boxSize;
delta2 -= round(delta2*invBoxSize)*boxSize; delta2 -= round(delta2*invBoxSize)*boxSize;
} }
fvec4 delta = min(abs(delta1), abs(delta2)); fvec4 delta = min(abs(delta1), abs(delta2));
float dx = (x == atomVoxelIndex[k].x ? 0.0f : delta[0]);
float dy = (y == atomVoxelIndex[k].y ? 0.0f : delta[1]); float dy = (y == atomVoxelIndex[k].y ? 0.0f : delta[1]);
float dist2 = maxDistanceSquared-dx*dx-dy*dy; float dz = (z == atomVoxelIndex[k].z ? 0.0f : delta[2]);
float dist2 = maxDistanceSquared-dy*dy-dz*dz;
if (dist2 > 0) { if (dist2 > 0) {
float dist = sqrtf(dist2); float dist = sqrtf(dist2);
minz = min(minz, atomPos[2]-dist); minx = min(minx, atomPos[0]-dist-xoffset);
maxz = max(maxz, atomPos[2]+dist); maxx = max(maxx, atomPos[0]+dist-xoffset);
} }
} }
if (minz == maxz) if (minx == maxx)
continue; continue;
bool needPeriodic = (centerPos[0]-blockWidth[0] < maxDistance || centerPos[0]+blockWidth[0] > periodicBoxSize[0]-maxDistance || bool needPeriodic = (centerPos[1]-blockWidth[1] < maxDistance || centerPos[1]+blockWidth[1] > periodicBoxSize[1]-maxDistance ||
centerPos[1]-blockWidth[1] < maxDistance || centerPos[1]+blockWidth[1] > periodicBoxSize[1]-maxDistance || centerPos[2]-blockWidth[2] < maxDistance || centerPos[2]+blockWidth[2] > periodicBoxSize[2]-maxDistance ||
minz < 0.0f || maxz > periodicBoxSize[2]); minx < 0.0f || maxx > periodicBoxVectors[0][0]);
int numRanges;
int rangeStart[2]; int rangeStart[2];
int rangeEnd[2]; int rangeEnd[2];
rangeStart[0] = findLowerBound(voxelIndex.x, voxelIndex.y, minz); rangeStart[0] = findLowerBound(voxelIndex.y, voxelIndex.z, minx);
if (needPeriodic) { if (needPeriodic) {
numRanges = 2; numRanges = 2;
rangeEnd[0] = findUpperBound(voxelIndex.x, voxelIndex.y, maxz); rangeEnd[0] = findUpperBound(voxelIndex.y, voxelIndex.z, maxx);
if (rangeStart[0] > 0) { if (rangeStart[0] > 0) {
rangeStart[1] = 0; rangeStart[1] = 0;
rangeEnd[1] = min(findUpperBound(voxelIndex.x, voxelIndex.y, maxz-periodicBoxSize[2]), rangeStart[0]); rangeEnd[1] = min(findUpperBound(voxelIndex.y, voxelIndex.z, maxx-periodicBoxSize[0]), rangeStart[0]);
} }
else { else {
rangeStart[1] = max(findLowerBound(voxelIndex.x, voxelIndex.y, minz+periodicBoxSize[2]), rangeEnd[0]); rangeStart[1] = max(findLowerBound(voxelIndex.y, voxelIndex.z, minx+periodicBoxSize[0]), rangeEnd[0]);
rangeEnd[1] = bins[voxelIndex.x][voxelIndex.y].size(); rangeEnd[1] = bins[voxelIndex.y][voxelIndex.z].size();
} }
} }
else { else {
numRanges = 1; numRanges = 1;
rangeEnd[0] = findUpperBound(voxelIndex.x, voxelIndex.y, maxz); rangeEnd[0] = findUpperBound(voxelIndex.y, voxelIndex.z, maxx);
} }
bool periodicRectangular = (needPeriodic && !triclinic);
// Loop over atoms and check to see if they are neighbors of this block. // Loop over atoms and check to see if they are neighbors of this block.
for (int range = 0; range < numRanges; range++) { for (int range = 0; range < numRanges; range++) {
for (int item = rangeStart[range]; item < rangeEnd[range]; item++) { for (int item = rangeStart[range]; item < rangeEnd[range]; item++) {
const int sortedIndex = bins[voxelIndex.x][voxelIndex.y][item].second; const int sortedIndex = bins[voxelIndex.y][voxelIndex.z][item].second;
// Avoid duplicate entries. // Avoid duplicate entries.
if (sortedIndex >= lastSortedIndex) if (sortedIndex >= lastSortedIndex)
...@@ -260,10 +292,15 @@ public: ...@@ -260,10 +292,15 @@ public:
fvec4 atomPos(atomLocations+4*sortedAtoms[sortedIndex]); fvec4 atomPos(atomLocations+4*sortedAtoms[sortedIndex]);
fvec4 delta = atomPos-centerPos; fvec4 delta = atomPos-centerPos;
if (needPeriodic) { if (periodicRectangular) {
fvec4 base = round(delta*invBoxSize)*boxSize; fvec4 base = round(delta*invBoxSize)*boxSize;
delta = delta-base; delta = delta-base;
} }
else if (needPeriodic) {
delta -= periodicBoxVec4[2]*floorf(delta[2]*recipBoxSize[2]+0.5f);
delta -= periodicBoxVec4[1]*floorf(delta[1]*recipBoxSize[1]+0.5f);
delta -= periodicBoxVec4[0]*floorf(delta[0]*recipBoxSize[0]+0.5f);
}
delta = max(0.0f, abs(delta)-blockWidth); delta = max(0.0f, abs(delta)-blockWidth);
float dSquared = dot3(delta, delta); float dSquared = dot3(delta, delta);
if (dSquared > maxDistanceSquared) if (dSquared > maxDistanceSquared)
...@@ -277,10 +314,15 @@ public: ...@@ -277,10 +314,15 @@ public:
for (int k = 0; k < (int) blockAtoms.size(); k++) { for (int k = 0; k < (int) blockAtoms.size(); k++) {
fvec4 pos1(&atomLocations[4*blockAtoms[k]]); fvec4 pos1(&atomLocations[4*blockAtoms[k]]);
delta = atomPos-pos1; delta = atomPos-pos1;
if (needPeriodic) { if (periodicRectangular) {
fvec4 base = round(delta*invBoxSize)*boxSize; fvec4 base = round(delta*invBoxSize)*boxSize;
delta = delta-base; delta = delta-base;
} }
else if (needPeriodic) {
delta -= periodicBoxVec4[2]*floorf(delta[2]*recipBoxSize[2]+0.5f);
delta -= periodicBoxVec4[1]*floorf(delta[1]*recipBoxSize[1]+0.5f);
delta -= periodicBoxVec4[0]*floorf(delta[0]*recipBoxSize[0]+0.5f);
}
float r2 = dot3(delta, delta); float r2 = dot3(delta, delta);
if (r2 < maxDistanceSquared) { if (r2 < maxDistanceSquared) {
any = true; any = true;
...@@ -308,10 +350,12 @@ public: ...@@ -308,10 +350,12 @@ public:
private: private:
int blockSize; int blockSize;
float voxelSizeX, voxelSizeY; float voxelSizeY, voxelSizeZ;
float minx, maxx, miny, maxy; float miny, maxy, minz, maxz;
int nx, ny; int ny, nz;
const float* periodicBoxSize; float periodicBoxSize[3], recipBoxSize[3];
bool triclinic;
const RealVec* periodicBoxVectors;
const bool usePeriodic; const bool usePeriodic;
vector<vector<vector<pair<float, int> > > > bins; vector<vector<vector<pair<float, int> > > > bins;
}; };
...@@ -331,6 +375,15 @@ CpuNeighborList::CpuNeighborList(int blockSize) : blockSize(blockSize) { ...@@ -331,6 +375,15 @@ CpuNeighborList::CpuNeighborList(int blockSize) : blockSize(blockSize) {
void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const vector<set<int> >& exclusions, void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const vector<set<int> >& exclusions,
const float* periodicBoxSize, bool usePeriodic, float maxDistance, ThreadPool& threads) { const float* periodicBoxSize, bool usePeriodic, float maxDistance, ThreadPool& threads) {
RealVec vectors[3];
vectors[0] = RealVec(periodicBoxSize[0], 0, 0);
vectors[1] = RealVec(0, periodicBoxSize[1], 0);
vectors[2] = RealVec(0, 0, periodicBoxSize[2]);
computeNeighborList(numAtoms, atomLocations, exclusions, vectors, usePeriodic, maxDistance, threads);
}
void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const vector<set<int> >& exclusions,
const RealVec* periodicBoxVectors, bool usePeriodic, float maxDistance, ThreadPool& threads) {
int numBlocks = (numAtoms+blockSize-1)/blockSize; int numBlocks = (numAtoms+blockSize-1)/blockSize;
blockNeighbors.resize(numBlocks); blockNeighbors.resize(numBlocks);
blockExclusions.resize(numBlocks); blockExclusions.resize(numBlocks);
...@@ -340,7 +393,9 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float ...@@ -340,7 +393,9 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float
this->exclusions = &exclusions; this->exclusions = &exclusions;
this->atomLocations = &atomLocations[0]; this->atomLocations = &atomLocations[0];
this->periodicBoxSize = periodicBoxSize; this->periodicBoxVectors[0] = periodicBoxVectors[0];
this->periodicBoxVectors[1] = periodicBoxVectors[1];
this->periodicBoxVectors[2] = periodicBoxVectors[2];
this->numAtoms = numAtoms; this->numAtoms = numAtoms;
this->usePeriodic = usePeriodic; this->usePeriodic = usePeriodic;
this->maxDistance = maxDistance; this->maxDistance = maxDistance;
...@@ -371,14 +426,14 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float ...@@ -371,14 +426,14 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float
// Build the voxel hash. // Build the voxel hash.
float edgeSizeX, edgeSizeY; float edgeSizeY, edgeSizeZ;
if (!usePeriodic) if (!usePeriodic)
edgeSizeX = edgeSizeY = maxDistance; // TODO - adjust this as needed edgeSizeY = edgeSizeZ = maxDistance; // TODO - adjust this as needed
else { else {
edgeSizeX = 0.6f*periodicBoxSize[0]/floorf(periodicBoxSize[0]/maxDistance); edgeSizeY = 0.6f*periodicBoxVectors[1][1]/floorf(periodicBoxVectors[1][1]/maxDistance);
edgeSizeY = 0.6f*periodicBoxSize[1]/floorf(periodicBoxSize[1]/maxDistance); edgeSizeZ = 0.6f*periodicBoxVectors[2][2]/floorf(periodicBoxVectors[2][2]/maxDistance);
} }
Voxels voxels(blockSize, edgeSizeX, edgeSizeY, minx, maxx, miny, maxy, periodicBoxSize, usePeriodic); Voxels voxels(blockSize, edgeSizeY, edgeSizeZ, miny, maxy, minz, maxz, periodicBoxVectors, usePeriodic);
for (int i = 0; i < numAtoms; i++) { for (int i = 0; i < numAtoms; i++) {
int atomIndex = atomBins[i].second; int atomIndex = atomBins[i].second;
sortedAtoms[i] = atomIndex; sortedAtoms[i] = atomIndex;
......
...@@ -463,9 +463,9 @@ void CpuNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& d ...@@ -463,9 +463,9 @@ void CpuNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& d
deltaR = posJ-posI; deltaR = posJ-posI;
if (periodic) { if (periodic) {
if (triclinic) { if (triclinic) {
deltaR -= periodicBoxVec4[2]*floor(deltaR[2]*recipBoxSize[2]+0.5f); deltaR -= periodicBoxVec4[2]*floorf(deltaR[2]*recipBoxSize[2]+0.5f);
deltaR -= periodicBoxVec4[1]*floor(deltaR[1]*recipBoxSize[1]+0.5f); deltaR -= periodicBoxVec4[1]*floorf(deltaR[1]*recipBoxSize[1]+0.5f);
deltaR -= periodicBoxVec4[0]*floor(deltaR[0]*recipBoxSize[0]+0.5f); deltaR -= periodicBoxVec4[0]*floorf(deltaR[0]*recipBoxSize[0]+0.5f);
} }
else { else {
fvec4 base = round(deltaR*invBoxSize)*boxSize; fvec4 base = round(deltaR*invBoxSize)*boxSize;
......
...@@ -48,10 +48,21 @@ ...@@ -48,10 +48,21 @@
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
void testNeighborList(bool periodic) { void testNeighborList(bool periodic, bool triclinic) {
const int numParticles = 500; const int numParticles = 500;
const float cutoff = 2.0f; const float cutoff = 2.0f;
const float boxSize[3] = {20.0f, 15.0f, 22.0f}; RealVec boxVectors[3];
if (triclinic) {
boxVectors[0] = RealVec(20, 0, 0);
boxVectors[1] = RealVec(5, 15, 0);
boxVectors[2] = RealVec(-3, -7, 22);
}
else {
boxVectors[0] = RealVec(20, 0, 0);
boxVectors[1] = RealVec(0, 15, 0);
boxVectors[2] = RealVec(0, 0, 22);
}
const float boxSize[3] = {boxVectors[0][0], boxVectors[1][1], boxVectors[2][2]};
const int blockSize = 8; const int blockSize = 8;
OpenMM_SFMT::SFMT sfmt; OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt); init_gen_rand(0, sfmt);
...@@ -69,7 +80,7 @@ void testNeighborList(bool periodic) { ...@@ -69,7 +80,7 @@ void testNeighborList(bool periodic) {
} }
ThreadPool threads; ThreadPool threads;
CpuNeighborList neighborList(blockSize); CpuNeighborList neighborList(blockSize);
neighborList.computeNeighborList(numParticles, positions, exclusions, boxSize, periodic, cutoff, threads); neighborList.computeNeighborList(numParticles, positions, exclusions, boxVectors, periodic, cutoff, threads);
// Convert the neighbor list to a set for faster lookup. // Convert the neighbor list to a set for faster lookup.
...@@ -94,15 +105,13 @@ void testNeighborList(bool periodic) { ...@@ -94,15 +105,13 @@ void testNeighborList(bool periodic) {
for (int i = 0; i < numParticles; i++) for (int i = 0; i < numParticles; i++)
for (int j = 0; j <= i; j++) { for (int j = 0; j <= i; j++) {
bool shouldInclude = (exclusions[i].find(j) == exclusions[i].end()); bool shouldInclude = (exclusions[i].find(j) == exclusions[i].end());
float dx = positions[4*i]-positions[4*j]; Vec3 diff(positions[4*i]-positions[4*j], positions[4*i+1]-positions[4*j+1], positions[4*i+2]-positions[4*j+2]);
float dy = positions[4*i+1]-positions[4*j+1];
float dz = positions[4*i+2]-positions[4*j+2];
if (periodic) { if (periodic) {
dx -= floor(dx/boxSize[0]+0.5f)*boxSize[0]; diff -= boxVectors[2]*floor(diff[2]/boxSize[2]+0.5);
dy -= floor(dy/boxSize[1]+0.5f)*boxSize[1]; diff -= boxVectors[1]*floor(diff[1]/boxSize[1]+0.5);
dz -= floor(dz/boxSize[2]+0.5f)*boxSize[2]; diff -= boxVectors[0]*floor(diff[0]/boxSize[0]+0.5);
} }
if (dx*dx + dy*dy + dz*dz > cutoff*cutoff) if (diff.dot(diff) > cutoff*cutoff)
shouldInclude = false; shouldInclude = false;
bool isIncluded = (neighbors.find(make_pair(i, j)) != neighbors.end() || neighbors.find(make_pair(j, i)) != neighbors.end()); bool isIncluded = (neighbors.find(make_pair(i, j)) != neighbors.end() || neighbors.find(make_pair(j, i)) != neighbors.end());
if (shouldInclude) if (shouldInclude)
...@@ -116,8 +125,9 @@ int main() { ...@@ -116,8 +125,9 @@ int main() {
cout << "CPU is not supported. Exiting." << endl; cout << "CPU is not supported. Exiting." << endl;
return 0; return 0;
} }
testNeighborList(false); testNeighborList(false, false);
testNeighborList(true); testNeighborList(true, false);
testNeighborList(true, true);
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -157,9 +157,9 @@ public: ...@@ -157,9 +157,9 @@ public:
int miny = centerVoxelIndex.y-dIndexY; int miny = centerVoxelIndex.y-dIndexY;
int maxy = centerVoxelIndex.y+dIndexY; int maxy = centerVoxelIndex.y+dIndexY;
if (usePeriodic) { if (usePeriodic) {
int yoffset = (int) ceil(boxz*periodicBoxVectors[2][1]/voxelSizeY); double yoffset = boxz*periodicBoxVectors[2][1]/voxelSizeY;
miny -= yoffset; miny -= (int) ceil(yoffset);
maxy -= yoffset-1; maxy -= (int) floor(yoffset);
maxy = min(maxy, miny+ny-1); maxy = min(maxy, miny+ny-1);
} }
for (int y = miny; y <= maxy; ++y) for (int y = miny; y <= maxy; ++y)
...@@ -168,9 +168,9 @@ public: ...@@ -168,9 +168,9 @@ public:
int minx = centerVoxelIndex.x-dIndexX; int minx = centerVoxelIndex.x-dIndexX;
int maxx = centerVoxelIndex.x+dIndexX; int maxx = centerVoxelIndex.x+dIndexX;
if (usePeriodic) { if (usePeriodic) {
int xoffset = (int) ceil((boxy*periodicBoxVectors[1][0]+boxz*periodicBoxVectors[2][0])/voxelSizeX); double xoffset = (boxy*periodicBoxVectors[1][0]+boxz*periodicBoxVectors[2][0])/voxelSizeX;
minx -= xoffset; minx -= (int) ceil(xoffset);
maxx -= xoffset-1; maxx -= (int) floor(xoffset);
maxx = min(maxx, minx+nx-1); maxx = min(maxx, minx+nx-1);
} }
for (int x = minx; x <= maxx; ++x) for (int x = minx; x <= maxx; ++x)
......
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