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
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"
62 #include "BondedGroupData.cuh"
63 #include "CachedAllocator.h"
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
<< ") "
89 // connect to particle sort signal
90 m_sort_connection
= m_pdata
->connectParticleSort(boost::bind(&BondedGroupData
<group_size
, Group
, name
>::setDirty
, this));
92 if (m_pdata
->getDomainDecomposition())
94 m_pdata
->connectSingleParticleMove(
95 boost::bind(&BondedGroupData
<group_size
, Group
, name
>::moveParticleGroups
, this, _1
, _2
, _3
));
99 // offer a default type mapping
100 for (unsigned int i
= 0; i
< n_group_types
; i
++)
106 std::string type_name
= std::string(name
) + std::string(suffix
);
107 m_type_mapping
.push_back(type_name
);
110 // initialize data structures
114 if (m_exec_conf
->isCUDAEnabled())
116 // create a ModernGPU context
117 m_mgpu_context
= mgpu::CreateCudaDeviceAttachStream(0);
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
,
139 if (m_exec_conf
->isCUDAEnabled())
141 // create a ModernGPU context
142 m_mgpu_context
= mgpu::CreateCudaDeviceAttachStream(0);
146 // initialize from snapshot
147 initializeFromSnapshot(snapshot
);
150 if (m_pdata
->getDomainDecomposition())
152 m_pdata
->connectSingleParticleMove(
153 boost::bind(&BondedGroupData
<group_size
, Group
, name
>::moveParticleGroups
, this, _1
, _2
, _3
));
159 template<unsigned int group_size
, typename Group
, const char *name
>
160 BondedGroupData
<group_size
, Group
, name
>::~BondedGroupData()
162 m_sort_connection
.disconnect();
164 if (m_particle_move_connection
.connected())
165 m_particle_move_connection
.disconnect();
169 template<unsigned int group_size
, typename Group
, const char *name
>
170 void BondedGroupData
<group_size
, Group
, name
>::initialize()
174 // clear set of active tags
177 // clear reservoir of recycled tags
178 while (! m_recycled_tags
.empty())
179 m_recycled_tags
.pop();
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
);
205 if (m_pdata
->getDomainDecomposition())
207 GPUVector
<ranks_t
> group_ranks(m_exec_conf
);
208 m_group_ranks
.swap(group_ranks
);
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
);
223 if (m_pdata
->getDomainDecomposition())
225 GPUVector
<ranks_t
> group_ranks_alt(m_exec_conf
);
226 m_group_ranks_alt
.swap(group_ranks_alt
);
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;
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
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
]));
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) ? "," : "");
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) ? "," : "");
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;
337 if (m_pdata
->getDomainDecomposition())
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
]))
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
358 m_group_rtag
[tag
] = getN();
360 assert(is_local
|| m_group_rtag
[tag
] == GROUP_NOT_LOCAL
);
364 // Otherwise, generate a new tag
367 // add new reverse-lookup tag
368 assert(m_group_rtag
.size() == getNGlobal());
370 m_group_rtag
.push_back(getN());
372 m_group_rtag
.push_back(GROUP_NOT_LOCAL
);
375 assert(tag
<= m_recycled_tags
.size() + getNGlobal());
379 m_groups
.push_back(member_tags
);
380 m_group_type
.push_back(type
);
381 m_group_tag
.push_back(tag
);
383 if (m_pdata
->getDomainDecomposition())
386 // initialize with zero
387 for (unsigned int i
= 0; i
< group_size
; ++i
)
390 m_group_ranks
.push_back(r
);
395 // add to set of active tags
396 m_tag_set
.insert(tag
);
398 // increment number of bonded groups
401 // set flag to rebuild GPU table
402 m_groups_dirty
= true;
405 m_group_num_change_signal();
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();
430 /*! \param tag Tag of bonded 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
];
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
,
455 m_exec_conf
->getMPICommunicator());
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());
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
)
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
;
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
,
541 m_exec_conf
->getMPICommunicator());
543 assert((unsigned int) res
<= group_size
);
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
);
556 m_group_rtag
[tag
] = GROUP_NOT_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
565 m_groups
[id
] = (members_t
) m_groups
[size
-1];
566 m_group_type
[id
] = (unsigned int) m_group_type
[size
-1];
568 if (m_pdata
->getDomainDecomposition())
569 m_group_ranks
[id
] = (ranks_t
) m_group_ranks
[size
-1];
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
578 m_group_type
.pop_back();
579 m_group_tag
.pop_back();
581 if (m_pdata
->getDomainDecomposition())
582 m_group_ranks
.pop_back();
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
);
593 // set flag to trigger rebuild of GPU table
594 m_groups_dirty
= true;
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
)
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
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");
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()
650 if (m_exec_conf
->isCUDAEnabled())
651 rebuildGPUTableGPU();
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
)
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
]++;
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
732 unsigned int gpos
= 0;
733 for (unsigned int j
= 0; j
< group_size
; ++j
)
740 unsigned int tag2
= g
.tag
[j
];
741 unsigned int idx2
= h_rtag
.data
[tag2
];
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();
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());
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
>(
800 m_gpu_table_indexer
.getH(),
805 d_gpu_pos_table
.data
,
806 m_gpu_table_indexer
.getW(),
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());
842 if (m_prof
) m_prof
->pop(m_exec_conf
);
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
));
867 if (m_pdata
->getDomainDecomposition())
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. "
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
];
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
;
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
];
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
);
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;
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
);
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
)
1024 // receive number of groups
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
)
1032 MPI_Irecv(&tag
, 1, MPI_UNSIGNED
, old_rank
, 0, m_exec_conf
->getMPICommunicator(), &req
);
1033 MPI_Wait(&req
, &stat
);
1036 MPI_Irecv(&members
, sizeof(members_t
), MPI_BYTE
, old_rank
, 0, m_exec_conf
->getMPICommunicator(), &req
);
1037 MPI_Wait(&req
, &stat
);
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
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
);
1054 for (unsigned int j
= 0; j
< group_size
; j
++)
1055 // initialize to zero
1058 m_group_ranks
.push_back(r
);
1059 m_group_rtag
[tag
] = n
;
1065 m_group_num_change_signal();
1066 m_groups_dirty
= true;
1070 template<class T
, typename Group
>
1071 void export_BondedGroupData(std::string name
, std::string snapshot_name
, bool export_struct
)
1073 // export group structure
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
;
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
);