Merge branch 'maint'
[hoomd-blue.git] / libhoomd / computes / NeighborList.cc
bloba58179e0775ad7f43b3102ac59606ed1878a93f6
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/python.hpp>
53 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
55 using namespace boost::python;
57 #ifdef ENABLE_MPI
58 #include "Communicator.h"
59 #endif
61 #include <boost/bind.hpp>
63 #include "NeighborList.h"
64 #include "BondedGroupData.h"
66 #include <sstream>
67 #include <fstream>
69 #include <iostream>
70 #include <stdexcept>
72 using namespace boost;
73 using namespace std;
75 /*! \file NeighborList.cc
76 \brief Defines the NeighborList class
79 /*! \param sysdef System the neighborlist is to compute neighbors for
80 \param r_cut Cuttoff radius under which particles are considered neighbors
81 \param r_buff Buffere radius around \a r_cut in which neighbors will be included
83 \post NeighborList is initialized and the list memory has been allocated,
84 but the list will not be computed until compute is called.
85 \post The storage mode defaults to half
87 NeighborList::NeighborList(boost::shared_ptr<SystemDefinition> sysdef, Scalar r_cut, Scalar r_buff)
88 : Compute(sysdef), m_r_cut(r_cut), m_r_buff(r_buff), m_d_max(1.0), m_filter_body(false), m_filter_diameter(false),
89 m_storage_mode(half), m_updates(0), m_forced_updates(0), m_dangerous_updates(0),
90 m_force_update(true), m_dist_check(true), m_has_been_updated_once(false), m_want_exclusions(false)
92 m_exec_conf->msg->notice(5) << "Constructing Neighborlist" << endl;
94 // check for two sensless errors the user could make
95 if (m_r_cut < 0.0)
97 m_exec_conf->msg->error() << "nlist: Requested cuttoff radius is less than zero" << endl;
98 throw runtime_error("Error initializing NeighborList");
101 if (m_r_buff < 0.0)
103 m_exec_conf->msg->error() << "nlist: Requested buffer radius is less than zero" << endl;
104 throw runtime_error("Error initializing NeighborList");
107 // initialize values
108 m_last_updated_tstep = 0;
109 m_last_checked_tstep = 0;
110 m_last_check_result = false;
111 m_every = 0;
112 m_Nmax = 0;
113 m_exclusions_set = false;
116 // initialize box length at last update
117 m_last_L = m_pdata->getGlobalBox().getNearestPlaneDistance();
118 m_last_L_local = m_pdata->getBox().getNearestPlaneDistance();
120 // allocate conditions flags
121 GPUFlags<unsigned int> conditions(exec_conf);
122 m_conditions.swap(conditions);
124 // allocate m_n_neigh
125 GPUArray<unsigned int> n_neigh(m_pdata->getMaxN(), exec_conf);
126 m_n_neigh.swap(n_neigh);
128 // allocate neighbor list
129 allocateNlist();
131 // allocate m_last_pos
132 GPUArray<Scalar4> last_pos(m_pdata->getMaxN(), exec_conf);
133 m_last_pos.swap(last_pos);
135 // allocate initial memory allowing 4 exclusions per particle (will grow to match specified exclusions)
136 GPUArray<unsigned int> n_ex_tag(m_pdata->getNGlobal(), exec_conf);
137 m_n_ex_tag.swap(n_ex_tag);
139 GPUArray<unsigned int> ex_list_tag(m_pdata->getNGlobal(), 1, exec_conf);
140 m_ex_list_tag.swap(ex_list_tag);
142 GPUArray<unsigned int> n_ex_idx(m_pdata->getMaxN(), exec_conf);
143 m_n_ex_idx.swap(n_ex_idx);
144 GPUArray<unsigned int> ex_list_idx(m_pdata->getMaxN(), 1, exec_conf);
145 m_ex_list_idx.swap(ex_list_idx);
147 // reset exclusions
148 clearExclusions();
150 m_ex_list_indexer = Index2D(m_ex_list_idx.getPitch(), 1);
151 m_ex_list_indexer_tag = Index2D(m_ex_list_tag.getPitch(), 1);
153 m_sort_connection = m_pdata->connectParticleSort(bind(&NeighborList::forceUpdate, this));
155 m_max_particle_num_change_connection = m_pdata->connectMaxParticleNumberChange(bind(&NeighborList::reallocate, this));
157 // allocate m_update_periods tracking info
158 m_update_periods.resize(100);
159 for (unsigned int i = 0; i < m_update_periods.size(); i++)
160 m_update_periods[i] = 0;
163 /*! Reallocate internal data structures upon change of local maximum particle number
165 void NeighborList::reallocate()
167 m_last_pos.resize(m_pdata->getMaxN());
168 m_n_ex_idx.resize(m_pdata->getMaxN());
169 unsigned int ex_list_height = m_ex_list_indexer.getH();
170 m_ex_list_idx.resize(m_pdata->getMaxN(), ex_list_height );
171 m_ex_list_indexer = Index2D(m_ex_list_idx.getPitch(), ex_list_height);
173 m_nlist.resize(m_pdata->getMaxN(), m_Nmax+1);
174 m_nlist_indexer = Index2D(m_nlist.getPitch(), m_Nmax);
176 m_n_neigh.resize(m_pdata->getMaxN());
178 if (m_n_ex_tag.getNumElements() != m_pdata->getNGlobal())
180 m_n_ex_tag.resize(m_pdata->getNGlobal());
181 m_ex_list_tag.resize(m_pdata->getNGlobal(), m_ex_list_tag.getHeight());
182 m_ex_list_indexer_tag = Index2D(m_ex_list_tag.getPitch(), m_ex_list_tag.getHeight());
184 // clear all exclusions
185 clearExclusions();
187 // they need to be added again
188 m_want_exclusions = true;
192 NeighborList::~NeighborList()
194 m_exec_conf->msg->notice(5) << "Destroying Neighborlist" << endl;
196 m_sort_connection.disconnect();
197 m_max_particle_num_change_connection.disconnect();
198 #ifdef ENABLE_MPI
199 if (m_migrate_request_connection.connected())
200 m_migrate_request_connection.disconnect();
201 if (m_comm_flags_request.connected())
202 m_comm_flags_request.disconnect();
203 #endif
206 /*! Updates the neighborlist if it has not yet been updated this times step
207 \param timestep Current time step of the simulation
209 void NeighborList::compute(unsigned int timestep)
211 // skip if we shouldn't compute this step
212 if (!shouldCompute(timestep) && !m_force_update)
213 return;
215 if (m_prof) m_prof->push("Neighbor");
217 // update the exclusion data if this is a forced update
218 if (m_force_update)
220 if (m_exclusions_set)
221 updateExListIdx();
224 // check if the list needs to be updated and update it
225 if (needsUpdating(timestep))
227 // rebuild the list until there is no overflow
228 bool overflowed = false;
231 buildNlist(timestep);
233 overflowed = checkConditions();
234 // if we overflowed, need to reallocate memory and reset the conditions
235 if (overflowed)
237 allocateNlist();
238 resetConditions();
240 } while (overflowed);
242 if (m_exclusions_set)
243 filterNlist();
245 setLastUpdatedPos();
246 m_has_been_updated_once = true;
249 if (m_prof) m_prof->pop();
252 /*! \param num_iters Number of iterations to average for the benchmark
253 \returns Milliseconds of execution time per calculation
255 Calls buildNlist repeatedly to benchmark the neighbor list.
257 double NeighborList::benchmark(unsigned int num_iters)
259 ClockSource t;
260 // warm up run
261 forceUpdate();
262 compute(0);
263 buildNlist(0);
265 #ifdef ENABLE_CUDA
266 if (exec_conf->isCUDAEnabled())
268 cudaThreadSynchronize();
269 CHECK_CUDA_ERROR();
271 #endif
273 // benchmark
274 uint64_t start_time = t.getTime();
275 for (unsigned int i = 0; i < num_iters; i++)
276 buildNlist(0);
278 #ifdef ENABLE_CUDA
279 if (exec_conf->isCUDAEnabled())
280 cudaThreadSynchronize();
281 #endif
282 uint64_t total_time_ns = t.getTime() - start_time;
284 // convert the run time to milliseconds
285 return double(total_time_ns) / 1e6 / double(num_iters);
288 /*! \param r_cut New cuttoff radius to set
289 \param r_buff New buffer radius to set
290 \note Changing the cuttoff radius does NOT immeadiately update the neighborlist.
291 The new cuttoff will take effect when compute is called for the next timestep.
293 void NeighborList::setRCut(Scalar r_cut, Scalar r_buff)
295 m_r_cut = r_cut;
296 m_r_buff = r_buff;
298 // check for two sensless errors the user could make
299 if (m_r_cut < 0.0)
301 m_exec_conf->msg->error() << "nlist: Requested cuttoff radius is less than zero" << endl;
302 throw runtime_error("Error changing NeighborList parameters");
305 if (m_r_buff < 0.0)
307 m_exec_conf->msg->error() << "nlist: Requested buffer radius is less than zero" << endl;
308 throw runtime_error("Error changing NeighborList parameters");
311 #ifdef ENABLE_MPI
312 if (m_comm)
314 Scalar rmax = m_r_cut + m_r_buff;
315 // add d_max - 1.0 all the time - this is needed so that all interacting slj particles are communicated
316 rmax += m_d_max - Scalar(1.0);
317 m_comm->setGhostLayerWidth(rmax);
318 m_comm->setRBuff(m_r_buff);
320 #endif
321 forceUpdate();
324 /*! \returns an estimate of the number of neighbors per particle
325 This mean-field estimate may be very bad dending on how clustered particles are.
326 Derived classes can override this method to provide better estimates.
328 \note Under NO circumstances should calling this method produce any
329 appreciable amount of overhead. This is mainly a warning to
330 derived classes.
332 Scalar NeighborList::estimateNNeigh()
334 // calculate a number density of particles
335 BoxDim box = m_pdata->getBox();
336 Scalar3 L = box.getL();
337 Scalar vol = L.x * L.y * L.z;
338 Scalar n_dens = Scalar(m_pdata->getN()) / vol;
340 // calculate the average number of neighbors by multiplying by the volume
341 // within the cutoff
342 Scalar r_max = m_r_cut + m_r_buff;
343 Scalar vol_cut = Scalar(4.0/3.0 * M_PI) * r_max * r_max * r_max;
344 return n_dens * vol_cut;
347 /*! \param tag1 TAG (not index) of the first particle in the pair
348 \param tag2 TAG (not index) of the second particle in the pair
349 \post The pair \a tag1, \a tag2 will not appear in the neighborlist
350 \note This only takes effect on the next call to compute() that updates the list
351 \note Duplicates are checked for and not added.
353 void NeighborList::addExclusion(unsigned int tag1, unsigned int tag2)
355 assert(tag1 < m_pdata->getNGlobal());
356 assert(tag2 < m_pdata->getNGlobal());
358 m_exclusions_set = true;
360 // don't add an exclusion twice
361 if (isExcluded(tag1, tag2))
362 return;
364 // this is clunky, but needed due to the fact that we cannot have an array handle in scope when
365 // calling grow exclusion list
366 bool grow = false;
368 // access arrays
369 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::readwrite);
371 // grow the list if necessary
372 if (h_n_ex_tag.data[tag1] == m_ex_list_indexer.getH())
373 grow = true;
375 if (h_n_ex_tag.data[tag2] == m_ex_list_indexer.getH())
376 grow = true;
379 if (grow)
380 growExclusionList();
383 // access arrays
384 ArrayHandle<unsigned int> h_ex_list_tag(m_ex_list_tag, access_location::host, access_mode::readwrite);
385 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::readwrite);
387 // add tag2 to tag1's exclusion list
388 unsigned int pos1 = h_n_ex_tag.data[tag1];
389 assert(pos1 < m_ex_list_indexer.getH());
390 h_ex_list_tag.data[m_ex_list_indexer_tag(tag1,pos1)] = tag2;
391 h_n_ex_tag.data[tag1]++;
393 // add tag1 to tag2's exclusion list
394 unsigned int pos2 = h_n_ex_tag.data[tag2];
395 assert(pos2 < m_ex_list_indexer.getH());
396 h_ex_list_tag.data[m_ex_list_indexer_tag(tag2,pos2)] = tag1;
397 h_n_ex_tag.data[tag2]++;
400 // Exclusions have been added, so assume the exclusion list is now current
401 m_want_exclusions = false;
403 forceUpdate();
406 /*! \post No particles are excluded from the neighbor list
408 void NeighborList::clearExclusions()
410 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::overwrite);
411 ArrayHandle<unsigned int> h_n_ex_idx(m_n_ex_idx, access_location::host, access_mode::overwrite);
413 memset(h_n_ex_tag.data, 0, sizeof(unsigned int)*m_pdata->getNGlobal());
414 memset(h_n_ex_idx.data, 0, sizeof(unsigned int)*m_pdata->getN());
415 m_exclusions_set = false;
417 forceUpdate();
420 //! Get number of exclusions involving n particles
421 unsigned int NeighborList::getNumExclusions(unsigned int size)
423 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::read);
424 unsigned int count = 0;
425 for (unsigned int i = 0; i < m_pdata->getN(); i++)
427 unsigned int num_excluded = h_n_ex_tag.data[i];
429 if (num_excluded == size) count++;
432 #ifdef ENABLE_MPI
433 if (m_pdata->getDomainDecomposition())
435 MPI_Allreduce(MPI_IN_PLACE,
436 &count,
438 MPI_INT,
439 MPI_SUM,
440 m_exec_conf->getMPICommunicator());
442 #endif
444 return count;
447 /*! \post Gather some statistics about exclusions usage.
449 void NeighborList::countExclusions()
451 unsigned int MAX_COUNT_EXCLUDED = 16;
452 unsigned int excluded_count[MAX_COUNT_EXCLUDED+2];
453 unsigned int num_excluded, max_num_excluded;
455 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::read);
457 max_num_excluded = 0;
458 for (unsigned int c=0; c <= MAX_COUNT_EXCLUDED+1; ++c)
459 excluded_count[c] = 0;
461 for (unsigned int i = 0; i < m_pdata->getNGlobal(); i++)
463 num_excluded = h_n_ex_tag.data[i];
465 if (num_excluded > max_num_excluded)
466 max_num_excluded = num_excluded;
468 if (num_excluded > MAX_COUNT_EXCLUDED)
469 num_excluded = MAX_COUNT_EXCLUDED + 1;
471 excluded_count[num_excluded] += 1;
474 m_exec_conf->msg->notice(2) << "-- Neighborlist exclusion statistics -- :" << endl;
475 for (unsigned int i=0; i <= MAX_COUNT_EXCLUDED; ++i)
477 if (excluded_count[i] > 0)
478 m_exec_conf->msg->notice(2) << "Particles with " << i << " exclusions : " << excluded_count[i] << endl;
481 if (excluded_count[MAX_COUNT_EXCLUDED+1])
483 m_exec_conf->msg->notice(2) << "Particles with more than " << MAX_COUNT_EXCLUDED << " exclusions: "
484 << excluded_count[MAX_COUNT_EXCLUDED+1] << endl;
487 if (m_filter_diameter)
488 m_exec_conf->msg->notice(2) << "Neighbors excluded by diameter (slj) : yes" << endl;
489 else
490 m_exec_conf->msg->notice(2) << "Neighbors excluded by diameter (slj) : no" << endl;
492 if (m_filter_body)
493 m_exec_conf->msg->notice(2) << "Neighbors excluded when in the same body: yes" << endl;
494 else
495 m_exec_conf->msg->notice(2) << "Neighbors excluded when in the same body: no" << endl;
497 if (!m_filter_body && m_sysdef->getRigidData()->getNumBodies() > 0)
499 m_exec_conf->msg->warning() << "Disabling the body exclusion will cause rigid bodies to behave erratically" << endl
500 << " unless inter-body pair forces are very small." << endl;
504 /*! After calling addExclusionFromBonds() all bonds specified in the attached ParticleData will be
505 added as exlusions. Any additional bonds added after this will not be automatically added as exclusions.
507 void NeighborList::addExclusionsFromBonds()
509 boost::shared_ptr<BondData> bond_data = m_sysdef->getBondData();
511 // access bond data by snapshot
512 BondData::Snapshot snapshot(bond_data->getNGlobal());
513 bond_data->takeSnapshot(snapshot);
515 // broadcast global bond list
516 std::vector<BondData::members_t> bonds;
518 #ifdef ENABLE_MPI
519 if (m_pdata->getDomainDecomposition())
521 if (m_exec_conf->getRank() == 0)
522 bonds = snapshot.groups;
524 bcast(bonds, 0, m_exec_conf->getMPICommunicator());
526 else
527 #endif
529 bonds = snapshot.groups;
532 // for each bond
533 for (unsigned int i = 0; i < bonds.size(); i++)
534 // add an exclusion
535 addExclusion(bonds[i].tag[0], bonds[i].tag[1]);
538 /*! After calling addExclusionsFromAngles(), all angles specified in the attached ParticleData will be added to the
539 exclusion list. Only the two end particles in the angle are excluded from interacting.
541 void NeighborList::addExclusionsFromAngles()
543 boost::shared_ptr<AngleData> angle_data = m_sysdef->getAngleData();
545 // access angle data by snapshot
546 AngleData::Snapshot snapshot(angle_data->getNGlobal());
547 angle_data->takeSnapshot(snapshot);
549 // broadcast global angle list
550 std::vector<AngleData::members_t> angles;
552 #ifdef ENABLE_MPI
553 if (m_pdata->getDomainDecomposition())
555 if (m_exec_conf->getRank() == 0)
556 angles = snapshot.groups;
558 bcast(angles, 0, m_exec_conf->getMPICommunicator());
560 else
561 #endif
563 angles = snapshot.groups;
566 // for each angle
567 for (unsigned int i = 0; i < angles.size(); i++)
568 addExclusion(angles[i].tag[0], angles[i].tag[2]);
571 /*! After calling addExclusionsFromDihedrals(), all dihedrals specified in the attached ParticleData will be added to the
572 exclusion list. Only the two end particles in the dihedral are excluded from interacting.
574 void NeighborList::addExclusionsFromDihedrals()
576 boost::shared_ptr<DihedralData> dihedral_data = m_sysdef->getDihedralData();
578 // access dihedral data by snapshot
579 DihedralData::Snapshot snapshot(dihedral_data->getNGlobal());
580 dihedral_data->takeSnapshot(snapshot);
582 // broadcast global dihedral list
583 std::vector<DihedralData::members_t> dihedrals;
585 #ifdef ENABLE_MPI
586 if (m_pdata->getDomainDecomposition())
588 if (m_exec_conf->getRank() == 0)
589 dihedrals = snapshot.groups;
591 bcast(dihedrals, 0, m_exec_conf->getMPICommunicator());
593 else
594 #endif
596 dihedrals = snapshot.groups;
599 // for each dihedral
600 for (unsigned int i = 0; i < dihedrals.size(); i++)
601 addExclusion(dihedrals[i].tag[0], dihedrals[i].tag[3]);
604 /*! \param tag1 First particle tag in the pair
605 \param tag2 Second particle tag in the pair
606 \return true if the particles \a tag1 and \a tag2 have been excluded from the neighbor list
608 bool NeighborList::isExcluded(unsigned int tag1, unsigned int tag2)
610 assert(tag1 < m_pdata->getNGlobal());
611 assert(tag2 < m_pdata->getNGlobal());
613 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::read);
614 ArrayHandle<unsigned int> h_ex_list_tag(m_ex_list_tag, access_location::host, access_mode::read);
616 unsigned int n_ex = h_n_ex_tag.data[tag1];
617 for (unsigned int i = 0; i < n_ex; i++)
619 if (h_ex_list_tag.data[m_ex_list_indexer_tag(tag1,i)] == tag2)
620 return true;
623 return false;
626 /*! Add topologically derived exclusions for angles
628 * This excludes all non-bonded interactions between all pairs particles
629 * that are bonded to the same atom.
630 * To make the process quasi-linear scaling with system size we first
631 * create a 1-d array the collects the number and index of bond partners.
633 void NeighborList::addOneThreeExclusionsFromTopology()
635 boost::shared_ptr<BondData> bond_data = m_sysdef->getBondData();
636 const unsigned int myNAtoms = m_pdata->getNGlobal();
637 const unsigned int MAXNBONDS = 7+1; //! assumed maximum number of bonds per atom plus one entry for the number of bonds.
638 const unsigned int nBonds = bond_data->getNGlobal();
640 if (nBonds == 0)
642 m_exec_conf->msg->warning() << "nlist: No bonds defined while trying to add topology derived 1-3 exclusions" << endl;
643 return;
646 // build a per atom list with all bonding partners from the list of bonds.
647 unsigned int *localBondList = new unsigned int[MAXNBONDS*myNAtoms];
648 memset((void *)localBondList,0,sizeof(unsigned int)*MAXNBONDS*myNAtoms);
650 for (unsigned int i = 0; i < nBonds; i++)
652 // loop over all bonds and make a 1D exlcusion map
653 Bond bondi = bond_data->getGroupByTag(i);
654 const unsigned int tagA = bondi.a;
655 const unsigned int tagB = bondi.b;
657 // next, incremement the number of bonds, and update the tags
658 const unsigned int nBondsA = ++localBondList[tagA*MAXNBONDS];
659 const unsigned int nBondsB = ++localBondList[tagB*MAXNBONDS];
661 if (nBondsA >= MAXNBONDS)
663 m_exec_conf->msg->error() << "nlist: Too many bonds to process exclusions for particle with tag: " << tagA << endl;
664 m_exec_conf->msg->error() << "Maximum allowed is currently: " << MAXNBONDS-1 << endl;
665 throw runtime_error("Error setting up toplogical exclusions in NeighborList");
668 if (nBondsB >= MAXNBONDS)
670 m_exec_conf->msg->error() << "nlist: Too many bonds to process exclusions for particle with tag: " << tagB << endl;
671 m_exec_conf->msg->error() << "Maximum allowed is currently: " << MAXNBONDS-1 << endl;
672 throw runtime_error("Error setting up toplogical exclusions in NeighborList");
675 localBondList[tagA*MAXNBONDS + nBondsA] = tagB;
676 localBondList[tagB*MAXNBONDS + nBondsB] = tagA;
679 // now loop over the atoms and build exclusions if we have more than
680 // one bonding partner, i.e. we are in the center of an angle.
681 for (unsigned int i = 0; i < myNAtoms; i++)
683 // now, loop over all atoms, and find those in the middle of an angle
684 const unsigned int iAtom = i*MAXNBONDS;
685 const unsigned int nBonds = localBondList[iAtom];
687 if (nBonds > 1) // need at least two bonds
689 for (unsigned int j = 1; j < nBonds; ++j)
691 for (unsigned int k = j+1; k <= nBonds; ++k)
692 addExclusion(localBondList[iAtom+j],localBondList[iAtom+k]);
696 // free temp memory
697 delete[] localBondList;
700 /*! Add topologically derived exclusions for dihedrals
702 * This excludes all non-bonded interactions between all pairs particles
703 * that are connected to a common bond.
705 * To make the process quasi-linear scaling with system size we first
706 * create a 1-d array the collects the number and index of bond partners.
707 * and then loop over bonded partners.
709 void NeighborList::addOneFourExclusionsFromTopology()
711 boost::shared_ptr<BondData> bond_data = m_sysdef->getBondData();
712 const unsigned int myNAtoms = m_pdata->getNGlobal();
713 const unsigned int MAXNBONDS = 7+1; //! assumed maximum number of bonds per atom plus one entry for the number of bonds.
714 const unsigned int nBonds = bond_data->getNGlobal();
716 if (nBonds == 0)
718 m_exec_conf->msg->warning() << "nlist: No bonds defined while trying to add topology derived 1-4 exclusions" << endl;
719 return;
722 // allocate and clear data.
723 unsigned int *localBondList = new unsigned int[MAXNBONDS*myNAtoms];
724 memset((void *)localBondList,0,sizeof(unsigned int)*MAXNBONDS*myNAtoms);
726 for (unsigned int i = 0; i < nBonds; i++)
728 // loop over all bonds and make a 1D exlcusion map
729 Bond bondi = bond_data->getGroupByTag(i);
730 const unsigned int tagA = bondi.a;
731 const unsigned int tagB = bondi.b;
733 // next, incrememt the number of bonds, and update the tags
734 const unsigned int nBondsA = ++localBondList[tagA*MAXNBONDS];
735 const unsigned int nBondsB = ++localBondList[tagB*MAXNBONDS];
737 if (nBondsA >= MAXNBONDS)
739 m_exec_conf->msg->error() << "nlist: Too many bonds to process exclusions for particle with tag: " << tagA << endl;
740 m_exec_conf->msg->error() << "Maximum allowed is currently: " << MAXNBONDS-1 << endl;
741 throw runtime_error("Error setting up toplogical exclusions in NeighborList");
744 if (nBondsB >= MAXNBONDS)
746 m_exec_conf->msg->error() << "nlist: Too many bonds to process exclusions for particle with tag: " << tagB << endl;
747 m_exec_conf->msg->error() << "Maximum allowed is currently: " << MAXNBONDS-1 << endl;
748 throw runtime_error("Error setting up toplogical exclusions in NeighborList");
751 localBondList[tagA*MAXNBONDS + nBondsA] = tagB;
752 localBondList[tagB*MAXNBONDS + nBondsB] = tagA;
755 // loop over all bonds
756 for (unsigned int i = 0; i < nBonds; i++)
758 Bond bondi = bond_data->getGroupByTag(i);
759 const unsigned int tagA = bondi.a;
760 const unsigned int tagB = bondi.b;
762 const unsigned int nBondsA = localBondList[tagA*MAXNBONDS];
763 const unsigned int nBondsB = localBondList[tagB*MAXNBONDS];
765 for (unsigned int j = 1; j <= nBondsA; j++)
767 const unsigned int tagJ = localBondList[tagA*MAXNBONDS+j];
768 if (tagJ == tagB) // skip the bond in the middle of the dihedral
769 continue;
771 for (unsigned int k = 1; k <= nBondsB; k++)
773 const unsigned int tagK = localBondList[tagB*MAXNBONDS+k];
774 if (tagK == tagA) // skip the bond in the middle of the dihedral
775 continue;
777 addExclusion(tagJ,tagK);
781 // free temp memory
782 delete[] localBondList;
786 /*! \returns true If any of the particles have been moved more than 1/2 of the buffer distance since the last call
787 to this method that returned true.
788 \returns false If none of the particles has been moved more than 1/2 of the buffer distance since the last call to this
789 method that returned true.
791 Note: this method relies on data set by setLastUpdatedPos(), which must be called to set the previous data used
792 in the next call to distanceCheck();
794 bool NeighborList::distanceCheck(unsigned int timestep)
796 ArrayHandle<Scalar4> h_pos(m_pdata->getPositions(), access_location::host, access_mode::read);
798 // sanity check
799 assert(h_pos.data);
801 // profile
802 if (m_prof) m_prof->push("Dist check");
804 // temporary storage for the result
805 bool result = false;
807 // get a local copy of the simulation box too
808 const BoxDim& box = m_pdata->getBox();
810 ArrayHandle<Scalar4> h_last_pos(m_last_pos, access_location::host, access_mode::read);
812 // get current nearest plane distances
813 Scalar3 L_g = m_pdata->getGlobalBox().getNearestPlaneDistance();
815 // Cutoff distance for inclusion in neighbor list
816 Scalar rmax = m_r_cut + m_r_buff;
817 if (!m_filter_diameter)
818 rmax += m_d_max - Scalar(1.0);
820 // Find direction of maximum box length contraction (smallest eigenvalue of deformation tensor)
821 Scalar3 lambda = L_g / m_last_L;
822 Scalar lambda_min = (lambda.x < lambda.y) ? lambda.x : lambda.y;
823 lambda_min = (lambda_min < lambda.z) ? lambda_min : lambda.z;
825 // maximum displacement for each particle (after subtraction of homogeneous dilations)
826 Scalar delta_max = (rmax*lambda_min - m_r_cut)/Scalar(2.0);
827 Scalar maxsq = delta_max > 0 ? delta_max*delta_max : 0;
829 for (unsigned int i = 0; i < m_pdata->getN(); i++)
831 Scalar3 dx = make_scalar3(h_pos.data[i].x - lambda.x*h_last_pos.data[i].x,
832 h_pos.data[i].y - lambda.y*h_last_pos.data[i].y,
833 h_pos.data[i].z - lambda.z*h_last_pos.data[i].z);
835 dx = box.minImage(dx);
837 if (dot(dx, dx) >= maxsq)
839 result = true;
840 break;
844 #ifdef ENABLE_MPI
845 if (m_pdata->getDomainDecomposition())
847 if (m_prof) m_prof->push("MPI allreduce");
848 // check if migrate criterium is fulfilled on any rank
849 int local_result = result ? 1 : 0;
850 int global_result = 0;
851 MPI_Allreduce(&local_result,
852 &global_result,
854 MPI_INT,
855 MPI_MAX,
856 m_exec_conf->getMPICommunicator());
857 result = (global_result > 0);
858 if (m_prof) m_prof->pop();
860 #endif
862 // don't worry about computing flops here, this is fast
863 if (m_prof) m_prof->pop();
865 return result;
868 /*! Copies the current positions of all particles over to m_last_x etc...
870 void NeighborList::setLastUpdatedPos()
872 ArrayHandle<Scalar4> h_pos(m_pdata->getPositions(), access_location::host, access_mode::read);
874 // sanity check
875 assert(h_pos.data);
877 // profile
878 if (m_prof) m_prof->push("Dist check");
880 // update the last position arrays
881 ArrayHandle<Scalar4> h_last_pos(m_last_pos, access_location::host, access_mode::overwrite);
882 for (unsigned int i = 0; i < m_pdata->getN(); i++)
884 h_last_pos.data[i] = make_scalar4(h_pos.data[i].x, h_pos.data[i].y, h_pos.data[i].z, Scalar(0.0));
887 // update last box nearest plane distance
888 m_last_L = m_pdata->getGlobalBox().getNearestPlaneDistance();
889 m_last_L_local = m_pdata->getBox().getNearestPlaneDistance();
891 if (m_prof) m_prof->pop();
894 bool NeighborList::shouldCheckDistance(unsigned int timestep)
896 return !m_force_update && !(timestep < (m_last_updated_tstep + m_every));
899 /*! \returns true If the neighbor list needs to be updated
900 \returns false If the neighbor list does not need to be updated
901 \note This is designed to be called if (needsUpdating()) then update every step.
902 It internally handles many state variables that rely on this assumption.
904 \param timestep Current time step in the simulation
906 bool NeighborList::needsUpdating(unsigned int timestep)
908 if (m_last_checked_tstep == timestep)
910 if (m_force_update)
912 // force update is counted only once per time step
913 m_force_update = false;
914 return true;
916 return m_last_check_result;
919 m_last_checked_tstep = timestep;
921 if (!m_force_update && !shouldCheckDistance(timestep))
923 m_last_check_result = false;
924 return false;
927 // temporary storage for return result
928 bool result = false;
930 // check if this is a dangerous time
931 // we are dangerous if m_every is greater than 1 and this is the first check after the
932 // last build
933 bool dangerous = false;
934 if (m_dist_check && (m_every > 1 && timestep == (m_last_updated_tstep + m_every)))
935 dangerous = true;
937 // if the update has been forced, the result defaults to true
938 if (m_force_update)
940 result = true;
941 m_force_update = false;
942 m_forced_updates += 1;
943 m_last_updated_tstep = timestep;
945 // when an update is forced, there is no way to tell if the build
946 // is dangerous or not: filter out the false positive errors
947 dangerous = false;
949 else
951 // not a forced update, perform the distance check to determine
952 // if the list needs to be updated - no dist check needed if r_buff is tiny
953 // it also needs to be updated if m_every is 0, or the check period is hit when distance checks are disabled
954 if (m_r_buff < 1e-6 ||
955 (!m_dist_check && (m_every == 0 || (m_every > 1 && timestep == (m_last_updated_tstep + m_every)))))
957 result = true;
959 else
961 result = distanceCheck(timestep);
964 if (result)
966 // record update histogram - but only if the period is positive
967 if (timestep > m_last_updated_tstep)
969 unsigned int period = timestep - m_last_updated_tstep;
970 if (period >= m_update_periods.size())
971 period = m_update_periods.size()-1;
972 m_update_periods[period]++;
975 m_last_updated_tstep = timestep;
976 m_updates += 1;
980 // warn the user if this is a dangerous build
981 if (result && dangerous)
983 m_exec_conf->msg->notice(2) << "nlist: Dangerous neighborlist build occured. Continuing this simulation may produce incorrect results and/or program crashes. Decrease the neighborlist check_period and rerun." << endl;
984 m_dangerous_updates += 1;
987 m_last_check_result = result;
988 return result;
991 /*! Generic statistics that apply to any neighbor list, like the number of updates,
992 average number of neighbors, etc... are printed to stdout. Derived classes should
993 print any pertinient information they see fit to.
995 void NeighborList::printStats()
997 // return earsly if the notice level is less than 1
998 if (m_exec_conf->msg->getNoticeLevel() < 1)
999 return;
1001 m_exec_conf->msg->notice(1) << "-- Neighborlist stats:" << endl;
1002 m_exec_conf->msg->notice(1) << m_updates << " normal updates / " << m_forced_updates << " forced updates / " << m_dangerous_updates << " dangerous updates" << endl;
1004 // access the number of neighbors to generate stats
1005 ArrayHandle<unsigned int> h_n_neigh(m_n_neigh, access_location::host, access_mode::read);
1007 // build some simple statistics of the number of neighbors
1008 unsigned int n_neigh_min = m_pdata->getN();
1009 unsigned int n_neigh_max = 0;
1010 Scalar n_neigh_avg = 0.0;
1012 for (unsigned int i = 0; i < m_pdata->getN(); i++)
1014 unsigned int n_neigh = (unsigned int)h_n_neigh.data[i];
1015 if (n_neigh < n_neigh_min)
1016 n_neigh_min = n_neigh;
1017 if (n_neigh > n_neigh_max)
1018 n_neigh_max = n_neigh;
1020 n_neigh_avg += Scalar(n_neigh);
1023 // divide to get the average
1024 n_neigh_avg /= Scalar(m_pdata->getN());
1025 m_exec_conf->msg->notice(1) << "n_neigh_min: " << n_neigh_min << " / n_neigh_max: " << n_neigh_max << " / n_neigh_avg: " << n_neigh_avg << endl;
1027 m_exec_conf->msg->notice(1) << "shortest rebuild period: " << getSmallestRebuild() << endl;
1030 void NeighborList::resetStats()
1032 m_updates = m_forced_updates = m_dangerous_updates = 0;
1034 for (unsigned int i = 0; i < m_update_periods.size(); i++)
1035 m_update_periods[i] = 0;
1038 unsigned int NeighborList::getSmallestRebuild()
1040 for (unsigned int i = 0; i < m_update_periods.size(); i++)
1042 if (m_update_periods[i] != 0)
1043 return i;
1045 return m_update_periods.size();
1048 /*! Loops through the particles and finds all of the particles \c j who's distance is less than
1049 \param timestep Current time step of the simulation
1050 \c r_cut \c + \c r_buff from particle \c i, includes either i < j or all neighbors depending
1051 on the mode set by setStorageMode()
1053 void NeighborList::buildNlist(unsigned int timestep)
1055 // sanity check
1056 assert(m_pdata);
1058 // start up the profile
1059 if (m_prof) m_prof->push("Build list");
1061 // access the particle data
1062 ArrayHandle<Scalar4> h_pos(m_pdata->getPositions(), access_location::host, access_mode::read);
1063 ArrayHandle<Scalar> h_diameter(m_pdata->getDiameters(), access_location::host, access_mode::read);
1064 ArrayHandle<unsigned int> h_body(m_pdata->getBodies(), access_location::host, access_mode::read);
1066 // sanity check
1067 assert(h_pos.data);
1068 assert(h_diameter.data);
1069 assert(h_body.data);
1071 // get a local copy of the simulation box too
1072 const BoxDim& box = m_pdata->getBox();
1073 Scalar3 nearest_plane_distance = box.getNearestPlaneDistance();
1075 // start by creating a temporary copy of r_cut sqaured
1076 Scalar rmax = m_r_cut + m_r_buff;
1077 // add d_max - 1.0, if diameter filtering is not already taking care of it
1078 if (!m_filter_diameter)
1079 rmax += m_d_max - Scalar(1.0);
1080 Scalar rmaxsq = rmax*rmax;
1082 if ((box.getPeriodic().x && nearest_plane_distance.x <= rmax * 2.0) ||
1083 (box.getPeriodic().y && nearest_plane_distance.y <= rmax * 2.0) ||
1084 (this->m_sysdef->getNDimensions() == 3 && box.getPeriodic().z && nearest_plane_distance.z <= rmax * 2.0))
1086 m_exec_conf->msg->error() << "nlist: Simulation box is too small! Particles would be interacting with themselves." << endl;
1087 throw runtime_error("Error updating neighborlist bins");
1090 // access the nlist data
1091 ArrayHandle<unsigned int> h_n_neigh(m_n_neigh, access_location::host, access_mode::overwrite);
1092 ArrayHandle<unsigned int> h_nlist(m_nlist, access_location::host, access_mode::overwrite);
1094 unsigned int conditions = 0;
1096 // start by clearing the entire list
1097 memset(h_n_neigh.data, 0, sizeof(unsigned int)*m_pdata->getN());
1099 // now we can loop over all particles in n^2 fashion and build the list
1100 for (int i = 0; i < (int)m_pdata->getN(); i++)
1102 Scalar3 pi = make_scalar3(h_pos.data[i].x, h_pos.data[i].y, h_pos.data[i].z);
1103 Scalar di = h_diameter.data[i];
1104 unsigned int bodyi = h_body.data[i];
1106 // for each other particle with i < j, including ghost particles
1107 for (unsigned int j = i + 1; j < m_pdata->getN() + m_pdata->getNGhosts(); j++)
1109 // calculate dr
1110 Scalar3 pj = make_scalar3(h_pos.data[j].x, h_pos.data[j].y, h_pos.data[j].z);
1111 Scalar3 dx = pj - pi;
1113 dx = box.minImage(dx);
1115 bool excluded = false;
1116 if (m_filter_body && bodyi != NO_BODY)
1117 excluded = (bodyi == h_body.data[j]);
1119 Scalar sqshift = Scalar(0.0);
1120 if (m_filter_diameter)
1122 // compute the shift in radius to accept neighbors based on their diameters
1123 Scalar delta = (di + h_diameter.data[j]) * Scalar(0.5) - Scalar(1.0);
1124 // r^2 < (r_max + delta)^2
1125 // r^2 < r_maxsq + delta^2 + 2*r_max*delta
1126 sqshift = (delta + Scalar(2.0) * rmax) * delta;
1129 // now compare rsq to rmaxsq and add to the list if it meets the criteria
1130 Scalar rsq = dot(dx, dx);
1131 if (rsq <= (rmaxsq + sqshift) && !excluded)
1133 if (m_storage_mode == full)
1135 unsigned int posi = h_n_neigh.data[i];
1136 if (posi < m_Nmax)
1137 h_nlist.data[m_nlist_indexer(i, posi)] = j;
1138 else
1139 conditions = max(conditions, h_n_neigh.data[i]+1);
1141 h_n_neigh.data[i]++;
1143 unsigned int posj = h_n_neigh.data[j];
1144 if (posj < m_Nmax)
1145 h_nlist.data[m_nlist_indexer(j, posj)] = i;
1146 else
1147 conditions = max(conditions, h_n_neigh.data[j]+1);
1149 h_n_neigh.data[j]++;
1151 else
1153 unsigned int pos = h_n_neigh.data[i];
1155 if (pos < m_Nmax)
1156 h_nlist.data[m_nlist_indexer(i, pos)] = j;
1157 else
1158 conditions = max(conditions, h_n_neigh.data[i]+1);
1160 h_n_neigh.data[i]++;
1166 // write out conditions
1167 m_conditions.resetFlags(conditions);
1169 if (m_prof) m_prof->pop();
1172 /*! Translates the exclusions set in \c m_n_ex_tag and \c m_ex_list_tag to indices in \c m_n_ex_idx and \c m_ex_list_idx
1174 void NeighborList::updateExListIdx()
1176 if (m_prof)
1177 m_prof->push("update-ex");
1178 // access data
1179 ArrayHandle<unsigned int> h_tag(m_pdata->getTags(), access_location::host, access_mode::read);
1180 ArrayHandle<unsigned int> h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);
1182 ArrayHandle<unsigned int> h_n_ex_tag(m_n_ex_tag, access_location::host, access_mode::read);
1183 ArrayHandle<unsigned int> h_ex_list_tag(m_ex_list_tag, access_location::host, access_mode::read);
1184 ArrayHandle<unsigned int> h_n_ex_idx(m_n_ex_idx, access_location::host, access_mode::overwrite);
1185 ArrayHandle<unsigned int> h_ex_list_idx(m_ex_list_idx, access_location::host, access_mode::overwrite);
1187 // translate the number and exclusions from one array to the other
1188 for (unsigned int idx = 0; idx < m_pdata->getN(); idx++)
1190 // get the tag for this index
1191 unsigned int tag = h_tag.data[idx];
1193 // copy the number of exclusions over
1194 unsigned int n = h_n_ex_tag.data[tag];
1195 h_n_ex_idx.data[idx] = n;
1197 // construct the exclusion list
1198 for (unsigned int offset = 0; offset < n; offset++)
1200 unsigned int ex_tag = h_ex_list_tag.data[m_ex_list_indexer_tag(tag,offset)];
1201 unsigned int ex_idx = h_rtag.data[ex_tag];
1203 // store excluded particle idx
1204 h_ex_list_idx.data[m_ex_list_indexer(idx, offset)] = ex_idx;
1208 if (m_prof)
1209 m_prof->pop();
1212 /*! Loops through the neighbor list and filters out any excluded pairs
1214 void NeighborList::filterNlist()
1216 if (m_prof)
1217 m_prof->push("filter");
1219 // access data
1221 ArrayHandle<unsigned int> h_n_ex_idx(m_n_ex_idx, access_location::host, access_mode::read);
1222 ArrayHandle<unsigned int> h_ex_list_idx(m_ex_list_idx, access_location::host, access_mode::read);
1223 ArrayHandle<unsigned int> h_n_neigh(m_n_neigh, access_location::host, access_mode::readwrite);
1224 ArrayHandle<unsigned int> h_nlist(m_nlist, access_location::host, access_mode::readwrite);
1226 // for each particle's neighbor list
1227 for (unsigned int idx = 0; idx < m_pdata->getN(); idx++)
1229 unsigned int n_neigh = h_n_neigh.data[idx];
1230 unsigned int n_ex = h_n_ex_idx.data[idx];
1231 unsigned int new_n_neigh = 0;
1233 // loop over the list, regenerating it as we go
1234 for (unsigned int cur_neigh_idx = 0; cur_neigh_idx < n_neigh; cur_neigh_idx++)
1236 unsigned int cur_neigh = h_nlist.data[m_nlist_indexer(idx, cur_neigh_idx)];
1238 // test if excluded
1239 bool excluded = false;
1240 for (unsigned int cur_ex_idx = 0; cur_ex_idx < n_ex; cur_ex_idx++)
1242 unsigned int cur_ex = h_ex_list_idx.data[m_ex_list_indexer(idx, cur_ex_idx)];
1243 if (cur_ex == cur_neigh)
1245 excluded = true;
1246 break;
1250 // add it back to the list if it is not excluded
1251 if (!excluded)
1253 h_nlist.data[m_nlist_indexer(idx, new_n_neigh)] = cur_neigh;
1254 new_n_neigh++;
1258 // update the number of neighbors
1259 h_n_neigh.data[idx] = new_n_neigh;
1262 if (m_prof)
1263 m_prof->pop();
1266 void NeighborList::allocateNlist()
1268 // round up to the nearest multiple of 8
1269 m_Nmax = m_Nmax + 8 - (m_Nmax & 7);
1271 m_exec_conf->msg->notice(6) << "nlist: (Re-)Allocating " << m_pdata->getMaxN() << " x " << m_Nmax+1 << endl;
1273 // re-allocate, overwriting old neighbor list
1274 GPUArray<unsigned int> nlist(m_pdata->getMaxN(), m_Nmax+1, exec_conf);
1275 m_nlist.swap(nlist);
1277 // update the indexer
1278 m_nlist_indexer = Index2D(m_nlist.getPitch(), m_Nmax);
1281 unsigned int NeighborList::readConditions()
1283 return m_conditions.readFlags();
1286 bool NeighborList::checkConditions()
1288 bool result = false;
1290 unsigned int conditions;
1291 conditions = readConditions();
1293 // up m_Nmax to the overflow value, reallocate memory and set the overflow condition
1294 if (conditions > m_Nmax)
1296 m_Nmax = conditions;
1297 result = true;
1300 return result;
1303 void NeighborList::resetConditions()
1305 m_conditions.resetFlags(0);
1308 void NeighborList::growExclusionList()
1310 unsigned int new_height = m_ex_list_indexer.getH() + 1;
1312 m_ex_list_tag.resize(m_pdata->getNGlobal(), new_height);
1313 m_ex_list_idx.resize(m_pdata->getMaxN(), new_height);
1315 // update the indexers
1316 m_ex_list_indexer = Index2D(m_ex_list_idx.getPitch(), new_height);
1317 m_ex_list_indexer_tag = Index2D(m_ex_list_tag.getPitch(), new_height);
1319 // we didn't copy data for the new idx list, force an update so it will be correct
1320 forceUpdate();
1323 #ifdef ENABLE_MPI
1324 //! Set the communicator to use
1325 void NeighborList::setCommunicator(boost::shared_ptr<Communicator> comm)
1327 if (!m_comm)
1329 // only add the migrate request on the first call
1330 m_migrate_request_connection = comm->addMigrateRequest(bind(&NeighborList::peekUpdate, this, _1));
1331 m_comm_flags_request = comm->addCommFlagsRequest(bind(&NeighborList::getRequestedCommFlags, this, _1));
1334 if (comm)
1336 m_comm = comm;
1338 Scalar rmax = m_r_cut + m_r_buff;
1339 // add d_max - 1.0 all the time - this is needed so that all interacting slj particles are communicated
1340 rmax += m_d_max - Scalar(1.0);
1341 m_comm->setGhostLayerWidth(rmax);
1342 m_comm->setRBuff(m_r_buff);
1346 //! Returns true if the particle migration criterium is fulfilled
1347 /*! \note The criterium for when to request particle migration is the same as the one for neighbor list
1348 rebuilds, which is implemented in needsUpdating().
1350 bool NeighborList::peekUpdate(unsigned int timestep)
1352 if (m_prof) m_prof->push("Neighbor");
1354 bool result = needsUpdating(timestep);
1356 if (m_prof) m_prof->pop();
1358 return result;
1360 #endif
1362 void export_NeighborList()
1364 class_< std::vector<unsigned int> >("std_vector_uint")
1365 .def(vector_indexing_suite<std::vector<unsigned int> >())
1366 .def("push_back", &std::vector<unsigned int>::push_back)
1369 scope in_nlist = class_<NeighborList, boost::shared_ptr<NeighborList>, bases<Compute>, boost::noncopyable >
1370 ("NeighborList", init< boost::shared_ptr<SystemDefinition>, Scalar, Scalar >())
1371 .def("setRCut", &NeighborList::setRCut)
1372 .def("setEvery", &NeighborList::setEvery)
1373 .def("setStorageMode", &NeighborList::setStorageMode)
1374 .def("addExclusion", &NeighborList::addExclusion)
1375 .def("clearExclusions", &NeighborList::clearExclusions)
1376 .def("countExclusions", &NeighborList::countExclusions)
1377 .def("addExclusionsFromBonds", &NeighborList::addExclusionsFromBonds)
1378 .def("addExclusionsFromAngles", &NeighborList::addExclusionsFromAngles)
1379 .def("addExclusionsFromDihedrals", &NeighborList::addExclusionsFromDihedrals)
1380 .def("addOneThreeExclusionsFromTopology", &NeighborList::addOneThreeExclusionsFromTopology)
1381 .def("addOneFourExclusionsFromTopology", &NeighborList::addOneFourExclusionsFromTopology)
1382 .def("setFilterBody", &NeighborList::setFilterBody)
1383 .def("getFilterBody", &NeighborList::getFilterBody)
1384 .def("setFilterDiameter", &NeighborList::setFilterDiameter)
1385 .def("getFilterDiameter", &NeighborList::getFilterDiameter)
1386 .def("setMaximumDiameter", &NeighborList::setMaximumDiameter)
1387 .def("forceUpdate", &NeighborList::forceUpdate)
1388 .def("estimateNNeigh", &NeighborList::estimateNNeigh)
1389 .def("getSmallestRebuild", &NeighborList::getSmallestRebuild)
1390 .def("getNumUpdates", &NeighborList::getNumUpdates)
1391 .def("getNumExclusions", &NeighborList::getNumExclusions)
1392 .def("wantExclusions", &NeighborList::wantExclusions)
1393 #ifdef ENABLE_MPI
1394 .def("setCommunicator", &NeighborList::setCommunicator)
1395 #endif
1398 enum_<NeighborList::storageMode>("storageMode")
1399 .value("half", NeighborList::half)
1400 .value("full", NeighborList::full)