C++-ify analysis nbsearch more.
[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  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * 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  * Neighborhood searching for analysis tools.
76  *
77  * This class implements neighborhood searching routines for analysis tools.
78  * The emphasis is in flexibility and ease of use; one main driver is to have
79  * a common implementation of grid-based searching to avoid replicating this in
80  * multiple tools (and to make more tools take advantage of the significant
81  * performance improvement this allows).
82  *
83  * To use the search, create an object of this type, call setCutoff() to
84  * initialize it, and then repeatedly call initSearch() to start a search with
85  * different sets of reference positions.  For each set of reference positions,
86  * use methods in the returned AnalysisNeighborhoodSearch to find the reference
87  * positions that are within the given cutoff from a provided position.
88  *
89  * initSearch() is thread-safe and can be called from multiple threads.  Each
90  * call returns a different instance of the search object that can be used
91  * independently of the others.  The returned AnalysisNeighborhoodSearch
92  * objects are also thread-safe, and can be used concurrently from multiple
93  * threads.  It is also possible to create multiple concurrent searches within
94  * a single thread.
95  *
96  * \todo
97  * Support for exclusions.
98  * The 4.5/4.6 C API had very low-level support for exclusions, which was not
99  * very convenient to use, and hadn't been tested much.  The internal code that
100  * it used to do the exclusion during the search itself is still there, but it
101  * needs more thought on what would be a convenient way to initialize it.
102  * Can be implemented once there is need for it in some calling code.
103  *
104  * \inpublicapi
105  * \ingroup module_selection
106  */
107 class AnalysisNeighborhood
108 {
109     public:
110         //! Searching algorithm to use.
111         enum SearchMode
112         {
113             //! Select algorithm based on heuristic efficiency considerations.
114             eSearchMode_Automatic,
115             //! Use a simple loop over all pairs.
116             eSearchMode_Simple,
117             //! Use grid-based searching whenever possible.
118             eSearchMode_Grid
119         };
120
121         //! Creates an uninitialized neighborhood search.
122         AnalysisNeighborhood();
123         ~AnalysisNeighborhood();
124
125         /*! \brief
126          * Set cutoff distance for the neighborhood searching.
127          *
128          * \param[in]  cutoff Cutoff distance for the search
129          *   (<=0 stands for no cutoff).
130          *
131          * Currently, can only be called before the first call to initSearch().
132          * If this method is not called, no cutoff is used in the searches.
133          *
134          * Does not throw.
135          */
136         void setCutoff(real cutoff);
137         /*! \brief
138          * Sets the algorithm to use for searching.
139          *
140          * \param[in] mode  Search mode to use.
141          *
142          * Note that if \p mode is \ref eSearchMode_Grid, it is still only a
143          * suggestion: grid-based searching may not be possible with the
144          * provided input, in which case a simple search is still used.
145          * This is mainly useful for testing purposes to force a mode.
146          *
147          * Does not throw.
148          */
149         void setMode(SearchMode mode);
150         //! Returns the currently active search mode.
151         SearchMode mode() const;
152
153         /*! \brief
154          * Initializes neighborhood search for a set of positions.
155          *
156          * \param[in] pbc PBC information for the frame.
157          * \param[in] n   Number of reference positions for the frame.
158          * \param[in] x   \p n reference positions for the frame.
159          * \returns   Search object that can be used to find positions from
160          *      \p x within the given cutoff.
161          * \throws    std::bad_alloc if out of memory.
162          */
163         AnalysisNeighborhoodSearch
164         initSearch(const t_pbc *pbc, int n, const rvec x[]);
165         /*! \brief
166          * Initializes neighborhood search for a set of positions.
167          *
168          * \param[in] pbc PBC information for the frame.
169          * \param[in] p   Reference positions for the frame.
170          * \returns   Search object that can be used to find positions from
171          *      \p p within the given cutoff.
172          * \throws    std::bad_alloc if out of memory.
173          */
174         AnalysisNeighborhoodSearch
175         initSearch(const t_pbc *pbc, const gmx_ana_pos_t *p);
176
177     private:
178         class Impl;
179
180         PrivateImplPointer<Impl> impl_;
181 };
182
183 /*! \brief
184  * Value type to represent a pair of positions found in neighborhood searching.
185  *
186  * Methods in this class do not throw.
187  *
188  * \inpublicapi
189  * \ingroup module_selection
190  */
191 class AnalysisNeighborhoodPair
192 {
193     public:
194         //! Initializes an invalid pair.
195         AnalysisNeighborhoodPair() : refIndex_(-1), testIndex_(0) {}
196         //! Initializes a pair object with the given data.
197         AnalysisNeighborhoodPair(int refIndex, int testIndex)
198             : refIndex_(refIndex), testIndex_(testIndex)
199         {
200         }
201
202         /*! \brief
203          * Whether this pair is valid.
204          *
205          * If isValid() returns false, other methods should not be called.
206          */
207         bool isValid() const { return refIndex_ >= 0; }
208
209         /*! \brief
210          * Returns the index of the reference position in the pair.
211          *
212          * This index is always the index into the position array provided to
213          * AnalysisNeighborhood::initSearch().
214          */
215         int refIndex() const
216         {
217             GMX_ASSERT(isValid(), "Accessing invalid object");
218             return refIndex_;
219         }
220         /*! \brief
221          * Returns the index of the test position in the pair.
222          *
223          * The contents of this index depends on the context (method call) that
224          * produces the pair.
225          * If there was no array in the call, this index is zero.
226          */
227         int testIndex() const
228         {
229             GMX_ASSERT(isValid(), "Accessing invalid object");
230             return testIndex_;
231         }
232
233     private:
234         int                     refIndex_;
235         int                     testIndex_;
236 };
237
238 /*! \brief
239  * Initialized neighborhood search with a fixed set of reference positions.
240  *
241  * An instance of this class is obtained through
242  * AnalysisNeighborhood::initSearch(), and can be used to do multiple searches
243  * against the provided set of reference positions.
244  * It is possible to create concurrent pair searches (including from different
245  * threads), as well as call other methods in this class while a pair search is
246  * in progress.
247  *
248  * This class works like a pointer: copies of it point to the same search.
249  * In general, avoid creating copies, and only use the copy/assignment support
250  * for moving the variable around.  With C++11, this class would best be
251  * movable.
252  *
253  * Methods in this class do not throw unless otherwise indicated.
254  *
255  * \todo
256  * Make it such that reset() is not necessary to call in code that repeatedly
257  * assigns the result of AnalysisNeighborhood::initSearch() to the same
258  * variable (see sm_distance.cpp).
259  *
260  * \todo
261  * Consider merging nearestPoint() and minimumDistance() by adding the distance
262  * to AnalysisNeighborhoodPair.
263  *
264  * \inpublicapi
265  * \ingroup module_selection
266  */
267 class AnalysisNeighborhoodSearch
268 {
269     public:
270         /*! \brief
271          * Internal short-hand type for a pointer to the implementation class.
272          *
273          * shared_ptr is used here to automatically keep a reference count to
274          * track whether an implementation class is still used outside the
275          * AnalysisNeighborhood object.  Ownership currently always stays with
276          * AnalysisNeighborhood; it always keeps one instance of the pointer.
277          */
278         typedef boost::shared_ptr<internal::AnalysisNeighborhoodSearchImpl>
279             ImplPointer;
280
281         /*! \brief
282          * Initializes an invalid search.
283          *
284          * Such an object cannot be used for searching.  It needs to be
285          * assigned a value from AnalysisNeighborhood::initSearch() before it
286          * can be used.  Provided to allow declaring a variable to hold the
287          * search before calling AnalysisNeighborhood::initSearch().
288          */
289         AnalysisNeighborhoodSearch();
290         /*! \brief
291          * Internally initialize the search.
292          *
293          * Used to implement AnalysisNeighborhood::initSearch().
294          * Cannot be called from user code.
295          */
296         explicit AnalysisNeighborhoodSearch(const ImplPointer &impl);
297
298         /*! \brief
299          * Clears this search.
300          *
301          * Equivalent to \c "*this = AnalysisNeighborhoodSearch();".
302          * Currently, this is necessary to avoid unnecessary memory allocation
303          * if the previous search variable is still in scope when you want to
304          * call AnalysisNeighborhood::initSearch() again.
305          */
306         void reset();
307
308         /*! \brief
309          * Returns the searching algorithm that this search is using.
310          *
311          * The return value is never AnalysisNeighborhood::eSearchMode_Automatic.
312          */
313         AnalysisNeighborhood::SearchMode mode() const;
314
315         /*! \brief
316          * Check whether a point is within a neighborhood.
317          *
318          * \param[in] x  Test position.
319          * \returns   true if the test position is within the cutoff of any
320          *     reference position.
321          */
322         bool isWithin(const rvec x) const;
323         /*! \brief
324          * Check whether a point is within a neighborhood.
325          *
326          * \param[in] p  Test positions.
327          * \param[in] i  Use the i'th position in \p p for testing.
328          * \returns   true if the test position is within the cutoff of any
329          *     reference position.
330          */
331         bool isWithin(const gmx_ana_pos_t *p, int i) const;
332         /*! \brief
333          * Calculates the minimum distance from the reference points.
334          *
335          * \param[in] x  Test position.
336          * \returns   The distance to the nearest reference position, or the
337          *     cutoff value if there are no reference positions within the
338          *     cutoff.
339          */
340         real minimumDistance(const rvec x) const;
341         /*! \brief
342          * Calculates the minimum distance from the reference points.
343          *
344          * \param[in] p  Test positions.
345          * \param[in] i  Use the i'th position in \p p for testing.
346          * \returns   The distance to the nearest reference position, or the
347          *     cutoff value if there are no reference positions within the
348          *     cutoff.
349          */
350         real minimumDistance(const gmx_ana_pos_t *p, int i) const;
351         /*! \brief
352          * Finds the closest reference point.
353          *
354          * \param[in] x  Test position.
355          * \returns   The reference index identifies the reference position
356          *     that is closest to the test position.
357          *     The test index is always zero.  The returned pair is invalid if
358          *     no reference position is within the cutoff.
359          */
360         AnalysisNeighborhoodPair nearestPoint(const rvec x) const;
361         /*! \brief
362          * Finds the closest reference point.
363          *
364          * \param[in] p  Test positions.
365          * \param[in] i  Use the i'th position in \p p for testing.
366          * \returns   The reference index identifies the reference position
367          *     that is closest to the test position.
368          *     The test index is always \p i.  The returned pair is invalid if
369          *     no reference position is within the cutoff.
370          */
371         AnalysisNeighborhoodPair nearestPoint(const gmx_ana_pos_t *p, int i) const;
372
373         /*! \brief
374          * Start a search to find reference positions within a cutoff.
375          *
376          * \param[in] x  Test position to search the neighbors for.
377          * \returns   Initialized search object to loop through all reference
378          *     positions within the configured cutoff.
379          * \throws    std::bad_alloc if out of memory.
380          *
381          * In the AnalysisNeighborhoodPair objects returned by the search, the
382          * test index is always zero.
383          */
384         AnalysisNeighborhoodPairSearch startPairSearch(const rvec x);
385         /*! \brief
386          * Start a search to find reference positions within a cutoff.
387          *
388          * \param[in] p  Test positions.
389          * \param[in] i  Use the i'th position in \p p for testing.
390          * \returns   Initialized search object to loop through all reference
391          *     positions within the configured cutoff.
392          * \throws    std::bad_alloc if out of memory.
393          *
394          * In the AnalysisNeighborhoodPair objects returned by the search, the
395          * test index is always \p i.
396          */
397         AnalysisNeighborhoodPairSearch startPairSearch(const gmx_ana_pos_t *p, int i);
398
399     private:
400         typedef internal::AnalysisNeighborhoodSearchImpl Impl;
401
402         ImplPointer             impl_;
403 };
404
405 /*! \brief
406  * Initialized neighborhood pair search with a fixed set of positions.
407  *
408  * This class is used to loop through pairs of neighbors within the cutoff
409  * provided to AnalysisNeighborhood.  The following code demonstrates its use:
410  * \code
411    gmx::AnalysisNeighborhood       nb;
412    nb.setCutoff(cutoff);
413    gmx::AnalysisNeighborhoodSearch search = nb.initSearch(pbc, nref, xref);
414    gmx::AnalysisNeighborhoodPairSearch pairSearch = search.startPairSearch(x);
415    gmx::AnalysisNeighborhoodPair pair;
416    while (pairSearch.findNextPair(&pair))
417    {
418        // <do something for each found pair the information in pair>
419    }
420  * \endcode
421  *
422  * It is not possible to use a single search object from multiple threads
423  * concurrently.
424  *
425  * This class works like a pointer: copies of it point to the same search.
426  * In general, avoid creating copies, and only use the copy/assignment support
427  * for moving the variable around.  With C++11, this class would best be
428  * movable.
429  *
430  * Methods in this class do not throw.
431  *
432  * \inpublicapi
433  * \ingroup module_selection
434  */
435 class AnalysisNeighborhoodPairSearch
436 {
437     public:
438         /*! \brief
439          * Internal short-hand type for a pointer to the implementation class.
440          *
441          * See AnalysisNeighborhoodSearch::ImplPointer for rationale of using
442          * shared_ptr and ownership semantics.
443          */
444         typedef boost::shared_ptr<internal::AnalysisNeighborhoodPairSearchImpl>
445             ImplPointer;
446
447         /*! \brief
448          * Internally initialize the search.
449          *
450          * Used to implement AnalysisNeighborhoodSearch::startPairSearch().
451          * Cannot be called from user code.
452          */
453         explicit AnalysisNeighborhoodPairSearch(const ImplPointer &impl);
454
455         /*! \brief
456          * Finds the next pair within the cutoff.
457          *
458          * \param[out] pair  Information about the found pair.
459          * \returns    false if there were no more pairs.
460          *
461          * If the method returns false, \p pair will be invalid.
462          *
463          * \see AnalysisNeighborhoodPair
464          * \see AnalysisNeighborhoodSearch::startPairSearch()
465          */
466         bool findNextPair(AnalysisNeighborhoodPair *pair);
467
468     private:
469         ImplPointer             impl_;
470 };
471
472 } // namespace gmx
473
474 #endif