8 #include <Caribou/config.h>
10 #include <Caribou/Topology/Grid/Internal/BaseUnidimensionalGrid.h>
11 #include <Caribou/Topology/Grid/Internal/BaseMultidimensionalGrid.h>
13 #include <Caribou/Geometry/Segment.h>
14 #include <Caribou/Geometry/RectangularQuad.h>
15 #include <Caribou/Geometry/RectangularHexahedron.h>
17 namespace caribou::topology {
22 static_assert(Dim > 0 and Dim < 4,
"A grid can only be of dimension 1, 2 or 3.");
26 struct Grid<1> :
public internal::BaseUnidimensionalGrid<Grid<1>>
28 static constexpr
size_t Dimension = 1;
30 using Base = internal::BaseUnidimensionalGrid<Grid<Dimension>>;
34 using ElementIndices = std::array<NodeIndex, caribou::geometry::traits<Element>::NumberOfNodesAtCompileTime>;
38 cell_at(
const GridCoordinates & coordinates)
const ->
Element
40 return cell_at(cell_index_at(coordinates));
45 cell_at(
const CellIndex & index)
const ->
Element {
46 const auto n0 = node(index);
47 const auto n1 = node(index + 1);
53 node_indices_of(
const GridCoordinates & coordinates)
const -> ElementIndices
55 return node_indices_of(cell_index_at(coordinates));
60 node_indices_of(
const CellIndex & index)
const -> ElementIndices
70 struct Grid<2> :
public internal::BaseMultidimensionalGrid<2, Grid<2>>
72 static constexpr
size_t Dimension = 2;
74 using Base = internal::BaseMultidimensionalGrid<Dimension, Grid<Dimension>>;
80 using ElementNodes = std::array<NodeIndex, geometry::traits<Element>::NumberOfNodesAtCompileTime>;
81 using EdgeNodes = std::array<NodeIndex, geometry::traits<Edge>::NumberOfNodesAtCompileTime>;
83 [[nodiscard]]
inline auto
84 cell_at(
const GridCoordinates & coordinates)
const ->
Element
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.;
91 [[nodiscard]]
inline auto
92 cell_at(
const CellIndex & cell_index)
const ->
Element
94 return cell_at(cell_coordinates_at(cell_index));
97 [[nodiscard]]
inline auto
98 node_indices_of(
const GridCoordinates & cell_coordinates)
const -> ElementNodes
100 GridCoordinates e1; e1 << 1, 0;
101 GridCoordinates e2; e2 << 0, 1;
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)
111 [[nodiscard]]
inline auto
112 node_indices_of(
const CellIndex & index)
const -> ElementNodes
114 return node_indices_of(cell_coordinates_at(index));
118 [[nodiscard]]
inline auto
133 const auto & n = m_number_of_subdivisions;
135 const auto & nx = n[0];
136 const auto & ny = n[1];
138 const auto nb_edges_per_row = (2*nx + 1);
139 const auto nb_edges_total = (nb_edges_per_row * ny) + nx;
141 return nb_edges_total;
145 [[nodiscard]]
inline auto
146 edge(
const EdgeIndex & index)
const noexcept -> EdgeNodes
148 const auto & n = m_number_of_subdivisions;
150 const auto & nx = n[0];
164 const auto nb_edges_per_row = (2*nx + 1);
168 const auto row = index / nb_edges_per_row;
169 const auto index_on_row = index % nb_edges_per_row;
176 const bool edge_is_on_the_x_direction = index_on_row < nx;
178 if (edge_is_on_the_x_direction) {
179 n0 = row * (nx+1) + index_on_row;
182 n0 = row * (nx+1) + index_on_row - nx;
191 struct Grid<3> :
public internal::BaseMultidimensionalGrid<3, Grid<3>>
193 static constexpr
size_t Dimension = 3;
195 using Base = internal::BaseMultidimensionalGrid<Dimension, Grid<Dimension>>;
198 using FaceIndex =
typename Base::UInt;
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>;
209 [[nodiscard]]
inline auto
210 cell_at(
const GridCoordinates & coordinates)
const noexcept ->
Element
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.;
217 [[nodiscard]]
inline auto
218 cell_at(
const CellIndex & cell_index)
const noexcept ->
Element
220 return cell_at(cell_coordinates_at(cell_index));
223 [[nodiscard]]
inline auto
224 node_indices_of(
const GridCoordinates & cell_coordinates)
const noexcept -> ElementNodes
226 GridCoordinates e1; e1 << 1, 0, 0;
227 GridCoordinates e2; e2 << 0, 1, 0;
228 GridCoordinates e3; e3 << 0, 0, 1;
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)
242 [[nodiscard]]
inline auto
243 node_indices_of(
const CellIndex & index)
const noexcept -> ElementNodes
245 return node_indices_of(cell_coordinates_at(index));
249 [[nodiscard]]
inline auto
260 const auto & n = m_number_of_subdivisions;
262 const auto & nx = n[0];
263 const auto & ny = n[1];
264 const auto & nz = n[2];
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);
270 const auto nb_slices = (nz+1);
272 const auto nb_edges_total = (nb_slices*nb_edges_per_slice) + (nz*nb_edges_between_slices);
274 return nb_edges_total;
278 [[nodiscard]]
inline auto
279 edge(
const EdgeIndex & index)
const noexcept -> EdgeNodes
289 const auto & n = m_number_of_subdivisions;
291 const auto & nx = n[0];
292 const auto & ny = n[1];
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);
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);
301 const bool edge_is_on_the_z_direction = index_on_slice > nb_edges_per_slice - 1;
303 const auto slice_corner_node_index = slice * (nx+1) * (ny+1);
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;
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;
315 if (edge_is_on_the_x_direction) {
316 n0 = slice_corner_node_index + row * (nx+1) + index_on_row;
319 n0 = slice_corner_node_index + row * (nx+1) + index_on_row - nx;
327 [[nodiscard]]
inline auto
338 const auto & n = Base::N();
340 const auto & nx = n[0];
341 const auto & ny = n[1];
342 const auto & nz = n[2];
344 const auto nb_faces_per_slice = nx*ny;
345 const auto nb_faces_between_slices = ((nx + 1) * ny) + (nx * (ny + 1));
347 const auto nb_slices = (nz+1);
349 const auto nb_faces = (nb_slices*nb_faces_per_slice) + (nz*nb_faces_between_slices);
355 [[nodiscard]]
inline auto
356 face(
const FaceIndex & index)
const noexcept -> FaceNodes
366 const auto & n = Base::N();
368 const auto & nx = n[0];
369 const auto & ny = n[1];
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));
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);
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;
381 GridCoordinates e1; e1 << 1, 0, 0;
382 GridCoordinates e2; e2 << 0, 1, 0;
383 GridCoordinates e3; e3 << 0, 0, 1;
385 if (face_is_parallel_to_xy_plane) {
392 const auto row = index_on_slice / nb_faces_per_row;
393 const auto index_on_row = index_on_slice % nb_faces_per_row;
395 NodeIndex n0 = slice_corner_node_index + row * (nx+1) + index_on_row;
396 const auto corner_coordinates = node_coordinates_at(n0);
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)
404 const auto index_inbetween_slices = index_on_slice - nb_faces_per_slice;
405 const auto nb_of_faces_between_slices_xz = nb_faces_per_row * (ny+1);
406 const bool face_is_parallel_to_xz_plane = index_inbetween_slices < nb_of_faces_between_slices_xz;
408 if (face_is_parallel_to_xz_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);
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)
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);
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)