HILA
Loading...
Searching...
No Matches
coordinates.h
Go to the documentation of this file.
1/**
2 * @file coordinates.h
3 * @brief This header file defines:
4 * - enum ::Direction
5 * - enum class ::Parity
6 * - class CoordinateVector
7 *
8 * These are used to traverse the lattice coordinate systems
9 *
10 */
11
12#ifndef COORDINATES_H_
13#define COORDINATES_H_
14
15#include "plumbing/defs.h"
16#include "datatypes/matrix.h"
17
18#if NDIM == 4
19/**
20 * @enum Direction
21 * @brief Enumerator for direction that assigns integer to direction to be interpreted as unit
22 * vector.
23 * @details In NDIM\f$=4\f$ (max dimensionality) we have:
24 *
25 * \f$\{e_x = 0, e_y = 1, e_z = 2, e_t = 3\}\f$
26 *
27 * Negative directions are defined as \f$ e_{-i} = \f$ NDIM \f$\cdot2 - 1 - e_i\f$
28 *
29 * Defined as unsigned, but note that Direction + int is not defined. To operate with int, Direction
30 * must be first cast to int
31 *
32 * Direction can be used as an array index (interchangably with int)
33 */
34enum Direction : unsigned {
35 e_x = 0,
36 e_y,
37 e_z,
38 e_t,
39 e_t_down,
40 e_z_down,
41 e_y_down,
42 e_x_down,
43 NDIRECTIONS
44};
45#elif NDIM == 3
46enum Direction : unsigned { e_x = 0, e_y, e_z, e_z_down, e_y_down, e_x_down, NDIRECTIONS };
47#elif NDIM == 2
48enum Direction : unsigned { e_x = 0, e_y, e_y_down, e_x_down, NDIRECTIONS };
49#elif NDIM == 1
50enum Direction : unsigned { e_x = 0, e_x_down, NDIRECTIONS };
51#endif
52
53/**
54 * @brief Number of directions
55 *
56 */
57constexpr unsigned NDIRS = NDIRECTIONS;
58
59// Increment for directions: ++dir, dir++ does the obvious
60// dir-- not defined, should we?
61
62static inline Direction next_direction(Direction dir) {
63 return static_cast<Direction>(static_cast<unsigned>(dir) + 1);
64}
65static inline Direction &operator++(Direction &dir) {
66 return dir = next_direction(dir);
67}
68static inline Direction operator++(Direction &dir, int) {
69 Direction d = dir;
70 ++dir;
71 return d;
72}
73
74/**
75 * @brief Macro to loop over (all) ::Direction(s)
76 *
77 */
78#define foralldir(d) for (Direction d = e_x; d < NDIM; ++d)
79
80inline Direction opp_dir(const Direction d) {
81 return static_cast<Direction>(NDIRS - 1 - static_cast<int>(d));
82}
83
84inline Direction opp_dir(const int d) {
85 return static_cast<Direction>(NDIRS - 1 - d);
86}
87
88/// unary + and -
89inline Direction operator-(const Direction d) {
90 return opp_dir(d);
91}
92
93static inline Direction operator+(const Direction d) {
94 return d;
95}
96
97/// is_up_dir is true if the dir is "up" to coord Direction
98static inline bool is_up_dir(const Direction d) {
99 return d < NDIM;
100}
101static inline bool is_up_dir(const int d) {
102 return d < NDIM;
103}
104
105static inline Direction abs(Direction dir) {
106 if (is_up_dir(dir))
107 return dir;
108 else
109 return -dir;
110}
111
112inline int dir_dot_product(Direction d1, Direction d2) {
113 if (d1 == d2)
114 return 1;
115 else if (d1 == -d2)
116 return -1;
117 else
118 return 0;
119}
120
121/// dir_mask_t type used in masking directions
122/// unsigned char is ok up to 4 dim (2*4 bits)
123using dir_mask_t = unsigned char;
124
125inline dir_mask_t get_dir_mask(const Direction d) {
126 return (dir_mask_t)(1 << d);
127}
128
129namespace hila {
130
131
132// define hila::direction_name() and hila::prettyprint(Direction)
133
134constexpr inline const char *direction_name(Direction d) {
135 switch (d) {
136 case e_x:
137 return "e_x";
138 case e_x_down:
139 return "-e_x";
140 case e_y:
141 return "e_y";
142 case e_y_down:
143 return "-e_y";
144#if NDIM > 2
145 case e_z:
146 return "e_z";
147 case e_z_down:
148 return "-e_z";
149#endif
150#if NDIM > 3
151 case e_t:
152 return "e_t";
153 case e_t_down:
154 return "-e_t";
155#endif
156 default:
157 return "ILLEGAL DIRECTION";
158 }
159}
160
161inline std::string prettyprint(Direction d) {
162 return direction_name(d);
163}
164
165} // namespace hila
166
167// This should not be used from loops ...
168inline std::ostream &operator<<(std::ostream &os, const Direction d) {
169 os << hila::direction_name(d);
170 return os;
171}
172
173
174/**
175 * @brief Parity enum with values EVEN, ODD, ALL; refers to parity of the site. Parity of site
176 * (x,y,z,t) is even if `(x+y+z+t)` is even, odd otherwise.
177 */
178enum class Parity : unsigned { none = 0, even, odd, all };
179
180// should use here #define instead of const Parity? Makes EVEN a protected symbol
181
182/**
183 * @name Parity constexpr aliases
184 * @brief Aliases for contents of ::Parity
185 */
186/** @{ */
187/** @brief bit pattern: 001*/
188constexpr Parity EVEN = Parity::even;
189/** @brief bit pattern: 010*/
190constexpr Parity ODD = Parity::odd;
191/** @brief bit pattern: 011*/
192constexpr Parity ALL = Parity::all;
193/** @} */
194
195// this is used in diagnostics - make static inline so can be defd here
196namespace hila {
197constexpr inline const char *parity_name(Parity p) {
198 switch (p) {
199 case EVEN:
200 return "EVEN";
201 case ODD:
202 return "ODD";
203 case ALL:
204 return "ALL";
205 default:
206 return "ILLEGAL PARITY";
207 }
208}
209
210inline std::string prettyprint(Parity p) {
211 return hila::parity_name(p);
212}
213
214} // namespace hila
215
216// This should not be used from loops ...
217inline std::ostream &operator<<(std::ostream &os, const Parity p) {
218 os << hila::parity_name(p);
219 return os;
220}
221
222// utilities for getting the bit patterns
223static inline unsigned parity_bits(Parity p) {
224 return 0x3 & static_cast<unsigned>(p);
225}
226static inline unsigned parity_bits_inverse(Parity p) {
227 return 0x3 & ~static_cast<unsigned>(p);
228}
229
230// turns EVEN <-> ODD, ALL remains. X->none, none->none
231static inline Parity opp_parity(const Parity p) {
232 unsigned u = parity_bits(p);
233 return static_cast<Parity>(0x3 & ((u << 1) | (u >> 1)));
234}
235
236// Define ~parity as opp_parity
237static inline Parity operator~(const Parity p) {
238 return opp_parity(p);
239}
240
241static inline bool is_even_odd_parity(Parity p) {
242 return (p == EVEN || p == ODD);
243}
244
245
246/// Positive mod(): we define here the positive mod utility function pmod(a,b).
247/// It mods the arguments 0 <= a < m. This is not the standard
248/// for integer operator% in c++, which gives negative results if a<0. This is useful
249/// in calculating lattice vector additions on a periodic box
250
251inline int pmod(const int a, const int b) {
252 int r = a % b;
253 if (r < 0)
254 r += b;
255 return r;
256}
257
258
259/**
260 * @brief Class for coordinate vector useful in indexing lattice
261 *
262 * @details Defined as Vector<NDIM, int> meaning that all operations from Matrix class are inherited
263 *
264 * Note: this is defined as a template, with generic "int" type T, and the type is defined below as
265 * alias:
266 * @code{.cpp}
267 * using CoordinateVector = CoordinateVector_t<int>
268 * @endcode
269 * Reason for this is that if CoordinateVector is used in Field variables (Field<CoordinateVector>)
270 * hilapp is able to upgrade the int to vectorized int when vectorized compilation are used (AVX2,
271 * AVX512)
272 *
273 * @tparam T int
274 */
275template <typename T>
276class CoordinateVector_t : public Vector<NDIM, T> {
277
278 public:
279 // std incantation for field types
280 using base_type = hila::arithmetic_type<T>;
281 using argument_type = T;
282
283 // define these to ensure std::is_trivial
284 CoordinateVector_t() = default;
285
286 ~CoordinateVector_t() = default;
287 CoordinateVector_t(const CoordinateVector_t &v) = default;
288
289 /// Construct from site index
290 // CoordinateVector_t(SiteIndex s);
291
292 // initialize with Direction -- useful for automatic conversion
293 explicit inline CoordinateVector_t(const Direction dir) {
294 foralldir(d) this->e(d) = dir_dot_product(d, dir);
295 }
296
297 // construct from vector - make this not explicit so that
298 // conversions from Vector methods are automatic
299 inline CoordinateVector_t(const Vector<NDIM, T> &v) {
300 foralldir(d) this->e(d) = v.e(d);
301 }
302
303 /// Construct CV automatically from right-size initializer list
304 /// This does not seem to be dangerous, so keep non-explicit
305 template <typename S, std::enable_if_t<hila::is_assignable<T &, S>::value, int> = 0>
306 inline CoordinateVector_t(std::initializer_list<S> rhs) {
307 assert(rhs.size() == NDIM && "CoordinateVector initializer list size does not match");
308 int i = 0;
309 for (auto it = rhs.begin(); it != rhs.end(); it++, i++)
310 this->e(i) = *it;
311 }
312
313 /// Construct from 0, using nullptr_t autocast
314 inline CoordinateVector_t(std::nullptr_t z) {
315 foralldir(d) this->e(d) = 0;
316 }
317
318 // /// cast to vector<NDIM,int> - useful for method inheritance
319 // inline operator Vector<NDIM, int>() {
320 // Vector<NDIM, int> v;
321 // foralldir(d) v.e(d) = this->e(d);
322 // return v;
323 // }
324
325 /// Assign from 0
326 inline CoordinateVector_t &operator=(std::nullptr_t z) out_only & {
327 foralldir(d) this->e(d) = 0;
328 return *this;
329 }
330
331 /// Assign from initializer list
332 template <typename S, std::enable_if_t<hila::is_assignable<T &, S>::value, int> = 0>
333 inline CoordinateVector_t &operator=(std::initializer_list<S> rhs) out_only & {
334 assert(rhs.size() == NDIM && "Initializer list has a wrong size in assignment");
335 int i = 0;
336 for (auto it = rhs.begin(); it != rhs.end(); it++, i++) {
337 this->e(i) = *it;
338 }
339 return *this;
340 }
341
342 // Assign from direction
343 inline CoordinateVector_t &operator=(Direction d) out_only & {
344 foralldir(dir) {
345 this->e(dir) = dir_dot_product(d, dir);
346 }
347 return *this;
348 }
349
350 // and delete assign to rvalue
351 template <typename S>
352 CoordinateVector_t &operator=(const S &s) && = delete;
353
354
355 bool operator==(const CoordinateVector_t<T> &rhs) const {
356 foralldir(d) {
357 if (this->e(d) != rhs.e(d))
358 return false;
359 }
360 return true;
361 }
362
363 // #pragma hila loop function
364 T &operator[](const int i) {
365 return this->e(i);
366 }
367 // #pragma hila loop function
368 T &operator[](const Direction d) {
369 return this->e((int)d);
370 }
371 // #pragma hila loop function
372 T operator[](const int i) const {
373 return this->e(i);
374 }
375 // #pragma hila loop function
376 T operator[](const Direction d) const {
377 return this->e((int)d);
378 }
379
380 // Parity of this coordinate
381 ::Parity parity() const {
382 int s = 0;
383 foralldir(d) s += this->e(d);
384 if (s % 2 == 0)
385 return Parity::even;
386 else
387 return Parity::odd;
388 }
389
390 // cast to std::array
391 // operator std::array<int, NDIM>() {
392 // std::array<int, NDIM> a;
393 // for (int d = 0; d < NDIM; d++)
394 // a[d] = this->e(d);
395 // return a;
396 // }
397
398 // cast to Vector - make this only explicit.
399 // S can be any type, because int is convertible to it
400
401 template <typename S>
402 explicit operator Vector<NDIM, S>() {
404 for (int d = 0; d < NDIM; d++)
405 a[d] = this->e(d);
406 return a;
407 }
408
409 // add coordinate vector -- def explicit as loop_function
410 // #pragma hila loop function //TODO
411 CoordinateVector_t &operator+=(const CoordinateVector_t &rhs) & {
412 foralldir(d) this->e(d) += rhs.e(d);
413 return *this;
414 }
415
416 CoordinateVector_t &operator-=(const CoordinateVector_t &rhs) & {
417 foralldir(d) this->e(d) -= rhs.e(d);
418 return *this;
419 }
420
421 // and also additions for Direction -- dir acts like a unit vector
422 // #pragma hila loop function //TODO
423 CoordinateVector_t &operator+=(const Direction dir) & {
424 if (is_up_dir(dir))
425 ++this->e(dir);
426 else
427 --this->e(-dir);
428 return *this;
429 }
430
431 CoordinateVector_t &operator-=(const Direction dir) & {
432 if (is_up_dir(dir))
433 --this->e(dir);
434 else
435 ++this->e(-dir);
436 return *this;
437 }
438
439 // unary - -explicitly loop_function
440 inline CoordinateVector_t operator-() const {
442 foralldir(d) res.e(d) = -this->e(d);
443 return res;
444 }
445
446 // unary + -explicitly loop_function
447 inline CoordinateVector_t operator+() const {
448 return *this;
449 }
450
451 inline T dot(const CoordinateVector_t &v) const {
452 T res(0);
453 foralldir(d) res += v.e(d) * this->e(d);
454 return res;
455 }
456
457
458 /// Positive mod for coordinate vector, see int mod(int a, int b). If
459 /// 2nd argument m is lattice.size(), this mods the vector a to periodic lattice.
460
463 foralldir(d) {
464 r.e(d) = pmod((*this)[d], m[d]);
465 }
466 return r;
467 }
468
469 /// @brief Convert momentum space CoordinateVector to wave number k, where -pi/2 < k_i <= pi_2
470 /// Utility function for FFT
471 /// wave vector k_i = 2 pi n_i / N_i, where N_i = lattice.size(i) and
472 /// where n_i is the coordinate modded to interval -N_i/2 < n_i <= N_i/2, or
473 /// if n_i > N_i/2 then n_i = n_i - N_i.
474 ///
475 /// @return wave number vector k
476 inline Vector<NDIM, double> convert_to_k() const;
477
478 /// Return site index of the coordinate vector -- assumes a valid lattice vector
479
480 // inline SiteIndex index() const;
481};
482
483/**
484 * @brief CoordinateVector alias for CoordinateVector_t
485 *
486 */
488
489template <typename T>
491 const CoordinateVector_t<T> &cv2) {
492 cv1 += cv2;
493 return cv1;
494}
495
496template <typename T>
498 const CoordinateVector_t<T> &cv2) {
499 cv1 -= cv2;
500 return cv1;
501}
502
503/// Special Direction operators: dir + dir -> CoordinateVector
504inline CoordinateVector operator+(const Direction d1, const Direction d2) {
506 foralldir(d) {
507 r.e(d) = dir_dot_product(d1, d);
508 r.e(d) += dir_dot_product(d2, d);
509 }
510 return r;
511}
512
513inline CoordinateVector operator-(const Direction d1, const Direction d2) {
515 foralldir(d) {
516 r.e(d) = dir_dot_product(d1, d);
517 r.e(d) -= dir_dot_product(d2, d);
518 }
519 return r;
520}
521
522/// Special operators: int*Direction -> CoordinateVector (of type int!)
523inline CoordinateVector operator*(const int i, const Direction dir) {
525 foralldir(d) r.e(d) = i * dir_dot_product(d, dir);
526 return r;
527}
528
529inline CoordinateVector operator*(const Direction d, const int i) {
530 return i * d;
531}
532
533// coordinate vector + Direction -- dir is a unit vector
534template <typename T>
536 cv += dir;
537 return cv;
538}
539
540template <typename T>
542 cv -= dir;
543 return cv;
544}
545
546template <typename T>
548 cv += dir;
549 return cv;
550}
551
552template <typename T>
554 foralldir(d) cv.e(d) = dir_dot_product(dir, d) - cv.e(d);
555 return cv;
556}
557
558
559/**
560 * @brief X-coordinate type - "dummy" class
561 * @details used only in loop index and is removed by code analysis. Generally empty except for
562 * method deceleration
563 */
565 public:
566 /**
567 * @brief Returns coordinate of site at index X
568 *
569 * @return const CoordinateVector&
570 */
572
573 /**
574 * @brief Returns dth dimension coordinate of X
575 *
576 * @param d direction to probe
577 * @return int
578 */
579 int coordinate(Direction d) const;
580
581 int x() const;
582 int y() const;
583#if NDIM > 2
584 int z() const;
585#if NDIM > 3
586 int t() const;
587#endif
588#endif
589
590 /**
591 * @brief Returns parity of site at index X
592 *
593 * @return ::Parity
594 */
596};
597
598/// this defines the "point" dummy variable!
599static const X_index_type X;
600
601/// X + dir -type: used in expressions of type f[X+dir]
602/// It's a dummy type, is not used in final code
603
605/// X + coordinate offset, used in f[X+CoordinateVector] or f[X+dir1+dir2] etc.
607
608/// Declarations X+smth, no need to implement these (type removed by hilapp)
609
611const X_plus_direction operator-(const X_index_type x, const Direction d);
612const X_plus_offset operator+(const X_index_type x, const CoordinateVector &cv);
613const X_plus_offset operator-(const X_index_type x, const CoordinateVector &cv);
618const X_plus_offset operator+(const X_plus_offset, const Direction d);
619const X_plus_offset operator-(const X_plus_offset, const Direction d);
622
623#endif
std::ostream & operator<<(std::ostream &strm, const Array< n, m, T > &A)
Stream operator.
Definition array.h:977
auto operator+(const Array< n, m, A > &a, const Array< n, m, B > &b)
Addition operator.
Definition array.h:740
Class for coordinate vector useful in indexing lattice.
CoordinateVector_t mod(const CoordinateVector_t &m) const
CoordinateVector_t(const Direction dir)
Construct from site index.
CoordinateVector_t(std::nullptr_t z)
Construct from 0, using nullptr_t autocast.
Vector< 4, double > convert_to_k() const
Convert momentum space CoordinateVector to wave number k, where -pi/2 < k_i <= pi_2 Utility function ...
Definition fft.h:29
CoordinateVector_t(std::initializer_list< S > rhs)
CoordinateVector_t & operator=(std::initializer_list< S > rhs) &
Assign from initializer list.
CoordinateVector_t & operator=(std::nullptr_t z) &
Assign from 0.
T e(const int i, const int j) const
Standard array indexing operation for matrices and vectors.
Definition matrix.h:286
Matrix class which defines matrix operations.
Definition matrix.h:1620
X-coordinate type - "dummy" class.
::Parity parity() const
Returns parity of site at index X.
int coordinate(Direction d) const
Returns dth dimension coordinate of X.
const CoordinateVector & coordinates() const
Returns coordinate of site at index X.
T abs(const Complex< T > &a)
Return absolute value of Complex number.
Definition cmplx.h:1187
Parity
Parity enum with values EVEN, ODD, ALL; refers to parity of the site. Parity of site (x,...
int pmod(const int a, const int b)
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
CoordinateVector operator*(const int i, const Direction dir)
Special operators: int*Direction -> CoordinateVector (of type int!)
Direction operator-(const Direction d)
unary + and -
Definition coordinates.h:89
This file defines all includes for HILA.
Definition of Matrix types.
Implement hila::swap for gauge fields.
Definition array.h:981
X + coordinate offset, used in f[X+CoordinateVector] or f[X+dir1+dir2] etc.