MADNESS  version 0.9
group.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2013 Virginia Tech
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31 
32  $Id$
33  */
34 
35 #ifndef MADNESS_WORLD_GROUP_H__INCLUDED
36 #define MADNESS_WORLD_GROUP_H__INCLUDED
37 
39 #include <madness/world/worldexc.h>
40 #include <madness/world/worldfwd.h>
42 
43 namespace madness {
44 
46 
52  class Group {
53  private:
54 
55  class Impl {
56  private:
57  World& world_;
58  DistributedID did_;
59  std::vector<ProcessID> group_to_world_map_;
60  ProcessID group_rank_;
61  mutable AtomicInt local_count_;
62  mutable AtomicInt remote_count_;
63 
65 
70  template <typename T, std::size_t N>
71  static T* begin(T (&a)[N]) { return a; }
72 
74 
79  template <typename T, std::size_t N>
80  static T* end(T (&a)[N]) { return (a + N); }
81 
83 
88  template <typename T, std::size_t N>
89  static std::size_t size(T (&)[N]) { return N; }
90 
92 
96  template <typename vectorT>
97  static typename vectorT::const_iterator begin(const vectorT &v) {
98  return v.begin();
99  }
100 
102 
106  template <typename vectorT>
107  static typename vectorT::const_iterator end(const vectorT &v) {
108  return v.end();
109  }
110 
112 
116  template <typename vectorT>
117  static typename disable_if<std::is_array<vectorT>, std::size_t>::type
118  size(const vectorT &v) { return v.size(); }
119 
120  public:
122 
127  template <typename A>
128  Impl(World& world, const A& group, const DistributedID& did) :
129  world_(world), did_(did),
130  group_to_world_map_(begin(group), end(group)),
131  group_rank_(-1), local_count_(), remote_count_()
132  {
133  // Check that there is at least one process in group
134  MADNESS_ASSERT(size(group) > 0ul);
135 
136  // Sort and remove duplicates from group
137  std::sort(group_to_world_map_.begin(), group_to_world_map_.end());
138  group_to_world_map_.erase(std::unique(group_to_world_map_.begin(),
139  group_to_world_map_.end()), group_to_world_map_.end());
140 
141  // Check that all processes in the group map are contained by world
142  MADNESS_ASSERT(group_to_world_map_.front() >= 0);
143  MADNESS_ASSERT(group_to_world_map_.back() < world_.size());
144 
145  // Get the group rank for this process
146  group_rank_ = rank(world_.rank());
147  MADNESS_ASSERT(group_rank_ != -1);
148 
149  // Initialize the use counter
150  local_count_ = 0;
151  remote_count_ = 0;
152  }
153 
155 
157  World& get_world() const { return world_; }
158 
160 
162  const DistributedID& id() const { return did_; }
163 
165 
167  ProcessID rank() const { return group_rank_; }
168 
170 
174  ProcessID rank(const ProcessID world_rank) const {
175  ProcessID result = std::distance(group_to_world_map_.begin(),
176  std::find(group_to_world_map_.begin(), group_to_world_map_.end(),
177  world_rank));
178  if(static_cast<std::size_t>(result) == group_to_world_map_.size())
179  result = -1;
180  return result;
181  }
182 
184 
186  ProcessID size() const { return group_to_world_map_.size(); }
187 
189 
191  ProcessID world_rank(const ProcessID group_rank) const {
192  MADNESS_ASSERT(group_rank >= 0);
193  MADNESS_ASSERT(group_rank < ProcessID(group_to_world_map_.size()));
194  return group_to_world_map_[group_rank];
195  }
196 
198 
203  void make_tree(const ProcessID group_root, ProcessID& parent,
204  ProcessID& child0, ProcessID& child1) const
205  {
206  const ProcessID group_size = group_to_world_map_.size();
207 
208  // Check that root is in the range of the group
209  MADNESS_ASSERT(group_root >= 0);
210  MADNESS_ASSERT(group_root < group_size);
211 
212  // Renumber processes so root has me == 0
213  const ProcessID me = (group_rank_ + group_size - group_root) % group_size;
214 
215  // Compute the group parent
216  parent = (me == 0 ? -1 : group_to_world_map_[(((me - 1) >> 1) + group_root) % group_size]);
217 
218  // Compute children
219  child0 = (me << 1) + 1 + group_root;
220  child1 = child0 + 1;
221 
222  const ProcessID end = group_size + group_root;
223  if(child0 < end)
224  child0 = group_to_world_map_[child0 % group_size];
225  else
226  child0 = -1;
227  if(child1 < end)
228  child1 = group_to_world_map_[child1 % group_size];
229  else
230  child1 = -1;
231  }
232 
234 
236  void local_update() const { local_count_++; }
237 
239 
246  void remote_update(const int n) const {
247  const int count = (remote_count_ += n);
248  if(count == 0)
249  Group::unregister_group(did_);
250  }
251 
253 
256  static void deleter(Impl* pimpl) {
257  // Note: Calling remote_update() breaks the no throw requirement
258  // of deleters. Unfortunately, this cannot be avoided since
259  // Group must be used concurrently in different threads, and all
260  // cleanup methods requires some type of locking.
261  pimpl->remote_update(-(pimpl->local_count_));
262  }
263  }; // struct Impl
264 
265  std::shared_ptr<Impl> pimpl_;
266 
267 
269 
275  void register_group() const;
276 
278 
282  static void unregister_group(const DistributedID& did);
283 
284  Group(Impl* pimpl) : pimpl_(pimpl) { }
285 
286  public:
287 
289 
291  Group() : pimpl_() { }
292 
294 
297  Group(const Group& other) : pimpl_(other.pimpl_) { }
298 
300 
307  template <typename A>
308  Group(World& world, const A& group, const DistributedID& did) :
309  pimpl_(new Impl(world, group, did), Impl::deleter)
310  {
311  register_group();
312  }
313 
315 
323  template <typename A>
324  Group(World& world, const A& group, const std::size_t tag) :
325  pimpl_(new Impl(world, group, DistributedID(uniqueidT(), tag)), Impl::deleter)
326  {
327  register_group();
328  }
329 
331 
340  template <typename A>
341  Group(World& world, const A& group, const uniqueidT& uid, const std::size_t tag) :
342  pimpl_(new Impl(world, group, DistributedID(uid, tag)), Impl::deleter)
343  {
344  register_group();
345  }
346 
348 
351  Group& operator=(const Group& other) {
352  pimpl_ = other.pimpl_;
353  return *this;
354  }
355 
357 
362 
364 
372  void local_update() const {
373  MADNESS_ASSERT(pimpl_);
374  pimpl_->local_update();
375  }
376 
378 
386  void remote_update() const {
387  MADNESS_ASSERT(pimpl_);
388  pimpl_->remote_update(1);
389  }
390 
392 
394  bool empty() const { return !pimpl_; }
395 
397 
399  const DistributedID& id() const {
400  MADNESS_ASSERT(pimpl_);
401  return pimpl_->id();
402  }
403 
405 
407  World& get_world() const {
408  MADNESS_ASSERT(pimpl_);
409  return pimpl_->get_world();
410  }
411 
413 
415  ProcessID rank() const {
416  MADNESS_ASSERT(pimpl_);
417  return pimpl_->rank();
418  }
419 
421 
425  MADNESS_ASSERT(pimpl_);
426  return pimpl_->rank(world_rank);
427  }
428 
430 
432  ProcessID size() const {
433  return (pimpl_ ? pimpl_->size() : 0);
434  }
435 
437 
440  ProcessID world_rank(const ProcessID group_rank) const {
441  MADNESS_ASSERT(pimpl_);
442  return pimpl_->world_rank(group_rank);
443  }
444 
446 
452  void make_tree(const ProcessID group_root, ProcessID& parent,
453  ProcessID& child1, ProcessID& child2) const
454  {
455  MADNESS_ASSERT(pimpl_);
456  pimpl_->make_tree(group_root, parent, child1, child2);
457  }
458 
459  template <typename Archive>
460  void serialize(const Archive&) {
461  MADNESS_ASSERT(false); // not allowed
462  }
463  }; // class Group
464 
465 } // namespace madness
466 
467 #endif // MADNESS_WORLD_GROUP_H__INCLUDED
void serialize(const Archive &)
Definition: group.h:460
Group(World &world, const A &group, const DistributedID &did)
Create a new group.
Definition: group.h:308
Definition: uniqueid.h:46
void local_update() const
Update local usage count.
Definition: group.h:372
ProcessID size() const
Returns the number of processes in this world (same as MPI_Comm_size())
Definition: worldfwd.h:533
ProcessID rank(const ProcessID world_rank) const
Map world rank to group rank.
Definition: group.h:424
void remote_update() const
Update remote usage count.
Definition: group.h:386
ProcessID rank() const
Group rank accessor.
Definition: group.h:415
disable_if from Boost for conditionally instantiating templates based on type
Definition: enable_if.h:78
bool empty() const
Quary empty group.
Definition: group.h:394
ProcessID world_rank(const ProcessID group_rank) const
Map group rank to world rank.
Definition: group.h:440
Group(const Group &other)
Copy constructor.
Definition: group.h:297
const T1 &f1 return GTEST_2_TUPLE_() T(f0, f1)
FLOAT a(int j, FLOAT z)
Definition: y1.cc:86
Group()
Default constructor.
Definition: group.h:291
ProcessID size() const
Group size accessor.
Definition: group.h:432
An integer with atomic set, get, read+inc, read+dec, dec+test operations.
Definition: atomicint.h:73
World & get_world() const
Parent world accessor.
Definition: group.h:407
A parallel world with full functionality wrapping an MPI communicator.
Definition: worldfwd.h:416
void make_tree(const ProcessID group_root, ProcessID &parent, ProcessID &child1, ProcessID &child2) const
Compute the binary tree parents and children.
Definition: group.h:452
const DistributedID & id() const
Group id accessor.
Definition: group.h:399
int ProcessID
Used to clearly identify process number/rank.
Definition: worldtypes.h:37
int distance(const madness::Hash_private::HashIterator< hashT > &it, const madness::Hash_private::HashIterator< hashT > &jt)
Definition: worldhashmap.h:608
std::pair< uniqueidT, std::size_t > DistributedID
Distributed ID which is used to identify objects.
Definition: dist_keys.h:44
ProcessID rank() const
Returns the process rank in this world (same as MPI_Comm_rank()))
Definition: worldfwd.h:526
static madness::Future< Group > get_group(const DistributedID &did)
Get group from the registry.
Definition: group.cc:89
A collection of processes.
Definition: group.h:52
Group(World &world, const A &group, const uniqueidT &uid, const std::size_t tag)
Create a new group.
Definition: group.h:341
Defines TaskInterface and implements WorldTaskQueue and associated stuff.
Group & operator=(const Group &other)
Copy assignment operator.
Definition: group.h:351
A future is a possibly yet unevaluated value.
Definition: ref.h:210
Implements MadnessException.
Implements World.
Group(World &world, const A &group, const std::size_t tag)
Create a new group.
Definition: group.h:324
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45