Caribou
Grid.h
1 #pragma once
2 
3 #include <vector>
4 #include <memory>
5 #include <cmath>
6 #include <array>
7 
8 #include <Caribou/config.h>
9 
10 #include <Caribou/Topology/Grid/Internal/BaseUnidimensionalGrid.h>
11 #include <Caribou/Topology/Grid/Internal/BaseMultidimensionalGrid.h>
12 
13 #include <Caribou/Geometry/Segment.h>
14 #include <Caribou/Geometry/RectangularQuad.h>
15 #include <Caribou/Geometry/RectangularHexahedron.h>
16 
17 namespace caribou::topology {
18 
19 template <size_t Dim>
20 struct Grid
21 {
22  static_assert(Dim > 0 and Dim < 4, "A grid can only be of dimension 1, 2 or 3.");
23 };
24 
25 template <>
26 struct Grid<1> : public internal::BaseUnidimensionalGrid<Grid<1>>
27 {
28  static constexpr size_t Dimension = 1;
29 
30  using Base = internal::BaseUnidimensionalGrid<Grid<Dimension>>;
31  using Base::Base;
32 
34  using ElementIndices = std::array<NodeIndex, caribou::geometry::traits<Element>::NumberOfNodesAtCompileTime>;
35 
36  [[nodiscard]] inline
37  auto
38  cell_at(const GridCoordinates & coordinates) const -> Element
39  {
40  return cell_at(cell_index_at(coordinates));
41  }
42 
43  [[nodiscard]] inline
44  auto
45  cell_at(const CellIndex & index) const -> Element {
46  const auto n0 = node(index);
47  const auto n1 = node(index + 1);
48  return Element (n0, n1);
49  }
50 
51  [[nodiscard]] inline
52  auto
53  node_indices_of(const GridCoordinates & coordinates) const -> ElementIndices
54  {
55  return node_indices_of(cell_index_at(coordinates));
56  }
57 
58  [[nodiscard]] inline
59  auto
60  node_indices_of(const CellIndex & index) const -> ElementIndices
61  {
62  return {{
63  index,
64  index + 1
65  }};
66  }
67 };
68 
69 template <>
70 struct Grid<2> : public internal::BaseMultidimensionalGrid<2, Grid<2>>
71 {
72  static constexpr size_t Dimension = 2;
73 
74  using Base = internal::BaseMultidimensionalGrid<Dimension, Grid<Dimension>>;
75  using Base::Base;
76 
79 
80  using ElementNodes = std::array<NodeIndex, geometry::traits<Element>::NumberOfNodesAtCompileTime>;
81  using EdgeNodes = std::array<NodeIndex, geometry::traits<Edge>::NumberOfNodesAtCompileTime>;
82 
83  [[nodiscard]] inline auto
84  cell_at(const GridCoordinates & coordinates) const -> Element
85  {
86  const auto H = Base::H();
87  const auto center = Base::m_anchor_position + (coordinates.array().cast<FLOATING_POINT_TYPE>() * H.array()).matrix() + H/2.;
88  return Element (center, H);
89  }
90 
91  [[nodiscard]] inline auto
92  cell_at(const CellIndex & cell_index) const -> Element
93  {
94  return cell_at(cell_coordinates_at(cell_index));
95  }
96 
97  [[nodiscard]] inline auto
98  node_indices_of(const GridCoordinates & cell_coordinates) const -> ElementNodes
99  {
100  GridCoordinates e1; e1 << 1, 0;
101  GridCoordinates e2; e2 << 0, 1;
102 
103  return {{
104  node_index_at(cell_coordinates),
105  node_index_at(cell_coordinates + e1),
106  node_index_at(cell_coordinates + e1 + e2),
107  node_index_at(cell_coordinates + e2)
108  }};
109  }
110 
111  [[nodiscard]] inline auto
112  node_indices_of(const CellIndex & index) const -> ElementNodes
113  {
114  return node_indices_of(cell_coordinates_at(index));
115  }
116 
118  [[nodiscard]] inline auto
119  number_of_edges() const noexcept -> UInt
120  {
121  // If the grid is
122  // Y
123  // `
124  // `_ _ _ _
125  // |_|_|_|_|
126  // |_|_|_|_|
127  // |_|_|_|_|... X
128  // Then one row is
129  // |_|_|_|_|
130  // And the total number of edges is
131  // 3 * |_|_|_|_| + _ _ _ _
132 
133  const auto & n = m_number_of_subdivisions;
134 
135  const auto & nx = n[0];
136  const auto & ny = n[1];
137 
138  const auto nb_edges_per_row = (2*nx + 1);
139  const auto nb_edges_total = (nb_edges_per_row * ny) + nx;
140 
141  return nb_edges_total;
142  }
143 
145  [[nodiscard]] inline auto
146  edge(const EdgeIndex & index) const noexcept -> EdgeNodes
147  {
148  const auto & n = m_number_of_subdivisions;
149 
150  const auto & nx = n[0];
151 
152  // If the grid is
153  // Y
154  // `
155  // `_ _ _ _
156  // |_|_|_|_|
157  // |_|_|_|_|
158  // |_|_|_|_|... X
159  // Then one row is
160  // |_|_|_|_|
161  // And the total number of edges is
162  // 3 * |_|_|_|_| + _ _ _ _
163 
164  const auto nb_edges_per_row = (2*nx + 1);
165 
166  NodeIndex n0, n1;
167 
168  const auto row = index / nb_edges_per_row;
169  const auto index_on_row = index % nb_edges_per_row;
170 
171  // If the row is
172  // |_|_|_|_|
173  // Then the edge is
174  // _ _ _ _ => x direction
175  // | | | | | => y direction
176  const bool edge_is_on_the_x_direction = index_on_row < nx;
177 
178  if (edge_is_on_the_x_direction) {
179  n0 = row * (nx+1) + index_on_row;
180  n1 = n0 + 1;
181  } else {
182  n0 = row * (nx+1) + index_on_row - nx;
183  n1 = n0 + (nx + 1);
184  }
185 
186  return {n0, n1};
187  }
188 };
189 
190 template <>
191 struct Grid<3> : public internal::BaseMultidimensionalGrid<3, Grid<3>>
192 {
193  static constexpr size_t Dimension = 3;
194 
195  using Base = internal::BaseMultidimensionalGrid<Dimension, Grid<Dimension>>;
196  using Base::Base;
197 
198  using FaceIndex = typename Base::UInt;
199 
203 
204  using ElementNodes = std::array<NodeIndex, geometry::traits<Element>::NumberOfNodesAtCompileTime>;
205  using FaceNodes = std::array<NodeIndex, geometry::traits<Face>::NumberOfNodesAtCompileTime>;
206  using EdgeNodes = std::array<NodeIndex, geometry::traits<Edge>::NumberOfNodesAtCompileTime>;
207 
208 
209  [[nodiscard]] inline auto
210  cell_at(const GridCoordinates & coordinates) const noexcept -> Element
211  {
212  const auto H = Base::H();
213  const auto center = Base::m_anchor_position + (coordinates.array().cast<FLOATING_POINT_TYPE>() * H.array()).matrix() + H/2.;
214  return Element (center, H);
215  }
216 
217  [[nodiscard]] inline auto
218  cell_at(const CellIndex & cell_index) const noexcept -> Element
219  {
220  return cell_at(cell_coordinates_at(cell_index));
221  }
222 
223  [[nodiscard]] inline auto
224  node_indices_of(const GridCoordinates & cell_coordinates) const noexcept -> ElementNodes
225  {
226  GridCoordinates e1; e1 << 1, 0, 0;
227  GridCoordinates e2; e2 << 0, 1, 0;
228  GridCoordinates e3; e3 << 0, 0, 1;
229 
230  return {{
231  node_index_at(cell_coordinates),
232  node_index_at(cell_coordinates + e1),
233  node_index_at(cell_coordinates + e1 + e2),
234  node_index_at(cell_coordinates + e2),
235  node_index_at(cell_coordinates + e3),
236  node_index_at(cell_coordinates + e1 + e3),
237  node_index_at(cell_coordinates + e1 + e2 + e3),
238  node_index_at(cell_coordinates + e2 + e3)
239  }};
240  }
241 
242  [[nodiscard]] inline auto
243  node_indices_of(const CellIndex & index) const noexcept -> ElementNodes
244  {
245  return node_indices_of(cell_coordinates_at(index));
246  }
247 
249  [[nodiscard]] inline auto
250  number_of_edges() const noexcept -> UInt
251  {
252  // Grid Slice Row
253  // _ _ _ _ _ _ _ _
254  // /_/_/_/_/| |_|_|_|_| |_|_|_|_|
255  // /_/_/_/_/ | |_|_|_|_|
256  // |_|_|_|_|/| |_|_|_|_|
257  // |_|_|_|_|/|
258  // |_|_|_|_|/
259 
260  const auto & n = m_number_of_subdivisions;
261 
262  const auto & nx = n[0];
263  const auto & ny = n[1];
264  const auto & nz = n[2];
265 
266  const auto nb_edges_per_row = (2*nx + 1);
267  const auto nb_edges_per_slice = (nb_edges_per_row * ny) + nx;
268  const auto nb_edges_between_slices = (nx + 1)*(ny + 1);
269 
270  const auto nb_slices = (nz+1);
271 
272  const auto nb_edges_total = (nb_slices*nb_edges_per_slice) + (nz*nb_edges_between_slices);
273 
274  return nb_edges_total;
275  }
276 
278  [[nodiscard]] inline auto
279  edge(const EdgeIndex & index) const noexcept -> EdgeNodes
280  {
281  // Grid Slice Row
282  // _ _ _ _ _ _ _ _
283  // /_/_/_/_/| |_|_|_|_| |_|_|_|_|
284  // /_/_/_/_/ | |_|_|_|_|
285  // |_|_|_|_|/| |_|_|_|_|
286  // |_|_|_|_|/|
287  // |_|_|_|_|/
288 
289  const auto & n = m_number_of_subdivisions;
290 
291  const auto & nx = n[0];
292  const auto & ny = n[1];
293 
294  const auto nb_edges_per_row = (2*nx + 1);
295  const auto nb_edges_per_slice = (nb_edges_per_row * ny) + nx;
296  const auto nb_edges_between_slices = (nx + 1)*(ny + 1);
297 
298  const auto slice = index / (nb_edges_per_slice + nb_edges_between_slices);
299  const auto index_on_slice = index % (nb_edges_per_slice + nb_edges_between_slices);
300 
301  const bool edge_is_on_the_z_direction = index_on_slice > nb_edges_per_slice - 1;
302 
303  const auto slice_corner_node_index = slice * (nx+1) * (ny+1);
304 
305  NodeIndex n0, n1;
306 
307  if (edge_is_on_the_z_direction) {
308  n0 = slice_corner_node_index + (index_on_slice - nb_edges_per_slice);
309  n1 = n0 + nb_edges_between_slices;
310  } else {
311  const auto row = index_on_slice / nb_edges_per_row;
312  const auto index_on_row = index_on_slice % nb_edges_per_row;
313  const bool edge_is_on_the_x_direction = index_on_row < nx;
314 
315  if (edge_is_on_the_x_direction) {
316  n0 = slice_corner_node_index + row * (nx+1) + index_on_row;
317  n1 = n0 + 1;
318  } else {
319  n0 = slice_corner_node_index + row * (nx+1) + index_on_row - nx;
320  n1 = n0 + (nx + 1);
321  }
322  }
323  return {n0, n1};
324  }
325 
327  [[nodiscard]] inline auto
328  number_of_faces() const noexcept -> UInt
329  {
330  // Grid Slice Row
331  // _ _ _ _ _ _ _ _ _ _ _ _
332  // /_/_/_/_/| |_|_|_|_| |_|_|_|_|
333  // /_/_/_/_/ | |_|_|_|_|
334  // |_|_|_|_|/| |_|_|_|_|
335  // |_|_|_|_|/|
336  // |_|_|_|_|/
337 
338  const auto & n = Base::N();
339 
340  const auto & nx = n[0];
341  const auto & ny = n[1];
342  const auto & nz = n[2];
343 
344  const auto nb_faces_per_slice = nx*ny;
345  const auto nb_faces_between_slices = ((nx + 1) * ny) + (nx * (ny + 1));
346 
347  const auto nb_slices = (nz+1);
348 
349  const auto nb_faces = (nb_slices*nb_faces_per_slice) + (nz*nb_faces_between_slices);
350 
351  return nb_faces;
352  }
353 
355  [[nodiscard]] inline auto
356  face(const FaceIndex & index) const noexcept -> FaceNodes
357  {
358  // Grid Slice Row
359  // _ _ _ _ _ _ _ _ _ _ _ _
360  // /_/_/_/_/| |_|_|_|_| |_|_|_|_|
361  // /_/_/_/_/ | |_|_|_|_|
362  // |_|_|_|_|/| |_|_|_|_|
363  // |_|_|_|_|/|
364  // |_|_|_|_|/
365 
366  const auto & n = Base::N();
367 
368  const auto & nx = n[0];
369  const auto & ny = n[1];
370 
371  const auto nb_faces_per_row = nx;
372  const auto nb_faces_per_slice = nx*ny;
373  const auto nb_faces_between_slices = ((nx + 1) * ny) + (nx * (ny + 1));
374 
375  const auto slice = index / (nb_faces_per_slice + nb_faces_between_slices);
376  const auto slice_corner_node_index = slice * (nx+1) * (ny+1);
377 
378  const auto index_on_slice = index % (nb_faces_per_slice + nb_faces_between_slices);
379  const bool face_is_parallel_to_xy_plane = index_on_slice < nb_faces_per_slice;
380 
381  GridCoordinates e1; e1 << 1, 0, 0;
382  GridCoordinates e2; e2 << 0, 1, 0;
383  GridCoordinates e3; e3 << 0, 0, 1;
384 
385  if (face_is_parallel_to_xy_plane) {
386  // (1) Faces on the slice (parallel to the x,y plane)
387  // y
388  // `
389  // |4|5|6|7|
390  // |0|1|2|3|...x
391 
392  const auto row = index_on_slice / nb_faces_per_row;
393  const auto index_on_row = index_on_slice % nb_faces_per_row;
394 
395  NodeIndex n0 = slice_corner_node_index + row * (nx+1) + index_on_row;
396  const auto corner_coordinates = node_coordinates_at(n0);
397  return {{
398  node_index_at(corner_coordinates),
399  node_index_at(corner_coordinates + e1),
400  node_index_at(corner_coordinates + e1 + e2),
401  node_index_at(corner_coordinates + e2)
402  }};
403  } else {
404  const auto index_inbetween_slices = index_on_slice - nb_faces_per_slice; // 20 - 8 = 12
405  const auto nb_of_faces_between_slices_xz = nb_faces_per_row * (ny+1); // 12
406  const bool face_is_parallel_to_xz_plane = index_inbetween_slices < nb_of_faces_between_slices_xz;
407 
408  if (face_is_parallel_to_xz_plane) {
409  // (2) Faces that are between two slices and that are parallel to the x,z plane
410  const auto row = index_inbetween_slices / nb_faces_per_row;
411  const auto index_on_row = index_inbetween_slices % nb_faces_per_row;
412  const auto n0 = slice_corner_node_index + row * (nx+1) + index_on_row;
413  const auto corner_coordinates = node_coordinates_at(n0);
414  return {{
415  node_index_at(corner_coordinates),
416  node_index_at(corner_coordinates + e1),
417  node_index_at(corner_coordinates + e1 + e3),
418  node_index_at(corner_coordinates + e3)
419  }};
420  } else {
421  // (3) Faces that are between two slices and that are parallel to the y,z plane
422  const auto index_in_yz_faces = index_inbetween_slices - nb_of_faces_between_slices_xz;
423  const auto n0 = slice_corner_node_index + index_in_yz_faces;
424  const auto corner_coordinates = node_coordinates_at(n0);
425  return {{
426  node_index_at(corner_coordinates),
427  node_index_at(corner_coordinates + e2),
428  node_index_at(corner_coordinates + e2 + e3),
429  node_index_at(corner_coordinates + e3)
430  }};
431  }
432  }
433  }
434 };
435 
436 } // namespace caribou::topology
caribou::topology::Grid< 3 >::face
auto face(const FaceIndex &index) const noexcept -> FaceNodes
Get the node indices of the face at the given face index.
Definition: Grid.h:356
caribou::geometry::RectangularHexahedron< Linear >
Linear Rectangular Hexahedron.
Definition: RectangularHexahedron.h:45
caribou::geometry::RectangularQuad
Definition: RectangularQuad.h:13
caribou::topology::Grid< 3 >::number_of_edges
auto number_of_edges() const noexcept -> UInt
Get the number of distinct edges in this grid.
Definition: Grid.h:250
caribou::topology::Grid< 3 >::number_of_faces
auto number_of_faces() const noexcept -> UInt
Get the number of distinct faces in this grid.
Definition: Grid.h:328
caribou::geometry::traits
Definition: Element.h:14
caribou::topology::Grid
Definition: Grid.h:21
caribou::geometry::Segment
Definition: Segment.h:10
caribou::topology::Grid< 2 >::edge
auto edge(const EdgeIndex &index) const noexcept -> EdgeNodes
Get the node indices of the edge at edge index.
Definition: Grid.h:146
caribou::topology::Grid< 2 >::number_of_edges
auto number_of_edges() const noexcept -> UInt
Get the number of distinct edges in this grid.
Definition: Grid.h:119
caribou::topology::Grid< 3 >::edge
auto edge(const EdgeIndex &index) const noexcept -> EdgeNodes
Get the node indices of the edge at edge index.
Definition: Grid.h:279