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