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
65 #include "thread_mpi/mutex.h"
67 #include "gromacs/legacyheaders/names.h"
68 #include "gromacs/math/vec.h"
69 #include "gromacs/pbcutil/pbc.h"
70 #include "gromacs/selection/position.h"
71 #include "gromacs/topology/block.h"
72 #include "gromacs/utility/arrayref.h"
73 #include "gromacs/utility/exceptions.h"
74 #include "gromacs/utility/gmxassert.h"
75 #include "gromacs/utility/smalloc.h"
76 #include "gromacs/utility/stringutil.h"
84 /********************************************************************
85 * Implementation class declarations
88 class AnalysisNeighborhoodSearchImpl
91 typedef AnalysisNeighborhoodPairSearch::ImplPointer
92 PairSearchImplPointer;
93 typedef std::vector<PairSearchImplPointer> PairSearchList;
94 typedef std::vector<std::vector<int> > CellList;
96 explicit AnalysisNeighborhoodSearchImpl(real cutoff);
97 ~AnalysisNeighborhoodSearchImpl();
100 * Initializes the search with a given box and reference positions.
102 * \param[in] mode Search mode to use.
103 * \param[in] bXY Whether to use 2D searching.
104 * \param[in] excls Exclusions.
105 * \param[in] pbc PBC information.
106 * \param[in] positions Set of reference positions.
108 void init(AnalysisNeighborhood::SearchMode mode,
110 const t_blocka *excls,
112 const AnalysisNeighborhoodPositions &positions);
113 PairSearchImplPointer getPairSearch();
115 real cutoffSquared() const { return cutoff2_; }
116 bool usesGridSearch() const { return bGrid_; }
119 //! Calculates offsets to neighboring grid cells that should be considered.
120 void initGridCellNeighborList();
122 * Determines a suitable grid size and sets up the cells.
124 * \param[in] pbc Information about the box.
125 * \returns false if grid search is not suitable.
127 bool initGridCells(const t_pbc &pbc);
129 * Sets ua a search grid for a given box.
131 * \param[in] pbc Information about the box.
132 * \returns false if grid search is not suitable.
134 bool initGrid(const t_pbc &pbc);
136 * Maps a point into a grid cell.
138 * \param[in] x Point to map.
139 * \param[out] cell Indices of the grid cell in which \p x lies.
140 * \param[out] xout Coordinates to use
141 * (will be within the triclinic unit cell).
143 void mapPointToGridCell(const rvec x, ivec cell, rvec xout) const;
145 * Calculates linear index of a grid cell.
147 * \param[in] cell Cell indices.
148 * \returns Linear index of \p cell.
150 int getGridCellIndex(const ivec cell) const;
152 * Adds an index into a grid cell.
154 * \param[in] cell Cell into which \p i should be added.
155 * \param[in] i Index to add.
157 void addToGridCell(const ivec cell, int i);
159 * Calculates the index of a neighboring grid cell.
161 * \param[in] sourceCell Location of the source cell.
162 * \param[in] index Index of the neighbor to calculate.
163 * \param[out] shift Shift to apply to get the periodic distance
164 * for distances between the cells.
165 * \returns Grid cell index of the neighboring cell.
167 int getNeighboringCell(const ivec sourceCell, int index, rvec shift) const;
169 //! Whether to try grid searching.
173 //! The cutoff squared.
175 //! Whether to do searching in XY plane only.
178 //! Number of reference points for the current frame.
180 //! Reference point positions.
182 //! Reference position exclusion IDs.
183 const int *refExclusionIds_;
185 const t_blocka *excls_;
189 //! Whether grid searching is actually used for the current positions.
191 //! Array allocated for storing in-unit-cell reference positions.
193 //! Allocation count for xref_alloc.
195 //! false if the box is rectangular.
197 //! Box vectors of a single grid cell.
199 //! The reciprocal cell vectors as columns; the inverse of \p cellbox.
201 //! Number of cells along each dimension.
203 //! Data structure to hold the grid cell contents.
205 //! Number of neighboring cells to consider.
207 //! Offsets of the neighboring cells to consider.
209 //! Allocation count for \p gnboffs.
212 tMPI::mutex createPairSearchMutex_;
213 PairSearchList pairSearchList_;
215 friend class AnalysisNeighborhoodPairSearchImpl;
217 GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisNeighborhoodSearchImpl);
220 class AnalysisNeighborhoodPairSearchImpl
223 explicit AnalysisNeighborhoodPairSearchImpl(const AnalysisNeighborhoodSearchImpl &search)
226 testExclusionIds_ = NULL;
230 clear_ivec(testcell_);
234 //! Initializes a search to find reference positions neighboring \p x.
235 void startSearch(const AnalysisNeighborhoodPositions &positions);
236 //! Searches for the next neighbor.
237 template <class Action>
238 bool searchNext(Action action);
239 //! Initializes a pair representing the pair found by searchNext().
240 void initFoundPair(AnalysisNeighborhoodPair *pair) const;
241 //! Advances to the next test position, skipping any remaining pairs.
242 void nextTestPosition();
245 //! Clears the loop indices.
246 void reset(int testIndex);
247 //! Checks whether a reference positiong should be excluded.
248 bool isExcluded(int j);
250 //! Parent search object.
251 const AnalysisNeighborhoodSearchImpl &search_;
252 //! Reference to the test positions.
253 ConstArrayRef<rvec> testPositions_;
254 //! Reference to the test exclusion indices.
255 const int *testExclusionIds_;
256 //! Number of excluded reference positions for current test particle.
258 //! Exclusions for current test particle.
260 //! Index of the currently active test position in \p testPositions_.
262 //! Stores test position during a pair loop.
264 //! Stores the previous returned position during a pair loop.
266 //! Stores the pair distance corresponding to previ_;
268 //! Stores the current exclusion index during loops.
270 //! Stores the test particle cell index during loops.
272 //! Stores the current cell neighbor index during pair loops.
274 //! Stores the index within the current cell during pair loops.
277 GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisNeighborhoodPairSearchImpl);
280 /********************************************************************
281 * AnalysisNeighborhoodSearchImpl
284 AnalysisNeighborhoodSearchImpl::AnalysisNeighborhoodSearchImpl(real cutoff)
290 cutoff_ = GMX_REAL_MAX;
293 cutoff2_ = sqr(cutoff_);
298 refExclusionIds_ = NULL;
299 std::memset(&pbc_, 0, sizeof(pbc_));
307 clear_mat(recipcell_);
308 clear_ivec(ncelldim_);
315 AnalysisNeighborhoodSearchImpl::~AnalysisNeighborhoodSearchImpl()
317 PairSearchList::const_iterator i;
318 for (i = pairSearchList_.begin(); i != pairSearchList_.end(); ++i)
320 GMX_RELEASE_ASSERT(i->unique(),
321 "Dangling AnalysisNeighborhoodPairSearch reference");
327 AnalysisNeighborhoodSearchImpl::PairSearchImplPointer
328 AnalysisNeighborhoodSearchImpl::getPairSearch()
330 tMPI::lock_guard<tMPI::mutex> lock(createPairSearchMutex_);
331 // TODO: Consider whether this needs to/can be faster, e.g., by keeping a
332 // separate pool of unused search objects.
333 PairSearchList::const_iterator i;
334 for (i = pairSearchList_.begin(); i != pairSearchList_.end(); ++i)
341 PairSearchImplPointer pairSearch(new AnalysisNeighborhoodPairSearchImpl(*this));
342 pairSearchList_.push_back(pairSearch);
346 void AnalysisNeighborhoodSearchImpl::initGridCellNeighborList()
348 int maxx, maxy, maxz;
351 /* Find the extent of the sphere in triclinic coordinates */
352 maxz = static_cast<int>(cutoff_ * recipcell_[ZZ][ZZ]) + 1;
353 rvnorm = sqrt(sqr(recipcell_[YY][YY]) + sqr(recipcell_[ZZ][YY]));
354 maxy = static_cast<int>(cutoff_ * rvnorm) + 1;
355 rvnorm = sqrt(sqr(recipcell_[XX][XX]) + sqr(recipcell_[YY][XX])
356 + sqr(recipcell_[ZZ][XX]));
357 maxx = static_cast<int>(cutoff_ * rvnorm) + 1;
359 /* Calculate the number of cells and reallocate if necessary */
360 ngridnb_ = (2 * maxx + 1) * (2 * maxy + 1) * (2 * maxz + 1);
361 if (gnboffs_nalloc_ < ngridnb_)
363 gnboffs_nalloc_ = ngridnb_;
364 srenew(gnboffs_, gnboffs_nalloc_);
367 /* Store the whole cube */
368 /* TODO: Prune off corners that are not needed */
370 for (int x = -maxx; x <= maxx; ++x)
372 for (int y = -maxy; y <= maxy; ++y)
374 for (int z = -maxz; z <= maxz; ++z)
385 bool AnalysisNeighborhoodSearchImpl::initGridCells(const t_pbc &pbc)
387 const real targetsize =
388 pow(pbc.box[XX][XX] * pbc.box[YY][YY] * pbc.box[ZZ][ZZ]
389 * 10 / nref_, static_cast<real>(1./3.));
392 for (int dd = 0; dd < DIM; ++dd)
394 ncelldim_[dd] = static_cast<int>(pbc.box[dd][dd] / targetsize);
395 cellCount *= ncelldim_[dd];
396 if (ncelldim_[dd] < 3)
401 // Never decrease the size of the cell vector to avoid reallocating
402 // memory for the nested vectors. The actual size of the vector is not
403 // used outside this function.
404 if (cells_.size() < static_cast<size_t>(cellCount))
406 cells_.resize(cellCount);
408 for (int ci = 0; ci < cellCount; ++ci)
415 bool AnalysisNeighborhoodSearchImpl::initGrid(const t_pbc &pbc)
417 /* TODO: This check could be improved. */
418 if (0.5*pbc.max_cutoff2 < cutoff2_)
423 if (!initGridCells(pbc))
428 bTric_ = TRICLINIC(pbc.box);
431 for (int dd = 0; dd < DIM; ++dd)
433 svmul(1.0 / ncelldim_[dd], pbc.box[dd], cellbox_[dd]);
435 m_inv_ur0(cellbox_, recipcell_);
439 for (int dd = 0; dd < DIM; ++dd)
441 cellbox_[dd][dd] = pbc.box[dd][dd] / ncelldim_[dd];
442 recipcell_[dd][dd] = 1.0 / cellbox_[dd][dd];
445 initGridCellNeighborList();
449 void AnalysisNeighborhoodSearchImpl::mapPointToGridCell(const rvec x,
458 tmvmul_ur0(recipcell_, xtmp, tx);
459 for (int dd = 0; dd < DIM; ++dd)
461 const int cellCount = ncelldim_[dd];
462 int cellIndex = static_cast<int>(floor(tx[dd]));
463 while (cellIndex < 0)
465 cellIndex += cellCount;
466 rvec_add(xtmp, pbc_.box[dd], xtmp);
468 while (cellIndex >= cellCount)
470 cellIndex -= cellCount;
471 rvec_sub(xtmp, pbc_.box[dd], xtmp);
473 cell[dd] = cellIndex;
478 for (int dd = 0; dd < DIM; ++dd)
480 const int cellCount = ncelldim_[dd];
481 int cellIndex = static_cast<int>(floor(xtmp[dd] * recipcell_[dd][dd]));
482 while (cellIndex < 0)
484 cellIndex += cellCount;
485 xtmp[dd] += pbc_.box[dd][dd];
487 while (cellIndex >= cellCount)
489 cellIndex -= cellCount;
490 xtmp[dd] -= pbc_.box[dd][dd];
492 cell[dd] = cellIndex;
495 copy_rvec(xtmp, xout);
498 int AnalysisNeighborhoodSearchImpl::getGridCellIndex(const ivec cell) const
500 GMX_ASSERT(cell[XX] >= 0 && cell[XX] < ncelldim_[XX],
501 "Grid cell X index out of range");
502 GMX_ASSERT(cell[YY] >= 0 && cell[YY] < ncelldim_[YY],
503 "Grid cell Y index out of range");
504 GMX_ASSERT(cell[ZZ] >= 0 && cell[ZZ] < ncelldim_[ZZ],
505 "Grid cell Z index out of range");
506 return cell[XX] + cell[YY] * ncelldim_[XX]
507 + cell[ZZ] * ncelldim_[XX] * ncelldim_[YY];
510 void AnalysisNeighborhoodSearchImpl::addToGridCell(const ivec cell, int i)
512 const int ci = getGridCellIndex(cell);
513 cells_[ci].push_back(i);
516 int AnalysisNeighborhoodSearchImpl::getNeighboringCell(
517 const ivec sourceCell, int index, rvec shift) const
520 ivec_add(sourceCell, gnboffs_[index], cell);
522 // TODO: Consider unifying with the similar shifting code in
523 // mapPointToGridCell().
525 for (int d = 0; d < DIM; ++d)
527 const int cellCount = ncelldim_[d];
530 cell[d] += cellCount;
531 rvec_add(shift, pbc_.box[d], shift);
533 else if (cell[d] >= cellCount)
535 cell[d] -= cellCount;
536 rvec_sub(shift, pbc_.box[d], shift);
540 return getGridCellIndex(cell);
543 void AnalysisNeighborhoodSearchImpl::init(
544 AnalysisNeighborhood::SearchMode mode,
546 const t_blocka *excls,
548 const AnalysisNeighborhoodPositions &positions)
550 GMX_RELEASE_ASSERT(positions.index_ == -1,
551 "Individual indexed positions not supported as reference");
553 if (bXY_ && pbc->ePBC != epbcNONE)
555 if (pbc->ePBC != epbcXY && pbc->ePBC != epbcXYZ)
557 std::string message =
558 formatString("Computations in the XY plane are not supported with PBC type '%s'",
560 GMX_THROW(NotImplementedError(message));
562 if (std::fabs(pbc->box[ZZ][XX]) > GMX_REAL_EPS*pbc->box[ZZ][ZZ] ||
563 std::fabs(pbc->box[ZZ][YY]) > GMX_REAL_EPS*pbc->box[ZZ][ZZ])
565 GMX_THROW(NotImplementedError("Computations in the XY plane are not supported when the last box vector is not parallel to the Z axis"));
567 set_pbc(&pbc_, epbcXY, const_cast<rvec *>(pbc->box));
569 else if (pbc != NULL)
575 pbc_.ePBC = epbcNONE;
577 nref_ = positions.count_;
578 // TODO: Consider whether it would be possible to support grid searching in
580 if (mode == AnalysisNeighborhood::eSearchMode_Simple
581 || pbc_.ePBC != epbcXYZ)
587 // TODO: Actually implement forcing eSearchMode_Grid
588 bGrid_ = initGrid(pbc_);
592 if (xref_nalloc_ < nref_)
594 srenew(xref_alloc_, nref_);
595 xref_nalloc_ = nref_;
599 for (int i = 0; i < nref_; ++i)
602 mapPointToGridCell(positions.x_[i], refcell, xref_alloc_[i]);
603 addToGridCell(refcell, i);
608 xref_ = positions.x_;
611 refExclusionIds_ = NULL;
614 // TODO: Check that the IDs are ascending, or remove the limitation.
615 refExclusionIds_ = positions.exclusionIds_;
616 GMX_RELEASE_ASSERT(refExclusionIds_ != NULL,
617 "Exclusion IDs must be set for reference positions "
618 "when exclusions are enabled");
622 /********************************************************************
623 * AnalysisNeighborhoodPairSearchImpl
626 void AnalysisNeighborhoodPairSearchImpl::reset(int testIndex)
628 testIndex_ = testIndex;
629 if (testIndex_ >= 0 && testIndex_ < static_cast<int>(testPositions_.size()))
631 copy_rvec(testPositions_[testIndex_], xtest_);
634 search_.mapPointToGridCell(testPositions_[testIndex], testcell_, xtest_);
638 copy_rvec(testPositions_[testIndex_], xtest_);
640 if (search_.excls_ != NULL)
642 const int exclIndex = testExclusionIds_[testIndex];
643 if (exclIndex < search_.excls_->nr)
645 const int startIndex = search_.excls_->index[exclIndex];
646 nexcl_ = search_.excls_->index[exclIndex + 1] - startIndex;
647 excl_ = &search_.excls_->a[startIndex];
663 void AnalysisNeighborhoodPairSearchImpl::nextTestPosition()
665 if (testIndex_ < static_cast<int>(testPositions_.size()))
672 bool AnalysisNeighborhoodPairSearchImpl::isExcluded(int j)
674 if (exclind_ < nexcl_)
676 const int refId = search_.refExclusionIds_[j];
677 while (exclind_ < nexcl_ && excl_[exclind_] < refId)
681 if (exclind_ < nexcl_ && refId == excl_[exclind_])
690 void AnalysisNeighborhoodPairSearchImpl::startSearch(
691 const AnalysisNeighborhoodPositions &positions)
693 testExclusionIds_ = positions.exclusionIds_;
694 GMX_RELEASE_ASSERT(search_.excls_ == NULL || testExclusionIds_ != NULL,
695 "Exclusion IDs must be set when exclusions are enabled");
696 if (positions.index_ < 0)
698 testPositions_ = constArrayRefFromArray<rvec>(positions.x_, positions.count_);
703 // Somewhat of a hack: setup the array such that only the last position
705 testPositions_ = constArrayRefFromArray<rvec>(positions.x_, positions.index_ + 1);
706 reset(positions.index_);
710 template <class Action>
711 bool AnalysisNeighborhoodPairSearchImpl::searchNext(Action action)
713 while (testIndex_ < static_cast<int>(testPositions_.size()))
717 GMX_RELEASE_ASSERT(!search_.bXY_, "Grid-based XY searches not implemented");
720 int cai = prevcai_ + 1;
722 for (; nbi < search_.ngridnb_; ++nbi)
725 const int ci = search_.getNeighboringCell(testcell_, nbi, shift);
726 const int cellSize = static_cast<int>(search_.cells_[ci].size());
727 for (; cai < cellSize; ++cai)
729 const int i = search_.cells_[ci][cai];
735 rvec_sub(xtest_, search_.xref_[i], dx);
736 rvec_add(dx, shift, dx);
737 const real r2 = norm2(dx);
738 if (r2 <= search_.cutoff2_)
756 for (int i = previ_ + 1; i < search_.nref_; ++i)
763 if (search_.pbc_.ePBC != epbcNONE)
765 pbc_dx(&search_.pbc_, xtest_, search_.xref_[i], dx);
769 rvec_sub(xtest_, search_.xref_[i], dx);
773 ? dx[XX]*dx[XX] + dx[YY]*dx[YY]
775 if (r2 <= search_.cutoff2_)
791 void AnalysisNeighborhoodPairSearchImpl::initFoundPair(
792 AnalysisNeighborhoodPair *pair) const
796 *pair = AnalysisNeighborhoodPair();
800 *pair = AnalysisNeighborhoodPair(previ_, testIndex_, prevr2_);
804 } // namespace internal
810 * Search action to find the next neighbor.
812 * Used as the action for AnalysisNeighborhoodPairSearchImpl::searchNext() to
813 * find the next neighbor.
815 * Simply breaks the loop on the first found neighbor.
817 bool withinAction(int /*i*/, real /*r2*/)
823 * Search action find the minimum distance.
825 * Used as the action for AnalysisNeighborhoodPairSearchImpl::searchNext() to
826 * find the nearest neighbor.
828 * With this action, AnalysisNeighborhoodPairSearchImpl::searchNext() always
829 * returns false, and the output is put into the variables passed by pointer
830 * into the constructor. If no neighbors are found, the output variables are
831 * not modified, i.e., the caller must initialize them.
837 * Initializes the action with given output locations.
839 * \param[out] closestPoint Index of the closest reference location.
840 * \param[out] minDist2 Minimum distance squared.
842 * The constructor call does not modify the pointed values, but only
843 * stores the pointers for later use.
844 * See the class description for additional semantics.
846 MindistAction(int *closestPoint, real *minDist2)
847 : closestPoint_(*closestPoint), minDist2_(*minDist2)
851 //! Processes a neighbor to find the nearest point.
852 bool operator()(int i, real r2)
866 GMX_DISALLOW_ASSIGN(MindistAction);
871 /********************************************************************
872 * AnalysisNeighborhood::Impl
875 class AnalysisNeighborhood::Impl
878 typedef AnalysisNeighborhoodSearch::ImplPointer SearchImplPointer;
879 typedef std::vector<SearchImplPointer> SearchList;
881 Impl() : cutoff_(0), excls_(NULL), mode_(eSearchMode_Automatic), bXY_(false)
886 SearchList::const_iterator i;
887 for (i = searchList_.begin(); i != searchList_.end(); ++i)
889 GMX_RELEASE_ASSERT(i->unique(),
890 "Dangling AnalysisNeighborhoodSearch reference");
894 SearchImplPointer getSearch();
896 tMPI::mutex createSearchMutex_;
897 SearchList searchList_;
899 const t_blocka *excls_;
904 AnalysisNeighborhood::Impl::SearchImplPointer
905 AnalysisNeighborhood::Impl::getSearch()
907 tMPI::lock_guard<tMPI::mutex> lock(createSearchMutex_);
908 // TODO: Consider whether this needs to/can be faster, e.g., by keeping a
909 // separate pool of unused search objects.
910 SearchList::const_iterator i;
911 for (i = searchList_.begin(); i != searchList_.end(); ++i)
918 SearchImplPointer search(new internal::AnalysisNeighborhoodSearchImpl(cutoff_));
919 searchList_.push_back(search);
923 /********************************************************************
924 * AnalysisNeighborhood
927 AnalysisNeighborhood::AnalysisNeighborhood()
932 AnalysisNeighborhood::~AnalysisNeighborhood()
936 void AnalysisNeighborhood::setCutoff(real cutoff)
938 GMX_RELEASE_ASSERT(impl_->searchList_.empty(),
939 "Changing the cutoff after initSearch() not currently supported");
940 impl_->cutoff_ = cutoff;
943 void AnalysisNeighborhood::setXYMode(bool bXY)
948 void AnalysisNeighborhood::setTopologyExclusions(const t_blocka *excls)
950 GMX_RELEASE_ASSERT(impl_->searchList_.empty(),
951 "Changing the exclusions after initSearch() not currently supported");
952 impl_->excls_ = excls;
955 void AnalysisNeighborhood::setMode(SearchMode mode)
960 AnalysisNeighborhood::SearchMode AnalysisNeighborhood::mode() const
965 AnalysisNeighborhoodSearch
966 AnalysisNeighborhood::initSearch(const t_pbc *pbc,
967 const AnalysisNeighborhoodPositions &positions)
969 Impl::SearchImplPointer search(impl_->getSearch());
970 search->init(mode(), impl_->bXY_, impl_->excls_, pbc, positions);
971 return AnalysisNeighborhoodSearch(search);
974 /********************************************************************
975 * AnalysisNeighborhoodSearch
978 AnalysisNeighborhoodSearch::AnalysisNeighborhoodSearch()
982 AnalysisNeighborhoodSearch::AnalysisNeighborhoodSearch(const ImplPointer &impl)
987 void AnalysisNeighborhoodSearch::reset()
992 AnalysisNeighborhood::SearchMode AnalysisNeighborhoodSearch::mode() const
994 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
995 return (impl_->usesGridSearch()
996 ? AnalysisNeighborhood::eSearchMode_Grid
997 : AnalysisNeighborhood::eSearchMode_Simple);
1000 bool AnalysisNeighborhoodSearch::isWithin(
1001 const AnalysisNeighborhoodPositions &positions) const
1003 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1004 internal::AnalysisNeighborhoodPairSearchImpl pairSearch(*impl_);
1005 pairSearch.startSearch(positions);
1006 return pairSearch.searchNext(&withinAction);
1009 real AnalysisNeighborhoodSearch::minimumDistance(
1010 const AnalysisNeighborhoodPositions &positions) const
1012 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1013 internal::AnalysisNeighborhoodPairSearchImpl pairSearch(*impl_);
1014 pairSearch.startSearch(positions);
1015 real minDist2 = impl_->cutoffSquared();
1016 int closestPoint = -1;
1017 MindistAction action(&closestPoint, &minDist2);
1018 (void)pairSearch.searchNext(action);
1019 return sqrt(minDist2);
1022 AnalysisNeighborhoodPair
1023 AnalysisNeighborhoodSearch::nearestPoint(
1024 const AnalysisNeighborhoodPositions &positions) const
1026 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1027 internal::AnalysisNeighborhoodPairSearchImpl pairSearch(*impl_);
1028 pairSearch.startSearch(positions);
1029 real minDist2 = impl_->cutoffSquared();
1030 int closestPoint = -1;
1031 MindistAction action(&closestPoint, &minDist2);
1032 (void)pairSearch.searchNext(action);
1033 return AnalysisNeighborhoodPair(closestPoint, 0, minDist2);
1036 AnalysisNeighborhoodPairSearch
1037 AnalysisNeighborhoodSearch::startPairSearch(
1038 const AnalysisNeighborhoodPositions &positions) const
1040 GMX_RELEASE_ASSERT(impl_, "Accessing an invalid search object");
1041 Impl::PairSearchImplPointer pairSearch(impl_->getPairSearch());
1042 pairSearch->startSearch(positions);
1043 return AnalysisNeighborhoodPairSearch(pairSearch);
1046 /********************************************************************
1047 * AnalysisNeighborhoodPairSearch
1050 AnalysisNeighborhoodPairSearch::AnalysisNeighborhoodPairSearch(
1051 const ImplPointer &impl)
1056 bool AnalysisNeighborhoodPairSearch::findNextPair(AnalysisNeighborhoodPair *pair)
1058 bool bFound = impl_->searchNext(&withinAction);
1059 impl_->initFoundPair(pair);
1063 void AnalysisNeighborhoodPairSearch::skipRemainingPairsForTestPosition()
1065 impl_->nextTestPosition();