SUNphi  1.0
Grid.hpp
Go to the documentation of this file.
1 #ifndef _GRID_HPP
2 #define _GRID_HPP
3 
4 /// \file Grid.hpp
5 ///
6 /// \brief Defines hypercubic cartesian grids
7 ///
8 /// An hypercubic grid with number of dimensions fixed at compile
9 /// time. Periodic boundary conditions are imposed at all faces and
10 /// lexicographic indexing with first-neighbours connectivity is
11 /// embedded. The coordinates of points and neighbors can be hashed,
12 /// deciding at compile time.
13 ///
14 /// Given the number of dimensions, the two orientations are provided,
15 /// such that the 2*nDims neighbors are stored putting first all
16 /// backwards, then forward directions.
17 
18 #include <array>
19 #include <vector>
20 
21 #include <debug/Crash.hpp>
22 #include <ios/Logger.hpp>
23 #include <math/Arithmetic.hpp>
24 #include <metaprogramming/CRTP.hpp>
25 #include <utility/Bits.hpp>
26 #include <utility/Flags.hpp>
27 #include <utility/Position.hpp>
28 
29 /// Provide the type needed to deal with grids
30 #define PROVIDE_COORDS_TYPES
31  /*! Type to hold sizes, coordinate, etc */
32  typedef std::array<Coord,NDims> Coords;
33  /*! Type to hold the neighbors */
34  typedef std::array<Coord,2*NDims> Neigh;
35  /*! Type to hold volume */
36  typedef Idx Vol;
37  /*! Type to hold side */
38  typedef Coord Side;
39  /*! Type to hold sides */
40  typedef Coords Sides
41 
42 /// Flag to enable Grid debug
43 #define GRID_DEBUG
44  true
45 
46 namespace SUNphi
47 {
48  /// Value to identifiy orientations
49  enum Orientation{BW=0,FW=1};
50 
51  /// Offset to move \c BW or \c FW
52  constexpr int moveOffset[2]=
53  {-1,+1};
54 
55  /// List of flags
56  enum class GridFlag{HASHED, ///< Hash data
57  SHIFTED_BC, ///< Implements shifted bounday conditions
58  ALWAYS_WRAPPING}; ///< Force wrapping
59 
60  /// Default parameters for grid
61  constexpr int GRID_DEFAULT_FLAGS=
62  combineFlags<GridFlag::HASHED>;
63 
64  /////////////////////////////////////////////////////////////////
65 
66  /// Hashable properties of a \c Grid
67  ///
68  /// Forward implementation
69  template <typename T, // External type inheriting from
70  int NDims, // Number of dimensions
71  typename Coord, // Type of coordinate values
72  typename Idx, // Type of index of points
73  bool Hashing> // Store or not tables
74  class GridHashable;
75 
76  /// Hashable properties of a \c Grid
77  ///
78  /// Hashing version
79  template <typename T, // External type inheriting from
80  int NDims, // Number of dimensions
81  typename Coord, // Type of coordinate values
82  typename Idx> // Type of index of points
83  class GridHashable<T,
84  NDims,
85  Coord,
86  Idx,
87  true>
88  {
89 
91 
92  private:
93 
94  /// Hashed coords of all points
95  std::vector<Coords> coordsOfPointsHashTable;
96 
97  /// Hashed neighbors
98  std::vector<Neigh> neighsOfPointsHashTable;
99 
100  /// Fills the required hashtable with the function
101  template <typename Tb, // Type of the hashtable
102  typename F> // Type of the function
103  void fillVolumeHashTable(Tb& tb, ///< Hashtable to fill
104  F f) ///< function to call
105  {
106  /// Proxy volume
107  const Idx volume=
108  CRTP_THIS.volume();
109 
110  // Check hashability
111  const auto& maxHashability=
112  tb.max_size();
113  if(static_cast<decltype(maxHashability)>(volume)>maxHashability)
114  CRASH<<"Cannot hash a volume of "<<volume<<", max allowed: "<<(int)maxHashability;
115 
116  // Resize the hash table
117  tb.resize(volume);
118 
119  // Fill the table
120  CRTP_THIS.forAllPoints([&](Idx i)
121  {
122  tb[i]=
123  f(i);
124  });
125  }
126 
127  /// Set the hash table of coordinates of all points
129  {
130  fillVolumeHashTable(coordsOfPointsHashTable,
131  [&](Idx i)
132  {
133  return
134  CRTP_THIS.computeCoordsOfPoint(i);
135  });
136  }
137 
138  /// Set the hash table of neighbors
140  {
141  fillVolumeHashTable(neighsOfPointsHashTable,
142  [&](Idx i)
143  {
144  /// Neighbors to store
145  Neigh out;
146 
147  // Loop on all oriented direction
148  CRTP_THIS.forAllOriDirs([&](int oriDir)
149  {
150  out[oriDir]=
151  CRTP_THIS.computeNeighOfPoint(i,oriDir);
152  });
153 
154  return out;
155  });
156  }
157 
158  public:
159 
161 
162  /// Fill all the HashTables
164  {
167  }
168 
169  /////////////////////////////////////////////////////////////////
170 
171  /// Get the coords of given point
172  const Coords& coordsOfPoint(Idx i) const
173  {
174  CRTP_THIS.assertPointIsInRange(i);
175 
176  return
177  coordsOfPointsHashTable[i];
178  }
179 
180  /// Return the neighbor in the given oriented dir
181  Idx neighOfPoint(const Idx i,
182  const int oriDir)
183  const
184  {
185  CRTP_THIS.assertPointIsInRange(i);
186  CRTP_THIS.assertOriDirIsInRange(oriDir);
187 
188  return
189  neighsOfPointsHashTable[i][oriDir];
190  }
191 
192  /// Tag asserting that hashing
193  static constexpr char hashingTag[]=
194  "Hashing";
195 
196  };
197 
198  /// Hashable properties of a \c Grid
199  ///
200  /// Not hashing version
201  template <typename T, // External type inheriting from
202  int NDims, // Number of dimensions
203  typename Coord, // Type of coordinate values
204  typename Idx> // Type of index of points
205  class GridHashable<T,
206  NDims,
207  Coord,
208  Idx,
209  false>
210  {
211 
213 
214  public:
215 
217 
218  /// Get the coords of given point, computing it
220  const
221  {
222  return
223  CRTP_THIS.computeCoordsOfPoint(i);
224  }
225 
226  /// Return the neighbor in the given oriented dir, computing it
227  Idx neighOfPoint(const Idx i,
228  const int oriDir)
229  const
230  {
231  return
232  CRTP_THIS.computeNeighOfPoint(i,oriDir);
233  }
234 
235  /// Fill all the HashTables (dummy version)
237  const
238  {
239  }
240 
241  /// Tag asserting not hashing
242  static constexpr char hashingTag[]=
243  "Not Hashing";
244  };
245 
246  /////////////////////////////////////////////////////////////////
247 
248  /// Shifted boundary condition feature
249  ///
250  /// Forward declaration
251  template <typename T, // External type inheriting from
252  int NDims, // Number of dimensions
253  typename Coord, // Type of coordinate values
254  typename Idx, // Type of index of points
255  bool Shifting> // Flag to choose if shifting is supported or not
256  class GridShiftableBC;
257 
258  /// Shifted boundary condition feature
259  ///
260  /// Version supporting shift
261  template <typename T, // External type inheriting from
262  int NDims, // Number of dimensions
263  typename Coord, // Type of coordinate values
264  typename Idx> // Type of index of points
265  class GridShiftableBC<T,
266  NDims,
267  Coord,
268  Idx,
269  true>
270  {
271 
273 
274  /// Direction identifying the face which is shifted
275  int _shiftedFace{0};
276 
277  /// Matrix storing the shift induced on each direction
278  Coords _shiftOfBC{0};
279 
280  public:
281 
283 
284  /// Set shift for boundary
285  void setShiftBC(const int dir, ///< Direction
286  const Coords& shift) ///< Amount to shift
287  {
288  // Check null shift at face dir
289  if(_shiftOfBC[dir]!=0)
290  CRASH<<"Shift of shiftedFace "<<dir<<"must be zero, it is"<<_shiftOfBC[dir];
291 
292  // Set shifted face
293  _shiftedFace=
294  dir;
295 
296  // Set shift at BC
297  CRTP_THIS.forAllDims([&](int mu)
298  {
299  _shiftOfBC[mu]=
300  safeModulo(shift[mu],CRTP_THIS.side(mu));
301  });
302 
303  /// Trigger hashtables rebuild
304  CRTP_THIS.fillHashTables();
305  }
306 
307  /// Gets the shifting face
308  int shiftedFace() const
309  {
310  return _shiftedFace;
311  }
312 
313  /// Gets the shifting of the given direction
314  Coord shiftOfBC(int mu) const
315  {
316  return _shiftOfBC[mu];
317  }
318 
319  /// Returns the shifted coord due to boundary passing
320  Coord getShiftedCoordPerpToMove(const Coords& in, ///< Input coords
321  const int ori, ///< Orientation
322  const int moveDir, ///< Face of move
323  const int perpDir, ///< Direction perpendicular to move
324  const Coord nBCpassed) ///< Number of BC passed (positive number)
325  const
326  {
327  if(shiftedFace()==moveDir)
328  {
329  /// Offset for the shift due to BC
330  const Coord muOffset=
331  this->shiftOfBC(perpDir)*moveOffset[ori]*nBCpassed;
332 
333  /// Raw destination
334  const Coord rawMuDest=
335  in[perpDir]+muOffset;
336 
337  /// Returned value
338  const Coord out=
339  safeModulo(rawMuDest,CRTP_THIS.side(perpDir));
340 
341  return out;
342  }
343  else
344  return
345  in[perpDir];
346  }
347  };
348 
349  /// Shifted boundary condition feature
350  ///
351  /// Version not supporting shift
352  template <typename T, // External type inheriting from
353  int NDims, // Number of dimensions
354  typename Coord, // Type of coordinate values
355  typename Idx> // Type of index of points
356  class GridShiftableBC<T,
357  NDims,
358  Coord,
359  Idx,
360  false>
361  {
363 
364  public:
365 
366  /// Gets the shifting face
367  constexpr int shiftedFace()
368  const
369  {
370  return NOT_PRESENT;
371  }
372 
373  /// Gets the shifting of the given direction
374  constexpr int shiftOfBC(int mu)
375  const
376  {
377  return
378  0;
379  }
380 
381  /// Returns the shifted coord due to boundary passing
382  ///
383  /// Dummy version
384  Coord getShiftedCoordPerpToMove(const Coords& in, ///< Input coords
385  const int ori, ///< Orientation
386  const int moveDir, ///< Face of move
387  const int perpDir, ///< Direction perpendicular to move
388  const Coord nBCpassed) ///< Number of BC passed (positive number)
389  const
390  {
391  return in[perpDir];
392  }
393  };
394 
395  /////////////////////////////////////////////////////////////////
396 
397  /// A grid of points spanning an hypercubic grid
398  template <int NDims=4, // Number of dimensions
399  typename Coord=int32_t, // Type of coordinate values
400  typename Idx=int64_t, // Type of index of points
401  int Flags=GRID_DEFAULT_FLAGS> // Flags
402  class Grid :
404  NDims,
405  Coord,
406  Idx,
409  NDims,
410  Coord,
411  Idx,
412  getFlag<Flags,GridFlag::SHIFTED_BC>>
413  {
414  public:
415 
417 
418  private:
419 
420  /// Side of the grid
421  Sides _sides;
422 
423  /// Volume of the grid
424  Idx _volume;
425 
426  /// Set the volume, calling computing routine
427  void setVolume()
428  {
429  /// Output volume, initially 1
430  _volume=
431  1;
432 
433  // Loop on all dimension, taking product
434  forAllDims([&](int mu)
435  {
436  _volume*=
437  side(mu);
438  });
439  }
440 
441  public:
442 
443  /// Flags of the class
444  static constexpr int flags=
445  Flags;
446 
447  /// Extract the flag determining whether is hashing
448  static constexpr bool isHashing=
449  getFlag<flags,GridFlag::HASHED>;
450 
451  /// Extract the flag determining whether BC might be shifted
452  static constexpr bool isShiftingBC=
453  getFlag<flags,GridFlag::SHIFTED_BC>;
454 
455  /// Number of dimensions
456  static constexpr int nDims=
457  NDims;
458 
459  /// Number of oriented directions
460  static constexpr int nOriDirs=
461  2*NDims;
462 
463  /// Get the volume
464  const Idx& volume()
465  const
466  {
467  return
468  _volume;
469  }
470 
471  /// Get the given side
472  Side side(const int mu)
473  const
474  {
475  return
476  _sides[mu];
477  }
478 
479  /// Get all sides
480  Sides sides()
481  const
482  {
483  return
484  _sides;
485  }
486 
487  /// Check that a given point is in range
488  void assertPointIsInRange(const Idx& i)
489  const
490  {
491  if constexpr(GRID_DEBUG)
492  if(i<0 or i>=volume())
493  CRASH<<"Cannot access to element "<<i;
494  }
495 
496  /// Check that a given oriented dir is in range
497  void assertOriDirIsInRange(const int& oriDir)
498  const
499  {
500  if constexpr(GRID_DEBUG)
501  if(oriDir<0 or oriDir>=2*NDims)
502  CRASH<<"Cannot use oriented dir "<<oriDir<<"out of range [0,"<<2*NDims<<"]";
503  }
504 
505  /// Check that a given set of coords are in range
506  void assertCoordsAreInRange(const Coords& cs)
507  const
508  {
509  if constexpr(GRID_DEBUG)
510  forAllDims([&](int mu)
511  {
512  /// Maximal value
513  const Side& m=
514  side(mu);
515 
516  /// Coord mu value
517  const Coord& c=
518  cs[mu];
519 
520  if(c<0 or c>=m)
521  CRASH<<"Cannot have dimension "<<mu<<" equal to "<<c<<", negative or larger than "<<m;
522  });
523  }
524 
525  /// Loop on all dimension calling the passed function
526  template <typename F> // Type of the function
527  static void forAllDims(F&& f) ///< Function to be called
528  {
529  for(int mu=0;mu<nDims;mu++)
530  f(mu);
531  }
532 
533  /// Loop on all oriented directions calling the passed function
534  template <typename F> // Type of the function
535  static void forAllOriDirs(F&& f) ///< Function to be called
536  {
537  for(int oriDir=0;oriDir<nOriDirs;oriDir++)
538  f(oriDir);
539  }
540 
541  /// Loop on all points calling the passed function
542  template <typename F> // Type of the function
543  void forAllPoints(F&& f) ///< Function to be called
544  const
545  {
546 
547  for(Idx i=0;i<volume();i++)
548  f(i);
549  }
550 
551  /// Orientation of an oriented directions
552  static Orientation oriOfOriDir(const int oriDir)
553  {
554  /// Output orientation
555  Orientation out;
556 
557  // Check smallest bit
558  if(bitOf(oriDir,0))
559  out=
560  FW;
561  else
562  out=
563  BW;
564 
565  return
566  out;
567  }
568 
569  /// Dimension of an oriented directions
570  int dimOfOriDir(const int oriDir) const
571  {
572  // Divide by two
573  return
574  oriDir>>1;
575  }
576 
577  /// Oriented direction given orientation and dimension
578  int oriDirOfOriAndDim(const Orientation ori,const int dim) const
579  {
580  return ori+dim*2;
581  }
582 
583  /// Set the sides and trigger the volume change
584  void setSides(const Sides& extSides)
585  {
586  _sides=
587  extSides;
588 
589  setVolume();
590 
591  if constexpr(isHashing)
592  this->fillHashTables();
593  }
594 
595  /// Compte the coordinate of point i
596  Coords computeCoordsOfPoint(Idx i) const
597  {
598  assertPointIsInRange(i);
599 
600  /// Result
601  Coords c;
602 
603  for(int mu=nDims-1;mu>=0;mu--)
604  {
605  /// Dividend, corresponding to the \c mu side length
606  const Side& d=
607  side(mu);
608 
609  /// Quozient, corresponding to the index of the remaining \c nDims-1 components
610  const Idx q=i/d;
611 
612  /// Remainder, corresponding to the coordinate
613  const Coord r=i-d*q;
614 
615  // Store the component
616  c[mu]=r;
617 
618  // Iterate on the remaining nDims-1 components
619  i=q;
620  }
621 
622  return
623  c;
624  }
625 
626  /// Compute the point of given coords
627  Idx pointOfCoords(const Coords& cs) const ///< Coordinates of the point
628  {
629  assertCoordsAreInRange(cs);
630 
631  /// Returned point
632  Idx out=
633  0;
634 
635  forAllDims([&](int mu)
636  {
637  /// Grid side
638  const Side& s=
639  side(mu);
640 
641  // Increment the coordinate
642  out=
643  out*s+cs[mu];
644  });
645 
646  return
647  out;
648  }
649 
650  /// Returns the coordinates shifted in the asked direction
651  ///
652  /// Periodic boundary conditions are always assumed
653  Coords shiftedCoords(const Coords& in, ///< Input coordinates
654  const int oriDir, ///< Oriented direction
655  const Coord amount=1) ///< Number of steps
656  const
657  {
658  /// Returned coordinates
659  Coords out;
660 
661  /// Orientation
662  const int ori=
663  oriOfOriDir(oriDir);
664 
665  /// Direction to shift
666  const int moveDir=
667  dimOfOriDir(oriDir);
668 
669  /// Offset to add
670  const Coord offset=
671  moveOffset[ori]*amount;
672 
673  /// Destintion not considering wrap
674  const Coord rawDest=
675  in[moveDir]+offset;
676 
677  /// Actual destintion
678  const Coord dest=
679  safeModulo(rawDest,side(moveDir));
680 
681  /// Absolute number of boundaries passed
682  const Coord nBCpassed=
683  ((rawDest<0)?(-rawDest+side(moveDir)):rawDest)/side(moveDir);
684 
685  forAllDims([&](int mu)
686  {
687  if(mu!=moveDir)
688  out[mu]=
689  this->getShiftedCoordPerpToMove(in,ori,moveDir,mu,nBCpassed);
690  else
691  out[mu]=
692  dest;
693  });
694 
695  return
696  out;
697  }
698 
699  /// Compute the neighbor in the oriented direction oriDir of point i
700  Idx computeNeighOfPoint(const Idx i, ///< Point
701  const int oriDir) ///< Oriented direction
702  const
703  {
704  assertPointIsInRange(i);
705  assertOriDirIsInRange(oriDir);
706 
707  return
708  pointOfCoords(shiftedCoords(this->coordsOfPoint(i),oriDir));
709  }
710 
711  /// Construct from sides
712  Grid(const Sides& sides={})
713  {
714  setSides(sides);
715  }
716 
717  };
718 
719  /// Deduction guide for bracket list
720  template <int NDims,
721  typename Side>
722  Grid(const Side(&sides)[NDims])
723  -> Grid<NDims,int>;
724 }
725 
726 #undef PROVIDE_COORDS
727 
728 #endif
Idx neighOfPoint(const Idx i, const int oriDir) const
Return the neighbor in the given oriented dir, computing it.
Definition: Grid.hpp:227
Orientation
Value to identifiy orientations.
Definition: Grid.hpp:49
#define CRTP_THIS
Access to the inheriting class.
Definition: CRTP.hpp:32
void fillHashTables() const
Fill all the HashTables (dummy version)
Definition: Grid.hpp:236
int shiftedFace() const
Gets the shifting face.
Definition: Grid.hpp:308
#define CRASH
Initialize the crasher.
Definition: Crash.hpp:13
void fillVolumeHashTable(Tb &tb, F f)
Fills the required hashtable with the function.
Definition: Grid.hpp:103
#define PROVIDE_CRTP_CAST_OPERATOR(CLASS)
Definition: CRTP.hpp:16
void setShiftBC(const int dir, const Coords &shift)
Set shift for boundary.
Definition: Grid.hpp:285
GridFlag
List of flags.
Definition: Grid.hpp:56
Coords coordsOfPoint(Idx i) const
Get the coords of given point, computing it.
Definition: Grid.hpp:219
void fillCoordsOfPointsHashTables()
Set the hash table of coordinates of all points.
Definition: Grid.hpp:128
void fillHashTables()
Fill all the HashTables.
Definition: Grid.hpp:163
#define PROVIDE_COORDS_TYPES
Provide the type needed to deal with grids.
Definition: Grid.hpp:30
Coord getShiftedCoordPerpToMove(const Coords &in, const int ori, const int moveDir, const int perpDir, const Coord nBCpassed) const
Returns the shifted coord due to boundary passing.
Definition: Grid.hpp:320
Idx neighOfPoint(const Idx i, const int oriDir) const
Return the neighbor in the given oriented dir.
Definition: Grid.hpp:181
const Coords & coordsOfPoint(Idx i) const
Get the coords of given point.
Definition: Grid.hpp:172
std::vector< Coords > coordsOfPointsHashTable
Hashed coords of all points.
Definition: Grid.hpp:95
Coord shiftOfBC(int mu) const
Gets the shifting of the given direction.
Definition: Grid.hpp:314
void fillNeighsOfPointsHashTables()
Set the hash table of neighbors.
Definition: Grid.hpp:139
A grid of points spanning an hypercubic grid.
Definition: Grid.hpp:402
std::vector< Neigh > neighsOfPointsHashTable
Hashed neighbors.
Definition: Grid.hpp:98
#define GRID_DEBUG
Flag to enable Grid debug.
Definition: Grid.hpp:43