ThunderEgg  1.0.0
Orthant.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) 2020-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_ORTHANT_H
22 #define THUNDEREGG_ORTHANT_H
23 
28 #include <ThunderEgg/Face.h>
29 #include <array>
30 #include <iostream>
31 #include <numeric>
32 #include <vector>
33 namespace ThunderEgg {
42 template<int D>
43 class Orthant
44 {
45 private:
49  unsigned char val = num_orthants;
50 
51 public:
52  static constexpr size_t num_orthants = 1 << D;
58  explicit Orthant(const unsigned char val_in)
59  : val(val_in)
60  {}
64  Orthant() {}
68  static Orthant<D> null() { return Orthant<D>(num_orthants); }
72  static Orthant<1> lower() { return Orthant<1>(0b0); }
76  static Orthant<1> upper() { return Orthant<1>(0b1); }
80  static Orthant<2> sw() { return Orthant<2>(0b00); }
84  static Orthant<2> se() { return Orthant<2>(0b01); }
88  static Orthant<2> nw() { return Orthant<2>(0b10); }
92  static Orthant<2> ne() { return Orthant<2>(0b11); }
96  static Orthant<3> bsw() { return Orthant<3>(0b000); }
100  static Orthant<3> bse() { return Orthant<3>(0b001); }
104  static Orthant<3> bnw() { return Orthant<3>(0b010); }
108  static Orthant<3> bne() { return Orthant<3>(0b011); }
112  static Orthant<3> tsw() { return Orthant<3>(0b100); }
116  static Orthant<3> tse() { return Orthant<3>(0b101); }
120  static Orthant<3> tnw() { return Orthant<3>(0b110); }
124  static Orthant<3> tne() { return Orthant<3>(0b111); }
130  class Range
131  {
132  public:
136  class Iterator : public std::input_iterator_tag
137  {
138  private:
142  Orthant<D> o;
143 
144  public:
150  explicit Iterator(Orthant<D> o_in)
151  : o(o_in)
152  {}
159  {
160  ++o.val;
161  return o;
162  }
168  const Orthant<D>& operator*() const { return o; }
174  const Orthant<D>* operator->() const { return &o; }
182  bool operator==(const Iterator& b) const { return o.val == b.o.val; }
190  bool operator!=(const Iterator& b) const { return o.val != b.o.val; }
191  };
197  Iterator begin() { return Iterator(Orthant<D>(0)); }
203  Iterator end() { return Iterator(null()); }
204  };
210  static Range getValues() { return Range(); }
216  size_t getIndex() const { return val; }
225  {
226  Orthant<D> retval = *this;
227  // flip the bit for that side
228  retval.val ^= (0x1 << s.getAxisIndex());
229  return retval;
230  }
236  std::array<Side<D>, D> getInteriorSides() const
237  {
238  std::array<Side<D>, D> retval;
239  for (size_t i = 0; i < D; i++) {
240  size_t side = 2 * i;
241  if (!((1 << i) & val)) {
242  side |= 1;
243  }
244  retval[i] = Side<D>(side);
245  }
246  return retval;
247  }
253  std::array<Side<D>, D> getExteriorSides() const
254  {
255  std::array<Side<D>, D> retval;
256  for (size_t i = 0; i < D; i++) {
257  size_t side = 2 * i;
258  if ((1 << i) & val) {
259  side |= 1;
260  }
261  retval[i] = Side<D>(side);
262  }
263  return retval;
264  }
272  bool isOnSide(Side<D> s) const
273  {
274  int idx = s.getIndex() / 2;
275  int remainder = s.getIndex() % 2;
276  bool is_bit_set = val & (0x1 << idx);
277  return is_bit_set == remainder;
278  }
279  bool isHigherOnAxis(size_t axis) const { return val & (0b1 << axis); }
280  bool isLowerOnAxis(size_t axis) const { return !(val & (0b1 << axis)); }
288  Orthant<D - 1> collapseOnAxis(size_t axis) const
289  {
290  size_t upper_mask = (~0x0U) << axis;
291  return Orthant<D - 1>(((val >> 1) & upper_mask) | (val & ~upper_mask));
292  }
308  static std::array<Orthant, num_orthants / 2> getValuesOnSide(Side<D> s)
309  {
310  unsigned int bit_to_insert = s.getAxisIndex();
311  unsigned int set_bit = s.isLowerOnAxis() ? 0 : 1;
312  unsigned int lower_mask = ~((~0x0U) << bit_to_insert);
313  unsigned int upper_mask = (~0x0U) << (bit_to_insert + 1);
314 
315  std::array<Orthant<D>, Orthant<D>::num_orthants / 2> retval;
316  for (size_t i = 0; i < Orthant<D>::num_orthants / 2; i++) {
317  size_t value = (i << 1) & upper_mask;
318  value |= i & lower_mask;
319  value |= set_bit << bit_to_insert;
320  retval[i] = Orthant<D>(value);
321  }
322  return retval;
323  }
331  bool operator==(const Orthant<D>& other) const { return val == other.val; }
339  bool operator!=(const Orthant<D>& other) const { return val != other.val; }
347  bool operator<(const Orthant<D>& other) const { return val < other.val; }
348 };
349 
360 inline std::ostream&
361 operator<<(std::ostream& os, const Orthant<0>& o)
362 {
363  if (o == Orthant<0>::null()) {
364  os << "Orthant<0>::null()";
365  } else {
366  os << "Orthant<0> invalid value: " << o.getIndex();
367  }
368  return os;
369 }
380 inline std::ostream&
381 operator<<(std::ostream& os, const Orthant<1>& o)
382 {
383  if (o == Orthant<1>::lower()) {
384  os << "Orthant<1>::lower()";
385  } else if (o == Orthant<1>::upper()) {
386  os << "Orthant<1>::upper()";
387  } else if (o == Orthant<1>::null()) {
388  os << "Orthant<1>::null()";
389  } else {
390  os << "Orthant<1> invalid value: " << o.getIndex();
391  }
392  return os;
393 }
404 inline std::ostream&
405 operator<<(std::ostream& os, const Orthant<2>& o)
406 {
407  if (o == Orthant<2>::sw()) {
408  os << "Orthant<2>::sw()";
409  } else if (o == Orthant<2>::se()) {
410  os << "Orthant<2>::se()";
411  } else if (o == Orthant<2>::nw()) {
412  os << "Orthant<2>::nw()";
413  } else if (o == Orthant<2>::ne()) {
414  os << "Orthant<2>::ne()";
415  } else if (o == Orthant<2>::null()) {
416  os << "Orthant<2>::null()";
417  } else {
418  os << "Orthant<2> invalid value: " << o.getIndex();
419  }
420  return os;
421 }
432 inline std::ostream&
433 operator<<(std::ostream& os, const Orthant<3>& o)
434 {
435  if (o == Orthant<3>::bsw()) {
436  os << "Orthant<3>::bsw()";
437  } else if (o == Orthant<3>::bse()) {
438  os << "Orthant<3>::bse()";
439  } else if (o == Orthant<3>::bnw()) {
440  os << "Orthant<3>::bnw()";
441  } else if (o == Orthant<3>::bne()) {
442  os << "Orthant<3>::bne()";
443  } else if (o == Orthant<3>::tsw()) {
444  os << "Orthant<3>::tsw()";
445  } else if (o == Orthant<3>::tse()) {
446  os << "Orthant<3>::tse()";
447  } else if (o == Orthant<3>::tnw()) {
448  os << "Orthant<3>::tnw()";
449  } else if (o == Orthant<3>::tne()) {
450  os << "Orthant<3>::tne()";
451  } else if (o == Orthant<3>::null()) {
452  os << "Orthant<3>::null()";
453  } else {
454  os << "Orthant<3> invalid value: " << o.getIndex();
455  }
456  return os;
457 }
458 void
459 to_json(tpl::nlohmann::json& j, const Orthant<0>& o);
460 void
461 to_json(tpl::nlohmann::json& j, const Orthant<1>& o);
462 void
463 to_json(tpl::nlohmann::json& j, const Orthant<2>& o);
464 void
465 to_json(tpl::nlohmann::json& j, const Orthant<3>& o);
466 void
467 from_json(const tpl::nlohmann::json& j, Orthant<0>& o);
468 void
469 from_json(const tpl::nlohmann::json& j, Orthant<1>& o);
470 void
471 from_json(const tpl::nlohmann::json& j, Orthant<2>& o);
472 void
473 from_json(const tpl::nlohmann::json& j, Orthant<3>& o);
474 } // namespace ThunderEgg
475 #endif
ThunderEgg::Orthant::ne
static Orthant< 2 > ne()
North-East quadrant of square.
Definition: Orthant.h:92
ThunderEgg::Orthant::getNbrOnSide
Orthant< D > getNbrOnSide(Side< D > s) const
Return the octant that neighbors this octant on a particular side.
Definition: Orthant.h:224
ThunderEgg::Orthant::collapseOnAxis
Orthant< D - 1 > collapseOnAxis(size_t axis) const
From the point of view of an axis, get orthant that this orthant lies on in the D-1 dimension.
Definition: Orthant.h:288
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::Orthant
An enum-style class that represents the octants of a cube.
Definition: Orthant.h:43
ThunderEgg::Orthant::operator<
bool operator<(const Orthant< D > &other) const
Less Tan operator.
Definition: Orthant.h:347
ThunderEgg::Orthant::Orthant
Orthant()
Default constructor that initializes the value to null().
Definition: Orthant.h:64
ThunderEgg::Orthant::bne
static Orthant< 3 > bne()
Bottom-North-East octant of cube.
Definition: Orthant.h:108
ThunderEgg::Orthant::se
static Orthant< 2 > se()
South-East quadrant of square.
Definition: Orthant.h:84
ThunderEgg::Orthant::getIndex
size_t getIndex() const
Get the integer value of the octant.
Definition: Orthant.h:216
Face.h
Face class.
ThunderEgg::Orthant::bnw
static Orthant< 3 > bnw()
Bottom-North-West octant of cube.
Definition: Orthant.h:104
ThunderEgg::Orthant::Range::Iterator::operator!=
bool operator!=(const Iterator &b) const
Check the iterators don't reference the same value.
Definition: Orthant.h:190
ThunderEgg::Orthant::Range::Iterator::operator++
const Orthant< D > & operator++()
Increment the Orthant value.
Definition: Orthant.h:158
ThunderEgg::Orthant::Range::Iterator::operator->
const Orthant< D > * operator->() const
Get a pointer to the Orthant object.
Definition: Orthant.h:174
ThunderEgg::Orthant::Range::end
Iterator end()
Returns an iterator with Orthant<D>::null()
Definition: Orthant.h:203
ThunderEgg::Orthant::tnw
static Orthant< 3 > tnw()
Top-North-West octant of cube.
Definition: Orthant.h:120
ThunderEgg::Orthant::operator==
bool operator==(const Orthant< D > &other) const
Equals operator.
Definition: Orthant.h:331
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::Orthant::getValues
static Range getValues()
Get a range of values that can be iterated over.
Definition: Orthant.h:210
ThunderEgg::Orthant::operator!=
bool operator!=(const Orthant< D > &other) const
Not Equals operator.
Definition: Orthant.h:339
ThunderEgg::Orthant::Range::Iterator::operator*
const Orthant< D > & operator*() const
Get a reference to the Orthant object.
Definition: Orthant.h:168
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::Orthant::getValuesOnSide
static std::array< Orthant, num_orthants/2 > getValuesOnSide(Side< D > s)
Get an array of all Orthant<D> values that lie on a particular side of the cube.
Definition: Orthant.h:308
ThunderEgg::Face::getIndex
size_t getIndex() const
Get the index for this Face.
Definition: Face.h:452
ThunderEgg::Orthant::bse
static Orthant< 3 > bse()
Bottom-South-East octant of cube.
Definition: Orthant.h:100
ThunderEgg::Orthant::getInteriorSides
std::array< Side< D >, D > getInteriorSides() const
Get the sides of the octant that are on the interior of the cube.
Definition: Orthant.h:236
ThunderEgg::Orthant::lower
static Orthant< 1 > lower()
Lower half of line.
Definition: Orthant.h:72
ThunderEgg::Orthant::Range::Iterator::Iterator
Iterator(Orthant< D > o_in)
Construct a new Iterator object with the given Orthant value.
Definition: Orthant.h:150
ThunderEgg::Orthant::getExteriorSides
std::array< Side< D >, D > getExteriorSides() const
Get the sides of the octant that are on the exterior of the cube.
Definition: Orthant.h:253
ThunderEgg::Orthant::tne
static Orthant< 3 > tne()
Top-North-East octant of cube.
Definition: Orthant.h:124
ThunderEgg::Orthant::nw
static Orthant< 2 > nw()
North-West quadrant of square.
Definition: Orthant.h:88
ThunderEgg::Orthant::tsw
static Orthant< 3 > tsw()
Top-South-West octant of cube.
Definition: Orthant.h:112
ThunderEgg::Orthant::Range::Iterator
Input iterator for Orthant values.
Definition: Orthant.h:136
ThunderEgg::Orthant::Range::begin
Iterator begin()
Returns an iterator with the lowest Orthant value.
Definition: Orthant.h:197
ThunderEgg::Orthant::tse
static Orthant< 3 > tse()
Top-South-East octant of cube.
Definition: Orthant.h:116
ThunderEgg::Orthant::Range
Range class for Orthant.
Definition: Orthant.h:130
ThunderEgg::Orthant::bsw
static Orthant< 3 > bsw()
Bottom-South-West octant of cube.
Definition: Orthant.h:96
ThunderEgg::operator<<
std::ostream & operator<<(std::ostream &os, const Side< 1 > &s)
ostream operator that prints a string representation of side enum.
ThunderEgg::Orthant::Orthant
Orthant(const unsigned char val_in)
Create new Orthant<D> with given value.
Definition: Orthant.h:58
ThunderEgg::Orthant::isOnSide
bool isOnSide(Side< D > s) const
Return whether or not the octant lies on a particular side of a cube.
Definition: Orthant.h:272
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
ThunderEgg::Orthant::upper
static Orthant< 1 > upper()
Upper half of line.
Definition: Orthant.h:76
ThunderEgg::Orthant::sw
static Orthant< 2 > sw()
South-West quadrant of square.
Definition: Orthant.h:80
ThunderEgg::Orthant::Range::Iterator::operator==
bool operator==(const Iterator &b) const
Check the iterators reference the same value.
Definition: Orthant.h:182