ThunderEgg  1.0.0
Face.h
Go to the documentation of this file.
1 /***************************************************************************
2  * ThunderEgg, a library for solvers on adaptively refined block-structured
3  * Cartesian grids.
4  *
5  * Copyright (c) 2021 Scott Aiton
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  ***************************************************************************/
20 
21 #ifndef THUNDEREGG_FACE_H
22 #define THUNDEREGG_FACE_H
23 
29 #include <ThunderEgg/tpl/json.hpp>
30 #include <array>
31 namespace ThunderEgg {
40 template<int D, int M>
41 class Face
42 {
43 private:
47  unsigned char value = number_of;
48 
52  static constexpr size_t twopow(size_t N) { return 0b1 << N; }
53 
57  static constexpr size_t factorial(size_t N) { return N == 0 ? 1 : N * factorial(N - 1); }
58 
62  static constexpr size_t choose(size_t N, size_t K)
63  {
64  return factorial(N) / (factorial(K) * factorial(N - K));
65  }
66 
67  static constexpr size_t sum(int N)
68  {
69  return N == -1 ? 0 : (twopow(D - N) * choose(D, N) + sum(N - 1));
70  }
71 
72 public:
73  static constexpr int dimensionality = M;
77  static constexpr size_t number_of = twopow(D - M) * choose(D, M);
78 
79  static constexpr size_t sum_of_faces = M <= 0 ? 0 : sum(M - 1);
85  explicit Face(unsigned char value)
86  : value(value)
87  {
88  static_assert(D <= 3 && D >= 0, "Only up to 3 dimensions supported");
89  static_assert(M >= 0 && M < D, "Invalid M value");
90  }
91 
95  Face()
96  {
97  static_assert(D <= 3 && D >= 0, "Only up to 3 dimensions supported");
98  static_assert(M >= 0 && M < D, "Invalid M value");
99  }
100 
106  static Face<D, M> null() { return Face<D, M>(number_of); }
107 
108  /*
109  * these can be cleaned up when version is bumped to c++20
110  */
111 
115  template<int N = 0>
116  static auto west() -> typename std::enable_if<D <= 3 && M == D - 1 && N == N, Face<D, M>>::type
117  {
118  return Face<D, M>(0b000);
119  }
123  template<int N = 0>
124  static auto east() -> typename std::enable_if<D <= 3 && M == D - 1 && N == N, Face<D, M>>::type
125  {
126  return Face<D, M>(0b001);
127  }
131  template<int N = 0>
132  static auto south() ->
133  typename std::enable_if<D <= 3 && D >= 2 && M == D - 1 && N == N, Face<D, M>>::type
134  {
135  return Face<D, M>(0b010);
136  }
140  template<int N = 0>
141  static auto north() ->
142  typename std::enable_if<D <= 3 && D >= 2 && M == D - 1 && N == N, Face<D, M>>::type
143  {
144  return Face<D, M>(0b011);
145  }
149  template<int N = 0>
150  static auto bottom() ->
151  typename std::enable_if<D <= 3 && D >= 3 && M == D - 1 && N == N, Face<D, M>>::type
152  {
153  return Face<D, M>(0b100);
154  }
158  template<int N = 0>
159  static auto top() ->
160  typename std::enable_if<D <= 3 && D >= 3 && M == D - 1 && N == N, Face<D, M>>::type
161  {
162  return Face<D, M>(0b101);
163  }
164 
168  template<int N = 0>
169  static auto sw() -> typename std::enable_if<D == 2 && M == 0 && N == N, Face<D, M>>::type
170  {
171  return Face<D, M>(0b00);
172  }
176  template<int N = 0>
177  static auto se() -> typename std::enable_if<D == 2 && M == 0 && N == N, Face<D, M>>::type
178  {
179  return Face<D, M>(0b01);
180  }
184  template<int N = 0>
185  static auto nw() -> typename std::enable_if<D == 2 && M == 0 && N == N, Face<D, M>>::type
186  {
187  return Face<D, M>(0b10);
188  }
192  template<int N = 0>
193  static auto ne() -> typename std::enable_if<D == 2 && M == 0 && N == N, Face<D, M>>::type
194  {
195  return Face<D, M>(0b11);
196  }
197 
201  template<int N = 0>
202  static auto bsw() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
203  {
204  return Face<D, M>(0b000);
205  }
209  template<int N = 0>
210  static auto bse() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
211  {
212  return Face<D, M>(0b001);
213  }
217  template<int N = 0>
218  static auto bnw() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
219  {
220  return Face<D, M>(0b010);
221  }
225  template<int N = 0>
226  static auto bne() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
227  {
228  return Face<D, M>(0b011);
229  }
233  template<int N = 0>
234  static auto tsw() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
235  {
236  return Face<D, M>(0b100);
237  }
241  template<int N = 0>
242  static auto tse() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
243  {
244  return Face<D, M>(0b101);
245  }
249  template<int N = 0>
250  static auto tnw() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
251  {
252  return Face<D, M>(0b110);
253  }
257  template<int N = 0>
258  static auto tne() -> typename std::enable_if<D == 3 && M == 0 && N == N, Face<D, M>>::type
259  {
260  return Face<D, M>(0b111);
261  }
262 
266  template<int N = 0>
267  static auto bs() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
268  {
269  return Face<D, M>(0b0000);
270  }
274  template<int N = 0>
275  static auto bn() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
276  {
277  return Face<D, M>(0b0001);
278  }
282  template<int N = 0>
283  static auto ts() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
284  {
285  return Face<D, M>(0b0010);
286  }
290  template<int N = 0>
291  static auto tn() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
292  {
293  return Face<D, M>(0b0011);
294  }
298  template<int N = 0>
299  static auto bw() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
300  {
301  return Face<D, M>(0b0100);
302  }
306  template<int N = 0>
307  static auto be() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
308  {
309  return Face<D, M>(0b0101);
310  }
314  template<int N = 0>
315  static auto tw() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
316  {
317  return Face<D, M>(0b0110);
318  }
322  template<int N = 0>
323  static auto te() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
324  {
325  return Face<D, M>(0b0111);
326  }
330  template<int N = 0>
331  static auto sw() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
332  {
333  return Face<D, M>(0b1000);
334  }
338  template<int N = 0>
339  static auto se() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
340  {
341  return Face<D, M>(0b1001);
342  }
346  template<int N = 0>
347  static auto nw() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
348  {
349  return Face<D, M>(0b1010);
350  }
354  template<int N = 0>
355  static auto ne() -> typename std::enable_if<D == 3 && M == 1 && N == N, Face<D, M>>::type
356  {
357  return Face<D, M>(0b1011);
358  }
359 
365  class Range
366  {
367  public:
371  class Iterator : public std::input_iterator_tag
372  {
373  private:
377  Face<D, M> s;
378 
379  public:
385  explicit Iterator(Face<D, M> s)
386  : s(s)
387  {}
394  {
395  ++s.value;
396  return s;
397  }
403  const Face<D, M>& operator*() const { return s; }
409  const Face<D, M>* operator->() const { return &s; }
417  bool operator==(const Iterator& b) const { return s.value == b.s.value; }
425  bool operator!=(const Iterator& b) const { return s.value != b.s.value; }
426  };
432  Iterator begin() { return Iterator(Face<D, M>(0)); }
438  Iterator end() { return Iterator(null()); }
439  };
445  static Range getValues() { return Range(); }
446 
452  size_t getIndex() const { return value; }
453 
457  template<int N = 0>
458  auto getAxisIndex() const ->
459  typename std::enable_if<D <= 3 && D >= 1 && M == D - 1 && N == N, size_t>::type
460  {
461  return value >> 1;
462  }
463 
467  template<int N = 0>
468  auto isLowerOnAxis() const ->
469  typename std::enable_if<D <= 3 && D >= 1 && M == D - 1 && N == N, bool>::type
470  {
471  return !(value & 0b1);
472  }
473 
477  template<int N = 0>
478  auto isHigherOnAxis() const ->
479  typename std::enable_if<D <= 3 && D >= 1 && M == D - 1 && N == N, bool>::type
480  {
481  return value & 0b1;
482  }
483 
489  Face<D, M> opposite() const { return Face<D, M>(value ^ ~((~0u) << (D - M))); }
490 
496  std::array<Face<D, D - 1>, D - M> getSides() const
497  {
498  std::array<Face<D, D - 1>, D - M> sides;
499  if constexpr (D > 1 && M == 0) {
500  for (size_t i = 0; i < D; i++) {
501  size_t side = 2 * i;
502  if ((1 << i) & value) {
503  side |= 1;
504  }
505  sides[i] = Face<D, D - 1>(side);
506  }
507  } else if constexpr (D == 3 && M == 1) {
508  size_t not_axis = value >> 2;
509  size_t curr_index = 0;
510  for (unsigned char i = 0; i < D; i++) {
511  if (i != not_axis) {
512  unsigned char bit = (value & (0b1 << curr_index)) >> curr_index;
513  sides[curr_index] = Face<D, D - 1>((i << 1) ^ bit);
514  curr_index++;
515  }
516  }
517  } else {
518  sides[0] = Face<D, D - 1>(value);
519  }
520  return sides;
521  }
522 
530  bool operator<(const Face<D, M>& other) const { return value < other.value; }
531 
539  bool operator==(const Face<D, M>& other) const { return value == other.value; }
540 
548  bool operator!=(const Face<D, M>& other) const { return value != other.value; }
549 };
550 
556 template<int D>
557 using Side = Face<D, D - 1>;
565 template<int D>
566 Side<D>
567 HigherSideOnAxis(size_t axis)
568 {
569  return Side<D>((axis << 1) + 1);
570 }
578 template<int D>
579 Side<D>
580 LowerSideOnAxis(size_t axis)
581 {
582  return Side<D>(axis << 1);
583 }
584 void
585 to_json(tpl::nlohmann::json& j, const Side<1>& s);
586 void
587 to_json(tpl::nlohmann::json& j, const Side<2>& s);
588 void
589 to_json(tpl::nlohmann::json& j, const Side<3>& s);
590 void
591 from_json(const tpl::nlohmann::json& j, Side<1>& s);
592 void
593 from_json(const tpl::nlohmann::json& j, Side<2>& s);
594 void
595 from_json(const tpl::nlohmann::json& j, Side<3>& s);
606 std::ostream&
607 operator<<(std::ostream& os, const Side<1>& s);
618 std::ostream&
619 operator<<(std::ostream& os, const Side<2>& s);
630 std::ostream&
631 operator<<(std::ostream& os, const Side<3>& s);
632 
636 using Edge = Face<3, 1>;
647 std::ostream&
648 operator<<(std::ostream& os, const Edge& o);
649 void
650 to_json(tpl::nlohmann::json& j, const Edge& o);
651 void
652 from_json(const tpl::nlohmann::json& j, Edge& o);
653 
659 template<int D>
671 std::ostream&
672 operator<<(std::ostream& os, const Corner<2>& o);
683 std::ostream&
684 operator<<(std::ostream& os, const Corner<3>& o);
685 void
686 to_json(tpl::nlohmann::json& j, const Corner<2>& o);
687 void
688 to_json(tpl::nlohmann::json& j, const Corner<3>& o);
689 void
690 from_json(const tpl::nlohmann::json& j, Corner<2>& o);
691 void
692 from_json(const tpl::nlohmann::json& j, Corner<3>& o);
693 } // namespace ThunderEgg
694 #endif
ThunderEgg::Face::operator==
bool operator==(const Face< D, M > &other) const
Equals operator.
Definition: Face.h:539
ThunderEgg::Face::north
static auto north() -> typename std::enable_if< D<=3 &&D >=2 &&M==D - 1 &&N==N, Face< D, M >>::type
north side
Definition: Face.h:141
ThunderEgg::Face::getAxisIndex
auto getAxisIndex() const -> typename std::enable_if< D<=3 &&D >=1 &&M==D - 1 &&N==N, size_t >::type
Get the axis index of this side.
Definition: Face.h:458
ThunderEgg::Face::bsw
static auto bsw() -> typename std::enable_if< D==3 &&M==0 &&N
bottom-south-west corner
ThunderEgg::Face::Face
Face()
Construct a new Face object with a null value.
Definition: Face.h:95
ThunderEgg::HigherSideOnAxis
Side< D > HigherSideOnAxis(size_t axis)
Get the higher side on a given axis.
Definition: Face.h:567
ThunderEgg::Face::operator<
bool operator<(const Face< D, M > &other) const
Compare the enum indexes.
Definition: Face.h:530
ThunderEgg::Face::Range
Range class for Face.
Definition: Face.h:365
ThunderEgg::Face::east
static auto east() -> typename std::enable_if< D<=3 &&M==D - 1 &&N==N, Face< D, M >>::type
east side
Definition: Face.h:124
ThunderEgg::Face::bnw
static auto bnw() -> typename std::enable_if< D==3 &&M==0 &&N
bottom-north-west corner
ThunderEgg::Face::top
static auto top() -> typename std::enable_if< D<=3 &&D >=3 &&M==D - 1 &&N==N, Face< D, M >>::type
top side
Definition: Face.h:159
ThunderEgg::Face::isHigherOnAxis
auto isHigherOnAxis() const -> typename std::enable_if< D<=3 &&D >=1 &&M==D - 1 &&N==N, bool >::type
Return if this side is higher on it's axis.
Definition: Face.h:478
ThunderEgg::Face::te
static auto te() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
top-east edge
Definition: Face.h:323
ThunderEgg::Face::bw
static auto bw() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
bottom-west edge
Definition: Face.h:299
ThunderEgg::Face::sw
static auto sw() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
south-west edge
Definition: Face.h:331
ThunderEgg::Face::ts
static auto ts() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
top-south edge
Definition: Face.h:283
ThunderEgg::Face::ne
static auto ne() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
north-east edge
Definition: Face.h:355
ThunderEgg::Face::tw
static auto tw() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
top-west edge
Definition: Face.h:315
ThunderEgg::Face::isLowerOnAxis
auto isLowerOnAxis() const -> typename std::enable_if< D<=3 &&D >=1 &&M==D - 1 &&N==N, bool >::type
Return if this side is lower on it's axis.
Definition: Face.h:468
ThunderEgg::Face::Range::Iterator
Input iterator for Side values.
Definition: Face.h:371
ThunderEgg::Face::west
static auto west() -> typename std::enable_if< D<=3 &&M==D - 1 &&N==N, Face< D, M >>::type
west side
Definition: Face.h:116
ThunderEgg::LowerSideOnAxis
Side< D > LowerSideOnAxis(size_t axis)
Get the lower side on a given axis.
Definition: Face.h:580
ThunderEgg::Face::tnw
static auto tnw() -> typename std::enable_if< D==3 &&M==0 &&N
top-north-west corner
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::Face::Range::Iterator::operator++
const Face< D, M > & operator++()
Increment the side value.
Definition: Face.h:393
ThunderEgg::Face::getIndex
size_t getIndex() const
Get the index for this Face.
Definition: Face.h:452
ThunderEgg::Face::Range::begin
Iterator begin()
Returns an iterator with the lowest Side value.
Definition: Face.h:432
ThunderEgg::Face::Range::Iterator::operator->
const Face< D, M > * operator->() const
Get a pointer to the side object.
Definition: Face.h:409
ThunderEgg::Face::Face
Face(unsigned char value)
Construct a new Face object.
Definition: Face.h:85
ThunderEgg::Face::tse
static auto tse() -> typename std::enable_if< D==3 &&M==0 &&N
top-south-east corner
ThunderEgg::Face::number_of
static constexpr size_t number_of
the number of faces
Definition: Face.h:77
ThunderEgg::Face::Range::Iterator::operator==
bool operator==(const Iterator &b) const
Check the iterators reference the same value.
Definition: Face.h:417
ThunderEgg::Face::getSides
std::array< Face< D, D - 1 >, D - M > getSides() const
Get the Sides that this Face lies on.
Definition: Face.h:496
ThunderEgg::Face::se
static auto se() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
south-east edge
Definition: Face.h:339
ThunderEgg::Face::Range::Iterator::operator!=
bool operator!=(const Iterator &b) const
Check the iterators don't reference the same value.
Definition: Face.h:425
ThunderEgg::Face::bn
static auto bn() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
bottom-north edge
Definition: Face.h:275
ThunderEgg::Face::nw
static auto nw() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
north-west edge
Definition: Face.h:347
ThunderEgg::Face::bs
static auto bs() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
bottom-south edge
Definition: Face.h:267
ThunderEgg::Face::bne
static auto bne() -> typename std::enable_if< D==3 &&M==0 &&N
bottom-north-east corner
ThunderEgg::Face::tsw
static auto tsw() -> typename std::enable_if< D==3 &&M==0 &&N
top-south-west corner
ThunderEgg::Face::bottom
static auto bottom() -> typename std::enable_if< D<=3 &&D >=3 &&M==D - 1 &&N==N, Face< D, M >>::type
bottom side
Definition: Face.h:150
ThunderEgg::Face::Range::end
Iterator end()
Returns an iterator with Edge<D,M>::null()
Definition: Face.h:438
ThunderEgg::Face::south
static auto south() -> typename std::enable_if< D<=3 &&D >=2 &&M==D - 1 &&N==N, Face< D, M >>::type
south side
Definition: Face.h:132
ThunderEgg::operator<<
std::ostream & operator<<(std::ostream &os, const Side< 1 > &s)
ostream operator that prints a string representation of side enum.
ThunderEgg::Face::Range::Iterator::Iterator
Iterator(Face< D, M > s)
Construct a new Iterator object with the given Side value.
Definition: Face.h:385
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
ThunderEgg::Face::Range::Iterator::operator*
const Face< D, M > & operator*() const
Get a reference to the side object.
Definition: Face.h:403
ThunderEgg::Face::tne
static auto tne() -> typename std::enable_if< D==3 &&M==0 &&N
top-north-east corner
ThunderEgg::Face::bse
static auto bse() -> typename std::enable_if< D==3 &&M==0 &&N
bottom-south-east corner
ThunderEgg::Face::opposite
Face< D, M > opposite() const
Get the face on the opposite side of the hypercube.
Definition: Face.h:489
ThunderEgg::Face::be
static auto be() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
bottom-east edge
Definition: Face.h:307
ThunderEgg::Face::getValues
static Range getValues()
Get a range of values that can be iterated over.
Definition: Face.h:445
ThunderEgg::Face::operator!=
bool operator!=(const Face< D, M > &other) const
Not Equals operator.
Definition: Face.h:548
ThunderEgg::Face::tn
static auto tn() -> typename std::enable_if< D==3 &&M==1 &&N==N, Face< D, M >>::type
top-north edge
Definition: Face.h:291