bc5baba8d156311576a793b962ea429b0a2b30d8
[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,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.
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 <vector>
53
54 #include <boost/shared_ptr.hpp>
55
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"
62
63 struct t_blocka;
64 struct t_pbc;
65
66 namespace gmx
67 {
68
69 namespace internal
70 {
71 class AnalysisNeighborhoodSearchImpl;
72 class AnalysisNeighborhoodPairSearchImpl;
73 };
74
75 class AnalysisNeighborhoodSearch;
76 class AnalysisNeighborhoodPairSearch;
77
78 /*! \brief
79  * Input positions for neighborhood searching.
80  *
81  * This class supports uniformly specifying sets of positions for various
82  * methods in the analysis neighborhood searching classes
83  * (AnalysisNeighborhood and AnalysisNeighborhoodSearch).
84  *
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
88  * access to them.
89  *
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.
95  *
96  * Methods in this class do not throw.
97  *
98  * \inpublicapi
99  * \ingroup module_selection
100  */
101 class AnalysisNeighborhoodPositions
102 {
103     public:
104         /*! \brief
105          * Initializes positions from a single position vector.
106          *
107          * For positions initialized this way, AnalysisNeighborhoodPair always
108          * returns zero in the corresponding index.
109          *
110          * This constructor is not explicit to allow directly passing an rvec
111          * to methods that accept positions.
112          */
113         AnalysisNeighborhoodPositions(const rvec &x)
114             : count_(1), index_(-1), x_(&x), exclusionIds_(NULL), indices_(NULL)
115         {
116         }
117         /*! \brief
118          * Initializes positions from an array of position vectors.
119          */
120         AnalysisNeighborhoodPositions(const rvec x[], int count)
121             : count_(count), index_(-1), x_(x), exclusionIds_(NULL), indices_(NULL)
122         {
123         }
124         /*! \brief
125          * Initializes positions from a vector of position vectors.
126          */
127         AnalysisNeighborhoodPositions(const std::vector<RVec> &x)
128             : count_(x.size()), index_(-1), x_(as_rvec_array(&x[0])),
129               exclusionIds_(NULL), indices_(NULL)
130         {
131         }
132
133         /*! \brief
134          * Sets indices to use for mapping exclusions to these positions.
135          *
136          * The exclusion IDs can always be set, but they are ignored unless
137          * actual exclusions have been set with
138          * AnalysisNeighborhood::setTopologyExclusions().
139          */
140         AnalysisNeighborhoodPositions &
141         exclusionIds(ConstArrayRef<int> ids)
142         {
143             GMX_ASSERT(static_cast<int>(ids.size()) == count_,
144                        "Exclusion id array should match the number of positions");
145             exclusionIds_ = ids.data();
146             return *this;
147         }
148         /*! \brief
149          * Sets indices that select a subset of all positions from the array.
150          *
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.
155          */
156         AnalysisNeighborhoodPositions &
157         indexed(ConstArrayRef<int> indices)
158         {
159             count_   = indices.size();
160             indices_ = indices.data();
161             return *this;
162         }
163
164         /*! \brief
165          * Selects a single position to use from an array.
166          *
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
171          * instead of zero.
172          *
173          * If used together with indexed(), \p index references the index array
174          * passed to indexed() instead of the position array.
175          */
176         AnalysisNeighborhoodPositions &selectSingleFromArray(int index)
177         {
178             GMX_ASSERT(index >= 0 && index < count_, "Invalid position index");
179             index_ = index;
180             return *this;
181         }
182
183     private:
184         int                     count_;
185         int                     index_;
186         const rvec             *x_;
187         const int              *exclusionIds_;
188         const int              *indices_;
189
190         //! To access the positions for initialization.
191         friend class internal::AnalysisNeighborhoodSearchImpl;
192         //! To access the positions for initialization.
193         friend class internal::AnalysisNeighborhoodPairSearchImpl;
194 };
195
196 /*! \brief
197  * Neighborhood searching for analysis tools.
198  *
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).
204  *
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.
210  *
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
216  * a single thread.
217  *
218  * \todo
219  * Generalize the exclusion machinery to make it easier to use for other cases
220  * than atom-atom exclusions from the topology.
221  *
222  * \inpublicapi
223  * \ingroup module_selection
224  */
225 class AnalysisNeighborhood
226 {
227     public:
228         //! Searching algorithm to use.
229         enum SearchMode
230         {
231             //! Select algorithm based on heuristic efficiency considerations.
232             eSearchMode_Automatic,
233             //! Use a simple loop over all pairs.
234             eSearchMode_Simple,
235             //! Use grid-based searching whenever possible.
236             eSearchMode_Grid
237         };
238
239         //! Creates an uninitialized neighborhood search.
240         AnalysisNeighborhood();
241         ~AnalysisNeighborhood();
242
243         /*! \brief
244          * Sets cutoff distance for the neighborhood searching.
245          *
246          * \param[in]  cutoff Cutoff distance for the search
247          *   (<=0 stands for no cutoff).
248          *
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.
251          *
252          * Does not throw.
253          */
254         void setCutoff(real cutoff);
255         /*! \brief
256          * Sets the search to prefer a grid that covers the bounding box of
257          * reference positions.
258          *
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.
262          *
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.
269          *
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`.
273          *
274          * Does not throw.
275          */
276         void setUseBoundingBox(bool bUseBoundingBox);
277         /*! \brief
278          * Sets the search to only happen in the XY plane.
279          *
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.
284          *
285          * Does not throw.
286          */
287         void setXYMode(bool bXY);
288         /*! \brief
289          * Sets atom exclusions from a topology.
290          *
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.
299          *
300          * Does not throw.
301          *
302          * \see AnalysisNeighborhoodPositions::exclusionIds()
303          */
304         void setTopologyExclusions(const t_blocka *excls);
305         /*! \brief
306          * Sets the algorithm to use for searching.
307          *
308          * \param[in] mode  Search mode to use.
309          *
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.
314          *
315          * Does not throw.
316          */
317         void setMode(SearchMode mode);
318         //! Returns the currently active search mode.
319         SearchMode mode() const;
320
321         /*! \brief
322          * Initializes neighborhood search for a set of positions.
323          *
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.
329          *
330          * Currently, the input positions cannot use
331          * AnalysisNeighborhoodPositions::selectSingleFromArray().
332          */
333         AnalysisNeighborhoodSearch
334         initSearch(const t_pbc                         *pbc,
335                    const AnalysisNeighborhoodPositions &positions);
336
337     private:
338         class Impl;
339
340         PrivateImplPointer<Impl> impl_;
341 };
342
343 /*! \brief
344  * Value type to represent a pair of positions found in neighborhood searching.
345  *
346  * Methods in this class do not throw.
347  *
348  * \inpublicapi
349  * \ingroup module_selection
350  */
351 class AnalysisNeighborhoodPair
352 {
353     public:
354         //! Initializes an invalid pair.
355         AnalysisNeighborhoodPair() : refIndex_(-1), testIndex_(0), distance2_(0.0)
356         {
357             clear_rvec(dx_);
358         }
359         //! Initializes a pair object with the given data.
360         AnalysisNeighborhoodPair(int refIndex, int testIndex, real distance2,
361                                  const rvec dx)
362             : refIndex_(refIndex), testIndex_(testIndex), distance2_(distance2)
363         {
364             copy_rvec(dx, dx_);
365         }
366
367         /*! \brief
368          * Whether this pair is valid.
369          *
370          * If isValid() returns false, other methods should not be called.
371          */
372         bool isValid() const { return refIndex_ >= 0; }
373
374         /*! \brief
375          * Returns the index of the reference position in the pair.
376          *
377          * This index is always the index into the position array provided to
378          * AnalysisNeighborhood::initSearch().
379          */
380         int refIndex() const
381         {
382             GMX_ASSERT(isValid(), "Accessing invalid object");
383             return refIndex_;
384         }
385         /*! \brief
386          * Returns the index of the test position in the pair.
387          *
388          * The contents of this index depends on the context (method call) that
389          * produces the pair.
390          * If there was no array in the call, this index is zero.
391          */
392         int testIndex() const
393         {
394             GMX_ASSERT(isValid(), "Accessing invalid object");
395             return testIndex_;
396         }
397         /*! \brief
398          * Returns the squared distance between the pair of positions.
399          */
400         real distance2() const
401         {
402             GMX_ASSERT(isValid(), "Accessing invalid object");
403             return distance2_;
404         }
405         /*! \brief
406          * Returns the shortest vector between the pair of positions.
407          *
408          * The vector is from the test position to the reference position.
409          */
410         const rvec &dx() const
411         {
412             GMX_ASSERT(isValid(), "Accessing invalid object");
413             return dx_;
414         }
415
416     private:
417         int                     refIndex_;
418         int                     testIndex_;
419         real                    distance2_;
420         rvec                    dx_;
421 };
422
423 /*! \brief
424  * Initialized neighborhood search with a fixed set of reference positions.
425  *
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
431  * in progress.
432  *
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
436  * movable.
437  *
438  * Methods in this class do not throw unless otherwise indicated.
439  *
440  * \todo
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).
444  *
445  * \todo
446  * Consider merging nearestPoint() and minimumDistance() by adding the distance
447  * to AnalysisNeighborhoodPair.
448  *
449  * \inpublicapi
450  * \ingroup module_selection
451  */
452 class AnalysisNeighborhoodSearch
453 {
454     public:
455         /*! \brief
456          * Internal short-hand type for a pointer to the implementation class.
457          *
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.
462          */
463         typedef boost::shared_ptr<internal::AnalysisNeighborhoodSearchImpl>
464             ImplPointer;
465
466         /*! \brief
467          * Initializes an invalid search.
468          *
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().
473          */
474         AnalysisNeighborhoodSearch();
475         /*! \brief
476          * Internally initialize the search.
477          *
478          * Used to implement AnalysisNeighborhood::initSearch().
479          * Cannot be called from user code.
480          */
481         explicit AnalysisNeighborhoodSearch(const ImplPointer &impl);
482
483         /*! \brief
484          * Clears this search.
485          *
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.
490          */
491         void reset();
492
493         /*! \brief
494          * Returns the searching algorithm that this search is using.
495          *
496          * The return value is never AnalysisNeighborhood::eSearchMode_Automatic.
497          */
498         AnalysisNeighborhood::SearchMode mode() const;
499
500         /*! \brief
501          * Check whether a point is within a neighborhood.
502          *
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.
506          */
507         bool isWithin(const AnalysisNeighborhoodPositions &positions) const;
508         /*! \brief
509          * Calculates the minimum distance from the reference points.
510          *
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
514          *     cutoff.
515          */
516         real minimumDistance(const AnalysisNeighborhoodPositions &positions) const;
517         /*! \brief
518          * Finds the closest reference point.
519          *
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.
526          */
527         AnalysisNeighborhoodPair
528         nearestPoint(const AnalysisNeighborhoodPositions &positions) const;
529
530         /*! \brief
531          * Start a search to find reference positions within a cutoff.
532          *
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.
537          */
538         AnalysisNeighborhoodPairSearch
539         startPairSearch(const AnalysisNeighborhoodPositions &positions) const;
540
541     private:
542         typedef internal::AnalysisNeighborhoodSearchImpl Impl;
543
544         ImplPointer             impl_;
545 };
546
547 /*! \brief
548  * Initialized neighborhood pair search with a fixed set of positions.
549  *
550  * This class is used to loop through pairs of neighbors within the cutoff
551  * provided to AnalysisNeighborhood.  The following code demonstrates its use:
552  * \code
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))
560    {
561        // <do something for each found pair the information in pair>
562    }
563  * \endcode
564  *
565  * It is not possible to use a single search object from multiple threads
566  * concurrently.
567  *
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
571  * movable.
572  *
573  * Methods in this class do not throw.
574  *
575  * \inpublicapi
576  * \ingroup module_selection
577  */
578 class AnalysisNeighborhoodPairSearch
579 {
580     public:
581         /*! \brief
582          * Internal short-hand type for a pointer to the implementation class.
583          *
584          * See AnalysisNeighborhoodSearch::ImplPointer for rationale of using
585          * shared_ptr and ownership semantics.
586          */
587         typedef boost::shared_ptr<internal::AnalysisNeighborhoodPairSearchImpl>
588             ImplPointer;
589
590         /*! \brief
591          * Internally initialize the search.
592          *
593          * Used to implement AnalysisNeighborhoodSearch::startPairSearch().
594          * Cannot be called from user code.
595          */
596         explicit AnalysisNeighborhoodPairSearch(const ImplPointer &impl);
597
598         /*! \brief
599          * Finds the next pair within the cutoff.
600          *
601          * \param[out] pair  Information about the found pair.
602          * \returns    false if there were no more pairs.
603          *
604          * If the method returns false, \p pair will be invalid.
605          *
606          * \see AnalysisNeighborhoodPair
607          * \see AnalysisNeighborhoodSearch::startPairSearch()
608          */
609         bool findNextPair(AnalysisNeighborhoodPair *pair);
610         /*! \brief
611          * Skip remaining pairs for a test position in the search.
612          *
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
620          * the outcome.
621          */
622         void skipRemainingPairsForTestPosition();
623
624     private:
625         ImplPointer             impl_;
626 };
627
628 } // namespace gmx
629
630 #endif