2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Implements neighborhood searching for analysis (from nbsearch.h).
40 * The grid implementation could still be optimized in several different ways:
41 * - Triclinic grid cells are not the most efficient shape, but make PBC
43 * - Pruning grid cells from the search list if they are completely outside
44 * the sphere that is being considered.
45 * - A better heuristic could be added for falling back to simple loops for a
46 * small number of reference particles.
47 * - A better heuristic for selecting the grid size.
48 * - A multi-level grid implementation could be used to be able to use small
49 * grids for short cutoffs with very inhomogeneous particle distributions
50 * without a memory cost.
52 * \author Teemu Murtola <teemu.murtola@gmail.com>
53 * \ingroup module_selection
57 #include "gromacs/selection/nbsearch.h"
65 #include "thread_mpi/mutex.h"
67 #include "gromacs/legacyheaders/names.h"
69 #include "gromacs/math/vec.h"
70 #include "gromacs/pbcutil/pbc.h"
71 #include "gromacs/selection/position.h"
72 #include "gromacs/topology/block.h"
73 #include "gromacs/utility/arrayref.h"
74 #include "gromacs/utility/exceptions.h"
75 #include "gromacs/utility/gmxassert.h"
76 #include "gromacs/utility/smalloc.h"
77 #include "gromacs/utility/stringutil.h"
85 /********************************************************************
86 * Implementation class declarations
89 class AnalysisNeighborhoodSearchImpl
92 typedef AnalysisNeighborhoodPairSearch::ImplPointer
93 PairSearchImplPointer;
94 typedef std::vector<PairSearchImplPointer> PairSearchList;
95 typedef std::vector<std::vector<int> > CellList;
97 explicit AnalysisNeighborhoodSearchImpl(real cutoff);
98 ~AnalysisNeighborhoodSearchImpl();
101 * Initializes the search with a given box and reference positions.
103 * \param[in] mode Search mode to use.
104 * \param[in] bXY Whether to use 2D searching.
105 * \param[in] excls Exclusions.
106 * \param[in] pbc PBC information.
107 * \param[in] positions Set of reference positions.
109 void init(AnalysisNeighborhood::SearchMode mode,
111 const t_blocka *excls,
113 const AnalysisNeighborhoodPositions &positions);
114 PairSearchImplPointer getPairSearch();
116 real cutoffSquared() const { return cutoff2_; }
117 bool usesGridSearch() const { return bGrid_; }
120 //! Calculates offsets to neighboring grid cells that should be considered.
121 void initGridCellNeighborList();
123 * Determines a suitable grid size and sets up the cells.
125 * \param[in] pbc Information about the box.
126 * \returns false if grid search is not suitable.
128 bool initGridCells(const t_pbc &pbc);
130 * Sets ua a search grid for a given box.
132 * \param[in] pbc Information about the box.
133 * \returns false if grid search is not suitable.
135 bool initGrid(const t_pbc &pbc);
137 * Maps a point into a grid cell.
139 * \param[in] x Point to map.
140 * \param[out] cell Indices of the grid cell in which \p x lies.
141 * \param[out] xout Coordinates to use
142 * (will be within the triclinic unit cell).
144 void mapPointToGridCell(const rvec x, ivec cell, rvec xout) const;
146 * Calculates linear index of a grid cell.
148 * \param[in] cell Cell indices.
149 * \returns Linear index of \p cell.
151 int getGridCellIndex(const ivec cell) const;
153 * Adds an index into a grid cell.
155 * \param[in] cell Cell into which \p i should be added.
156 * \param[in] i Index to add.
158 void addToGridCell(const ivec cell, int i);
160 * Calculates the index of a neighboring grid cell.
162 * \param[in] sourceCell Location of the source cell.
163 * \param[in] index Index of the neighbor to calculate.
164 * \param[out] shift Shift to apply to get the periodic distance
165 * for distances between the cells.
166 * \returns Grid cell index of the neighboring cell.
168 int getNeighboringCell(const ivec sourceCell, int index, rvec shift) const;
170 //! Whether to try grid searching.
174 //! The cutoff squared.
176 //! Whether to do searching in XY plane only.
179 //! Number of reference points for the current frame.
181 //! Reference point positions.
183 //! Reference position exclusion IDs.
184 const int *refExclusionIds_;
186 const t_blocka *excls_;
190 //! Whether grid searching is actually used for the current positions.
192 //! Array allocated for storing in-unit-cell reference positions.
194 //! Allocation count for xref_alloc.
196 //! false if the box is rectangular.
198 //! Box vectors of a single grid cell.
200 //! The reciprocal cell vectors as columns; the inverse of \p cellbox.
202 //! Number of cells along each dimension.
204 //! Data structure to hold the grid cell contents.
206 //! Number of neighboring cells to consider.
208 //! Offsets of the neighboring cells to consider.
210 //! Allocation count for \p gnboffs.
213 tMPI::mutex createPairSearchMutex_;
214 PairSearchList pairSearchList_;
216 friend class AnalysisNeighborhoodPairSearchImpl;
218 GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisNeighborhoodSearchImpl);
221 class AnalysisNeighborhoodPairSearchImpl
224 explicit AnalysisNeighborhoodPairSearchImpl(const AnalysisNeighborhoodSearchImpl &search)
227 testExclusionIds_ = NULL;
231 clear_ivec(testcell_);
235 //! Initializes a search to find reference positions neighboring \p x.
236 void startSearch(const AnalysisNeighborhoodPositions &positions);
237 //! Searches for the next neighbor.
238 template <class Action>
239 bool searchNext(Action action);
240 //! Initializes a pair representing the pair found by searchNext().
241 void initFoundPair(AnalysisNeighborhoodPair *pair) const;
242 //! Advances to the next test position, skipping any remaining pairs.
243 void nextTestPosition();
246 //! Clears the loop indices.
247 void reset(int testIndex);
248 //! Checks whether a reference positiong should be excluded.
249 bool isExcluded(int j);
251 //! Parent search object.
252 const AnalysisNeighborhoodSearchImpl &search_;
253 //! Reference to the test positions.
254 ConstArrayRef<rvec> testPositions_;
255 //! Reference to the test exclusion indices.
256 const int *testExclusionIds_;
257 //! Number of excluded reference positions for current test particle.
259 //! Exclusions for current test particle.
261 //! Index of the currently active test position in \p testPositions_.
263 //! Stores test position during a pair loop.
265 //! Stores the previous returned position during a pair loop.
267 //! Stores the pair distance corresponding to previ_;
269 //! Stores the current exclusion index during loops.
271 //! Stores the test particle cell index during loops.
273 //! Stores the current cell neighbor index during pair loops.
275 //! Stores the index within the current cell during pair loops.
278 GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisNeighborhoodPairSearchImpl);
281 /********************************************************************
282 * AnalysisNeighborhoodSearchImpl
285 AnalysisNeighborhoodSearchImpl::AnalysisNeighborhoodSearchImpl(real cutoff)
291 cutoff_ = GMX_REAL_MAX;
294 cutoff2_ = sqr(cutoff_);
299 refExclusionIds_ = NULL;
300 std::memset(&pbc_, 0, sizeof(pbc_));
308 clear_mat(recipcell_);
309 clear_ivec(ncelldim_);
316 AnalysisNeighborhoodSearchImpl::~AnalysisNeighborhoodSearchImpl()
318 PairSearchList::const_iterator i;
319 for (i = pairSearchList_.begin(); i != pairSearchList_.end(); ++i)
321 GMX_RELEASE_ASSERT(i->unique(),
322 "Dangling AnalysisNeighborhoodPairSearch reference");
328 AnalysisNeighborhoodSearchImpl::PairSearchImplPointer
329 AnalysisNeighborhoodSearchImpl::getPairSearch()
331 tMPI::lock_guard<tMPI::mutex> lock(createPairSearchMutex_);
332 // TODO: Consider whether this needs to/can be faster, e.g., by keeping a
333 // separate pool of unused search objects.
334 PairSearchList::const_iterator i;
335 for (i = pairSearchList_.begin(); i != pairSearchList_.end(); ++i)
342 PairSearchImplPointer pairSearch(new AnalysisNeighborhoodPairSearchImpl(*this));
343 pairSearchList_.push_back(pairSearch);
347 void AnalysisNeighborhoodSearchImpl::initGridCellNeighborList()
349 int maxx, maxy, maxz;
352 /* Find the extent of the sphere in triclinic coordinates */
353 maxz = static_cast<int>(cutoff_ * recipcell_[ZZ][ZZ]) + 1;
354 rvnorm = sqrt(sqr(recipcell_[YY][YY]) + sqr(recipcell_[ZZ][YY]));
355 maxy = static_cast<int>(cutoff_ * rvnorm) + 1;
356 rvnorm = sqrt(sqr(recipcell_[XX][XX]) + sqr(recipcell_[YY][XX])
357 + sqr(recipcell_[ZZ][XX]));
358 maxx = static_cast<int>(cutoff_ * rvnorm) + 1;
360 /* Calculate the number of cells and reallocate if necessary */
361 ngridnb_ = (2 * maxx + 1) * (2 * maxy + 1) * (2 * maxz + 1);
362 if (gnboffs_nalloc_ < ngridnb_)
364 gnboffs_nalloc_ = ngridnb_;
365 srenew(gnboffs_, gnboffs_nalloc_);
368 /* Store the whole cube */
369 /* TODO: Prune off corners that are not needed */
371 for (int x = -maxx; x <= maxx; ++x)
373 for (int y = -maxy; y <= maxy; ++y)
375 for (int z = -maxz; z <= maxz; ++z)
386 bool AnalysisNeighborhoodSearchImpl::initGridCells(const t_pbc &pbc)
388 const real targetsize =
389 pow(pbc.box[XX][XX] * pbc.box[YY][YY] * pbc.box[ZZ][ZZ]
390 * 10 / nref_, static_cast<real>(1./3.));
393 for (int dd = 0; dd < DIM; ++dd)
395 ncelldim_[dd] = static_cast<int>(pbc.box[dd][dd] / targetsize);
396 cellCount *= ncelldim_[dd];
397 if (ncelldim_[dd] < 3)
402 // Never decrease the size of the cell vector to avoid reallocating
403 // memory for the nested vectors. The actual size of the vector is not
404 // used outside this function.
405 if (cells_.size() < static_cast<size_t>(cellCount))
407 cells_.resize(cellCount);
409 for (int ci = 0; ci < cellCount; ++ci)
416 bool AnalysisNeighborhoodSearchImpl::initGrid(const t_pbc &pbc)
418 /* TODO: This check could be improved. */
419 if (0.5*pbc.max_cutoff2 < cutoff2_)
424 if (!initGridCells(pbc))
429 bTric_ = TRICLINIC(pbc.box);
432 for (int dd = 0; dd < DIM; ++dd)
434 svmul(1.0 / ncelldim_[dd], pbc.box[dd], cellbox_[dd]);
436 m_inv_ur0(cellbox_, recipcell_);
440 for (int dd = 0; dd < DIM; ++dd)
442 cellbox_[dd][dd] = pbc.box[dd][dd] / ncelldim_[dd];
443 recipcell_[dd][dd] = 1.0 / cellbox_[dd][dd];
446 initGridCellNeighborList();
450 void AnalysisNeighborhoodSearchImpl::mapPointToGridCell(const rvec x,
459 tmvmul_ur0(recipcell_, xtmp, tx);
460 for (int dd = 0; dd < DIM; ++dd)
462 const int cellCount = ncelldim_[dd];
463 int cellIndex = static_cast<int>(floor(tx[dd]));
464 while (cellIndex < 0)
466 cellIndex += cellCount;
467 rvec_add(xtmp, pbc_.box[dd], xtmp);
469 while (cellIndex >= cellCount)
471 cellIndex -= cellCount;
472 rvec_sub(xtmp, pbc_.box[dd], xtmp);
474 cell[dd] = cellIndex;
479 for (int dd = 0; dd < DIM; ++dd)
481 const int cellCount = ncelldim_[dd];
482 int cellIndex = static_cast<int>(floor(xtmp[dd] * recipcell_[dd][dd]));
483 while (cellIndex < 0)
485 cellIndex += cellCount;
486 xtmp[dd] += pbc_.box[dd][dd];
488 while (cellIndex >= cellCount)
490 cellIndex -= cellCount;
491 xtmp[dd] -= pbc_.box[dd][dd];
493 cell[dd] = cellIndex;
496 copy_rvec(xtmp, xout);
499 int AnalysisNeighborhoodSearchImpl::getGridCellIndex(const ivec cell) const
501 GMX_ASSERT(cell[XX] >= 0 && cell[XX] < ncelldim_[XX],
502 "Grid cell X index out of range");
503 GMX_ASSERT(cell[YY] >= 0 && cell[YY] < ncelldim_[YY],
504 "Grid cell Y index out of range");
505 GMX_ASSERT(cell[ZZ] >= 0 && cell[ZZ] < ncelldim_[ZZ],
506 "Grid cell Z index out of range");
507 return cell[XX] + cell[YY] * ncelldim_[XX]
508 + cell[ZZ] * ncelldim_[XX] * ncelldim_[YY];
511 void AnalysisNeighborhoodSearchImpl::addToGridCell(const ivec cell, int i)
513 const int ci = getGridCellIndex(cell);
514 cells_[ci].push_back(i);
517 int AnalysisNeighborhoodSearchImpl::getNeighboringCell(
518 const ivec sourceCell, int index, rvec shift) const
521 ivec_add(sourceCell, gnboffs_[index], cell);
523 // TODO: Consider unifying with the similar shifting code in
524 // mapPointToGridCell().
526 for (int d = 0; d < DIM; ++d)
528 const int cellCount = ncelldim_[d];
531 cell[d] += cellCount;
532 rvec_add(shift, pbc_.box[d], shift);
534 else if (cell[d] >= cellCount)
536 cell[d] -= cellCount;
537 rvec_sub(shift, pbc_.box[d], shift);
541 return getGridCellIndex(cell);
544 void AnalysisNeighborhoodSearchImpl::init(
545 AnalysisNeighborhood::SearchMode mode,
547 const t_blocka *excls,
549 const AnalysisNeighborhoodPositions &positions)
551 GMX_RELEASE_ASSERT(positions.index_ == -1,
552 "Individual indexed positions not supported as reference");
554 if (bXY_ && pbc->ePBC != epbcNONE)
556 if (pbc->ePBC != epbcXY && pbc->ePBC != epbcXYZ)
558 std::string message =
559 formatString("Computations in the XY plane are not supported with PBC type '%s'",
561 GMX_THROW(NotImplementedError(message));
563 if (std::fabs(pbc->box[ZZ][XX]) > GMX_REAL_EPS*pbc->box[ZZ][ZZ] ||
564 std::fabs(pbc->box[ZZ][YY]) > GMX_REAL_EPS*pbc->box[ZZ][ZZ])
566 GMX_THROW(NotImplementedError("Computations in the XY plane are not supported when the last box vector is not parallel to the Z axis"));
568 set_pbc(&pbc_, epbcXY, const_cast<rvec *>(pbc->box));
570 else if (pbc != NULL)
576 pbc_.ePBC = epbcNONE;
578 nref_ = positions.count_;
579 // TODO: Consider whether it would be possible to support grid searching in
581 if (mode == AnalysisNeighborhood::eSearchMode_Simple
582 || pbc_.ePBC != epbcXYZ)
588 // TODO: Actually implement forcing eSearchMode_Grid
589 bGrid_ = initGrid(pbc_);
593 if (xref_nalloc_ < nref_)
595 srenew(xref_alloc_, nref_);
596 xref_nalloc_ = nref_;
600 for (int i = 0; i < nref_; ++i)
603 mapPointToGridCell(positions.x_[i], refcell, xref_alloc_[i]);
604 addToGridCell(refcell, i);
609 xref_ = positions.x_;
612 refExclusionIds_ = NULL;
615 // TODO: Check that the IDs are ascending, or remove the limitation.
616 refExclusionIds_ = positions.exclusionIds_;
617 GMX_RELEASE_ASSERT(refExclusionIds_ != NULL,
618 "Exclusion IDs must be set for reference positions "
619 "when exclusions are enabled");
623 /********************************************************************
624 * AnalysisNeighborhoodPairSearchImpl
627 void AnalysisNeighborhoodPairSearchImpl::reset(int testIndex)
629 testIndex_ = testIndex;
630 if (testIndex_ >= 0 && testIndex_ < static_cast<int>(testPositions_.size()))
632 copy_rvec(testPositions_[testIndex_], xtest_);
635 search_.mapPointToGridCell(testPositions_[testIndex], testcell_, xtest_);
639 copy_rvec(testPositions_[testIndex_], xtest_);
641 if (search_.excls_ != NULL)
643 const int exclIndex = testExclusionIds_[testIndex];
644 if (exclIndex < search_.excls_->nr)
646 const int startIndex = search_.excls_->index[exclIndex];
647 nexcl_ = search_.excls_->index[exclIndex + 1] - startIndex;
648 excl_ = &search_.excls_->a[startIndex];
664 void AnalysisNeighborhoodPairSearchImpl::nextTestPosition()
666 if (testIndex_ < static_cast<int>(testPositions_.size()))
673 bool AnalysisNeighborhoodPairSearchImpl::isExcluded(int j)
675 if (exclind_ < nexcl_)
677 const int refId = search_.refExclusionIds_[j];
678 while (exclind_ < nexcl_ && excl_[exclind_] < refId)
682 if (exclind_ < nexcl_ && refId == excl_[exclind_])
691 void AnalysisNeighborhoodPairSearchImpl::startSearch(
692 const AnalysisNeighborhoodPositions &positions)
694 testExclusionIds_ = positions.exclusionIds_;
695 GMX_RELEASE_ASSERT(search_.excls_ == NULL || testExclusionIds_ != NULL,
696 "Exclusion IDs must be set when exclusions are enabled");
697 if (positions.index_ < 0)
699 testPositions_ = constArrayRefFromArray<rvec>(positions.x_, positions.count_);
704 // Somewhat of a hack: setup the array such that only the last position
706 testPositions_ = constArrayRefFromArray<rvec>(positions.x_, positions.index_ + 1);
707 reset(positions.index_);
711 template <class Action>
712 bool AnalysisNeighborhoodPairSearchImpl::searchNext(Action action)
714 while (testIndex_ < static_cast<int>(testPositions_.size()))
718 GMX_RELEASE_ASSERT(!search_.bXY_, "Grid-based XY searches not implemented");
721 int cai = prevcai_ + 1;
723 for (; nbi < search_.ngridnb_; ++nbi)
726 const int ci = search_.getNeighboringCell(testcell_, nbi, shift);
727 const int cellSize = static_cast<int>(search_.cells_[ci].size());
728 for (; cai < cellSize; ++cai)
730 const int i = search_.cells_[ci][cai];
736 rvec_sub(xtest_, search_.xref_[i], dx);
737 rvec_add(dx, shift, dx);
738 const real r2 = norm2(dx);
739 if (r2 <= search_.cutoff2_)
757 for (int i = previ_ + 1; i < search_.nref_; ++i)
764 if (search_.pbc_.ePBC != epbcNONE)
766 pbc_dx(&search_.pbc_, xtest_, search_.xref_[i], dx);
770 rvec_sub(xtest_, search_.xref_[i], dx);
774 ? dx[XX]*dx[XX] + dx[YY]*dx[YY]
776 if (r2 <= search_.cutoff2_)
792 void AnalysisNeighborhoodPairSearchImpl::initFoundPair(
793 AnalysisNeighborhoodPair *pair) const
797 *pair = AnalysisNeighborhoodPair();
801 *pair = AnalysisNeighborhoodPair(previ_, testIndex_, prevr2_);
805 } // namespace internal
811 * Search action to find the next neighbor.
813 * Used as the action for AnalysisNeighborhoodPairSearchImpl::searchNext() to
814 * find the next neighbor.
816 * Simply breaks the loop on the first found neighbor.
818 bool withinAction(int /*i*/, real /*r2*/)
824 * Search action find the minimum distance.
826 * Used as the action for AnalysisNeighborhoodPairSearchImpl::searchNext() to
827 * find the nearest neighbor.
829 * With this action, AnalysisNeighborhoodPairSearchImpl::searchNext() always
830 * returns false, and the output is put into the variables passed by pointer
831 * into the constructor. If no neighbors are found, the output variables are
832 * not modified, i.e., the caller must initialize them.
838 * Initializes the action with given output locations.
840 * \param[out] closestPoint Index of the closest reference location.
841 * \param[out] minDist2 Minimum distance squared.
843 * The constructor call does not modify the pointed values, but only
844 * stores the pointers for later use.
845 * See the class description for additional semantics.
847 MindistAction(int *closestPoint, real *minDist2)
848 : closestPoint_(*closestPoint), minDist2_(*minDist2)
852 //! Processes a neighbor to find the nearest point.
853 bool operator()(int i, real r2)
867 GMX_DISALLOW_ASSIGN(MindistAction);
872 /********************************************************************
873 * AnalysisNeighborhood::Impl
876 class AnalysisNeighborhood::Impl
879 typedef AnalysisNeighborhoodSearch::ImplPointer SearchImplPointer;
880 typedef std::vector<SearchImplPointer> SearchList;
882 Impl() : cutoff_(0), excls_(NULL), mode_(eSearchMode_Automatic), bXY_(false)
887 SearchList::const_iterator i;
888 for (i = searchList_.begin(); i != searchList_.end(); ++i)
890 GMX_RELEASE_ASSERT(i->unique(),
891 "Dangling AnalysisNeighborhoodSearch reference");
895 SearchImplPointer getSearch();
897 tMPI::mutex createSearchMutex_;
898 SearchList searchList_;
900 const t_blocka *excls_;
905 AnalysisNeighborhood::Impl::SearchImplPointer
906 AnalysisNeighborhood::Impl::getSearch()
908 tMPI::lock_guard<tMPI::mutex> lock(createSearchMutex_);
909 // TODO: Consider whether this needs to/can be faster, e.g., by keeping a
910 // separate pool of unused search objects.
911 SearchList::const_iterator i;
912 for (i = searchList_.begin(); i != searchList_.end(); ++i)
919 SearchImplPointer search(new internal::AnalysisNeighborhoodSearchImpl(cutoff_));
920 searchList_.push_back(search);
924 /********************************************************************
925 * AnalysisNeighborhood
928 AnalysisNeighborhood::AnalysisNeighborhood()
933 AnalysisNeighborhood::~AnalysisNeighborhood()
937 void AnalysisNeighborhood::setCutoff(real cutoff)
939 GMX_RELEASE_ASSERT(impl_->searchList_.empty(),
940 "Changing the cutoff after initSearch() not currently supported");
941 impl_->cutoff_ = cutoff;
944 void AnalysisNeighborhood::setXYMode(bool bXY)
949 void AnalysisNeighborhood::setTopologyExclusions(const t_blocka *excls)
951 GMX_RELEASE_ASSERT(impl_->searchList_.empty(),
952 "Changing the exclusions after initSearch() not currently supported");
953 impl_->excls_ = excls;
956 void AnalysisNeighborhood::setMode(SearchMode mode)
961 AnalysisNeighborhood::SearchMode AnalysisNeighborhood::mode() const
966 AnalysisNeighborhoodSearch
967 AnalysisNeighborhood::initSearch(const t_pbc *pbc,
968 const AnalysisNeighborhoodPositions &positions)
970 Impl::SearchImplPointer search(impl_->getSearch());
971 search->init(mode(), impl_->bXY_, impl_->excls_, pbc, positions);
972 return AnalysisNeighborhoodSearch(search);
975 /********************************************************************
976 * AnalysisNeighborhoodSearch
979 AnalysisNeighborhoodSearch::AnalysisNeighborhoodSearch()
983 AnalysisNeighborhoodSearch::AnalysisNeighborhoodSearch(const ImplPointer &impl)
988 void AnalysisNeighborhoodSearch::reset()
993 AnalysisNeighborhood::SearchMode AnalysisNeighborhoodSearch::mode() const
995 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
996 return (impl_->usesGridSearch()
997 ? AnalysisNeighborhood::eSearchMode_Grid
998 : AnalysisNeighborhood::eSearchMode_Simple);
1001 bool AnalysisNeighborhoodSearch::isWithin(
1002 const AnalysisNeighborhoodPositions &positions) const
1004 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1005 internal::AnalysisNeighborhoodPairSearchImpl pairSearch(*impl_);
1006 pairSearch.startSearch(positions);
1007 return pairSearch.searchNext(&withinAction);
1010 real AnalysisNeighborhoodSearch::minimumDistance(
1011 const AnalysisNeighborhoodPositions &positions) const
1013 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1014 internal::AnalysisNeighborhoodPairSearchImpl pairSearch(*impl_);
1015 pairSearch.startSearch(positions);
1016 real minDist2 = impl_->cutoffSquared();
1017 int closestPoint = -1;
1018 MindistAction action(&closestPoint, &minDist2);
1019 (void)pairSearch.searchNext(action);
1020 return sqrt(minDist2);
1023 AnalysisNeighborhoodPair
1024 AnalysisNeighborhoodSearch::nearestPoint(
1025 const AnalysisNeighborhoodPositions &positions) const
1027 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1028 internal::AnalysisNeighborhoodPairSearchImpl pairSearch(*impl_);
1029 pairSearch.startSearch(positions);
1030 real minDist2 = impl_->cutoffSquared();
1031 int closestPoint = -1;
1032 MindistAction action(&closestPoint, &minDist2);
1033 (void)pairSearch.searchNext(action);
1034 return AnalysisNeighborhoodPair(closestPoint, 0, minDist2);
1037 AnalysisNeighborhoodPairSearch
1038 AnalysisNeighborhoodSearch::startPairSearch(
1039 const AnalysisNeighborhoodPositions &positions) const
1041 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1042 Impl::PairSearchImplPointer pairSearch(impl_->getPairSearch());
1043 pairSearch->startSearch(positions);
1044 return AnalysisNeighborhoodPairSearch(pairSearch);
1047 /********************************************************************
1048 * AnalysisNeighborhoodPairSearch
1051 AnalysisNeighborhoodPairSearch::AnalysisNeighborhoodPairSearch(
1052 const ImplPointer &impl)
1057 bool AnalysisNeighborhoodPairSearch::findNextPair(AnalysisNeighborhoodPair *pair)
1059 bool bFound = impl_->searchNext(&withinAction);
1060 impl_->initFoundPair(pair);
1064 void AnalysisNeighborhoodPairSearch::skipRemainingPairsForTestPosition()
1066 impl_->nextTestPosition();