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.
36 * \brief API for neighborhood searching for analysis.
38 * The main part of the API is the class gmx::AnalysisNeighborhood.
39 * See the class documentation for usage.
41 * The classes within this file can be used independently of the other parts
43 * The library also uses the classes internally.
45 * \author Teemu Murtola <teemu.murtola@gmail.com>
47 * \ingroup module_selection
49 #ifndef GMX_SELECTION_NBSEARCH_H
50 #define GMX_SELECTION_NBSEARCH_H
52 #include <boost/shared_ptr.hpp>
54 #include "../math/vectypes.h"
55 #include "../utility/common.h"
56 #include "../utility/gmxassert.h"
57 #include "../utility/real.h"
66 class AnalysisNeighborhoodSearchImpl;
67 class AnalysisNeighborhoodPairSearchImpl;
70 class AnalysisNeighborhoodSearch;
71 class AnalysisNeighborhoodPairSearch;
74 * Input positions for neighborhood searching.
76 * This class supports uniformly specifying sets of positions for various
77 * methods in the analysis neighborhood searching classes
78 * (AnalysisNeighborhood and AnalysisNeighborhoodSearch).
80 * Note that copies are not made: only a reference to the positions passed to
81 * the constructors are kept. The caller is responsible to ensure that those
82 * positions remain in scope as long as the neighborhood search object requires
85 * Also note that in addition to constructors here, Selection and
86 * SelectionPosition provide conversions operators to this type. It is done
87 * this way to not introduce a cyclic dependency between the selection code and
88 * the neighborhood search code, which in turn allows splitting this search
89 * code into a separate lower-level module if desired at some point.
91 * Methods in this class do not throw.
94 * \ingroup module_selection
96 class AnalysisNeighborhoodPositions
100 * Initializes positions from a single position vector.
102 * For positions initialized this way, AnalysisNeighborhoodPair always
103 * returns zero in the corresponding index.
105 * This constructor is not explicit to allow directly passing an rvec
106 * to methods that accept positions.
108 AnalysisNeighborhoodPositions(const rvec &x)
109 : count_(1), index_(-1), x_(&x)
113 * Initializes positions from an array of position vectors.
115 AnalysisNeighborhoodPositions(const rvec x[], int count)
116 : count_(count), index_(-1), x_(x)
121 * Selects a single position to use from an array.
123 * If called, a single position from the array of positions passed to
124 * the constructor is used instead of the whole array.
125 * In contrast to the AnalysisNeighborhoodPositions(const rvec &)
126 * constructor, AnalysisNeighborhoodPair objects return \p index
129 AnalysisNeighborhoodPositions &selectSingleFromArray(int index)
131 GMX_ASSERT(index >= 0 && index < count_, "Invalid position index");
141 //! To access the positions for initialization.
142 friend class internal::AnalysisNeighborhoodSearchImpl;
143 //! To access the positions for initialization.
144 friend class internal::AnalysisNeighborhoodPairSearchImpl;
148 * Neighborhood searching for analysis tools.
150 * This class implements neighborhood searching routines for analysis tools.
151 * The emphasis is in flexibility and ease of use; one main driver is to have
152 * a common implementation of grid-based searching to avoid replicating this in
153 * multiple tools (and to make more tools take advantage of the significant
154 * performance improvement this allows).
156 * To use the search, create an object of this type, call setCutoff() to
157 * initialize it, and then repeatedly call initSearch() to start a search with
158 * different sets of reference positions. For each set of reference positions,
159 * use methods in the returned AnalysisNeighborhoodSearch to find the reference
160 * positions that are within the given cutoff from a provided position.
162 * initSearch() is thread-safe and can be called from multiple threads. Each
163 * call returns a different instance of the search object that can be used
164 * independently of the others. The returned AnalysisNeighborhoodSearch
165 * objects are also thread-safe, and can be used concurrently from multiple
166 * threads. It is also possible to create multiple concurrent searches within
170 * Support for exclusions.
171 * The 4.5/4.6 C API had very low-level support for exclusions, which was not
172 * very convenient to use, and hadn't been tested much. The internal code that
173 * it used to do the exclusion during the search itself is still there, but it
174 * needs more thought on what would be a convenient way to initialize it.
175 * Can be implemented once there is need for it in some calling code.
178 * \ingroup module_selection
180 class AnalysisNeighborhood
183 //! Searching algorithm to use.
186 //! Select algorithm based on heuristic efficiency considerations.
187 eSearchMode_Automatic,
188 //! Use a simple loop over all pairs.
190 //! Use grid-based searching whenever possible.
194 //! Creates an uninitialized neighborhood search.
195 AnalysisNeighborhood();
196 ~AnalysisNeighborhood();
199 * Set cutoff distance for the neighborhood searching.
201 * \param[in] cutoff Cutoff distance for the search
202 * (<=0 stands for no cutoff).
204 * Currently, can only be called before the first call to initSearch().
205 * If this method is not called, no cutoff is used in the searches.
209 void setCutoff(real cutoff);
211 * Sets the algorithm to use for searching.
213 * \param[in] mode Search mode to use.
215 * Note that if \p mode is \ref eSearchMode_Grid, it is still only a
216 * suggestion: grid-based searching may not be possible with the
217 * provided input, in which case a simple search is still used.
218 * This is mainly useful for testing purposes to force a mode.
222 void setMode(SearchMode mode);
223 //! Returns the currently active search mode.
224 SearchMode mode() const;
227 * Initializes neighborhood search for a set of positions.
229 * \param[in] pbc PBC information for the frame.
230 * \param[in] positions Set of reference positions to use.
231 * \returns Search object that can be used to find positions from
232 * \p x within the given cutoff.
233 * \throws std::bad_alloc if out of memory.
235 * Currently, the input positions cannot use
236 * AnalysisNeighborhoodPositions::selectSingleFromArray().
238 AnalysisNeighborhoodSearch
239 initSearch(const t_pbc *pbc,
240 const AnalysisNeighborhoodPositions &positions);
245 PrivateImplPointer<Impl> impl_;
249 * Value type to represent a pair of positions found in neighborhood searching.
251 * Methods in this class do not throw.
254 * \ingroup module_selection
256 class AnalysisNeighborhoodPair
259 //! Initializes an invalid pair.
260 AnalysisNeighborhoodPair() : refIndex_(-1), testIndex_(0) {}
261 //! Initializes a pair object with the given data.
262 AnalysisNeighborhoodPair(int refIndex, int testIndex)
263 : refIndex_(refIndex), testIndex_(testIndex)
268 * Whether this pair is valid.
270 * If isValid() returns false, other methods should not be called.
272 bool isValid() const { return refIndex_ >= 0; }
275 * Returns the index of the reference position in the pair.
277 * This index is always the index into the position array provided to
278 * AnalysisNeighborhood::initSearch().
282 GMX_ASSERT(isValid(), "Accessing invalid object");
286 * Returns the index of the test position in the pair.
288 * The contents of this index depends on the context (method call) that
290 * If there was no array in the call, this index is zero.
292 int testIndex() const
294 GMX_ASSERT(isValid(), "Accessing invalid object");
304 * Initialized neighborhood search with a fixed set of reference positions.
306 * An instance of this class is obtained through
307 * AnalysisNeighborhood::initSearch(), and can be used to do multiple searches
308 * against the provided set of reference positions.
309 * It is possible to create concurrent pair searches (including from different
310 * threads), as well as call other methods in this class while a pair search is
313 * This class works like a pointer: copies of it point to the same search.
314 * In general, avoid creating copies, and only use the copy/assignment support
315 * for moving the variable around. With C++11, this class would best be
318 * Methods in this class do not throw unless otherwise indicated.
321 * Make it such that reset() is not necessary to call in code that repeatedly
322 * assigns the result of AnalysisNeighborhood::initSearch() to the same
323 * variable (see sm_distance.cpp).
326 * Consider merging nearestPoint() and minimumDistance() by adding the distance
327 * to AnalysisNeighborhoodPair.
330 * \ingroup module_selection
332 class AnalysisNeighborhoodSearch
336 * Internal short-hand type for a pointer to the implementation class.
338 * shared_ptr is used here to automatically keep a reference count to
339 * track whether an implementation class is still used outside the
340 * AnalysisNeighborhood object. Ownership currently always stays with
341 * AnalysisNeighborhood; it always keeps one instance of the pointer.
343 typedef boost::shared_ptr<internal::AnalysisNeighborhoodSearchImpl>
347 * Initializes an invalid search.
349 * Such an object cannot be used for searching. It needs to be
350 * assigned a value from AnalysisNeighborhood::initSearch() before it
351 * can be used. Provided to allow declaring a variable to hold the
352 * search before calling AnalysisNeighborhood::initSearch().
354 AnalysisNeighborhoodSearch();
356 * Internally initialize the search.
358 * Used to implement AnalysisNeighborhood::initSearch().
359 * Cannot be called from user code.
361 explicit AnalysisNeighborhoodSearch(const ImplPointer &impl);
364 * Clears this search.
366 * Equivalent to \c "*this = AnalysisNeighborhoodSearch();".
367 * Currently, this is necessary to avoid unnecessary memory allocation
368 * if the previous search variable is still in scope when you want to
369 * call AnalysisNeighborhood::initSearch() again.
374 * Returns the searching algorithm that this search is using.
376 * The return value is never AnalysisNeighborhood::eSearchMode_Automatic.
378 AnalysisNeighborhood::SearchMode mode() const;
381 * Check whether a point is within a neighborhood.
383 * \param[in] positions Set of test positions to use.
384 * \returns true if any of the test positions is within the cutoff of
385 * any reference position.
387 bool isWithin(const AnalysisNeighborhoodPositions &positions) const;
389 * Calculates the minimum distance from the reference points.
391 * \param[in] positions Set of test positions to use.
392 * \returns The distance to the nearest reference position, or the
393 * cutoff value if there are no reference positions within the
396 real minimumDistance(const AnalysisNeighborhoodPositions &positions) const;
398 * Finds the closest reference point.
400 * \param[in] positions Set of test positions to use.
401 * \returns The reference index identifies the reference position
402 * that is closest to the test positions.
403 * The test index identifies the test position that is closest to
404 * the provided test position. The returned pair is invalid if
405 * no reference position is within the cutoff.
407 AnalysisNeighborhoodPair
408 nearestPoint(const AnalysisNeighborhoodPositions &positions) const;
411 * Start a search to find reference positions within a cutoff.
413 * \param[in] positions Set of test positions to use.
414 * \returns Initialized search object to loop through all reference
415 * positions within the configured cutoff.
416 * \throws std::bad_alloc if out of memory.
418 AnalysisNeighborhoodPairSearch
419 startPairSearch(const AnalysisNeighborhoodPositions &positions) const;
422 typedef internal::AnalysisNeighborhoodSearchImpl Impl;
428 * Initialized neighborhood pair search with a fixed set of positions.
430 * This class is used to loop through pairs of neighbors within the cutoff
431 * provided to AnalysisNeighborhood. The following code demonstrates its use:
433 gmx::AnalysisNeighborhood nb;
434 nb.setCutoff(cutoff);
435 gmx::AnalysisNeighborhoodPositions refPos(xref, nref);
436 gmx::AnalysisNeighborhoodSearch search = nb.initSearch(pbc, refPos);
437 gmx::AnalysisNeighborhoodPairSearch pairSearch = search.startPairSearch(selection);
438 gmx::AnalysisNeighborhoodPair pair;
439 while (pairSearch.findNextPair(&pair))
441 // <do something for each found pair the information in pair>
445 * It is not possible to use a single search object from multiple threads
448 * This class works like a pointer: copies of it point to the same search.
449 * In general, avoid creating copies, and only use the copy/assignment support
450 * for moving the variable around. With C++11, this class would best be
453 * Methods in this class do not throw.
456 * \ingroup module_selection
458 class AnalysisNeighborhoodPairSearch
462 * Internal short-hand type for a pointer to the implementation class.
464 * See AnalysisNeighborhoodSearch::ImplPointer for rationale of using
465 * shared_ptr and ownership semantics.
467 typedef boost::shared_ptr<internal::AnalysisNeighborhoodPairSearchImpl>
471 * Internally initialize the search.
473 * Used to implement AnalysisNeighborhoodSearch::startPairSearch().
474 * Cannot be called from user code.
476 explicit AnalysisNeighborhoodPairSearch(const ImplPointer &impl);
479 * Finds the next pair within the cutoff.
481 * \param[out] pair Information about the found pair.
482 * \returns false if there were no more pairs.
484 * If the method returns false, \p pair will be invalid.
486 * \see AnalysisNeighborhoodPair
487 * \see AnalysisNeighborhoodSearch::startPairSearch()
489 bool findNextPair(AnalysisNeighborhoodPair *pair);
491 * Skip remaining pairs for a test position in the search.
493 * When called after findNextPair(), makes subsequent calls to
494 * findNextPair() skip any pairs that have the same test position as
495 * that previously returned.
496 * This is useful if the caller wants to search whether any reference
497 * position within the cutoff satisfies some condition. This method
498 * can be used to skip remaining pairs after the first such position
499 * has been found if the remaining pairs would not have an effect on
502 void skipRemainingPairsForTestPosition();