2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, 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
54 #include <boost/shared_ptr.hpp>
56 #include "gromacs/math/vec.h"
57 #include "gromacs/math/vectypes.h"
58 #include "gromacs/utility/arrayref.h"
59 #include "gromacs/utility/classhelpers.h"
60 #include "gromacs/utility/gmxassert.h"
61 #include "gromacs/utility/real.h"
71 class AnalysisNeighborhoodSearchImpl;
72 class AnalysisNeighborhoodPairSearchImpl;
75 class AnalysisNeighborhoodSearch;
76 class AnalysisNeighborhoodPairSearch;
79 * Input positions for neighborhood searching.
81 * This class supports uniformly specifying sets of positions for various
82 * methods in the analysis neighborhood searching classes
83 * (AnalysisNeighborhood and AnalysisNeighborhoodSearch).
85 * Note that copies are not made: only a reference to the positions passed to
86 * the constructors are kept. The caller is responsible to ensure that those
87 * positions remain in scope as long as the neighborhood search object requires
90 * Also note that in addition to constructors here, Selection and
91 * SelectionPosition provide conversions operators to this type. It is done
92 * this way to not introduce a cyclic dependency between the selection code and
93 * the neighborhood search code, which in turn allows splitting this search
94 * code into a separate lower-level module if desired at some point.
96 * Methods in this class do not throw.
99 * \ingroup module_selection
101 class AnalysisNeighborhoodPositions
105 * Initializes positions from a single position vector.
107 * For positions initialized this way, AnalysisNeighborhoodPair always
108 * returns zero in the corresponding index.
110 * This constructor is not explicit to allow directly passing an rvec
111 * to methods that accept positions.
113 AnalysisNeighborhoodPositions(const rvec &x)
114 : count_(1), index_(-1), x_(&x), exclusionIds_(NULL), indices_(NULL)
118 * Initializes positions from an array of position vectors.
120 AnalysisNeighborhoodPositions(const rvec x[], int count)
121 : count_(count), index_(-1), x_(x), exclusionIds_(NULL), indices_(NULL)
125 * Initializes positions from a vector of position vectors.
127 AnalysisNeighborhoodPositions(const std::vector<RVec> &x)
128 : count_(x.size()), index_(-1), x_(as_rvec_array(&x[0])),
129 exclusionIds_(NULL), indices_(NULL)
134 * Sets indices to use for mapping exclusions to these positions.
136 * The exclusion IDs can always be set, but they are ignored unless
137 * actual exclusions have been set with
138 * AnalysisNeighborhood::setTopologyExclusions().
140 AnalysisNeighborhoodPositions &
141 exclusionIds(ConstArrayRef<int> ids)
143 GMX_ASSERT(static_cast<int>(ids.size()) == count_,
144 "Exclusion id array should match the number of positions");
145 exclusionIds_ = ids.data();
149 * Sets indices that select a subset of all positions from the array.
151 * If called, selected positions from the array of positions passed to
152 * the constructor is used instead of the whole array.
153 * All returned indices from AnalysisNeighborhoodPair objects are
154 * indices to the \p indices array passed here.
156 AnalysisNeighborhoodPositions &
157 indexed(ConstArrayRef<int> indices)
159 count_ = indices.size();
160 indices_ = indices.data();
165 * Selects a single position to use from an array.
167 * If called, a single position from the array of positions passed to
168 * the constructor is used instead of the whole array.
169 * In contrast to the AnalysisNeighborhoodPositions(const rvec &)
170 * constructor, AnalysisNeighborhoodPair objects return \p index
173 * If used together with indexed(), \p index references the index array
174 * passed to indexed() instead of the position array.
176 AnalysisNeighborhoodPositions &selectSingleFromArray(int index)
178 GMX_ASSERT(index >= 0 && index < count_, "Invalid position index");
187 const int *exclusionIds_;
190 //! To access the positions for initialization.
191 friend class internal::AnalysisNeighborhoodSearchImpl;
192 //! To access the positions for initialization.
193 friend class internal::AnalysisNeighborhoodPairSearchImpl;
197 * Neighborhood searching for analysis tools.
199 * This class implements neighborhood searching routines for analysis tools.
200 * The emphasis is in flexibility and ease of use; one main driver is to have
201 * a common implementation of grid-based searching to avoid replicating this in
202 * multiple tools (and to make more tools take advantage of the significant
203 * performance improvement this allows).
205 * To use the search, create an object of this type, call setCutoff() to
206 * initialize it, and then repeatedly call initSearch() to start a search with
207 * different sets of reference positions. For each set of reference positions,
208 * use methods in the returned AnalysisNeighborhoodSearch to find the reference
209 * positions that are within the given cutoff from a provided position.
211 * initSearch() is thread-safe and can be called from multiple threads. Each
212 * call returns a different instance of the search object that can be used
213 * independently of the others. The returned AnalysisNeighborhoodSearch
214 * objects are also thread-safe, and can be used concurrently from multiple
215 * threads. It is also possible to create multiple concurrent searches within
219 * Generalize the exclusion machinery to make it easier to use for other cases
220 * than atom-atom exclusions from the topology.
223 * \ingroup module_selection
225 class AnalysisNeighborhood
228 //! Searching algorithm to use.
231 //! Select algorithm based on heuristic efficiency considerations.
232 eSearchMode_Automatic,
233 //! Use a simple loop over all pairs.
235 //! Use grid-based searching whenever possible.
239 //! Creates an uninitialized neighborhood search.
240 AnalysisNeighborhood();
241 ~AnalysisNeighborhood();
244 * Sets cutoff distance for the neighborhood searching.
246 * \param[in] cutoff Cutoff distance for the search
247 * (<=0 stands for no cutoff).
249 * Currently, can only be called before the first call to initSearch().
250 * If this method is not called, no cutoff is used in the searches.
254 void setCutoff(real cutoff);
256 * Sets the search to prefer a grid that covers the bounding box of
257 * reference positions.
259 * By default, non-periodic dimensions will ignore the size of the box
260 * passed to initSearch() and construct a grid based on the bounding
261 * box of the reference positions.
263 * If you call this method with `false`, the size of the box will be
264 * used instead to set the grid. If one of the box vectors is zero,
265 * then grid searching will not be used for that dimension. This
266 * allows you to control the size of the used grid in case the default
267 * is not suitable. However, in this case the grid will currently
268 * always start at the origin.
270 * Currently, this only influences cases where the grid is not
271 * periodic in some dimensions, i.e., `pbc` passed to initSearch() is
272 * NULL, `epbcNONE`, or `epbcXY`.
276 void setUseBoundingBox(bool bUseBoundingBox);
278 * Sets the search to only happen in the XY plane.
280 * Z component of the coordinates is not used in the searching,
281 * and returned distances are computed in the XY plane.
282 * Only boxes with the third box vector parallel to the Z axis are
283 * currently implemented.
287 void setXYMode(bool bXY);
289 * Sets atom exclusions from a topology.
291 * The \p excls structure specifies the exclusions from test positions
292 * to reference positions, i.e., a block starting at `excls->index[i]`
293 * specifies the exclusions for test position `i`, and the indices in
294 * `excls->a` are indices of the reference positions. If `excls->nr`
295 * is smaller than a test position id, then such test positions do not
296 * have any exclusions.
297 * It is assumed that the indices within a block of indices in
298 * `excls->a` is ascending.
302 * \see AnalysisNeighborhoodPositions::exclusionIds()
304 void setTopologyExclusions(const t_blocka *excls);
306 * Sets the algorithm to use for searching.
308 * \param[in] mode Search mode to use.
310 * Note that if \p mode is \ref eSearchMode_Grid, it is still only a
311 * suggestion: grid-based searching may not be possible with the
312 * provided input, in which case a simple search is still used.
313 * This is mainly useful for testing purposes to force a mode.
317 void setMode(SearchMode mode);
318 //! Returns the currently active search mode.
319 SearchMode mode() const;
322 * Initializes neighborhood search for a set of positions.
324 * \param[in] pbc PBC information for the frame.
325 * \param[in] positions Set of reference positions to use.
326 * \returns Search object that can be used to find positions from
327 * \p x within the given cutoff.
328 * \throws std::bad_alloc if out of memory.
330 * Currently, the input positions cannot use
331 * AnalysisNeighborhoodPositions::selectSingleFromArray().
333 AnalysisNeighborhoodSearch
334 initSearch(const t_pbc *pbc,
335 const AnalysisNeighborhoodPositions &positions);
340 PrivateImplPointer<Impl> impl_;
344 * Value type to represent a pair of positions found in neighborhood searching.
346 * Methods in this class do not throw.
349 * \ingroup module_selection
351 class AnalysisNeighborhoodPair
354 //! Initializes an invalid pair.
355 AnalysisNeighborhoodPair() : refIndex_(-1), testIndex_(0), distance2_(0.0)
359 //! Initializes a pair object with the given data.
360 AnalysisNeighborhoodPair(int refIndex, int testIndex, real distance2,
362 : refIndex_(refIndex), testIndex_(testIndex), distance2_(distance2)
368 * Whether this pair is valid.
370 * If isValid() returns false, other methods should not be called.
372 bool isValid() const { return refIndex_ >= 0; }
375 * Returns the index of the reference position in the pair.
377 * This index is always the index into the position array provided to
378 * AnalysisNeighborhood::initSearch().
382 GMX_ASSERT(isValid(), "Accessing invalid object");
386 * Returns the index of the test position in the pair.
388 * The contents of this index depends on the context (method call) that
390 * If there was no array in the call, this index is zero.
392 int testIndex() const
394 GMX_ASSERT(isValid(), "Accessing invalid object");
398 * Returns the squared distance between the pair of positions.
400 real distance2() const
402 GMX_ASSERT(isValid(), "Accessing invalid object");
406 * Returns the shortest vector between the pair of positions.
408 * The vector is from the test position to the reference position.
410 const rvec &dx() const
412 GMX_ASSERT(isValid(), "Accessing invalid object");
424 * Initialized neighborhood search with a fixed set of reference positions.
426 * An instance of this class is obtained through
427 * AnalysisNeighborhood::initSearch(), and can be used to do multiple searches
428 * against the provided set of reference positions.
429 * It is possible to create concurrent pair searches (including from different
430 * threads), as well as call other methods in this class while a pair search is
433 * This class works like a pointer: copies of it point to the same search.
434 * In general, avoid creating copies, and only use the copy/assignment support
435 * for moving the variable around. With C++11, this class would best be
438 * Methods in this class do not throw unless otherwise indicated.
441 * Make it such that reset() is not necessary to call in code that repeatedly
442 * assigns the result of AnalysisNeighborhood::initSearch() to the same
443 * variable (see sm_distance.cpp).
446 * Consider merging nearestPoint() and minimumDistance() by adding the distance
447 * to AnalysisNeighborhoodPair.
450 * \ingroup module_selection
452 class AnalysisNeighborhoodSearch
456 * Internal short-hand type for a pointer to the implementation class.
458 * shared_ptr is used here to automatically keep a reference count to
459 * track whether an implementation class is still used outside the
460 * AnalysisNeighborhood object. Ownership currently always stays with
461 * AnalysisNeighborhood; it always keeps one instance of the pointer.
463 typedef boost::shared_ptr<internal::AnalysisNeighborhoodSearchImpl>
467 * Initializes an invalid search.
469 * Such an object cannot be used for searching. It needs to be
470 * assigned a value from AnalysisNeighborhood::initSearch() before it
471 * can be used. Provided to allow declaring a variable to hold the
472 * search before calling AnalysisNeighborhood::initSearch().
474 AnalysisNeighborhoodSearch();
476 * Internally initialize the search.
478 * Used to implement AnalysisNeighborhood::initSearch().
479 * Cannot be called from user code.
481 explicit AnalysisNeighborhoodSearch(const ImplPointer &impl);
484 * Clears this search.
486 * Equivalent to \c "*this = AnalysisNeighborhoodSearch();".
487 * Currently, this is necessary to avoid unnecessary memory allocation
488 * if the previous search variable is still in scope when you want to
489 * call AnalysisNeighborhood::initSearch() again.
494 * Returns the searching algorithm that this search is using.
496 * The return value is never AnalysisNeighborhood::eSearchMode_Automatic.
498 AnalysisNeighborhood::SearchMode mode() const;
501 * Check whether a point is within a neighborhood.
503 * \param[in] positions Set of test positions to use.
504 * \returns true if any of the test positions is within the cutoff of
505 * any reference position.
507 bool isWithin(const AnalysisNeighborhoodPositions &positions) const;
509 * Calculates the minimum distance from the reference points.
511 * \param[in] positions Set of test positions to use.
512 * \returns The distance to the nearest reference position, or the
513 * cutoff value if there are no reference positions within the
516 real minimumDistance(const AnalysisNeighborhoodPositions &positions) const;
518 * Finds the closest reference point.
520 * \param[in] positions Set of test positions to use.
521 * \returns The reference index identifies the reference position
522 * that is closest to the test positions.
523 * The test index identifies the test position that is closest to
524 * the provided test position. The returned pair is invalid if
525 * no reference position is within the cutoff.
527 AnalysisNeighborhoodPair
528 nearestPoint(const AnalysisNeighborhoodPositions &positions) const;
531 * Start a search to find reference positions within a cutoff.
533 * \param[in] positions Set of test positions to use.
534 * \returns Initialized search object to loop through all reference
535 * positions within the configured cutoff.
536 * \throws std::bad_alloc if out of memory.
538 AnalysisNeighborhoodPairSearch
539 startPairSearch(const AnalysisNeighborhoodPositions &positions) const;
542 typedef internal::AnalysisNeighborhoodSearchImpl Impl;
548 * Initialized neighborhood pair search with a fixed set of positions.
550 * This class is used to loop through pairs of neighbors within the cutoff
551 * provided to AnalysisNeighborhood. The following code demonstrates its use:
553 gmx::AnalysisNeighborhood nb;
554 nb.setCutoff(cutoff);
555 gmx::AnalysisNeighborhoodPositions refPos(xref, nref);
556 gmx::AnalysisNeighborhoodSearch search = nb.initSearch(pbc, refPos);
557 gmx::AnalysisNeighborhoodPairSearch pairSearch = search.startPairSearch(selection);
558 gmx::AnalysisNeighborhoodPair pair;
559 while (pairSearch.findNextPair(&pair))
561 // <do something for each found pair the information in pair>
565 * It is not possible to use a single search object from multiple threads
568 * This class works like a pointer: copies of it point to the same search.
569 * In general, avoid creating copies, and only use the copy/assignment support
570 * for moving the variable around. With C++11, this class would best be
573 * Methods in this class do not throw.
576 * \ingroup module_selection
578 class AnalysisNeighborhoodPairSearch
582 * Internal short-hand type for a pointer to the implementation class.
584 * See AnalysisNeighborhoodSearch::ImplPointer for rationale of using
585 * shared_ptr and ownership semantics.
587 typedef boost::shared_ptr<internal::AnalysisNeighborhoodPairSearchImpl>
591 * Internally initialize the search.
593 * Used to implement AnalysisNeighborhoodSearch::startPairSearch().
594 * Cannot be called from user code.
596 explicit AnalysisNeighborhoodPairSearch(const ImplPointer &impl);
599 * Finds the next pair within the cutoff.
601 * \param[out] pair Information about the found pair.
602 * \returns false if there were no more pairs.
604 * If the method returns false, \p pair will be invalid.
606 * \see AnalysisNeighborhoodPair
607 * \see AnalysisNeighborhoodSearch::startPairSearch()
609 bool findNextPair(AnalysisNeighborhoodPair *pair);
611 * Skip remaining pairs for a test position in the search.
613 * When called after findNextPair(), makes subsequent calls to
614 * findNextPair() skip any pairs that have the same test position as
615 * that previously returned.
616 * This is useful if the caller wants to search whether any reference
617 * position within the cutoff satisfies some condition. This method
618 * can be used to skip remaining pairs after the first such position
619 * has been found if the remaining pairs would not have an effect on
622 void skipRemainingPairsForTestPosition();