IPPL (Independent Parallel Particle Layer)
IPPL
Loading...
Searching...
No Matches
Partitioner.hpp
Go to the documentation of this file.
1//
2// Class Partitioner
3// Partition a domain into subdomains.
4//
5
6#include <algorithm>
7#include <numeric>
8#include <vector>
9
10namespace ippl {
11 namespace detail {
12
13 template <unsigned Dim>
14 template <typename view_type>
16 const std::array<bool, Dim>& isParallel, int nSplits) const {
17 using NDIndex_t = NDIndex<Dim>;
18
19 // Recursively split the domain until we have generated all the domains.
20 std::vector<NDIndex_t> domains_c(nSplits);
21 NDIndex_t leftDomain;
22
23 // Start with the whole domain.
24 domains_c[0] = domain;
25 int v;
26 unsigned int d = 0;
27
28 int v1, v2, rm, vtot, vl, vr;
29 double a, lmax, len;
30
31 for (v = nSplits, rm = 0; v > 1; v /= 2) {
32 rm += (v % 2);
33 }
34
35 if (rm == 0) {
36 // nSplits is a power of 2
37
38 std::vector<NDIndex_t> copy_c(nSplits);
39
40 for (v = 1; v < nSplits; v *= 2) {
41 // Go to the next parallel dimension.
42 while (!isParallel[d])
43 if (++d == Dim)
44 d = 0;
45
46 // Split all the current nSplits.
47 int i, j;
48 for (i = 0, j = 0; i < v; ++i, j += 2) {
49 // Split to the left and to the right, saving both.
50 domains_c[i].split(copy_c[j], copy_c[j + 1], d);
51 }
52 // Copy back.
53 std::copy(copy_c.begin(), copy_c.begin() + v * 2, domains_c.begin());
54
55 // On to the next dimension.
56 if (++d == Dim)
57 d = 0;
58 }
59
60 } else {
61 vtot = 1; // count the number of nSplits to make sure that it worked
62 // nSplits is not a power of 2 so we need to do some fancy splitting
63 // sorry... this would be much cleaner with recursion
64 /*
65 The way this works is to recursively split on the longest dimension.
66 Suppose you request 11 nSplits. It will split the longest dimension
67 in the ratio 5:6 and put the new domains in node 0 and node 5. Then
68 it splits the longest dimension of the 0 domain and puts the results
69 in node 0 and node 2 and then splits the longest dimension of node 5
70 and puts the results in node 5 and node 8. etc.
71 The logic is kind of bizarre, but it works.
72 */
73 for (v = 1; v < 2 * nSplits; ++v) {
74 // kind of reverse the bits of v
75 for (v2 = v, v1 = 1; v2 > 1; v2 /= 2) {
76 v1 = 2 * v1 + (v2 % 2);
77 }
78 vl = 0;
79 vr = nSplits;
80
81 while (v1 > 1) {
82 if ((v1 % 2) == 1) {
83 vl = vl + (vr - vl) / 2;
84 } else {
85 vr = vl + (vr - vl) / 2;
86 }
87 v1 /= 2;
88 }
89
90 v2 = vl + (vr - vl) / 2;
91
92 if (v2 > vl) {
93 a = v2 - vl;
94 a /= vr - vl;
95 vr = v2;
96 leftDomain = domains_c[vl];
97 lmax = 0;
98 d = std::numeric_limits<unsigned int>::max();
99 for (unsigned int dd = 0; dd < Dim; ++dd) {
100 if (isParallel[dd]) {
101 if ((len = leftDomain[dd].length()) > lmax) {
102 lmax = len;
103 d = dd;
104 }
105 }
106 }
107 NDIndex_t temp;
108 domains_c[vl].split(temp, domains_c[vr], d, a);
109 domains_c[vl] = temp;
110 ++vtot;
111 }
112 }
113
114 v = vtot;
115 }
116
117 // Make sure v is the same number of nSplits at this stage.
118 PAssert_EQ(v, nSplits);
119
120 for (size_t i = 0; i < domains_c.size(); ++i) {
121 view(i) = domains_c[i];
122 }
123 }
124 } // namespace detail
125} // namespace ippl
constexpr unsigned Dim
#define PAssert_EQ(a, b)
Definition PAssert.h:123
Definition Archive.h:20
void split(const NDIndex< Dim > &domain, view_type &view, const std::array< bool, Dim > &isParallel, int nSplits) const