Fix potential problem in Messenger related to MPI window
[hoomd-blue.git] / libhoomd / data_structures / BondedGroupData.cc
blob0e6643c5c46206234617132b1cf3b333a96c3c29
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: jglaser
52 /*! \file BondedGroupData.h
53 \brief Defines implementation of BondedGroupData
57 #include "BondedGroupData.h"
58 #include "ParticleData.h"
59 #include "Index1D.h"
61 #ifdef ENABLE_CUDA
62 #include "BondedGroupData.cuh"
63 #include "CachedAllocator.h"
64 #endif
66 //! Names of bonded groups
67 char name_bond_data[] = "bond";
68 char name_angle_data[] = "angle";
69 char name_dihedral_data[] = "dihedral";
70 char name_improper_data[] = "improper";
73 * Implementation of BondedGroupData methods
76 /*! \param exec_conf Execution configuration
77 \param pdata The particle data to associate with
78 \param n_group_types Number of bonded group types to initialize
80 template<unsigned int group_size, typename Group, const char *name>
81 BondedGroupData<group_size, Group, name>::BondedGroupData(
82 boost::shared_ptr<ParticleData> pdata,
83 unsigned int n_group_types)
84 : m_exec_conf(pdata->getExecConf()), m_pdata(pdata), m_nglobal(0), m_groups_dirty(true)
86 m_exec_conf->msg->notice(5) << "Constructing BondedGroupData (" << name<< "s, n=" << group_size << ") "
87 << endl;
89 // connect to particle sort signal
90 m_sort_connection = m_pdata->connectParticleSort(boost::bind(&BondedGroupData<group_size, Group, name>::setDirty, this));
91 #ifdef ENABLE_MPI
92 if (m_pdata->getDomainDecomposition())
94 m_pdata->connectSingleParticleMove(
95 boost::bind(&BondedGroupData<group_size, Group, name>::moveParticleGroups, this, _1, _2, _3));
97 #endif
99 // offer a default type mapping
100 for (unsigned int i = 0; i < n_group_types; i++)
102 char suffix[2];
103 suffix[0] = 'A' + i;
104 suffix[1] = '\0';
106 std::string type_name = std::string(name) + std::string(suffix);
107 m_type_mapping.push_back(type_name);
110 // initialize data structures
111 initialize();
113 #ifdef ENABLE_CUDA
114 if (m_exec_conf->isCUDAEnabled())
116 // create a ModernGPU context
117 m_mgpu_context = mgpu::CreateCudaDeviceAttachStream(0);
119 #endif
122 /*! \param exec_conf Execution configuration
123 \param pdata The particle data to associate with
124 \param snapshot Snapshot to initialize from
126 template<unsigned int group_size, typename Group, const char *name>
127 BondedGroupData<group_size, Group, name>::BondedGroupData(
128 boost::shared_ptr<ParticleData> pdata,
129 const Snapshot& snapshot)
130 : m_exec_conf(pdata->getExecConf()), m_pdata(pdata), m_nglobal(0), m_groups_dirty(true)
132 m_exec_conf->msg->notice(5) << "Constructing BondedGroupData (" << name << ") " << endl;
134 // connect to particle sort signal
135 m_sort_connection = m_pdata->connectParticleSort(boost::bind(&BondedGroupData<group_size, Group, name>::setDirty,
136 this));
138 #ifdef ENABLE_CUDA
139 if (m_exec_conf->isCUDAEnabled())
141 // create a ModernGPU context
142 m_mgpu_context = mgpu::CreateCudaDeviceAttachStream(0);
144 #endif
146 // initialize from snapshot
147 initializeFromSnapshot(snapshot);
149 #ifdef ENABLE_MPI
150 if (m_pdata->getDomainDecomposition())
152 m_pdata->connectSingleParticleMove(
153 boost::bind(&BondedGroupData<group_size, Group, name>::moveParticleGroups, this, _1, _2, _3));
155 #endif
158 //! Destructor
159 template<unsigned int group_size, typename Group, const char *name>
160 BondedGroupData<group_size, Group, name>::~BondedGroupData()
162 m_sort_connection.disconnect();
163 #ifdef ENABLE_MPI
164 if (m_particle_move_connection.connected())
165 m_particle_move_connection.disconnect();
166 #endif
169 template<unsigned int group_size, typename Group, const char *name>
170 void BondedGroupData<group_size, Group, name>::initialize()
172 m_nglobal = 0;
174 // clear set of active tags
175 m_tag_set.clear();
177 // clear reservoir of recycled tags
178 while (! m_recycled_tags.empty())
179 m_recycled_tags.pop();
181 // allocate arrays
182 GPUVector<members_t> groups(m_exec_conf);
183 m_groups.swap(groups);
185 GPUVector<unsigned int> type_id(m_exec_conf);
186 m_group_type.swap(type_id);
188 GPUVector<unsigned int> group_tag(m_exec_conf);
189 m_group_tag.swap(group_tag);
191 GPUVector<unsigned int> group_rtag(m_exec_conf);
192 m_group_rtag.swap(group_rtag);
194 // Lookup by particle index table
195 GPUVector<members_t> gpu_table(m_exec_conf);
196 m_gpu_table.swap(gpu_table);
198 GPUVector<unsigned int> gpu_pos_table(m_exec_conf);
199 m_gpu_pos_table.swap(gpu_pos_table);
201 GPUVector<unsigned int> n_groups(m_exec_conf);
202 m_n_groups.swap(n_groups);
204 #ifdef ENABLE_MPI
205 if (m_pdata->getDomainDecomposition())
207 GPUVector<ranks_t> group_ranks(m_exec_conf);
208 m_group_ranks.swap(group_ranks);
210 #endif
212 // allocate stand-by arrays
213 GPUVector<unsigned int> type_id_alt(m_exec_conf);
214 m_group_type_alt.swap(type_id_alt);
216 GPUVector<unsigned int> group_tag_alt(m_exec_conf);
217 m_group_tag_alt.swap(group_tag_alt);
219 GPUVector<members_t> groups_alt(m_exec_conf);
220 m_groups_alt.swap(groups_alt);
222 #ifdef ENABLE_MPI
223 if (m_pdata->getDomainDecomposition())
225 GPUVector<ranks_t> group_ranks_alt(m_exec_conf);
226 m_group_ranks_alt.swap(group_ranks_alt);
228 #endif
230 #ifdef ENABLE_CUDA
231 // allocate condition variable
232 GPUArray<unsigned int> condition(1, m_exec_conf);
233 m_condition.swap(condition);
235 ArrayHandle<unsigned int> h_condition(m_condition, access_location::host, access_mode::overwrite);
236 *h_condition.data = 0;
237 m_next_flag = 1;
238 #endif
240 m_tag_set.clear();
243 //! Initialize from a snapshot
244 template<unsigned int group_size, typename Group, const char *name>
245 void BondedGroupData<group_size, Group, name>::initializeFromSnapshot(const Snapshot& snapshot)
247 // check that all fields in the snapshot have correct length
248 if (m_exec_conf->getRank() == 0 && ! snapshot.validate())
250 m_exec_conf->msg->error() << "init.*: invalid " << name << " data snapshot."
251 << std::endl << std::endl;
252 throw std::runtime_error(std::string("Error initializing ") + name + std::string(" data."));
255 // re-initialize data structures
256 initialize();
258 #ifdef ENABLE_MPI
259 if (m_pdata->getDomainDecomposition())
261 // broadcast to all processors (temporarily)
262 std::vector<members_t> all_groups;
263 std::vector<unsigned int> all_type;
265 if (m_exec_conf->getRank() == 0)
267 all_groups = snapshot.groups;
268 all_type = snapshot.type_id;
269 m_type_mapping = snapshot.type_mapping;
272 bcast(all_groups, 0, m_exec_conf->getMPICommunicator());
273 bcast(all_type, 0, m_exec_conf->getMPICommunicator());
274 bcast(m_type_mapping, 0, m_exec_conf->getMPICommunicator());
276 // iterate over groups and add those that have local particles
277 for (unsigned int group_tag = 0; group_tag < all_groups.size(); ++group_tag)
278 addBondedGroup(Group(all_type[group_tag], all_groups[group_tag]));
280 else
281 #endif
283 m_type_mapping = snapshot.type_mapping;
285 for (unsigned group_idx = 0; group_idx < snapshot.groups.size(); group_idx++)
286 addBondedGroup(Group(snapshot.type_id[group_idx], snapshot.groups[group_idx]));
290 /*! \param type_id Type of bonded group to add
291 \param member_tags Particle members of group
293 template<unsigned int group_size, typename Group, const char *name>
294 unsigned int BondedGroupData<group_size, Group, name>::addBondedGroup(Group g)
296 unsigned int type = g.get_type();
297 members_t member_tags = g.get_members();
299 // check for some silly errors a user could make
300 for (unsigned int i = 0; i < group_size; ++i)
301 if (member_tags.tag[i] >= m_pdata->getNGlobal())
303 std::ostringstream oss;
304 oss << name << ".*: Particle tag out of bounds when attempting to add " << name << ": ";
305 for (unsigned int j = 0; j < group_size; ++j)
306 oss << member_tags.tag[j] << ((j != group_size - 1) ? "," : "");
307 oss << std::endl;
308 m_exec_conf->msg->error() << oss.str();
309 throw runtime_error(std::string("Error adding ") + name);
312 for (unsigned int i = 0; i < group_size; ++i)
313 for (unsigned int j = 0; j < group_size; ++j)
314 if (i != j && member_tags.tag[i] == member_tags.tag[j])
316 std::ostringstream oss;
317 oss << name << ".*: The same particle can only occur once in a " << name << ": ";
318 for (unsigned int k = 0; k < group_size; ++k)
319 oss << member_tags.tag[k] << ((k != group_size - 1) ? "," : "");
320 oss << std::endl;
321 m_exec_conf->msg->error() << oss.str();
322 throw runtime_error(std::string("Error adding ") + name);
325 if (type >= m_type_mapping.size())
327 m_exec_conf->msg->error() << name << ".*: Invalid " << name << " type " << type
328 << "! The number of types is " << m_type_mapping.size() << std::endl;
329 throw std::runtime_error(std::string("Error adding ") + name);
332 unsigned int tag = 0;
334 // determine if bonded group needs to be added to local data
335 bool is_local = true;
336 #ifdef ENABLE_MPI
337 if (m_pdata->getDomainDecomposition())
339 is_local = false;
340 // if any of the member tags is local, store this bond
341 for (unsigned int i = 0; i < group_size; ++i)
342 if (m_pdata->isParticleLocal(member_tags.tag[i]))
344 is_local = true;
345 break;
348 #endif
350 // first check if we can recycle a deleted tag
351 if (m_recycled_tags.size())
353 tag = m_recycled_tags.top();
354 m_recycled_tags.pop();
356 // update reverse-lookup tag to point to end of local group data
357 if (is_local)
358 m_group_rtag[tag] = getN();
360 assert(is_local || m_group_rtag[tag] == GROUP_NOT_LOCAL);
362 else
364 // Otherwise, generate a new tag
365 tag = getNGlobal();
367 // add new reverse-lookup tag
368 assert(m_group_rtag.size() == getNGlobal());
369 if (is_local)
370 m_group_rtag.push_back(getN());
371 else
372 m_group_rtag.push_back(GROUP_NOT_LOCAL);
375 assert(tag <= m_recycled_tags.size() + getNGlobal());
377 if (is_local)
379 m_groups.push_back(member_tags);
380 m_group_type.push_back(type);
381 m_group_tag.push_back(tag);
382 #ifdef ENABLE_MPI
383 if (m_pdata->getDomainDecomposition())
385 ranks_t r;
386 // initialize with zero
387 for (unsigned int i = 0; i < group_size; ++i)
388 r.idx[i] = 0;
390 m_group_ranks.push_back(r);
392 #endif
395 // add to set of active tags
396 m_tag_set.insert(tag);
398 // increment number of bonded groups
399 m_nglobal++;
401 // set flag to rebuild GPU table
402 m_groups_dirty = true;
404 // notifiy observers
405 m_group_num_change_signal();
407 return tag;
410 //! Return the nth active global tag
411 /*! \param n Index of bond in global bond table
413 template<unsigned int group_size, typename Group, const char *name>
414 unsigned int BondedGroupData<group_size, Group, name>::getNthTag(unsigned int n) const
416 if (n >= getNGlobal())
418 m_exec_conf->msg->error() << name << ".*: " << name << " index " << n << " out of bounds!"
419 << "The number of " << name << "s is " << getNGlobal() << std::endl;
420 throw std::runtime_error(std::string("Error getting ") + name);
423 assert(m_tag_set.size() == getNGlobal());
424 std::set<unsigned int>::const_iterator it = m_tag_set.begin();
425 std::advance(it, n);
426 return *it;
430 /*! \param tag Tag of bonded group
431 * \returns the group
433 template<unsigned int group_size, typename Group, const char *name>
434 const Group BondedGroupData<group_size, Group, name>::getGroupByTag(unsigned int tag) const
436 // Find position of bonded group in list
437 unsigned int group_idx = m_group_rtag[tag];
439 unsigned int type;
440 members_t members;
442 #ifdef ENABLE_MPI
443 if (m_pdata->getDomainDecomposition())
445 int my_rank = m_exec_conf->getRank();
446 // set local to rank if the bond is local, -1 if not
447 int rank = group_idx < m_groups.size() ? my_rank : -1;
449 // the highest rank owning the group sends it to the others
450 MPI_Allreduce(MPI_IN_PLACE,
451 &rank,
453 MPI_INT,
454 MPI_MAX,
455 m_exec_conf->getMPICommunicator());
457 if (rank == -1)
459 m_exec_conf->msg->error() << "Trying to find " << name << " " << tag
460 << " which does not exist!" << endl;
461 throw runtime_error(std::string("Error getting ") + name);
464 if (rank == (int)my_rank)
466 type = m_group_type[group_idx];
467 members = m_groups[group_idx];
470 bcast(type, rank, m_exec_conf->getMPICommunicator());
471 bcast(members, rank, m_exec_conf->getMPICommunicator());
473 else
474 #endif
476 if (group_idx == GROUP_NOT_LOCAL)
478 m_exec_conf->msg->error() << "Trying to get type of " << name << " " << tag
479 << " which does not exist!" << endl;
480 throw runtime_error(std::string("Error getting ") + name);
483 type = m_group_type[group_idx];
484 members = m_groups[group_idx];
487 return Group(type,members);
490 /*! \param idx Tag of bonded group
491 * \return Member tags of bonded group
493 template<unsigned int group_size, typename Group, const char *name>
494 unsigned int BondedGroupData<group_size, Group, name>::getTypeByIndex(unsigned int group_idx) const
496 assert (group_idx < getN());
497 return m_group_type[group_idx];
500 /*! \param idx Tag of bonded group
501 * \return Type of bonded group
503 template<unsigned int group_size, typename Group, const char *name>
504 const typename BondedGroupData<group_size, Group, name>::members_t BondedGroupData<group_size, Group, name>::getMembersByIndex(unsigned int group_idx) const
506 assert (group_idx < getN());
507 return m_groups[group_idx];
510 /*! \param tag Tag of bonded group to remove
512 template<unsigned int group_size, typename Group, const char *name>
513 void BondedGroupData<group_size, Group, name>::removeBondedGroup(unsigned int tag)
515 // sanity check
516 if (tag >= m_group_rtag.size())
518 m_exec_conf->msg->error() << "Trying to remove " << name << " " << tag << " which does not exist!" << endl;
519 throw runtime_error(std::string("Error removing ") + name);
522 // Find position of bonded group in list
523 unsigned int id = m_group_rtag[tag];
525 bool is_local = id < getN();
526 assert(is_local || id == GROUP_NOT_LOCAL);
528 bool is_available = is_local;
530 #ifdef ENABLE_MPI
531 if (m_pdata->getDomainDecomposition())
533 int res = is_local ? 1 : 0;
535 // check that group is local on some processors
536 MPI_Allreduce(MPI_IN_PLACE,
537 &res,
539 MPI_INT,
540 MPI_SUM,
541 m_exec_conf->getMPICommunicator());
543 assert((unsigned int) res <= group_size);
544 is_available = res;
546 #endif
548 if (! is_available)
550 m_exec_conf->msg->error() << "Trying to remove " << name << " " << tag
551 << " which has been previously removed!" << endl;
552 throw runtime_error(std::string("Error removing ") + name);
555 // delete from map
556 m_group_rtag[tag] = GROUP_NOT_LOCAL;
558 if (is_local)
560 unsigned int size = m_groups.size();
561 // If the bonded group is in the middle of the list, move the last element to
562 // to the position of the removed element
563 if (id < (size-1))
565 m_groups[id] = (members_t) m_groups[size-1];
566 m_group_type[id] = (unsigned int) m_group_type[size-1];
567 #ifdef ENABLE_MPI
568 if (m_pdata->getDomainDecomposition())
569 m_group_ranks[id] = (ranks_t) m_group_ranks[size-1];
570 #endif
571 unsigned int last_tag = m_group_tag[size-1];
572 m_group_rtag[last_tag] = id;
573 m_group_tag[id] = last_tag;
576 // delete last element
577 m_groups.pop_back();
578 m_group_type.pop_back();
579 m_group_tag.pop_back();
580 #ifdef ENABLE_MPI
581 if (m_pdata->getDomainDecomposition())
582 m_group_ranks.pop_back();
583 #endif
586 // remove from set of active tags
587 m_tag_set.erase(tag);
589 // maintain a stack of deleted group tags for future recycling
590 m_recycled_tags.push(tag);
591 m_nglobal--;
593 // set flag to trigger rebuild of GPU table
594 m_groups_dirty = true;
596 // notifiy observers
597 m_group_num_change_signal();
600 /*! \param name Type name
602 template<unsigned int group_size, typename Group, const char *name>
603 unsigned int BondedGroupData<group_size, Group, name>::getTypeByName(const std::string &type_name) const
605 // search for the name
606 for (unsigned int i = 0; i < m_type_mapping.size(); i++)
608 if (m_type_mapping[i] == type_name)
609 return i;
612 m_exec_conf->msg->error() << name << " type " << type_name << " not found!" << endl;
613 throw runtime_error("Error mapping type name");
615 // silence compiler warning
616 return 0;
619 template<unsigned int group_size, typename Group, const char *name>
620 const std::string BondedGroupData<group_size, Group, name>::getNameByType(unsigned int type) const
622 // check for an invalid request
623 if (type >= m_type_mapping.size())
625 m_exec_conf->msg->error() << "Requesting type name for non-existant type " << type << endl;
626 throw runtime_error("Error mapping type name");
629 // return the name
630 return m_type_mapping[type];
633 template<unsigned int group_size, typename Group, const char *name>
634 void BondedGroupData<group_size, Group, name>::setTypeName(unsigned int type, const std::string& new_name)
636 // check for an invalid request
637 if (type >= this->m_type_mapping.size())
639 m_exec_conf->msg->error() << "Setting type name for non-existant type " << type << endl;
640 throw runtime_error("Error mapping type name");
643 m_type_mapping[type] = new_name;
646 template<unsigned int group_size, typename Group, const char *name>
647 void BondedGroupData<group_size, Group, name>::rebuildGPUTable()
649 #ifdef ENABLE_CUDA
650 if (m_exec_conf->isCUDAEnabled())
651 rebuildGPUTableGPU();
652 else
653 #endif
655 if (m_prof) m_prof->push("update " + std::string(name) + " table");
657 ArrayHandle< unsigned int > h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);
659 m_n_groups.resize(m_pdata->getN()+m_pdata->getNGhosts());
661 unsigned int num_groups_max = 0;
663 ArrayHandle<unsigned int> h_n_groups(m_n_groups, access_location::host, access_mode::overwrite);
665 unsigned int N = m_pdata->getN()+m_pdata->getNGhosts();
666 // count the number of bonded groups per particle
667 // start by initializing the n_groups values to 0
668 memset(h_n_groups.data, 0, sizeof(unsigned int) * N);
670 // loop through the particles and count the number of groups based on each particle index
671 for (unsigned int cur_group = 0; cur_group < getN(); cur_group++)
673 members_t g = m_groups[cur_group];
674 for (unsigned int i = 0; i < group_size; ++i)
676 unsigned int tag = g.tag[i];
677 unsigned int idx = h_rtag.data[tag];
679 if (idx == NOT_LOCAL)
681 // incomplete group
682 std::ostringstream oss;
683 oss << name << ".*: " << name << " ";
684 for (unsigned int k = 0; k < group_size; ++k)
685 oss << g.tag[k] << ((k != group_size - 1) ? ", " : " ");
686 oss << "incomplete!" << std::endl;
687 m_exec_conf->msg->error() << oss.str();
688 throw std::runtime_error("Error building GPU group table.");
691 h_n_groups.data[idx]++;
695 // find the maximum number of groups
696 for (unsigned int i = 0; i < N; i++)
697 if (h_n_groups.data[i] > num_groups_max)
698 num_groups_max = h_n_groups.data[i];
701 // resize lookup table
702 m_gpu_table_indexer = Index2D(m_pdata->getN()+m_pdata->getNGhosts(), num_groups_max);
703 m_gpu_table.resize(m_gpu_table_indexer.getNumElements());
704 m_gpu_pos_table.resize(m_gpu_table_indexer.getNumElements());
707 ArrayHandle<unsigned int> h_n_groups(m_n_groups, access_location::host, access_mode::overwrite);
708 ArrayHandle<members_t> h_gpu_table(m_gpu_table, access_location::host, access_mode::overwrite);
709 ArrayHandle<unsigned int> h_gpu_pos_table(m_gpu_pos_table, access_location::host, access_mode::overwrite);
711 // now, update the actual table
712 // zero the number of bonded groups counter (again)
713 memset(h_n_groups.data, 0, sizeof(unsigned int) * (m_pdata->getN()+m_pdata->getNGhosts()));
715 // loop through all group and add them to each column in the list
716 for (unsigned int cur_group = 0; cur_group < getN(); cur_group++)
718 members_t g = m_groups[cur_group];
720 for (unsigned int i = 0; i < group_size; ++i)
722 unsigned int tag1 = g.tag[i];
723 unsigned int idx1 = h_rtag.data[tag1];
724 unsigned int num = h_n_groups.data[idx1]++;
726 members_t h;
727 // last element = type
728 h.idx[group_size-1] = m_group_type[cur_group];
730 // list all group members j!=i in p.idx
731 unsigned int n = 0;
732 unsigned int gpos = 0;
733 for (unsigned int j = 0; j < group_size; ++j)
735 if (j == i)
737 gpos = j;
738 continue;
740 unsigned int tag2 = g.tag[j];
741 unsigned int idx2 = h_rtag.data[tag2];
742 h.idx[n++] = idx2;
745 h_gpu_table.data[m_gpu_table_indexer(idx1, num)] = h;
746 h_gpu_pos_table.data[m_gpu_table_indexer(idx1, num)] = gpos;
751 if (m_prof) m_prof->pop();
755 #ifdef ENABLE_CUDA
756 template<unsigned int group_size, typename Group, const char *name>
757 void BondedGroupData<group_size, Group, name>::rebuildGPUTableGPU()
759 if (m_prof) m_prof->push(m_exec_conf, "update " + std::string(name) + " table");
761 // resize groups counter
762 m_n_groups.resize(m_pdata->getN()+m_pdata->getNGhosts());
764 // resize GPU table to current number of particles
765 m_gpu_table_indexer = Index2D(m_pdata->getN()+m_pdata->getNGhosts(), m_gpu_table_indexer.getH());
766 m_gpu_table.resize(m_gpu_table_indexer.getNumElements());
767 m_gpu_pos_table.resize(m_gpu_table_indexer.getNumElements());
769 bool done = false;
770 while (!done)
772 unsigned int flag = 0;
775 ArrayHandle<members_t> d_groups(m_groups, access_location::device, access_mode::read);
776 ArrayHandle<unsigned int> d_group_type(m_group_type, access_location::device, access_mode::read);
777 ArrayHandle<unsigned int> d_rtag(m_pdata->getRTags(), access_location::device, access_mode::read);
778 ArrayHandle<unsigned int> d_n_groups(m_n_groups, access_location::device, access_mode::overwrite);
779 ArrayHandle<members_t> d_gpu_table(m_gpu_table, access_location::device, access_mode::overwrite);
780 ArrayHandle<unsigned int> d_gpu_pos_table(m_gpu_pos_table, access_location::device, access_mode::overwrite);
781 ArrayHandle<unsigned int> d_condition(m_condition, access_location::device, access_mode::readwrite);
783 // allocate scratch buffers
784 const CachedAllocator& alloc = m_exec_conf->getCachedAllocator();
785 unsigned int tmp_size = m_groups.size()*group_size;
786 unsigned int nptl = m_pdata->getN()+m_pdata->getNGhosts();
787 ScopedAllocation<unsigned int> d_scratch_g(alloc, tmp_size);
788 ScopedAllocation<unsigned int> d_scratch_idx(alloc, tmp_size);
789 ScopedAllocation<unsigned int> d_offsets(alloc, tmp_size);
790 ScopedAllocation<unsigned int> d_seg_offsets(alloc, nptl);
792 // fill group table on GPU
793 gpu_update_group_table<group_size, members_t>(
794 m_groups.size(),
795 nptl,
796 d_groups.data,
797 d_group_type.data,
798 d_rtag.data,
799 d_n_groups.data,
800 m_gpu_table_indexer.getH(),
801 d_condition.data,
802 m_next_flag,
803 flag,
804 d_gpu_table.data,
805 d_gpu_pos_table.data,
806 m_gpu_table_indexer.getW(),
807 d_scratch_g.data,
808 d_scratch_idx.data,
809 d_offsets.data,
810 d_seg_offsets.data,
811 m_mgpu_context);
813 if (m_exec_conf->isCUDAErrorCheckingEnabled()) CHECK_CUDA_ERROR();
815 if (flag >= m_next_flag+1)
817 // incomplete group detected
818 unsigned int group_idx = flag - m_next_flag - 1;
819 members_t g = m_groups[group_idx];
821 std::ostringstream oss;
822 oss << name << ".*: " << name << " ";
823 for (unsigned int k = 0; k < group_size; ++k)
824 oss << g.tag[k] << ((k != group_size - 1) ? ", " : " ");
825 oss << "incomplete!" << std::endl;
826 m_exec_conf->msg->error() << oss.str();
827 throw std::runtime_error("Error building GPU group table.");
830 if (flag == m_next_flag)
832 // grow array by incrementing groups per particle
833 m_gpu_table_indexer = Index2D(m_pdata->getN()+m_pdata->getNGhosts(), m_gpu_table_indexer.getH()+1);
834 m_gpu_table.resize(m_gpu_table_indexer.getNumElements());
835 m_gpu_pos_table.resize(m_gpu_table_indexer.getNumElements());
836 m_next_flag++;
838 else
839 done = true;
842 if (m_prof) m_prof->pop(m_exec_conf);
844 #endif
846 /*! \param snapshot Snapshot that will contain the group data
848 * Data in the snapshot is in tag order, where non-existant tags are skipped
850 template<unsigned int group_size, typename Group, const char *name>
851 void BondedGroupData<group_size, Group, name>::takeSnapshot(Snapshot& snapshot) const
853 // allocate memory in snapshot
854 snapshot.resize(getNGlobal());
856 std::map<unsigned int, unsigned int> rtag_map;
858 for (unsigned int group_idx = 0; group_idx < getN(); group_idx++)
860 unsigned int tag = m_group_tag[group_idx];
861 assert(m_group_rtag[tag] == group_idx);
863 rtag_map.insert(std::pair<unsigned int,unsigned int>(tag, group_idx));
866 #ifdef ENABLE_MPI
867 if (m_pdata->getDomainDecomposition())
869 // gather local data
870 std::vector<unsigned int> types; // Group types
871 std::vector<members_t> members; // Group members
873 for (unsigned int group_idx = 0; group_idx < getN(); ++group_idx)
875 types.push_back(m_group_type[group_idx]);
876 members.push_back(m_groups[group_idx]);
879 std::vector< std::vector<unsigned int> > types_proc; // Group types of every processor
880 std::vector< std::vector<members_t> > members_proc; // Group members of every processor
882 std::vector< std::map<unsigned int, unsigned int> > rtag_map_proc; // List of reverse-lookup maps
884 unsigned int size = m_exec_conf->getNRanks();
886 // resize arrays to accumulate group data of all ranks
887 types_proc.resize(size);
888 members_proc.resize(size);
889 rtag_map_proc.resize(size);
891 // gather all processors' data
892 gather_v(types, types_proc, 0, m_exec_conf->getMPICommunicator());
893 gather_v(members, members_proc, 0, m_exec_conf->getMPICommunicator());
894 gather_v(rtag_map, rtag_map_proc, 0, m_exec_conf->getMPICommunicator());
896 if (m_exec_conf->getRank() == 0)
898 assert(rtag_map_proc.size() == size);
900 // create single map of all group ranks and indices
901 // groups present on more than one processor will count as one group
902 std::map<unsigned int, std::pair<unsigned int, unsigned int> > rank_rtag_map;
903 std::map<unsigned int, unsigned int>::iterator it;
904 for (unsigned int irank = 0; irank < size; ++irank)
905 for (it = rtag_map_proc[irank].begin(); it != rtag_map_proc[irank].end(); ++it)
906 rank_rtag_map.insert(std::make_pair(it->first, std::make_pair(irank, it->second)));
908 // add groups to snapshot
909 std::map<unsigned int, std::pair<unsigned int, unsigned int> >::iterator rank_rtag_it;
910 for (unsigned int group_tag = 0; group_tag < getNGlobal(); group_tag++)
912 rank_rtag_it = rank_rtag_map.find(group_tag);
913 if (rank_rtag_it == rank_rtag_map.end())
915 m_exec_conf->msg->error()
916 << endl << "Could not find " << name << " " << group_tag << " on any processor. "
917 << endl << endl;
918 throw std::runtime_error("Error gathering "+std::string(name)+"s");
921 // rank contains the processor rank on which the particle was found
922 std::pair<unsigned int, unsigned int> rank_idx = rank_rtag_it->second;
923 unsigned int rank = rank_idx.first;
924 unsigned int idx = rank_idx.second;
926 snapshot.type_id[group_tag] = types_proc[rank][idx];
927 snapshot.groups[group_tag] = members_proc[rank][idx];
931 else
932 #endif
934 assert(getN() == getNGlobal());
935 std::map<unsigned int, unsigned int>::iterator rtag_it;
936 for (rtag_it = rtag_map.begin(); rtag_it != rtag_map.end(); ++rtag_it)
938 unsigned int group_idx = rtag_it->second;
939 snapshot.groups[group_idx] = m_groups[group_idx];
940 snapshot.type_id[group_idx] = m_group_type[group_idx];
944 snapshot.type_mapping = m_type_mapping;
947 #ifdef ENABLE_MPI
948 template<unsigned int group_size, typename Group, const char *name>
949 void BondedGroupData<group_size, Group, name>::moveParticleGroups(unsigned int tag, unsigned int old_rank, unsigned int new_rank)
951 unsigned int my_rank = m_exec_conf->getRank();
953 // move groups connected to a particle
954 if (my_rank == old_rank)
956 std::vector<unsigned int> send_groups;
958 // create a list of groups connected to the particle
959 for (unsigned int group_idx = 0; group_idx < m_groups.size(); ++group_idx)
961 members_t members = m_groups[group_idx];
962 bool send = false;
963 for (unsigned int i = 0; i < group_size; ++i)
964 if (members.tag[i] == tag) send = true;
965 unsigned int group_tag = m_group_tag[group_idx];
966 if (send) send_groups.push_back(group_tag);
969 MPI_Status stat;
970 MPI_Request req;
971 unsigned int num = send_groups.size();
973 MPI_Isend(&num, 1, MPI_UNSIGNED, new_rank, 0, m_exec_conf->getMPICommunicator(), &req);
974 MPI_Wait(&req, &stat);
976 for (std::vector<unsigned int>::iterator it = send_groups.begin(); it != send_groups.end(); ++it)
978 // send group properties to other rank
979 unsigned int group_tag = *it;
980 unsigned int group_idx = m_group_rtag[group_tag];
981 assert(group_idx != GROUP_NOT_LOCAL);
983 MPI_Isend(&group_tag, 1, MPI_UNSIGNED, new_rank, 0, m_exec_conf->getMPICommunicator(), &req);
984 MPI_Wait(&req, &stat);
985 members_t members = m_groups[group_idx];
986 MPI_Isend(&members, sizeof(members_t), MPI_BYTE, new_rank, 0, m_exec_conf->getMPICommunicator(), &req);
987 MPI_Wait(&req, &stat);
988 unsigned int type = m_group_type[group_idx];
989 MPI_Isend(&type, 1, MPI_UNSIGNED, new_rank, 0, m_exec_conf->getMPICommunicator(), &req);
990 MPI_Wait(&req, &stat);
992 // remove groups that are no longer local
993 for (std::vector<unsigned int>::iterator it = send_groups.begin(); it != send_groups.end(); ++it)
995 unsigned int group_tag = *it;
996 unsigned int group_idx = m_group_rtag[group_tag];
997 members_t members = m_groups[group_idx];
998 bool is_local = false;
999 for (unsigned int i = 0; i < group_size; ++i)
1000 if (m_pdata->isParticleLocal(members.tag[i])) is_local = true;
1002 if (!is_local)
1004 m_group_rtag[group_tag] = GROUP_NOT_LOCAL;
1006 m_groups.erase(group_idx);
1007 m_group_type.erase(group_idx);
1008 m_group_ranks.erase(group_idx);
1009 m_group_tag.erase(group_idx);
1011 // reindex rtags
1012 ArrayHandle<unsigned int> h_group_rtag(m_group_rtag, access_location::host, access_mode::readwrite);
1013 ArrayHandle<unsigned int> h_group_tag(m_group_tag, access_location::host, access_mode::read);
1014 for (unsigned int i = 0; i < m_groups.size(); ++i)
1015 h_group_rtag.data[h_group_tag.data[i]] = i;
1019 else if (my_rank == new_rank)
1021 MPI_Status stat;
1022 MPI_Request req;
1024 // receive number of groups
1025 unsigned int num;
1026 MPI_Irecv(&num, 1, MPI_UNSIGNED, old_rank, 0, m_exec_conf->getMPICommunicator(), &req);
1027 MPI_Wait(&req, &stat);
1029 for (unsigned int i =0; i < num; ++i)
1031 unsigned int tag;
1032 MPI_Irecv(&tag, 1, MPI_UNSIGNED, old_rank, 0, m_exec_conf->getMPICommunicator(), &req);
1033 MPI_Wait(&req, &stat);
1035 members_t members;
1036 MPI_Irecv(&members, sizeof(members_t), MPI_BYTE, old_rank, 0, m_exec_conf->getMPICommunicator(), &req);
1037 MPI_Wait(&req, &stat);
1039 unsigned int type;
1040 MPI_Irecv(&type, 1, MPI_UNSIGNED, old_rank, 0, m_exec_conf->getMPICommunicator(), &req);
1041 MPI_Wait(&req, &stat);
1043 bool is_local = m_group_rtag[tag] != NOT_LOCAL;
1045 // if not already local
1046 if (! is_local)
1048 // append to end of group data
1049 unsigned int n = m_groups.size();
1050 m_group_tag.push_back(tag);
1051 m_groups.push_back(members);
1052 m_group_type.push_back(type);
1053 ranks_t r;
1054 for (unsigned int j = 0; j < group_size; j++)
1055 // initialize to zero
1056 r.idx[j] = 0;
1058 m_group_ranks.push_back(r);
1059 m_group_rtag[tag] = n;
1064 // notify observers
1065 m_group_num_change_signal();
1066 m_groups_dirty = true;
1068 #endif
1070 template<class T, typename Group>
1071 void export_BondedGroupData(std::string name, std::string snapshot_name, bool export_struct)
1073 // export group structure
1074 if (export_struct)
1075 Group::export_to_python();
1077 scope outer = class_<T, boost::shared_ptr<T> , boost::noncopyable>(name.c_str(),
1078 init<boost::shared_ptr<ParticleData>, unsigned int>())
1079 .def(init<boost::shared_ptr<ParticleData>, const typename T::Snapshot& >())
1080 .def("initializeFromSnapshot", &T::initializeFromSnapshot)
1081 .def("takeSnapshot", &T::takeSnapshot)
1082 .def("getN", &T::getN)
1083 .def("getNGlobal", &T::getNGlobal)
1084 .def("getNTypes", &T::getNTypes)
1085 .def("getNthTag", &T::getNthTag)
1086 .def("getGroupByTag", &T::getGroupByTag)
1087 .def("getTypeByName", &T::getTypeByName)
1088 .def("setTypeName", &T::setTypeName)
1089 .def("getNameByType", &T::getNameByType)
1090 .def("addBondedGroup", &T::addBondedGroup)
1091 .def("removeBondedGroup", &T::removeBondedGroup)
1092 .def("setProfiler", &T::setProfiler)
1095 typedef typename T::Snapshot Snapshot;
1096 class_<Snapshot, boost::shared_ptr<Snapshot> >
1097 (snapshot_name.c_str(), init<unsigned int>())
1098 .def_readwrite("groups", &Snapshot::groups)
1099 .def_readwrite("type_id", &Snapshot::type_id)
1100 .def_readwrite("type_mapping", &Snapshot::type_mapping)
1101 .def("resize", &Snapshot::resize)
1105 template<unsigned int group_size, typename Group, const char *name>
1106 void BondedGroupData<group_size, Group, name>::Snapshot::replicate(unsigned int n,
1107 unsigned int old_n_particles)
1109 unsigned int old_size = groups.size();
1110 groups.resize(n*old_size);
1111 type_id.resize(n*old_size);
1113 for (unsigned int i = 0; i < old_size; ++i)
1115 typename BondedGroupData<group_size, Group, name>::members_t g;
1116 g = groups[i];
1117 unsigned int type = type_id[i];
1119 // replicate bonded group
1120 for (unsigned int j = 0; j < n; ++j)
1122 typename BondedGroupData<group_size, Group, name>::members_t h;
1124 // update particle tags
1125 for (unsigned int k = 0; k < group_size; ++k)
1126 h.tag[k] = g.tag[k] + old_n_particles*j;
1128 groups[old_size*j+i] = h;
1129 type_id[old_size*j+i] = type;
1134 //! Explicit template instantiations
1135 template class BondedGroupData<2, Bond, name_bond_data>;
1136 template void export_BondedGroupData<BondData,Bond>(std::string name,std::string snapshot_name, bool export_struct);
1138 template class BondedGroupData<3, Angle, name_angle_data>;
1139 template void export_BondedGroupData<AngleData,Angle>(std::string name,std::string snapshot_name, bool export_struct);
1141 template class BondedGroupData<4, Dihedral, name_dihedral_data>;
1142 template void export_BondedGroupData<DihedralData,Dihedral>(std::string name,std::string snapshot_name, bool export_struct);
1144 template class BondedGroupData<4, Dihedral, name_improper_data>;
1145 template void export_BondedGroupData<ImproperData,Dihedral>(std::string name,std::string snapshot_name, bool export_struct);