HILA
Loading...
Searching...
No Matches
lattice.h
1#ifndef LATTICE_H
2#define LATTICE_H
3
4#include <sstream>
5#include <iostream>
6#include <fstream>
7#include <array>
8#include <vector>
9
10// SUBNODE_LAYOUT is now defined in main.mk
11// #define SUBNODE_LAYOUT
12
13#include "plumbing/defs.h"
15#include "plumbing/timing.h"
16
17#ifdef SUBNODE_LAYOUT
18#ifndef VECTOR_SIZE
19#if defined(CUDA) || defined(HIP)
20#define VECTOR_SIZE 8 // Size of float, length 1 vectors
21#else
22#define VECTOR_SIZE (256 / 8) // this is for AVX2
23#endif
24#endif
25// This is the vector size used to determine the layout
26constexpr unsigned number_of_subnodes = VECTOR_SIZE / sizeof(float);
27#endif
28
29namespace hila {
30/// list of field boundary conditions - used only if SPECIAL_BOUNDARY_CONDITIONS defined
31enum class bc { PERIODIC, ANTIPERIODIC, DIRICHLET };
32
33/// False if we have b.c. which does not require communication
35 if (bc == hila::bc::DIRICHLET) {
36 return false;
37 } else {
38 return true;
39 }
40}
41
42} // namespace hila
43
44void test_std_gathers();
45void report_too_large_node(); // report on too large node
46
47/// useful information about a node
48struct node_info {
49 CoordinateVector min, size;
50 unsigned evensites, oddsites;
51};
52
53/// Some backends need specialized lattice data
54/// in loops. Forward declaration here and
55/// implementations in backend headers.
56/// Loops generated by hilapp can access
57/// this through lattice.backend_lattice.
59
60/// The lattice struct defines the lattice geometry ans sets up MPI communication
61/// patterns
63 private:
64 CoordinateVector l_size;
65 size_t l_volume = 0; // use this to flag initialization
66
67 int l_label; // running number, identification of the lattice (TODO)
68
69 public:
70 /// Information about the node stored on this process
71 struct node_struct {
72 lattice_struct *parent = nullptr; // parent lattice, in order to access methods
73 int rank; // rank of this node
74 size_t sites, evensites, oddsites;
75 size_t field_alloc_size; // how many sites/node in allocations
76 CoordinateVector min, size; // node local coordinate ranges
77 unsigned nn[NDIRS]; // nn-node of node down/up to dirs
78 bool first_site_even; // is location min even or odd?
79
80#ifdef EVEN_SITES_FIRST
81 std::vector<CoordinateVector> coordinates;
82#endif
83
84 Vector<NDIM, unsigned> size_factor; // components: 1, size[0], size[0]*size[1], ...
85
86 void setup(node_info &ni, lattice_struct &lattice);
87
88#ifdef SUBNODE_LAYOUT
89 /// If we have vectorized-style layout, we introduce "subnodes"
90 /// size is mynode.size/subnodes.divisions, which is not
91 /// constant across nodes
92 struct subnode_struct {
93 CoordinateVector divisions, size; // div to subnodes to directions, size
94 size_t sites, evensites, oddsites;
95 Direction merged_subnodes_dir;
96
97 void setup(const node_struct &tn);
98 } subnodes;
99#endif
100
101 unsigned volume() const {
102 return sites;
103 }
104
105 /// true if this node is on the edge of the lattice to dir d
106 bool is_on_edge(Direction d) const {
107 return (is_up_dir(d) && min[d] + size[d] == parent->size(d)) ||
108 (!is_up_dir(d) && min[-d] == 0);
109 }
110
111 } mynode;
112
113 /// information about all nodes
114 struct allnodes {
115 int number; // number of nodes
116 CoordinateVector n_divisions; // number of node divisions to dir
117 // lattice division: div[d] will have num_dir[d]+1 elements, last size
118 // TODO: is this needed at all?
119 std::vector<unsigned> divisors[NDIM];
120 CoordinateVector max_size; // size of largest node
121
122 std::vector<node_info> nodelist;
123
124 unsigned *RESTRICT map_array; // mapping (optional)
125 unsigned *RESTRICT map_inverse; // inv of it
126
127 void create_remap(); // create remap_node
128 unsigned remap(unsigned i) const; // use remap
129 unsigned inverse_remap(unsigned i) const; // inverse remap
130
131 } nodes;
132
133 /// Information necessary to communicate with a node
135 unsigned rank; // rank of communicated with node
136 size_t sites, evensites, oddsites;
137 size_t buffer; // offset from the start of field array
138 unsigned *sitelist;
139
140 // Get a vector containing the sites of parity par and number of elements
141 const unsigned *RESTRICT get_sitelist(Parity par, int &size) const {
142 if (par == ALL) {
143 size = sites;
144 return sitelist;
145 } else if (par == EVEN) {
146 size = evensites;
147 return sitelist;
148 } else {
149 size = oddsites;
150 return sitelist + evensites;
151 }
152 }
153
154 // The number of sites that need to be communicated
155 unsigned n_sites(Parity par) const {
156 if (par == ALL) {
157 return sites;
158 } else if (par == EVEN) {
159 return evensites;
160 } else {
161 return oddsites;
162 }
163 }
164
165 // The local index of a site that is sent to neighbour
166 unsigned site_index(unsigned site, Parity par) const {
167 if (par == ODD) {
168 return sitelist[evensites + site];
169 } else {
170 return sitelist[site];
171 }
172 }
173
174 // The offset of the halo from the start of the field array
175 unsigned offset(Parity par) const {
176 if (par == ODD) {
177 return buffer + evensites;
178 } else {
179 return buffer;
180 }
181 }
182 };
183
184 /// nn-communication has only 1 node to talk to
186 unsigned *index;
187 comm_node_struct from_node, to_node;
188 unsigned receive_buf_size; // only for general gathers
189 };
190
191 /// general communication
193 unsigned *index;
194 std::vector<comm_node_struct> from_node;
195 std::vector<comm_node_struct> to_node;
196 size_t receive_buf_size;
197 };
198
199 /// nearest neighbour comminfo struct
200 std::array<nn_comminfo_struct, NDIRS> nn_comminfo;
201
202 /// Main neighbour index array
204
205 /// implement waiting using mask_t - unsigned char is good for up to 4 dim.
207
208#ifdef SPECIAL_BOUNDARY_CONDITIONS
209 /// special boundary pointers are needed only in cases neighbour
210 /// pointers must be modified (new halo elements). That is known only during
211 /// runtime.
212 struct special_boundary_struct {
213 unsigned *neighbours;
214 unsigned *move_index;
215 size_t offset, n_even, n_odd, n_total;
216 bool is_needed;
217 };
218 // holder for nb ptr info
219 special_boundary_struct special_boundaries[NDIRS];
220#endif
221
222#ifndef VANILLA
223 backend_lattice_struct *backend_lattice;
224#endif
225
226 void setup(const CoordinateVector &siz);
227 void setup_layout();
228 void setup_nodes();
229
230 // Std accessors:
231 // volume
232 int64_t volume() const {
233 return l_volume;
234 }
235
236 // size routines
237 int size(Direction d) const {
238 return l_size[d];
239 }
240 int size(int d) const {
241 return l_size[d];
242 }
243 CoordinateVector size() const {
244 return l_size;
245 }
246
247 int node_rank() const {
248 return mynode.rank;
249 }
250 int n_nodes() const {
251 return nodes.number;
252 }
253 // std::vector<node_info> nodelist() { return nodes.nodelist; }
254 // CoordinateVector min_coordinate() const { return mynode.min; }
255 // int min_coordinate(Direction d) const { return mynode.min[d]; }
256
257 bool is_on_mynode(const CoordinateVector &c) const;
258 int node_rank(const CoordinateVector &c) const;
259 unsigned site_index(const CoordinateVector &c) const;
260 unsigned site_index(const CoordinateVector &c, const unsigned node) const;
261 unsigned field_alloc_size() const {
262 return mynode.field_alloc_size;
263 }
264
265 void create_std_gathers();
266 gen_comminfo_struct create_general_gather(const CoordinateVector &r);
267 std::vector<comm_node_struct> create_comm_node_vector(CoordinateVector offset, unsigned *index,
268 bool receive);
269
270 // bool first_site_even() const {
271 // return mynode.first_site_even;
272 // };
273
274#ifdef SPECIAL_BOUNDARY_CONDITIONS
275 void init_special_boundaries();
276 void setup_special_boundary_array(Direction d);
277
278 const unsigned *get_neighbour_array(Direction d, hila::bc bc);
279#else
280 const unsigned *get_neighbour_array(Direction d, hila::bc bc) {
281 return neighb[d];
282 }
283#endif
284
285 unsigned remap_node(const unsigned i);
286
287#ifdef EVEN_SITES_FIRST
288 unsigned loop_begin(Parity P) const {
289 if (P == ODD) {
290 return mynode.evensites;
291 } else {
292 return 0;
293 }
294 }
295 unsigned loop_end(Parity P) const {
296 if (P == EVEN) {
297 return mynode.evensites;
298 } else {
299 return mynode.sites;
300 }
301 }
302
303 inline const CoordinateVector &coordinates(unsigned idx) const {
304 return mynode.coordinates[idx];
305 }
306
307 inline int coordinate(unsigned idx, Direction d) const {
308 return mynode.coordinates[idx][d];
309 }
310
311 inline Parity site_parity(unsigned idx) const {
312 if (idx < mynode.evensites)
313 return EVEN;
314 else
315 return ODD;
316 }
317
318#else // Now not EVEN_SITES_FIRST
319
320 unsigned loop_begin(Parity P) const {
321 assert(P == ALL && "Only parity ALL when EVEN_SITES_FIRST is off");
322 return 0;
323 }
324 unsigned loop_end(Parity P) const {
325 return mynode.sites;
326 }
327
328 // Use computation to get coordinates: from fastest
329 // to lowest, dir = 0, 1, 2, ...
330 // each coordinate is c[d] = (idx/size_factor[d]) % size[d] + min[d], but
331 // do it like below to avoid the mod
332
333 inline const CoordinateVector coordinates(unsigned idx) const {
335 unsigned vdiv, ndiv;
336
337 vdiv = idx;
338 for (int d = 0; d < NDIM - 1; ++d) {
339 ndiv = vdiv / mynode.size[d];
340 c[d] = vdiv - ndiv * mynode.size[d] + mynode.min[d];
341 vdiv = ndiv;
342 }
343 c[NDIM - 1] = vdiv + mynode.min[NDIM - 1];
344
345 return c;
346 }
347
348 inline int coordinate(unsigned idx, Direction d) const {
349 return (idx / mynode.size_factor[d]) % mynode.size[d] + mynode.min[d];
350 }
351
352 inline Parity site_parity(unsigned idx) const {
353 return coordinates(idx).parity();
354 }
355
356#endif
357
358 CoordinateVector local_coordinates(unsigned idx) const {
359 return coordinates(idx) - mynode.min;
360 }
361
362 lattice_struct::nn_comminfo_struct get_comminfo(int d) {
363 return nn_comminfo[d];
364 }
365
366 /* MPI functions and variables. Define here in lattice? */
367 void initialize_wait_arrays();
368
369
370 MPI_Comm mpi_comm_lat;
371
372 // Guarantee 64 bits for these - 32 can overflow!
373 int64_t n_gather_done = 0, n_gather_avoided = 0;
374
375
376 /// Return the coordinates of a site, where 1st dim (x) runs fastest etc.
377 /// Useful in
378 /// for (int64_t i=0; i<lattice.volume(); i++) {
379 /// auto c = lattice.global_coordinates(i);
380
382 CoordinateVector site;
383 foralldir(dir) {
384 site[dir] = index % size(dir);
385 index /= size(dir);
386 }
387 return site;
388 }
389
390 int id() const {
391 return l_label;
392 }
393};
394
395/// global handle to lattice
396extern lattice_struct lattice;
397
398// Keep track of defined lattices
399extern std::vector<lattice_struct *> lattices;
400
401
402#if defined(CUDA) || defined(HIP)
403__device__ __host__ int loop_lattice_size(Direction d);
404#else
405inline int loop_lattice_size(Direction d) {
406 return lattice.size(d);
407}
408#endif
409
410
411#ifdef VANILLA
412#include "plumbing/backend_cpu/lattice.h"
413#elif defined(CUDA) || defined(HIP)
414#include "plumbing/backend_gpu/lattice.h"
415#elif defined(VECTORIZED)
416#include "plumbing/backend_vector/lattice_vector.h"
417#endif
418
419
420//////////////////////////////////////////////////////////////////////
421// Define looping utilities
422// forallcoordinates(cv) - loops over coordinates in "natural" order
423// forcoordinaterange(cv, min, max) - loops over a box subvolume in natural order
424// Note - not meant for regular lattice traversal.
425
426// clang-format off
427#if NDIM == 4
428
429#define forallcoordinates(cv) \
430for (cv[3] = 0; cv[3] < lattice.size(3); cv[3]++) \
431for (cv[2] = 0; cv[2] < lattice.size(2); cv[2]++) \
432for (cv[1] = 0; cv[1] < lattice.size(1); cv[1]++) \
433for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
434
435#define forcoordinaterange(cv,cmin,cmax) \
436for (cv[3] = cmin[3]; cv[3] <= cmax[3]; cv[3]++) \
437for (cv[2] = cmin[2]; cv[2] <= cmax[2]; cv[2]++) \
438for (cv[1] = cmin[1]; cv[1] <= cmax[1]; cv[1]++) \
439for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
440
441#elif NDIM == 3
442
443#define forallcoordinates(cv) \
444for (cv[2] = 0; cv[2] < lattice.size(2); cv[2]++) \
445for (cv[1] = 0; cv[1] < lattice.size(1); cv[1]++) \
446for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
447
448#define forcoordinaterange(cv,cmin,cmax) \
449for (cv[2] = cmin[2]; cv[2] <= cmax[2]; cv[2]++) \
450for (cv[1] = cmin[1]; cv[1] <= cmax[1]; cv[1]++) \
451for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
452
453#elif NDIM == 2
454
455#define forallcoordinates(cv) \
456for (cv[1] = 0; cv[1] < lattice.size(1); cv[1]++) \
457for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
458
459#define forcoordinaterange(cv,cmin,cmax) \
460for (cv[1] = cmin[1]; cv[1] <= cmax[1]; cv[1]++) \
461for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
462
463#elif NDIM == 1
464
465#define forallcoordinates(cv) \
466for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
467
468#define forcoordinaterange(cv,cmin,cmax) \
469for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
470
471#endif
472// clang-format on
473
474#endif
Matrix class which defines matrix operations.
Definition matrix.h:1679
dir_mask_t *__restrict__ wait_arr_
implement waiting using mask_t - unsigned char is good for up to 4 dim.
Definition lattice.h:206
void setup_nodes()
invert the mynode index -> location (only on this node)
Definition lattice.cpp:291
void setup(const CoordinateVector &siz)
General lattice setup.
Definition lattice.cpp:33
bool is_on_mynode(const CoordinateVector &c) const
Is the coordinate on THIS node.
Definition lattice.cpp:118
CoordinateVector global_coordinates(size_t index) const
Definition lattice.h:381
unsigned *__restrict__ neighb[NDIRS]
Main neighbour index array.
Definition lattice.h:203
void create_std_gathers()
Definition lattice.cpp:430
std::array< nn_comminfo_struct, NDIRS > nn_comminfo
nearest neighbour comminfo struct
Definition lattice.h:200
unsigned site_index(const CoordinateVector &c) const
Definition lattice.cpp:136
This header file defines:
Parity
Parity enum with values EVEN, ODD, ALL; refers to parity of the site. Parity of site (x,...
constexpr Parity EVEN
bit pattern: 001
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:78
constexpr unsigned NDIRS
Number of directions.
Definition coordinates.h:57
constexpr Parity ODD
bit pattern: 010
unsigned char dir_mask_t
Direction
Enumerator for direction that assigns integer to direction to be interpreted as unit vector.
Definition coordinates.h:34
constexpr Parity ALL
bit pattern: 011
This file defines all includes for HILA.
#define RESTRICT
Definition defs.h:50
Invert diagonal + const. matrix using Sherman-Morrison formula.
Definition array.h:920
bc
list of field boundary conditions - used only if SPECIAL_BOUNDARY_CONDITIONS defined
Definition lattice.h:31
bool bc_need_communication(hila::bc bc)
False if we have b.c. which does not require communication.
Definition lattice.h:34
Helper class for loading the vectorized lattice.
information about all nodes
Definition lattice.h:114
unsigned remap(unsigned i) const
And the call interface for remapping.
Information necessary to communicate with a node.
Definition lattice.h:134
general communication
Definition lattice.h:192
nn-communication has only 1 node to talk to
Definition lattice.h:185
Information about the node stored on this process.
Definition lattice.h:71
void setup(node_info &ni, lattice_struct &lattice)
Fill in mynode fields – node_rank() must be set up OK.
Definition lattice.cpp:354
bool is_on_edge(Direction d) const
true if this node is on the edge of the lattice to dir d
Definition lattice.h:106
useful information about a node
Definition lattice.h:48