HILA
Loading...
Searching...
No Matches
setup_layout_generic.cpp
1/// Setup layout does the node division. This version
2/// first tries an even distribution, with equally sized
3/// nodes, and if that fails allows slightly different
4/// node sizes.
5
6#include "plumbing/defs.h"
7#include "plumbing/lattice.h"
8
9/***************************************************************/
10
11/* number of primes to be used in factorization */
12#define NPRIMES 12
13const static int prime[NPRIMES] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
14
15/* Set up now squaresize and nsquares - arrays
16 * Print info to outf as we proceed
17 */
18
19void lattice_struct::setup_layout() {
20 int nfactors[NPRIMES];
21 CoordinateVector nodesiz;
22
23 print_dashed_line();
24 hila::out0 << "LAYOUT: lattice size ";
25 foralldir(d) {
26 if (d != 0)
27 hila::out0 << " x ";
28 hila::out0 << size(d);
29 }
30 hila::out0 << " = " << l_volume << " sites\n";
31 hila::out0 << "Dividing to " << hila::number_of_nodes() << " nodes\n";
32
33 foralldir(d) if (size(d) % 2 != 0) {
34 hila::out0 << "Lattice must be even to all directions (odd size:TODO)\n";
36 }
37
38 // Factorize the node number in primes
39 // These factors must be used in slicing the lattice!
40 int nn = hila::number_of_nodes();
41
42 int i = nn;
43 for (int n = 0; n < NPRIMES; n++) {
44 nfactors[n] = 0;
45 while (i % prime[n] == 0) {
46 i /= prime[n];
47 nfactors[n]++;
48 }
49 }
50 if (i != 1) {
51 hila::out0 << "Cannot factorize " << nn << " nodes with primes up to " << prime[NPRIMES - 1]
52 << '\n';
54 }
55
56 int64_t remainder = l_volume % nn; // remainder = 0 even division
57
58 // strategy: try to increase the box size to one of the directions until rem = 0
59 // find the optimal direction to do it
60 // Use simple heuristic: take the dim with the least amount of added "ghost sites"
61
62 CoordinateVector nsize;
63 int64_t ghosts[NDIM]; // int is too small
64
65 foralldir(d) {
66 int64_t cosize = l_volume / size(d);
67 int64_t n = size(d);
68 while ((n * cosize) % nn != 0)
69 n++; // virtual size can be odd
70 // now nsize is the new would-be size
71 ghosts[d] = (n - size(d)) * cosize;
72 nsize[d] = n;
73 }
74
75 int mdir = 0;
76 bool secondtime = false;
77 do {
78 // try the division a couple of times, if the 1st fails
79
80 foralldir(j) if (ghosts[mdir] > ghosts[j]) mdir = j;
81 // mdir is the direction where we do uneven division (if done)
82 // hila::out0 << "MDIR " << mdir << " ghosts mdir " << ghosts[mdir] << " nsize " <<
83 // nsize[mdir] << '\n';
84
85 foralldir(i) {
86 nodesiz[i] = (i == mdir) ? nsize[i] : size(i); // start with ghosted lattice size
87 nodes.n_divisions[i] = 1;
88 }
89
90 for (int n = NPRIMES - 1; n >= 0; n--)
91 for (int i = 0; i < nfactors[n]; i++) {
92 // figure out which direction to divide -- start from the largest prime,
93 // because we don't want this to be last divisor! (would probably wind up
94 // with size 1)
95
96 // find largest divisible dimension of h-cubes - start from last, because
97 int msize = 1, dir;
98 for (dir = 0; dir < NDIM; dir++)
99 if (nodesiz[dir] > msize && nodesiz[dir] % prime[n] == 0)
100 msize = nodesiz[dir];
101
102 // if one direction with largest dimension has already been
103 // divided, divide it again. Otherwise divide first direction
104 // with largest dimension.
105
106 // Switch here to first divide along t-direction, in
107 // order to
108 // a) minimize spatial blocks
109 // b) In sf t-division is cheaper (1 non-communicating slice)
110
111 for (dir = NDIM - 1; dir >= 0; dir--)
112 if (nodesiz[dir] == msize && nodes.n_divisions[dir] > 1 &&
113 nodesiz[dir] % prime[n] == 0)
114 break;
115
116 // If not previously sliced, take one direction to slice
117 if (dir < 0)
118 for (dir = NDIM - 1; dir >= 0; dir--)
119 if (nodesiz[dir] == msize && nodesiz[dir] % prime[n] == 0)
120 break;
121
122 if (dir < 0) {
123 // This cannot happen
124 hila::out0 << "CANNOT HAPPEN! in setup_layout_generic.c\n";
126 }
127
128 // Now slice it
129 nodesiz[dir] /= prime[n];
130 nodes.n_divisions[dir] *= prime[n];
131 }
132
133 // now check that the div makes sens
134 bool fail = false;
135 foralldir(dir) if (nodesiz[dir] < 2) fail = true; // don't allow nodes of size 1
136 if (fail && !secondtime) {
137 secondtime = true;
138 ghosts[mdir] =
139 (1ULL << 62); // this short-circuits direction mdir, some other taken next
140 } else if (fail) {
141 hila::out0 << "Could not successfully lay out the lattice with "
142 << hila::number_of_nodes() << " nodes\n";
144 }
145
146 } while (secondtime);
147
148 // set up struct nodes variables
149 nodes.number = hila::number_of_nodes();
150 foralldir(dir) {
151 nodes.divisors[dir].resize(nodes.n_divisions[dir] + 1);
152 // Node divisors: note, this MUST BE compatible with
153 // node_rank in lattice.cpp
154 // to be sure, we use naively the same method than in node_rank
155 // last element will be size(dir), for convenience
156 int n = -1;
157 for (int i = 0; i <= size(dir); i++)
158 if ((i * nodes.n_divisions[dir]) / size(dir) != n) {
159 ++n;
160 nodes.divisors[dir][n] = i;
161 }
162 // hila::out0 << "Divisors ";
163 // for (int i=0;i<nodes.n_divisions[dir]; i++) hila::out0 << nodes.divisors[dir][i]
164 // << " "; hila::out0 << '\n';
165 }
166
167 // Now division done - check how good it is
168 int ghost_slices = nsize[mdir] - size(mdir);
169 if (ghost_slices > 0) {
170 hila::out0 << "\nUsing uneven node division to direction " << mdir << ":\n";
171 hila::out0 << "Lengths: " << nodes.n_divisions[mdir] - ghost_slices << " * ("
172 << nodesiz[mdir] << " sites) + " << ghost_slices << " * (" << nodesiz[mdir] - 1
173 << " sites)\n";
174 hila::out0 << "Divisions: ";
175 for (int i = 0; i < nodes.n_divisions[mdir]; i++) {
176 if (i > 0)
177 hila::out0 << " - ";
178 hila::out0 << nodes.divisors[mdir][i + 1] - nodes.divisors[mdir][i];
179 }
180 hila::out0 << "\nFilling efficiency: " << (100.0 * size(mdir)) / nsize[mdir] << "%\n";
181
182 if (ghost_slices > nodes.n_divisions[mdir] / 2)
183 hila::out0 << "NOTE: number of smaller nodes > large nodes \n";
184 }
185
186 // this was hila::number_of_nodes() > 1
187 if (1) {
188 hila::out0 << "\nSites on node: ";
189 foralldir(dir) {
190 if (dir > 0)
191 hila::out0 << " x ";
192 if (dir == mdir && ghost_slices > 0)
193 hila::out0 << '(' << nodesiz[dir] - 1 << '-' << nodesiz[dir] << ')';
194 else
195 hila::out0 << nodesiz[dir];
196 }
197 int ns = 1;
198 foralldir(dir) ns *= nodesiz[dir];
199 if (ghost_slices > 0) {
200 int ns2 = ns * (nodesiz[mdir] - 1) / nodesiz[mdir];
201 hila::out0 << " = " << ns2 << " - " << ns << '\n';
202 } else {
203 hila::out0 << " = " << ns << '\n';
204 }
205
206 hila::out0 << "Processor layout: ";
207 foralldir(dir) {
208 if (dir > 0)
209 hila::out0 << " x ";
210 hila::out0 << nodes.n_divisions[dir];
211 }
212 hila::out0 << " = " << hila::number_of_nodes() << " nodes\n";
213 }
214
215 // For MPI, remap the nodes for periodic torus
216 // in the desired manner
217 // we have at least 2 options:
218 // map_node_layout_trivial.c
219 // map_node_layout_block2.c - for 2^n n.n. blocks
220
221 nodes.create_remap();
222
223
224 print_dashed_line();
225}
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:78
This file defines all includes for HILA.
int number_of_nodes()
how many nodes there are
Definition com_mpi.cpp:245
std::ostream out0
This writes output only from main process (node 0)
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...