Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / selection / nbsearch.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2011,2012,2013, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \file
36  * \brief API for neighborhood searching for analysis.
37  *
38  * The main part of the API is the class gmx::AnalysisNeighborhood.
39  * See the class documentation for usage.
40  *
41  * The classes within this file can be used independently of the other parts
42  * of the library.
43  * The library also uses the classes internally.
44  *
45  * \author Teemu Murtola <teemu.murtola@gmail.com>
46  * \inpublicapi
47  * \ingroup module_selection
48  */
49 #ifndef GMX_SELECTION_NBSEARCH_H
50 #define GMX_SELECTION_NBSEARCH_H
51
52 #include <boost/shared_ptr.hpp>
53
54 #include "../legacyheaders/typedefs.h"
55 #include "../utility/common.h"
56 #include "../utility/gmxassert.h"
57
58 #include "indexutil.h"
59
60 struct gmx_ana_pos_t;
61
62 namespace gmx
63 {
64
65 namespace internal
66 {
67 class AnalysisNeighborhoodSearchImpl;
68 class AnalysisNeighborhoodPairSearchImpl;
69 };
70
71 class AnalysisNeighborhoodSearch;
72 class AnalysisNeighborhoodPairSearch;
73
74 /*! \brief
75  * Input positions for neighborhood searching.
76  *
77  * This class supports uniformly specifying sets of positions for various
78  * methods in the analysis neighborhood searching classes
79  * (AnalysisNeighborhood and AnalysisNeighborhoodSearch).
80  *
81  * Note that copies are not made: only a reference to the positions passed to
82  * the constructors are kept.  The caller is responsible to ensure that those
83  * positions remain in scope as long as the neighborhood search object requires
84  * access to them.
85  *
86  * Also note that in addition to constructors here, Selection and
87  * SelectionPosition provide conversions operators to this type.  It is done
88  * this way to not introduce a cyclic dependency between the selection code and
89  * the neighborhood search code, which in turn allows splitting this search
90  * code into a separate lower-level module if desired at some point.
91  *
92  * Methods in this class do not throw.
93  *
94  * \inpublicapi
95  * \ingroup module_selection
96  */
97 class AnalysisNeighborhoodPositions
98 {
99     public:
100         /*! \brief
101          * Initializes positions from a single position vector.
102          *
103          * For positions initialized this way, AnalysisNeighborhoodPair always
104          * returns zero in the corresponding index.
105          *
106          * This constructor is not explicit to allow directly passing an rvec
107          * to methods that accept positions.
108          */
109         AnalysisNeighborhoodPositions(const rvec &x)
110             : count_(1), index_(-1), x_(&x)
111         {
112         }
113         /*! \brief
114          * Initializes positions from an array of position vectors.
115          */
116         AnalysisNeighborhoodPositions(const rvec x[], int count)
117             : count_(count), index_(-1), x_(x)
118         {
119         }
120
121         /*! \brief
122          * Selects a single position to use from an array.
123          *
124          * If called, a single position from the array of positions passed to
125          * the constructor is used instead of the whole array.
126          * In contrast to the AnalysisNeighborhoodPositions(const rvec &)
127          * constructor, AnalysisNeighborhoodPair objects return \p index
128          * instead of zero.
129          */
130         AnalysisNeighborhoodPositions &selectSingleFromArray(int index)
131         {
132             GMX_ASSERT(index >= 0 && index < count_, "Invalid position index");
133             index_ = index;
134             return *this;
135         }
136
137     private:
138         int                     count_;
139         int                     index_;
140         const rvec             *x_;
141
142         //! To access the positions for initialization.
143         friend class internal::AnalysisNeighborhoodSearchImpl;
144         //! To access the positions for initialization.
145         friend class internal::AnalysisNeighborhoodPairSearchImpl;
146 };
147
148 /*! \brief
149  * Neighborhood searching for analysis tools.
150  *
151  * This class implements neighborhood searching routines for analysis tools.
152  * The emphasis is in flexibility and ease of use; one main driver is to have
153  * a common implementation of grid-based searching to avoid replicating this in
154  * multiple tools (and to make more tools take advantage of the significant
155  * performance improvement this allows).
156  *
157  * To use the search, create an object of this type, call setCutoff() to
158  * initialize it, and then repeatedly call initSearch() to start a search with
159  * different sets of reference positions.  For each set of reference positions,
160  * use methods in the returned AnalysisNeighborhoodSearch to find the reference
161  * positions that are within the given cutoff from a provided position.
162  *
163  * initSearch() is thread-safe and can be called from multiple threads.  Each
164  * call returns a different instance of the search object that can be used
165  * independently of the others.  The returned AnalysisNeighborhoodSearch
166  * objects are also thread-safe, and can be used concurrently from multiple
167  * threads.  It is also possible to create multiple concurrent searches within
168  * a single thread.
169  *
170  * \todo
171  * Support for exclusions.
172  * The 4.5/4.6 C API had very low-level support for exclusions, which was not
173  * very convenient to use, and hadn't been tested much.  The internal code that
174  * it used to do the exclusion during the search itself is still there, but it
175  * needs more thought on what would be a convenient way to initialize it.
176  * Can be implemented once there is need for it in some calling code.
177  *
178  * \inpublicapi
179  * \ingroup module_selection
180  */
181 class AnalysisNeighborhood
182 {
183     public:
184         //! Searching algorithm to use.
185         enum SearchMode
186         {
187             //! Select algorithm based on heuristic efficiency considerations.
188             eSearchMode_Automatic,
189             //! Use a simple loop over all pairs.
190             eSearchMode_Simple,
191             //! Use grid-based searching whenever possible.
192             eSearchMode_Grid
193         };
194
195         //! Creates an uninitialized neighborhood search.
196         AnalysisNeighborhood();
197         ~AnalysisNeighborhood();
198
199         /*! \brief
200          * Set cutoff distance for the neighborhood searching.
201          *
202          * \param[in]  cutoff Cutoff distance for the search
203          *   (<=0 stands for no cutoff).
204          *
205          * Currently, can only be called before the first call to initSearch().
206          * If this method is not called, no cutoff is used in the searches.
207          *
208          * Does not throw.
209          */
210         void setCutoff(real cutoff);
211         /*! \brief
212          * Sets the algorithm to use for searching.
213          *
214          * \param[in] mode  Search mode to use.
215          *
216          * Note that if \p mode is \ref eSearchMode_Grid, it is still only a
217          * suggestion: grid-based searching may not be possible with the
218          * provided input, in which case a simple search is still used.
219          * This is mainly useful for testing purposes to force a mode.
220          *
221          * Does not throw.
222          */
223         void setMode(SearchMode mode);
224         //! Returns the currently active search mode.
225         SearchMode mode() const;
226
227         /*! \brief
228          * Initializes neighborhood search for a set of positions.
229          *
230          * \param[in] pbc        PBC information for the frame.
231          * \param[in] positions  Set of reference positions to use.
232          * \returns   Search object that can be used to find positions from
233          *      \p x within the given cutoff.
234          * \throws    std::bad_alloc if out of memory.
235          *
236          * Currently, the input positions cannot use
237          * AnalysisNeighborhoodPositions::selectSingleFromArray().
238          */
239         AnalysisNeighborhoodSearch
240         initSearch(const t_pbc                         *pbc,
241                    const AnalysisNeighborhoodPositions &positions);
242
243     private:
244         class Impl;
245
246         PrivateImplPointer<Impl> impl_;
247 };
248
249 /*! \brief
250  * Value type to represent a pair of positions found in neighborhood searching.
251  *
252  * Methods in this class do not throw.
253  *
254  * \inpublicapi
255  * \ingroup module_selection
256  */
257 class AnalysisNeighborhoodPair
258 {
259     public:
260         //! Initializes an invalid pair.
261         AnalysisNeighborhoodPair() : refIndex_(-1), testIndex_(0) {}
262         //! Initializes a pair object with the given data.
263         AnalysisNeighborhoodPair(int refIndex, int testIndex)
264             : refIndex_(refIndex), testIndex_(testIndex)
265         {
266         }
267
268         /*! \brief
269          * Whether this pair is valid.
270          *
271          * If isValid() returns false, other methods should not be called.
272          */
273         bool isValid() const { return refIndex_ >= 0; }
274
275         /*! \brief
276          * Returns the index of the reference position in the pair.
277          *
278          * This index is always the index into the position array provided to
279          * AnalysisNeighborhood::initSearch().
280          */
281         int refIndex() const
282         {
283             GMX_ASSERT(isValid(), "Accessing invalid object");
284             return refIndex_;
285         }
286         /*! \brief
287          * Returns the index of the test position in the pair.
288          *
289          * The contents of this index depends on the context (method call) that
290          * produces the pair.
291          * If there was no array in the call, this index is zero.
292          */
293         int testIndex() const
294         {
295             GMX_ASSERT(isValid(), "Accessing invalid object");
296             return testIndex_;
297         }
298
299     private:
300         int                     refIndex_;
301         int                     testIndex_;
302 };
303
304 /*! \brief
305  * Initialized neighborhood search with a fixed set of reference positions.
306  *
307  * An instance of this class is obtained through
308  * AnalysisNeighborhood::initSearch(), and can be used to do multiple searches
309  * against the provided set of reference positions.
310  * It is possible to create concurrent pair searches (including from different
311  * threads), as well as call other methods in this class while a pair search is
312  * in progress.
313  *
314  * This class works like a pointer: copies of it point to the same search.
315  * In general, avoid creating copies, and only use the copy/assignment support
316  * for moving the variable around.  With C++11, this class would best be
317  * movable.
318  *
319  * Methods in this class do not throw unless otherwise indicated.
320  *
321  * \todo
322  * Make it such that reset() is not necessary to call in code that repeatedly
323  * assigns the result of AnalysisNeighborhood::initSearch() to the same
324  * variable (see sm_distance.cpp).
325  *
326  * \todo
327  * Consider merging nearestPoint() and minimumDistance() by adding the distance
328  * to AnalysisNeighborhoodPair.
329  *
330  * \inpublicapi
331  * \ingroup module_selection
332  */
333 class AnalysisNeighborhoodSearch
334 {
335     public:
336         /*! \brief
337          * Internal short-hand type for a pointer to the implementation class.
338          *
339          * shared_ptr is used here to automatically keep a reference count to
340          * track whether an implementation class is still used outside the
341          * AnalysisNeighborhood object.  Ownership currently always stays with
342          * AnalysisNeighborhood; it always keeps one instance of the pointer.
343          */
344         typedef boost::shared_ptr<internal::AnalysisNeighborhoodSearchImpl>
345             ImplPointer;
346
347         /*! \brief
348          * Initializes an invalid search.
349          *
350          * Such an object cannot be used for searching.  It needs to be
351          * assigned a value from AnalysisNeighborhood::initSearch() before it
352          * can be used.  Provided to allow declaring a variable to hold the
353          * search before calling AnalysisNeighborhood::initSearch().
354          */
355         AnalysisNeighborhoodSearch();
356         /*! \brief
357          * Internally initialize the search.
358          *
359          * Used to implement AnalysisNeighborhood::initSearch().
360          * Cannot be called from user code.
361          */
362         explicit AnalysisNeighborhoodSearch(const ImplPointer &impl);
363
364         /*! \brief
365          * Clears this search.
366          *
367          * Equivalent to \c "*this = AnalysisNeighborhoodSearch();".
368          * Currently, this is necessary to avoid unnecessary memory allocation
369          * if the previous search variable is still in scope when you want to
370          * call AnalysisNeighborhood::initSearch() again.
371          */
372         void reset();
373
374         /*! \brief
375          * Returns the searching algorithm that this search is using.
376          *
377          * The return value is never AnalysisNeighborhood::eSearchMode_Automatic.
378          */
379         AnalysisNeighborhood::SearchMode mode() const;
380
381         /*! \brief
382          * Check whether a point is within a neighborhood.
383          *
384          * \param[in] positions  Set of test positions to use.
385          * \returns   true if any of the test positions is within the cutoff of
386          *     any reference position.
387          */
388         bool isWithin(const AnalysisNeighborhoodPositions &positions) const;
389         /*! \brief
390          * Calculates the minimum distance from the reference points.
391          *
392          * \param[in] positions  Set of test positions to use.
393          * \returns   The distance to the nearest reference position, or the
394          *     cutoff value if there are no reference positions within the
395          *     cutoff.
396          */
397         real minimumDistance(const AnalysisNeighborhoodPositions &positions) const;
398         /*! \brief
399          * Finds the closest reference point.
400          *
401          * \param[in] positions  Set of test positions to use.
402          * \returns   The reference index identifies the reference position
403          *     that is closest to the test positions.
404          *     The test index identifies the test position that is closest to
405          *     the provided test position.  The returned pair is invalid if
406          *     no reference position is within the cutoff.
407          */
408         AnalysisNeighborhoodPair
409         nearestPoint(const AnalysisNeighborhoodPositions &positions) const;
410
411         /*! \brief
412          * Start a search to find reference positions within a cutoff.
413          *
414          * \param[in] positions  Set of test positions to use.
415          * \returns   Initialized search object to loop through all reference
416          *     positions within the configured cutoff.
417          * \throws    std::bad_alloc if out of memory.
418          */
419         AnalysisNeighborhoodPairSearch
420         startPairSearch(const AnalysisNeighborhoodPositions &positions) const;
421
422     private:
423         typedef internal::AnalysisNeighborhoodSearchImpl Impl;
424
425         ImplPointer             impl_;
426 };
427
428 /*! \brief
429  * Initialized neighborhood pair search with a fixed set of positions.
430  *
431  * This class is used to loop through pairs of neighbors within the cutoff
432  * provided to AnalysisNeighborhood.  The following code demonstrates its use:
433  * \code
434    gmx::AnalysisNeighborhood       nb;
435    nb.setCutoff(cutoff);
436    gmx::AnalysisNeighborhoodPositions refPos(xref, nref);
437    gmx::AnalysisNeighborhoodSearch search = nb.initSearch(pbc, refPos);
438    gmx::AnalysisNeighborhoodPairSearch pairSearch = search.startPairSearch(selection);
439    gmx::AnalysisNeighborhoodPair pair;
440    while (pairSearch.findNextPair(&pair))
441    {
442        // <do something for each found pair the information in pair>
443    }
444  * \endcode
445  *
446  * It is not possible to use a single search object from multiple threads
447  * concurrently.
448  *
449  * This class works like a pointer: copies of it point to the same search.
450  * In general, avoid creating copies, and only use the copy/assignment support
451  * for moving the variable around.  With C++11, this class would best be
452  * movable.
453  *
454  * Methods in this class do not throw.
455  *
456  * \inpublicapi
457  * \ingroup module_selection
458  */
459 class AnalysisNeighborhoodPairSearch
460 {
461     public:
462         /*! \brief
463          * Internal short-hand type for a pointer to the implementation class.
464          *
465          * See AnalysisNeighborhoodSearch::ImplPointer for rationale of using
466          * shared_ptr and ownership semantics.
467          */
468         typedef boost::shared_ptr<internal::AnalysisNeighborhoodPairSearchImpl>
469             ImplPointer;
470
471         /*! \brief
472          * Internally initialize the search.
473          *
474          * Used to implement AnalysisNeighborhoodSearch::startPairSearch().
475          * Cannot be called from user code.
476          */
477         explicit AnalysisNeighborhoodPairSearch(const ImplPointer &impl);
478
479         /*! \brief
480          * Finds the next pair within the cutoff.
481          *
482          * \param[out] pair  Information about the found pair.
483          * \returns    false if there were no more pairs.
484          *
485          * If the method returns false, \p pair will be invalid.
486          *
487          * \see AnalysisNeighborhoodPair
488          * \see AnalysisNeighborhoodSearch::startPairSearch()
489          */
490         bool findNextPair(AnalysisNeighborhoodPair *pair);
491         /*! \brief
492          * Skip remaining pairs for a test position in the search.
493          *
494          * When called after findNextPair(), makes subsequent calls to
495          * findNextPair() skip any pairs that have the same test position as
496          * that previously returned.
497          * This is useful if the caller wants to search whether any reference
498          * position within the cutoff satisfies some condition.  This method
499          * can be used to skip remaining pairs after the first such position
500          * has been found if the remaining pairs would not have an effect on
501          * the outcome.
502          */
503         void skipRemainingPairsForTestPosition();
504
505     private:
506         ImplPointer             impl_;
507 };
508
509 } // namespace gmx
510
511 #endif