* The grid implementation could still be optimized in several different ways:
* - Triclinic grid cells are not the most efficient shape, but make PBC
* handling easier.
- * - Precalculating the required PBC shift for a pair of cells outside the
- * inner loop. After this is done, it should be quite straightforward to
- * move to rectangular cells.
* - Pruning grid cells from the search list if they are completely outside
* the sphere that is being considered.
* - A better heuristic could be added for falling back to simple loops for a
* \param[in] i Index to add.
*/
void addToGridCell(const ivec cell, int i);
+ /*! \brief
+ * Calculates the index of a neighboring grid cell.
+ *
+ * \param[in] sourceCell Location of the source cell.
+ * \param[in] index Index of the neighbor to calculate.
+ * \param[out] shift Shift to apply to get the periodic distance
+ * for distances between the cells.
+ * \returns Grid cell index of the neighboring cell.
+ */
+ int getNeighboringCell(const ivec sourceCell, int index, rvec shift) const;
//! Whether to try grid searching.
bool bTryGrid_;
cells_[ci].push_back(i);
}
+int AnalysisNeighborhoodSearchImpl::getNeighboringCell(
+ const ivec sourceCell, int index, rvec shift) const
+{
+ ivec cell;
+ ivec_add(sourceCell, gnboffs_[index], cell);
+
+ // TODO: Consider unifying with the similar shifting code in
+ // mapPointToGridCell().
+ clear_rvec(shift);
+ for (int d = 0; d < DIM; ++d)
+ {
+ const int cellCount = ncelldim_[d];
+ if (cell[d] < 0)
+ {
+ cell[d] += cellCount;
+ rvec_add(shift, pbc_.box[d], shift);
+ }
+ else if (cell[d] >= cellCount)
+ {
+ cell[d] -= cellCount;
+ rvec_sub(shift, pbc_.box[d], shift);
+ }
+ }
+
+ return getGridCellIndex(cell);
+}
+
void AnalysisNeighborhoodSearchImpl::init(
AnalysisNeighborhood::SearchMode mode,
bool bXY,
for (; nbi < search_.ngridnb_; ++nbi)
{
- ivec cell;
-
- ivec_add(testcell_, search_.gnboffs_[nbi], cell);
- cell[XX] = (cell[XX] + search_.ncelldim_[XX]) % search_.ncelldim_[XX];
- cell[YY] = (cell[YY] + search_.ncelldim_[YY]) % search_.ncelldim_[YY];
- cell[ZZ] = (cell[ZZ] + search_.ncelldim_[ZZ]) % search_.ncelldim_[ZZ];
-
- const int ci = search_.getGridCellIndex(cell);
+ rvec shift;
+ const int ci = search_.getNeighboringCell(testcell_, nbi, shift);
const int cellSize = static_cast<int>(search_.cells_[ci].size());
- /* TODO: Calculate the required PBC shift outside the inner loop */
for (; cai < cellSize; ++cai)
{
const int i = search_.cells_[ci][cai];
continue;
}
rvec dx;
- pbc_dx_aiuc(&search_.pbc_, xtest_, search_.xref_[i], dx);
+ rvec_sub(xtest_, search_.xref_[i], dx);
+ rvec_add(dx, shift, dx);
const real r2 = norm2(dx);
if (r2 <= search_.cutoff2_)
{
#include "gromacs/random/random.h"
#include "gromacs/topology/block.h"
#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
#include "testutils/testasserts.h"
}
}
+//! Helper function for formatting test failure messages.
+std::string formatVector(const rvec x)
+{
+ return gmx::formatString("[%.3f, %.3f, %.3f]", x[XX], x[YY], x[ZZ]);
+}
+
/*! \brief
* Helper function to check that all expected pairs were found.
*/
-static void checkAllPairsFound(const RefPairList &refPairs)
+void checkAllPairsFound(const RefPairList &refPairs, const rvec refPos[],
+ int testPosIndex, const rvec testPos)
{
// This could be elegantly expressed with Google Mock matchers, but that
// has a significant effect on the runtime of the tests...
+ int count = 0;
+ RefPairList::const_iterator first;
for (RefPairList::const_iterator i = refPairs.begin(); i != refPairs.end(); ++i)
{
if (!i->bFound)
{
- ADD_FAILURE()
- << "Some pairs within the cutoff were not found.";
- break;
+ ++count;
+ first = i;
}
}
+ if (count > 0)
+ {
+ ADD_FAILURE()
+ << "Some pairs (" << count << "/" << refPairs.size() << ") "
+ << "within the cutoff were not found. First pair:\n"
+ << " Ref: " << first->refIndex << " at "
+ << formatVector(refPos[first->refIndex]) << "\n"
+ << "Test: " << testPosIndex << " at " << formatVector(testPos) << "\n"
+ << "Dist: " << first->distance;
+ }
}
void NeighborhoodSearchTest::testPairSearch(
{
if (prevTestPos != -1)
{
- checkAllPairsFound(refPairs);
+ checkAllPairsFound(refPairs, data.refPos_, prevTestPos,
+ data.testPositions_[prevTestPos].x);
}
const int testIndex = pair.testIndex();
if (remainingTestPositions.count(testIndex) == 0)
<< "Distance computed by the neighborhood search does not match.";
}
}
- checkAllPairsFound(refPairs);
+ checkAllPairsFound(refPairs, data.refPos_, prevTestPos,
+ data.testPositions_[prevTestPos].x);
for (std::set<int>::const_iterator i = remainingTestPositions.begin();
i != remainingTestPositions.end(); ++i)
{