Merge branch 'maint'
[hoomd-blue.git] / libhoomd / computes / NeighborList.h
blob4455e6eaf508d43d6685aac6dec82323202f7ee4
1 /*
2 Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 the University of Michigan All rights reserved.
6 HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 copyright is held, by various Contributors who have granted The Regents of the
8 University of Michigan the right to modify and/or distribute such Contributions.
10 You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 and binary forms, provided you abide by the following conditions:
13 * Redistributions of source code must retain the above copyright notice, this
14 list of conditions, and the following disclaimer both in the code and
15 prominently in any materials provided with the distribution.
17 * Redistributions in binary form must reproduce the above copyright notice, this
18 list of conditions, and the following disclaimer in the documentation and/or
19 other materials provided with the distribution.
21 * All publications and presentations based on HOOMD-blue, including any reports
22 or published results obtained, in whole or in part, with HOOMD-blue, will
23 acknowledge its use according to the terms posted at the time of submission on:
24 http://codeblue.umich.edu/hoomd-blue/citations.html
26 * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 http://codeblue.umich.edu/hoomd-blue/
29 * Apart from the above required attributions, neither the name of the copyright
30 holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 promote products derived from this software without specific prior written
32 permission.
34 Disclaimer
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 // Maintainer: joaander
52 #include <boost/shared_ptr.hpp>
53 #include <boost/signals2.hpp>
54 #include <vector>
56 #include "Compute.h"
57 #include "GPUArray.h"
58 #include "GPUFlags.h"
59 #include "Index1D.h"
61 /*! \file NeighborList.h
62 \brief Declares the NeighborList class
65 #ifdef NVCC
66 #error This header cannot be compiled by nvcc
67 #endif
69 #ifndef __NEIGHBORLIST_H__
70 #define __NEIGHBORLIST_H__
72 #ifdef ENABLE_MPI
73 #include "Communicator.h"
74 #endif
76 //! Computes a Neibhorlist from the particles
77 /*! \b Overview:
79 A particle \c i is a neighbor of particle \c j if the distance between
80 particle them is less than or equal to \c r_cut. The neighborlist for a given particle
81 \c i includes all of these neighbors at a minimum. Other particles particles are included
82 in the list: those up to \c r_max which includes a buffer distance so that the neighbor list
83 doesn't need to be updated every step.
85 There are two ways of storing this information. One is to store only half of the
86 neighbors (only those with i < j), and the other is to store all neighbors. There are
87 potential tradeoffs between number of computations and memory access complexity for
88 each method. NeighborList supports both of these modes via a switch: setStorageMode();
90 Some classes with either setting, full or half, but they are faster with the half setting. However,
91 others may require that the neighbor list storage mode is set to full.
93 <b>Data access:</b>
95 Up to Nmax neighbors can be stored for each particle. Data is stored in a 2D matrix array in memory. Each element
96 in the matrix stores the index of the neighbor with the highest bits reserved for flags. An indexer for accessing
97 elements can be gotten with getNlistIndexer() and the array itself can be accessed with getNlistArray().
99 The number of neighbors for each particle is stored in an auxilliary array accessed with getNNeighArray().
101 - <code>jf = nlist[nlist_indexer(i,n)]</code> is the index of neighbor \a n of particle \a i, where \a n can vary from
102 0 to <code>n_neigh[i] - 1</code>
104 \a jf includes flags in the highest bits. The format and use of these flags are yet to be determined.
106 \b Filtering:
108 By default, a neighbor list includes all particles within a single cutoff distance r_cut. Various filters can be
109 applied to remove unwanted neighbors from the list.
110 - setFilterBody() prevents two particles of the same body from being neighbors
111 - setFilterRcutType() enables individual r_cut values for each pair of particle types
112 - setFilterDiameter() enables slj type diameter filtering (TODO: need to specify exactly what this does)
114 \b Algorithms:
116 This base class supplys a dumb O(N^2) algorithm for generating this list. It is very
117 slow, but functional. Derived classes implement O(N) efficient straetegies using the CellList.
119 <b>Needs updage check:</b>
121 When compute() is called, the neighbor list is updated, but only if it needs to be. Checks
122 are performed to see if any particle has moved more than half of the buffer distance, and
123 only then is the list actually updated. This check can even be avoided for a number of time
124 steps by calling setEvery(). If the caller wants to forces a full update, forceUpdate()
125 can be called before compute() to do so. Note that if the particle data is resorted,
126 an update is automatically forced.
128 The CUDA profiler expects the exact same sequence of kernels on every run. Due to the non-deterministic cell list,
129 a different sequence of calls may be generated with nlist builds at different times. To work around this problem
130 setEvery takes a dist_check parameter. When dist_check=True, the above described behavior is followed. When
131 dist_check is false, the nlist is built exactly m_every steps. This is intended for use in profiling only.
133 \b Exclusions:
135 Exclusions are stored in \a ex_list, a data structure similar in structure to \a nlist, except this time exclusions
136 are stored. User-specified exclusions are stored by tag and translated to indices whenever a particle sort occurs
137 (updateExListIdx()). If any exclusions are set, filterNlist() is called after buildNlist(). filterNlist() loops
138 through the neighbor list and removes any particles that are excluded. This allows an arbitrary number of exclusions
139 to be processed without slowing the performance of the buildNlist() step itself.
141 <b>Overvlow handling:</b>
142 For easy support of derived GPU classes to implement overvlow detectio the overflow condition is storeed in the
143 GPUArray \a d_conditions.
145 - 0: Maximum nlist size (implementations are free to write to this element only in overflow conditions if they
146 choose.)
147 - Further indices may be added to handle other conditions at a later time.
149 Condition flags are to be set during the buildNlist() call and will be checked by compute() which will then
150 take the appropriate action.
152 \ingroup computes
154 class NeighborList : public Compute
156 public:
157 //! Simple enum for the storage modes
158 enum storageMode
160 half, //!< Only neighbors i,j are stored where i < j
161 full //!< All neighbors are stored
164 //! Constructs the compute
165 NeighborList(boost::shared_ptr<SystemDefinition> sysdef, Scalar r_cut, Scalar r_buff);
167 //! Destructor
168 virtual ~NeighborList();
170 //! \name Set parameters
171 // @{
173 //! Change the cuttoff radius
174 virtual void setRCut(Scalar r_cut, Scalar r_buff);
176 //! Change how many timesteps before checking to see if the list should be rebuilt
177 /*! \param every Number of time steps to wait before beignning to check if particles have moved a sufficient distance
178 to require a neighbor list upate.
179 \param dist_check Set to false to enforce nlist builds exactly \a every steps
181 void setEvery(unsigned int every, bool dist_check=true)
183 m_every = every;
184 m_dist_check = dist_check;
185 forceUpdate();
188 //! Set the storage mode
189 /*! \param mode Storage mode to set
190 - half only stores neighbors where i < j
191 - full stores all neighbors
193 The neighborlist is not immediately updated to reflect this change. It will take effect
194 when compute is called for the next timestep.
196 void setStorageMode(storageMode mode)
198 m_storage_mode = mode;
199 forceUpdate();
202 // @}
203 //! \name Get properties
204 // @{
206 //! Get the storage mode
207 storageMode getStorageMode()
209 return m_storage_mode;
212 // @}
213 //! \name Statistics
214 // @{
216 //! Print statistics on the neighborlist
217 virtual void printStats();
219 //! Clear the count of updates the neighborlist has performed
220 virtual void resetStats();
222 //! Gets the shortest rebuild period this nlist has experienced since a call to resetStats
223 unsigned int getSmallestRebuild();
225 // @}
226 //! \name Get data
227 // @{
229 //! Get the number of neighbors array
230 const GPUArray<unsigned int>& getNNeighArray()
232 return m_n_neigh;
235 //! Get the neighbor list
236 const GPUArray<unsigned int>& getNListArray()
238 return m_nlist;
241 //! Get the number of exclusions array
242 const GPUArray<unsigned int>& getNExArray()
244 return m_n_ex_idx;
247 //! Get the exclusion list
248 const GPUArray<unsigned int>& getExListArray()
250 return m_ex_list_idx;
253 //! Get the neighbor list indexer
254 /*! \note Do not save indexers across calls. Get a new indexer after every call to compute() - they will
255 change.
257 const Index2D& getNListIndexer()
259 return m_nlist_indexer;
262 const Index2D& getExListIndexer()
264 return m_ex_list_indexer;
267 bool getExclusionsSet()
269 return m_exclusions_set;
272 bool wantExclusions()
274 return m_want_exclusions;
277 //! Gives an estimate of the number of nearest neighbors per particle
278 virtual Scalar estimateNNeigh();
280 // @}
281 //! \name Handle exclusions
282 // @{
284 //! Exclude a pair of particles from being added to the neighbor list
285 void addExclusion(unsigned int tag1, unsigned int tag2);
287 //! Clear all existing exclusions
288 void clearExclusions();
290 //! Collect some statistics on exclusions.
291 void countExclusions();
293 //! Get number of exclusions involving n particles
294 /*! \param n Size of the exclusion
295 * \returns Number of excluded particles
297 unsigned int getNumExclusions(unsigned int size);
299 //! Add an exclusion for every bond in the ParticleData
300 void addExclusionsFromBonds();
302 //! Add exclusions from angles
303 void addExclusionsFromAngles();
305 //! Add exclusions from dihedrals
306 void addExclusionsFromDihedrals();
308 //! Test if an exclusion has been made
309 bool isExcluded(unsigned int tag1, unsigned int tag2);
311 //! Add an exclusion for every 1,3 pair
312 void addOneThreeExclusionsFromTopology();
314 //! Add an exclusion for every 1,4 pair
315 void addOneFourExclusionsFromTopology();
317 //! Enable/disable body filtering
318 virtual void setFilterBody(bool filter_body)
320 // only set the body exclusions if there are bodies in the rigid data, otherwise it just wastes time
321 if (m_sysdef->getRigidData()->getNumBodies() > 0)
323 m_filter_body = filter_body;
324 forceUpdate();
328 //! Test if body filtering is set
329 virtual bool getFilterBody()
331 return m_filter_body;
334 //! Enable/disable diameter filtering
335 virtual void setFilterDiameter(bool filter_diameter)
337 m_filter_diameter = filter_diameter;
338 forceUpdate();
341 //! Test if diameter filtering is set
342 virtual bool getFilterDiameter()
344 return m_filter_diameter;
347 //! Set the maximum diameter to use in computing neighbor lists
348 virtual void setMaximumDiameter(Scalar d_max)
350 m_d_max = d_max;
352 #ifdef ENABLE_MPI
353 if (m_comm)
355 Scalar rmax = m_r_cut + m_r_buff;
356 // add d_max - 1.0 all the time - this is needed so that all interacting slj particles are communicated
357 rmax += m_d_max - Scalar(1.0);
358 m_comm->setGhostLayerWidth(rmax);
359 m_comm->setRBuff(m_r_buff);
361 #endif
362 forceUpdate();
365 // @}
367 //! Computes the NeighborList if it needs updating
368 void compute(unsigned int timestep);
370 //! Benchmark the neighbor list
371 virtual double benchmark(unsigned int num_iters);
373 //! Forces a full update of the list on the next call to compute()
374 void forceUpdate()
376 m_force_update = true;
379 //! Get the number of updates
380 virtual unsigned int getNumUpdates()
382 return m_updates + m_forced_updates;
386 #ifdef ENABLE_MPI
387 //! Set the communicator to use
388 /*! \param comm MPI communication class
390 virtual void setCommunicator(boost::shared_ptr<Communicator> comm);
392 //! Returns true if the particle migration criterium is fulfilled
393 /*! \param timestep The current timestep
395 bool peekUpdate(unsigned int timestep);
396 #endif
398 //! Return true if the neighbor list has been updated this time step
399 /*! \param timestep Current time step
401 * This is supposed to be called after a call to compute().
403 bool hasBeenUpdated(unsigned int timestep)
405 return m_last_updated_tstep == timestep && m_has_been_updated_once;
408 protected:
409 Scalar m_r_cut; //!< The cuttoff radius
410 Scalar m_r_buff; //!< The buffer around the cuttoff
411 Scalar m_d_max; //!< The maximum diameter of any particle in the system (or greater)
412 bool m_filter_body; //!< Set to true if particles in the same body are to be filtered
413 bool m_filter_diameter; //!< Set to true if particles are to be filtered by diameter (slj style)
414 storageMode m_storage_mode; //!< The storage mode
416 Index2D m_nlist_indexer; //!< Indexer for accessing the neighbor list
417 GPUArray<unsigned int> m_nlist; //!< Neighbor list data
418 GPUArray<unsigned int> m_n_neigh; //!< Number of neighbors for each particle
419 GPUArray<Scalar4> m_last_pos; //!< coordinates of last updated particle positions
420 Scalar3 m_last_L; //!< Box lengths at last update
421 Scalar3 m_last_L_local; //!< Local Box lengths at last update
422 unsigned int m_Nmax; //!< Maximum number of neighbors that can be held in m_nlist
423 GPUFlags<unsigned int> m_conditions; //!< Condition flags set during the buildNlist() call
425 GPUArray<unsigned int> m_ex_list_tag; //!< List of excluded particles referenced by tag
426 GPUArray<unsigned int> m_ex_list_idx; //!< List of excluded particles referenced by index
427 GPUArray<unsigned int> m_n_ex_tag; //!< Number of exclusions for a given particle tag
428 GPUArray<unsigned int> m_n_ex_idx; //!< Number of exclusions for a given particle index
429 Index2D m_ex_list_indexer; //!< Indexer for accessing the exclusion list
430 Index2D m_ex_list_indexer_tag; //!< Indexer for accessing the by-tag exclusion list
431 bool m_exclusions_set; //!< True if any exclusions have been set
433 boost::signals2::connection m_sort_connection; //!< Connection to the ParticleData sort signal
434 boost::signals2::connection m_max_particle_num_change_connection; //!< Connection to max particle number change signal
435 #ifdef ENABLE_MPI
436 boost::signals2::connection m_migrate_request_connection; //!< Connection to trigger particle migration
437 boost::signals2::connection m_comm_flags_request; //!< Connection to request ghost particle fields
438 #endif
440 //! Return true if we are supposed to do a distance check in this time step
441 bool shouldCheckDistance(unsigned int timestep);
443 //! Performs the distance check
444 virtual bool distanceCheck(unsigned int timestep);
446 //! Updates the previous position table for use in the next distance check
447 virtual void setLastUpdatedPos();
449 //! Builds the neighbor list
450 virtual void buildNlist(unsigned int timestep);
452 //! Updates the idx exlcusion list
453 virtual void updateExListIdx();
455 //! Filter the neighbor list of excluded particles
456 virtual void filterNlist();
458 #ifdef ENABLE_MPI
459 CommFlags getRequestedCommFlags(unsigned int timestep)
461 // exclusions require ghost particle tags
462 CommFlags flags(0);
463 if (m_exclusions_set) flags[comm_flag::tag] = 1;
464 return flags;
466 #endif
468 private:
469 int64_t m_updates; //!< Number of times the neighbor list has been updated
470 int64_t m_forced_updates; //!< Number of times the neighbor list has been foribly updated
471 int64_t m_dangerous_updates; //!< Number of dangerous builds counted
472 bool m_force_update; //!< Flag to handle the forcing of neighborlist updates
473 bool m_dist_check; //!< Set to false to disable distance checks (nlist always built m_every steps)
474 bool m_has_been_updated_once; //!< True if the neighbor list has been updated at least once
476 unsigned int m_last_updated_tstep; //!< Track the last time step we were updated
477 unsigned int m_last_checked_tstep; //!< Track the last time step we have checked
478 bool m_last_check_result; //!< Last result of rebuild check
479 unsigned int m_every; //!< No update checks will be performed until m_every steps after the last one
480 vector<unsigned int> m_update_periods; //!< Steps between updates
482 bool m_want_exclusions; //!< True if we want updated exclusions
484 //! Test if the list needs updating
485 bool needsUpdating(unsigned int timestep);
487 //! Reallocate internal data structures
488 void reallocate();
490 //! Allocate the nlist array
491 void allocateNlist();
493 //! Check the status of the conditions
494 bool checkConditions();
496 //! Read back the conditions
497 virtual unsigned int readConditions();
499 //! Resets the condition status
500 virtual void resetConditions();
502 //! Grow the exclusions list memory capacity by one row
503 void growExclusionList();
506 //! Exports NeighborList to python
507 void export_NeighborList();
509 #endif