ThunderEgg  1.0.0
PatchView.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_PATCHVIEW_H
22 #define THUNDEREGG_PATCHVIEW_H
30 namespace ThunderEgg {
36 template<typename T, int D>
37 class PatchView : public View<T, D + 1>
38 {
39 private:
40  template<int M>
41  struct SliceInfo
42  {
43  std::array<int, M + 1> strides;
44  std::array<int, M + 1> ghost_start;
45  std::array<int, M + 1> start;
46  std::array<int, M + 1> end;
47  std::array<int, M + 1> ghost_end;
48  std::array<int, D + 1> first_value;
49  };
50 
54  template<int M>
55  static std::array<int, M + 1> DetermineGhostStart(int num_ghost_cells)
56  {
57  std::array<int, M + 1> start;
58  start.fill(-num_ghost_cells);
59  start[M] = 0;
60  return start;
61  }
62 
66  template<int M>
67  static std::array<int, M + 1> DetermineStart()
68  {
69  std::array<int, M + 1> start;
70  start.fill(0);
71  return start;
72  }
73 
77  template<int M>
78  static std::array<int, M + 1> DetermineEnd(const std::array<int, M + 1>& lengths)
79  {
80  std::array<int, M + 1> end = lengths;
81  Loop::Unroll<0, M>([&](int i) { end[i]--; });
82  return end;
83  }
84 
88  template<int M>
89  static std::array<int, M + 1> DetermineGhostEnd(const std::array<int, M + 1>& lengths,
90  int num_ghost_cells)
91  {
92  std::array<int, M + 1> end = lengths;
93  Loop::Unroll<0, M - 1>([&](int i) { end[i] += num_ghost_cells - 1; });
94  end[M] = lengths[M] - 1;
95  return end;
96  }
97 
106  template<int M>
107  SliceInfo<M> getSliceOnPriv(Face<D, M> f, const std::array<int, D - M>& offset) const
108  {
109  SliceInfo<M> info;
110 
111  info.first_value = this->getGhostStart();
112 
113  std::array<Side<D>, D - M> sides = f.getSides();
114  size_t lengths_index = 0;
115  size_t sides_index = 0;
116 
117  for (size_t axis = 0; axis < (size_t)D; axis++) {
118  if (sides_index < sides.size() && sides[sides_index].getAxisIndex() == axis) {
119  if (sides[sides_index].isLowerOnAxis()) {
120  info.first_value[axis] = offset[sides_index];
121  } else {
122  info.first_value[axis] = this->getEnd()[axis] - offset[sides_index];
123  }
124  sides_index++;
125  } else {
126  info.strides[lengths_index] = this->getStrides()[axis];
127  info.ghost_start[lengths_index] = this->getGhostStart()[axis];
128  info.start[lengths_index] = this->getStart()[axis];
129  info.end[lengths_index] = this->getEnd()[axis];
130  info.ghost_end[lengths_index] = this->getGhostEnd()[axis];
131  lengths_index++;
132  }
133  }
134  info.strides[M] = this->getStrides()[D];
135  info.ghost_start[M] = this->getGhostStart()[D];
136  info.start[M] = this->getStart()[D];
137  info.end[M] = this->getEnd()[D];
138  info.ghost_end[M] = this->getGhostEnd()[D];
139  return info;
140  }
141 
142 public:
143  using T_ptr = typename View<T, D>::T_ptr;
148  : View<T, D + 1>()
149  {}
150 
160  PatchView(T_ptr data,
161  const std::array<int, D + 1>& strides,
162  const std::array<int, D + 1>& ghost_start,
163  const std::array<int, D + 1>& start,
164  const std::array<int, D + 1>& end,
165  const std::array<int, D + 1>& ghost_end)
166  : View<T, D + 1>(data, strides, ghost_start, start, end, ghost_end)
167  {}
168 
178  PatchView(T_ptr data,
179  const std::array<int, D + 1>& strides,
180  const std::array<int, D + 1>& lengths,
181  int num_ghost_cells)
182  : View<T, D + 1>(data,
183  strides,
184  DetermineGhostStart<D>(num_ghost_cells),
185  DetermineStart<D>(),
186  DetermineEnd<D>(lengths),
187  DetermineGhostEnd<D>(lengths, num_ghost_cells))
188  {}
189 
199  template<int M>
200  View<T, M + 1> getSliceOn(Face<D, M> f, const std::array<int, D - M>& offset) const
201  {
202  SliceInfo<M> info = getSliceOnPriv<M>(f, offset);
203 
204  T_ptr new_data = (&(*this)[info.first_value]);
205  return View<T, M + 1>(
206  new_data, info.strides, info.ghost_start, info.start, info.end, info.ghost_end);
207  }
208 
218  template<int M>
220  Face<D, M> f,
221  const std::array<size_t, D - M>& offset) const
222  {
223  using noconst_T = typename std::remove_const<T>::type;
224  using noconst_T_ptr = typename std::add_pointer<noconst_T>::type;
225  std::array<int, M + 1> new_strides;
226  std::array<int, M + 1> new_ghost_start;
227  std::array<int, M + 1> new_start;
228  std::array<int, M + 1> new_end;
229  std::array<int, M + 1> new_ghost_end;
230  std::array<int, D + 1> first_value;
231 
232  first_value = this->getGhostStart();
233 
234  std::array<Side<D>, D - M> sides = f.getSides();
235  size_t lengths_index = 0;
236  size_t sides_index = 0;
237 
238  for (size_t axis = 0; axis < (size_t)D; axis++) {
239  if (sides_index < sides.size() && sides[sides_index].getAxisIndex() == axis) {
240  if (sides[sides_index].isLowerOnAxis()) {
241  first_value[axis] = -1 - offset[sides_index];
242  } else {
243  first_value[axis] = this->getEnd()[axis] + 1 + offset[sides_index];
244  }
245  sides_index++;
246  } else {
247  new_strides[lengths_index] = this->getStrides()[axis];
248  new_ghost_start[lengths_index] = this->getGhostStart()[axis];
249  new_start[lengths_index] = this->getStart()[axis];
250  new_end[lengths_index] = this->getEnd()[axis];
251  new_ghost_end[lengths_index] = this->getGhostEnd()[axis];
252  lengths_index++;
253  }
254  }
255  new_strides[M] = this->getStrides()[D];
256  new_ghost_start[M] = this->getGhostStart()[D];
257  new_start[M] = this->getStart()[D];
258  new_end[M] = this->getEnd()[D];
259  new_ghost_end[M] = this->getGhostEnd()[D];
260 
261  noconst_T_ptr new_data = const_cast<noconst_T_ptr>(
262  &(*this)[first_value]); // Thunderegg doesn't care if values in ghosts are modified
263  return View<noconst_T, M + 1>(
264  new_data, new_strides, new_ghost_start, new_start, new_end, new_ghost_end);
265  }
266 
267  ComponentView<T, D> getComponentView(int component_index) const
268  {
269  if constexpr (ENABLE_DEBUG) {
270  if (component_index < this->getStart()[D] || component_index > this->getEnd()[D]) {
271  throw RuntimeError("invalid component index");
272  }
273  }
274  std::array<int, D> new_strides;
275  std::array<int, D> new_ghost_start;
276  std::array<int, D> new_start;
277  std::array<int, D> new_end;
278  std::array<int, D> new_ghost_end;
279  std::array<int, D + 1> first_value;
280 
281  first_value = this->getGhostStart();
282  first_value[D] = component_index;
283 
284  for (size_t axis = 0; axis < (size_t)D; axis++) {
285  new_strides[axis] = this->getStrides()[axis];
286  new_ghost_start[axis] = this->getGhostStart()[axis];
287  new_start[axis] = this->getStart()[axis];
288  new_end[axis] = this->getEnd()[axis];
289  new_ghost_end[axis] = this->getGhostEnd()[axis];
290  }
291 
292  T_ptr new_data = (&(*this)[first_value]);
293  return ComponentView<T, D>(
294  new_data, new_strides, new_ghost_start, new_start, new_end, new_ghost_end);
295  }
296  operator PatchView<std::add_const_t<T>, D>() const
297  {
298  return PatchView<std::add_const_t<T>, D>(this->getData() +
299  this->getIndex(this->getGhostStart()),
300  this->getStrides(),
301  this->getGhostStart(),
302  this->getStart(),
303  this->getEnd(),
304  this->getGhostEnd());
305  }
306 };
307 extern template class PatchView<double, 1>;
308 extern template View<double, 1>
309 PatchView<double, 1>::getSliceOn(Face<1, 0>, const std::array<int, 1>&) const;
310 extern template View<double, 1>
311 PatchView<double, 1>::getGhostSliceOn(Face<1, 0>, const std::array<size_t, 1>&) const;
312 
313 extern template class PatchView<double, 2>;
314 extern template View<double, 1>
315 PatchView<double, 2>::getSliceOn(Face<2, 0>, const std::array<int, 2>&) const;
316 extern template View<double, 2>
317 PatchView<double, 2>::getSliceOn(Face<2, 1>, const std::array<int, 1>&) const;
318 extern template View<double, 1>
319 PatchView<double, 2>::getGhostSliceOn(Face<2, 0>, const std::array<size_t, 2>&) const;
320 extern template View<double, 2>
321 PatchView<double, 2>::getGhostSliceOn(Face<2, 1>, const std::array<size_t, 1>&) const;
322 
323 extern template class PatchView<double, 3>;
324 extern template View<double, 1>
325 PatchView<double, 3>::getSliceOn(Face<3, 0>, const std::array<int, 3>&) const;
326 extern template View<double, 2>
327 PatchView<double, 3>::getSliceOn(Face<3, 1>, const std::array<int, 2>&) const;
328 extern template View<double, 3>
329 PatchView<double, 3>::getSliceOn(Face<3, 2>, const std::array<int, 1>&) const;
330 extern template View<double, 1>
331 PatchView<double, 3>::getGhostSliceOn(Face<3, 0>, const std::array<size_t, 3>&) const;
332 extern template View<double, 2>
333 PatchView<double, 3>::getGhostSliceOn(Face<3, 1>, const std::array<size_t, 2>&) const;
334 extern template View<double, 3>
335 PatchView<double, 3>::getGhostSliceOn(Face<3, 2>, const std::array<size_t, 1>&) const;
336 
337 extern template class PatchView<const double, 1>;
338 extern template View<const double, 1>
339 PatchView<const double, 1>::getSliceOn(Face<1, 0>, const std::array<int, 1>&) const;
340 extern template View<double, 1>
341 PatchView<const double, 1>::getGhostSliceOn(Face<1, 0>, const std::array<size_t, 1>&) const;
342 
343 extern template class PatchView<const double, 2>;
344 extern template View<const double, 1>
345 PatchView<const double, 2>::getSliceOn(Face<2, 0>, const std::array<int, 2>&) const;
346 extern template View<const double, 2>
347 PatchView<const double, 2>::getSliceOn(Face<2, 1>, const std::array<int, 1>&) const;
348 extern template View<double, 1>
349 PatchView<const double, 2>::getGhostSliceOn(Face<2, 0>, const std::array<size_t, 2>&) const;
350 extern template View<double, 2>
351 PatchView<const double, 2>::getGhostSliceOn(Face<2, 1>, const std::array<size_t, 1>&) const;
352 
353 extern template class PatchView<const double, 3>;
354 extern template View<const double, 1>
355 PatchView<const double, 3>::getSliceOn(Face<3, 0>, const std::array<int, 3>&) const;
356 extern template View<const double, 2>
357 PatchView<const double, 3>::getSliceOn(Face<3, 1>, const std::array<int, 2>&) const;
358 extern template View<const double, 3>
359 PatchView<const double, 3>::getSliceOn(Face<3, 2>, const std::array<int, 1>&) const;
360 extern template View<double, 1>
361 PatchView<const double, 3>::getGhostSliceOn(Face<3, 0>, const std::array<size_t, 3>&) const;
362 extern template View<double, 2>
363 PatchView<const double, 3>::getGhostSliceOn(Face<3, 1>, const std::array<size_t, 2>&) const;
364 extern template View<double, 3>
365 PatchView<const double, 3>::getGhostSliceOn(Face<3, 2>, const std::array<size_t, 1>&) const;
366 } // namespace ThunderEgg
367 #endif
ThunderEgg::View
Array for acessing data of a patch. It supports variable striding.
Definition: View.h:40
ThunderEgg::Loop::Unroll
static void Unroll(T lambda)
Unroll a fixed-length loop.
Definition: Loops.h:72
ThunderEgg::View< T, D+1 >::getStrides
const std::array< int, D > & getStrides() const
Get the strides of the patch in each direction.
Definition: View.h:203
ThunderEgg::PatchView::getSliceOn
View< T, M+1 > getSliceOn(Face< D, M > f, const std::array< int, D - M > &offset) const
Get the slice on a given face.
Definition: PatchView.h:200
ThunderEgg::View< T, D+1 >::getGhostStart
const std::array< int, D > & getGhostStart() const
Get the coordinate of the first ghost cell element.
Definition: View.h:215
ThunderEgg::PatchView::getGhostSliceOn
View< typename std::remove_const< T >::type, M+1 > getGhostSliceOn(Face< D, M > f, const std::array< size_t, D - M > &offset) const
Get the gosts slice on a given face.
Definition: PatchView.h:219
ThunderEgg::ComponentView
Array for acessing data of a patch. It supports variable striding.
Definition: ComponentView.h:38
ThunderEgg::PatchView
View for accessing data of a patch. It supports variable striding.
Definition: PatchView.h:37
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::View< T, D+1 >::getEnd
const std::array< int, D > & getEnd() const
Get the coordinate of the last element.
Definition: View.h:211
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::PatchView::PatchView
PatchView(T_ptr data, const std::array< int, D+1 > &strides, const std::array< int, D+1 > &ghost_start, const std::array< int, D+1 > &start, const std::array< int, D+1 > &end, const std::array< int, D+1 > &ghost_end)
Construct a new View object.
Definition: PatchView.h:160
ThunderEgg::PatchView::PatchView
PatchView(T_ptr data, const std::array< int, D+1 > &strides, const std::array< int, D+1 > &lengths, int num_ghost_cells)
Construct a new View object.
Definition: PatchView.h:178
ComponentView.h
ComponentView class.
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
ThunderEgg::PatchView::PatchView
PatchView()
Construct a new PatchView with size 0.
Definition: PatchView.h:147
ThunderEgg::View< T, D+1 >::getGhostEnd
const std::array< int, D > & getGhostEnd() const
Get the coordinate of the last ghost cell element.
Definition: View.h:219
ThunderEgg::View< T, D+1 >::getStart
const std::array< int, D > & getStart() const
Get the coordinate of the first element.
Definition: View.h:207
ThunderEgg::RuntimeError
ThunderEgg runtime exception.
Definition: RuntimeError.h:36