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 /// is the lattice initialized
231 bool is_initialized() const {
232 // using l_volume as the flag
233 return l_volume != 0;
234 }
235
236
237 // Std accessors:
238 // volume
239 int64_t volume() const {
240 return l_volume;
241 }
242
243 // size routines
244 int size(Direction d) const {
245 return l_size[d];
246 }
247 int size(int d) const {
248 return l_size[d];
249 }
250 CoordinateVector size() const {
251 return l_size;
252 }
253
254 int node_rank() const {
255 return mynode.rank;
256 }
257 int n_nodes() const {
258 return nodes.number;
259 }
260 // std::vector<node_info> nodelist() { return nodes.nodelist; }
261 // CoordinateVector min_coordinate() const { return mynode.min; }
262 // int min_coordinate(Direction d) const { return mynode.min[d]; }
263
264 bool is_on_mynode(const CoordinateVector &c) const;
265 int node_rank(const CoordinateVector &c) const;
266 unsigned site_index(const CoordinateVector &c) const;
267 unsigned site_index(const CoordinateVector &c, const unsigned node) const;
268 unsigned field_alloc_size() const {
269 return mynode.field_alloc_size;
270 }
271
272 void create_std_gathers();
273 gen_comminfo_struct create_general_gather(const CoordinateVector &r);
274 std::vector<comm_node_struct> create_comm_node_vector(CoordinateVector offset, unsigned *index,
275 bool receive);
276
277 // bool first_site_even() const {
278 // return mynode.first_site_even;
279 // };
280
281#ifdef SPECIAL_BOUNDARY_CONDITIONS
282 void init_special_boundaries();
283 void setup_special_boundary_array(Direction d);
284
285 const unsigned *get_neighbour_array(Direction d, hila::bc bc);
286#else
287 const unsigned *get_neighbour_array(Direction d, hila::bc bc) {
288 return neighb[d];
289 }
290#endif
291
292 unsigned remap_node(const unsigned i);
293
294#ifdef EVEN_SITES_FIRST
295 unsigned loop_begin(Parity P) const {
296 if (P == ODD) {
297 return mynode.evensites;
298 } else {
299 return 0;
300 }
301 }
302 unsigned loop_end(Parity P) const {
303 if (P == EVEN) {
304 return mynode.evensites;
305 } else {
306 return mynode.sites;
307 }
308 }
309
310 inline const CoordinateVector &coordinates(unsigned idx) const {
311 return mynode.coordinates[idx];
312 }
313
314 inline int coordinate(unsigned idx, Direction d) const {
315 return mynode.coordinates[idx][d];
316 }
317
318 inline Parity site_parity(unsigned idx) const {
319 if (idx < mynode.evensites)
320 return EVEN;
321 else
322 return ODD;
323 }
324
325#else // Now not EVEN_SITES_FIRST
326
327 unsigned loop_begin(Parity P) const {
328 assert(P == ALL && "Only parity ALL when EVEN_SITES_FIRST is off");
329 return 0;
330 }
331 unsigned loop_end(Parity P) const {
332 return mynode.sites;
333 }
334
335 // Use computation to get coordinates: from fastest
336 // to lowest, dir = 0, 1, 2, ...
337 // each coordinate is c[d] = (idx/size_factor[d]) % size[d] + min[d], but
338 // do it like below to avoid the mod
339
340 inline const CoordinateVector coordinates(unsigned idx) const {
342 unsigned vdiv, ndiv;
343
344 vdiv = idx;
345 for (int d = 0; d < NDIM - 1; ++d) {
346 ndiv = vdiv / mynode.size[d];
347 c[d] = vdiv - ndiv * mynode.size[d] + mynode.min[d];
348 vdiv = ndiv;
349 }
350 c[NDIM - 1] = vdiv + mynode.min[NDIM - 1];
351
352 return c;
353 }
354
355 inline int coordinate(unsigned idx, Direction d) const {
356 return (idx / mynode.size_factor[d]) % mynode.size[d] + mynode.min[d];
357 }
358
359 inline Parity site_parity(unsigned idx) const {
360 return coordinates(idx).parity();
361 }
362
363#endif
364
365 CoordinateVector local_coordinates(unsigned idx) const {
366 return coordinates(idx) - mynode.min;
367 }
368
369 lattice_struct::nn_comminfo_struct get_comminfo(int d) {
370 return nn_comminfo[d];
371 }
372
373 /* MPI functions and variables. Define here in lattice? */
374 void initialize_wait_arrays();
375
376
377 MPI_Comm mpi_comm_lat;
378
379 // Guarantee 64 bits for these - 32 can overflow!
380 int64_t n_gather_done = 0, n_gather_avoided = 0;
381
382
383 /// Return the coordinates of a site, where 1st dim (x) runs fastest etc.
384 /// Useful in
385 /// for (int64_t i=0; i<lattice.volume(); i++) {
386 /// auto c = lattice.global_coordinates(i);
387
389 CoordinateVector site;
390 foralldir(dir) {
391 site[dir] = index % size(dir);
392 index /= size(dir);
393 }
394 return site;
395 }
396
397 int id() const {
398 return l_label;
399 }
400};
401
402/// global handle to lattice
403extern lattice_struct lattice;
404
405// Keep track of defined lattices
406extern std::vector<lattice_struct *> lattices;
407
408
409#if defined(CUDA) || defined(HIP)
410__device__ __host__ int loop_lattice_size(Direction d);
411#else
412inline int loop_lattice_size(Direction d) {
413 return lattice.size(d);
414}
415#endif
416
417
418#ifdef VANILLA
419#include "plumbing/backend_cpu/lattice.h"
420#elif defined(CUDA) || defined(HIP)
421#include "plumbing/backend_gpu/lattice.h"
422#elif defined(VECTORIZED)
423#include "plumbing/backend_vector/lattice_vector.h"
424#endif
425
426
427//////////////////////////////////////////////////////////////////////
428// Define looping utilities
429// forallcoordinates(cv) - loops over coordinates in "natural" order
430// forcoordinaterange(cv, min, max) - loops over a box subvolume in natural order
431// Note - not meant for regular lattice traversal.
432
433// clang-format off
434#if NDIM == 4
435
436#define forallcoordinates(cv) \
437for (cv[3] = 0; cv[3] < lattice.size(3); cv[3]++) \
438for (cv[2] = 0; cv[2] < lattice.size(2); cv[2]++) \
439for (cv[1] = 0; cv[1] < lattice.size(1); cv[1]++) \
440for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
441
442#define forcoordinaterange(cv,cmin,cmax) \
443for (cv[3] = cmin[3]; cv[3] <= cmax[3]; cv[3]++) \
444for (cv[2] = cmin[2]; cv[2] <= cmax[2]; cv[2]++) \
445for (cv[1] = cmin[1]; cv[1] <= cmax[1]; cv[1]++) \
446for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
447
448#elif NDIM == 3
449
450#define forallcoordinates(cv) \
451for (cv[2] = 0; cv[2] < lattice.size(2); cv[2]++) \
452for (cv[1] = 0; cv[1] < lattice.size(1); cv[1]++) \
453for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
454
455#define forcoordinaterange(cv,cmin,cmax) \
456for (cv[2] = cmin[2]; cv[2] <= cmax[2]; cv[2]++) \
457for (cv[1] = cmin[1]; cv[1] <= cmax[1]; cv[1]++) \
458for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
459
460#elif NDIM == 2
461
462#define forallcoordinates(cv) \
463for (cv[1] = 0; cv[1] < lattice.size(1); cv[1]++) \
464for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
465
466#define forcoordinaterange(cv,cmin,cmax) \
467for (cv[1] = cmin[1]; cv[1] <= cmax[1]; cv[1]++) \
468for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
469
470#elif NDIM == 1
471
472#define forallcoordinates(cv) \
473for (cv[0] = 0; cv[0] < lattice.size(0); cv[0]++)
474
475#define forcoordinaterange(cv,cmin,cmax) \
476for (cv[0] = cmin[0]; cv[0] <= cmax[0]; cv[0]++)
477
478#endif
479// clang-format on
480
481#endif
Matrix class which defines matrix operations.
Definition matrix.h:1620
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:388
bool is_initialized() const
is the lattice initialized
Definition lattice.h:231
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:51
Implement hila::swap for gauge fields.
Definition array.h:981
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