LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
mesh_hierarchy.cc
1
6#include "mesh_hierarchy.h"
7
8#include <spdlog/fmt/ostr.h>
9#include <spdlog/spdlog.h>
10
11#include "lf/mesh/hybrid2d/hybrid2d.h"
12#include "lf/mesh/utils/utils.h"
13
14namespace lf::refinement {
15
16// Debugging function: check validity of index vectors
17bool checkValidIndex(const std::vector<glb_idx_t> &idx_vec) {
18 const size_type n_idx = idx_vec.size();
19 for (int n = 0; n < n_idx; n++) {
20 if (idx_vec[n] == idx_nil) {
21 return false;
22 }
23 }
24 return true;
25}
26
27std::shared_ptr<spdlog::logger> &MeshHierarchy::Logger() {
28 static auto logger =
29 base::InitLogger("lf::refinement::MeshHierarchy::Logger");
30 return logger;
31}
32
33// Implementation of MeshHierarchy
34MeshHierarchy::MeshHierarchy(const std::shared_ptr<mesh::Mesh> &base_mesh,
35 std::unique_ptr<mesh::MeshFactory> mesh_factory)
36 : mesh_factory_(std::move(mesh_factory)) {
37 LF_VERIFY_MSG(base_mesh, "No valid mesh supplied");
38 LF_VERIFY_MSG(base_mesh->DimMesh() == 2, "Implemented only for 2D meshes");
39 // Set coarsest mesh
40 meshes_.push_back(base_mesh);
41 {
42 // Refinement edge has to be set for edges
43 refinement_edges_.emplace_back(base_mesh->NumEntities(0), idx_nil);
44 for (const mesh::Entity *cell : base_mesh->Entities(0)) {
45 lf::base::glb_idx_t cell_index = base_mesh->Index(*cell);
46 if (cell->RefEl() == lf::base::RefEl::kTria()) {
47 (refinement_edges_.back())[cell_index] = LongestEdge(*cell);
48 }
49 } // end loop over cells
50
51 // Setting up child information
52 std::vector<CellChildInfo> cell_child_info(base_mesh->NumEntities(0));
53 std::vector<EdgeChildInfo> edge_child_info(base_mesh->NumEntities(1));
54 std::vector<PointChildInfo> point_child_info(base_mesh->NumEntities(2));
55 cell_child_infos_.push_back(std::move(cell_child_info));
56 edge_child_infos_.push_back(std::move(edge_child_info));
57 point_child_infos_.push_back(std::move(point_child_info));
58 }
59 {
60 // No parents for entities on the coarsest level
61 std::vector<ParentInfo> cell_parent_info(base_mesh->NumEntities(0));
62 std::vector<ParentInfo> edge_parent_info(base_mesh->NumEntities(1));
63 std::vector<ParentInfo> point_parent_info(base_mesh->NumEntities(2));
64 parent_infos_.push_back({std::move(cell_parent_info),
65 std::move(edge_parent_info),
66 std::move(point_parent_info)});
67 }
68 edge_marked_.push_back(
69 std::move(std::vector<bool>(base_mesh->NumEntities(1), false)));
70}
71
73 LF_VERIFY_MSG(
74 ref_pat == RefPat::rp_regular || ref_pat == RefPat::rp_barycentric,
75 "Only regular or barycentric uniform refinement possible");
76 // Retrieve the finest mesh in the hierarchy
77 const mesh::Mesh &finest_mesh(*meshes_.back());
78 // Arrays containing refinement information for finest mesh
79 std::vector<PointChildInfo> &finest_point_ci(point_child_infos_.back());
80 std::vector<EdgeChildInfo> &finest_edge_ci(edge_child_infos_.back());
81 std::vector<CellChildInfo> &finest_cell_ci(cell_child_infos_.back());
82
83 LF_VERIFY_MSG(finest_point_ci.size() == finest_mesh.NumEntities(2),
84 "length mismatch PointChildInfo vector");
85 LF_VERIFY_MSG(finest_edge_ci.size() == finest_mesh.NumEntities(1),
86 "length mismatch EdgeChildInfo vector");
87 LF_VERIFY_MSG(finest_cell_ci.size() == finest_mesh.NumEntities(0),
88 "length mismatch CellChildInfo vector");
89
90 // Flag all points as to be copied
91 for (const mesh::Entity *point : finest_mesh.Entities(2)) {
92 const lf::base::glb_idx_t point_index = finest_mesh.Index(*point);
93 PointChildInfo &pt_child_info(finest_point_ci[point_index]);
94 // Set the information about a point's children except the child pointer
95 pt_child_info.ref_pat = RefPat::rp_copy;
96 }
97 // Flag all edges as to be split
98 for (const mesh::Entity *edge : finest_mesh.Entities(1)) {
99 const lf::base::glb_idx_t edge_index = finest_mesh.Index(*edge);
100 EdgeChildInfo &ed_child_info(finest_edge_ci[edge_index]);
101 ed_child_info.ref_pat_ = RefPat::rp_split;
102 }
103 // All cells are to be refined regularly
104 for (const mesh::Entity *cell : finest_mesh.Entities(0)) {
105 const lf::base::glb_idx_t cell_index = finest_mesh.Index(*cell);
106 CellChildInfo &cell_child_info(finest_cell_ci[cell_index]);
107 cell_child_info.ref_pat_ = ref_pat;
108 }
109 // With all refinement patterns set, generate the new mesh
111 // Finish initialization
113}
114
116 // Target the finest mesh
117 const lf::mesh::Mesh &finest_mesh(*meshes_.back());
118 // Arrays containing refinement information for finest mesh
119 std::vector<PointChildInfo> &finest_point_ci(point_child_infos_.back());
120 std::vector<EdgeChildInfo> &finest_edge_ci(edge_child_infos_.back());
121 std::vector<CellChildInfo> &finest_cell_ci(cell_child_infos_.back());
122
123 LF_VERIFY_MSG(finest_point_ci.size() == finest_mesh.NumEntities(2),
124 "length mismatch PointChildInfo vector");
125 LF_VERIFY_MSG(finest_edge_ci.size() == finest_mesh.NumEntities(1),
126 "length mismatch EdgeChildInfo vector");
127 LF_VERIFY_MSG(finest_cell_ci.size() == finest_mesh.NumEntities(0),
128 "length mismatch CellChildInfo vector");
129
130 // Flag all points as to be copied
131 for (const mesh::Entity *point : finest_mesh.Entities(2)) {
132 const glb_idx_t point_index = finest_mesh.Index(*point);
133 PointChildInfo &pt_child_info(finest_point_ci[point_index]);
134 // Set the information about a point's children except the child pointer
135 pt_child_info.ref_pat = RefPat::rp_copy;
136 }
137
138 // Set the split refinement patterrn for all marked edges
139 for (const lf::mesh::Entity *edge : finest_mesh.Entities(1)) {
140 LF_VERIFY_MSG(edge->RefEl() == lf::base::RefEl::kSegment(),
141 "Wrong type for an edge");
142 const glb_idx_t edge_index = finest_mesh.Index(*edge);
143 EdgeChildInfo &ed_ci(finest_edge_ci[edge_index]);
144 LF_VERIFY_MSG(ed_ci.ref_pat_ == RefPat::rp_nil,
145 "Edge " << edge_index << " already refined!");
146 if ((edge_marked_.back())[edge_index]) {
147 // Edge is to be refined
148 ed_ci.ref_pat_ = RefPat::rp_split;
149 } else {
150 // Just copy edge
151 ed_ci.ref_pat_ = RefPat::rp_copy;
152 }
153 }
154 // Now all edges are initially marked to be split or copied
155
156 // To keep the mesh conforming refinement might have to propagate
157 // This is achieved in the following REPEAT ... UNTIL loop.
158 bool refinement_complete;
159 do {
160 refinement_complete = true;
161 // Visit all cells and update their refinement patterns
162 for (const lf::mesh::Entity *cell : finest_mesh.Entities(0)) {
163 // Obtain unique index of current cell
164 const glb_idx_t cell_index = finest_mesh.Index(*cell);
165 // Detailed description of refinement status
166 CellChildInfo &cell_child_info(finest_cell_ci[cell_index]);
167
168 // Global indices of edges
169 std::array<glb_idx_t, 4> cell_edge_indices{};
170
171 // Find edges which are marked as split
172 std::array<bool, 4> edge_split{{false, false, false, false}};
173 // Local indices of edges marked as split
174 std::array<sub_idx_t, 4> split_edge_idx{};
175 // Array of references to edge sub-entities of current cell
177 cell->SubEntities(1);
178 const size_type num_edges = cell->RefEl().NumSubEntities(1);
179 LF_VERIFY_MSG(num_edges <= 4, "Too many edges = " << num_edges);
180 // Obtain information about current splitting pattern of
181 // the edges of the cell. Count edges that will be split.
182 size_type split_edge_cnt = 0;
183 for (int k = 0; k < num_edges; k++) {
184 const glb_idx_t edge_index = finest_mesh.Index(*sub_edges[k]);
185 cell_edge_indices[k] = edge_index;
186 edge_split[k] =
187 (finest_edge_ci[edge_index].ref_pat_ == RefPat::rp_split);
188 if (edge_split[k]) {
189 split_edge_idx[split_edge_cnt] = k;
190 split_edge_cnt++;
191 }
192 }
193 switch (cell->RefEl()) {
194 case lf::base::RefEl::kTria(): {
195 // Case of a triangular cell: In this case bisection refinement
196 // is performed starting with the refinement edge.
197 // Local index of refinement edge for the current triangle, also
198 // called the "anchor edge" in the case of repeated bisection
199 const sub_idx_t anchor = refinement_edges_.back()[cell_index];
200 LF_VERIFY_MSG(anchor < 3, "Illegal anchor = " << anchor);
201
202 // Refinement edge will always be the anchor edge
203 finest_cell_ci[cell_index].anchor_ = anchor;
204 const sub_idx_t mod_0 = anchor;
205 const sub_idx_t mod_1 = (anchor + 1) % 3;
206 const sub_idx_t mod_2 = (anchor + 2) % 3;
207 // Flag tuple indicating splitting status of an edge: true <-> split
208 std::tuple<bool, bool, bool> split_status(
209 {edge_split[mod_0], edge_split[mod_1], edge_split[mod_2]});
210
211 // Determine updated refinement pattern for triangle depending on the
212 // splitting status of its edges. If the triangle is subdivided, the
213 // refinement must always be split in a first bisection step, even if
214 // it may not have been marked as split. In this case refinement may
215 // spread to neighboring cells and we have to iterative once more.
216 // Therefore the refinement_complete flag has to be set to 'false'.
217
218 if (split_status ==
219 std::tuple<bool, bool, bool>({false, false, false})) {
220 // No edge to be split: just copy triangle
221 LF_VERIFY_MSG(split_edge_cnt == 0, "Wrong number of split edges");
222 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_copy;
223 } else if (split_status ==
224 std::tuple<bool, bool, bool>({true, false, false})) {
225 // Only refinement edge has to be split by a single bisection
226 // No additional edge will be split
227 LF_VERIFY_MSG(split_edge_cnt == 1, "Wrong number of split edges");
228 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_bisect;
229 } else if (split_status ==
230 std::tuple<bool, bool, bool>({true, true, false})) {
231 // Trisection refinement, no extra splitting of edges
232 LF_VERIFY_MSG(split_edge_cnt == 2, "Wrong number of split edges");
233 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_trisect;
234 } else if (split_status ==
235 std::tuple<bool, bool, bool>({false, true, false})) {
236 // Trisection refinement, triggering splitting of refinement edge
237 LF_VERIFY_MSG(split_edge_cnt == 1, "Wrong number of split edges");
238 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_trisect;
239 finest_edge_ci[cell_edge_indices[anchor]].ref_pat_ =
240 RefPat::rp_split;
241 refinement_complete = false;
242 } else if (split_status ==
243 std::tuple<bool, bool, bool>({true, false, true})) {
244 // Trisection refinement (other side), no extra splitting of edges
245 LF_VERIFY_MSG(split_edge_cnt == 2, "Wrong number of split edges");
246 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_trisect_left;
247 } else if (split_status ==
248 std::tuple<bool, bool, bool>({false, false, true})) {
249 // Trisection refinement (other side), triggering splitting of
250 // refinement edge
251 LF_VERIFY_MSG(split_edge_cnt == 1, "Wrong number of split edges");
252 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_trisect_left;
253 finest_edge_ci[cell_edge_indices[anchor]].ref_pat_ =
254 RefPat::rp_split;
255 refinement_complete = false;
256 } else if (split_status ==
257 std::tuple<bool, bool, bool>({true, true, true})) {
258 // All edges of the triangle are to be split
259 // If the implementation relies on quadsection refinement, the the
260 // child triangles may become more and more distorted! Thus it is
261 // advisable to employ regular refinement.
262 LF_VERIFY_MSG(split_edge_cnt == 3, "Wrong number of split edges");
263 // OLD IMPLEMENTATION
264 // finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_quadsect;
265 // NEW IMPLEMENTATION
266 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_regular;
267 } else if (split_status ==
268 std::tuple<bool, bool, bool>({false, true, true})) {
269 // Quadsection refinement requiring splitting of refinement edge
270 LF_VERIFY_MSG(split_edge_cnt == 2, "Wrong number of split edges");
271 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_quadsect;
272 finest_edge_ci[cell_edge_indices[anchor]].ref_pat_ =
273 RefPat::rp_split;
274 refinement_complete = false;
275 } else {
276 LF_VERIFY_MSG(false, "Impossible case");
277 }
278 break;
279 } // end case of a triangle
280 case lf::base::RefEl::kQuad(): {
281 // There is no refinement edge for quadrilaterals and so no extra edge
282 // splitting will be necessary. The refinement pattern for a
283 // quadrilateral will be determined from the number of edges split and
284 // their location to each other.
285 switch (split_edge_cnt) {
286 case 0: {
287 // No edge split: quadrilateral has to be copied
288 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_copy;
289 break;
290 }
291 case 1: {
292 // One edge split: trisection refinement of the quadrilateral
293 // Anchor edge is the split edge
294 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_trisect;
295 finest_cell_ci[cell_index].anchor_ = split_edge_idx[0];
296 break;
297 }
298 case 2: {
299 if ((split_edge_idx[1] - split_edge_idx[0]) == 2) {
300 // If the two split edges are opposite to each other, then
301 // bisection of the quadrilateral is the right refinement
302 // pattern.
303 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_bisect;
304 finest_cell_ci[cell_index].anchor_ = split_edge_idx[0];
305 } else {
306 // Tthe two split edges are adjacent, this case can be
307 // accommodated by quadsection refinement. Anchor is the split
308 // edge with the lower index (modulo 4).
309 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_quadsect;
310 if (((split_edge_idx[0] + 1) % 4) == split_edge_idx[1]) {
311 finest_cell_ci[cell_index].anchor_ = split_edge_idx[0];
312 } else if (((split_edge_idx[1] + 1) % 4) == split_edge_idx[0]) {
313 finest_cell_ci[cell_index].anchor_ = split_edge_idx[1];
314 } else {
315 LF_VERIFY_MSG(false,
316 "Quad: impossible situation for 2 split edges");
317 }
318 }
319 break;
320 }
321 case 3: {
322 // Three edges of the quadrilateral are split, which can be
323 // accommodated only by the rp_threeedge refinement pattern
324 // anchor is the edge with the middle index
325 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_threeedge;
326 if (!edge_split[0]) { // Split edges 1,2,3, middle edge 2
327 finest_cell_ci[cell_index].anchor_ = 2;
328 } else if (!edge_split[1]) { // Split edges 0,2,3, middle edge 3
329 finest_cell_ci[cell_index].anchor_ = 3;
330 } else if (!edge_split[2]) { // Split edges 0,1,3, middle edge 0
331 finest_cell_ci[cell_index].anchor_ = 0;
332 } else if (!edge_split[3]) { // Split edges 0,1,2, middle edge 1
333 finest_cell_ci[cell_index].anchor_ = 1;
334 } else {
335 LF_VERIFY_MSG(false, "Inconsistent split pattern");
336 }
337 break;
338 }
339 case 4: {
340 // All edges are split => regular refinement
341 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_regular;
342 break;
343 }
344 default: {
345 LF_VERIFY_MSG(false, "Illegal number " << split_edge_cnt
346 << " of split edges");
347 break;
348 }
349 } // end switch split_edge_cnt
350 break;
351 } // end case of a quadrilateral
352 default: {
353 LF_VERIFY_MSG(false, "Illegal cell type");
354 break;
355 }
356 } // end switch cell type
357 } // end loop over cells
358 } while (!refinement_complete);
359
360 // Create finer mesh according to set refinment edges
362 // Finish initialization
364} // end RefineMarked
365
366// NOLINTNEXTLINE
368 SPDLOG_LOGGER_DEBUG(Logger(),
369 "Entering MeshHierarchy::PerformRefinement: {} levels",
370 meshes_.size());
371
372 // This function expects that the refinement patterns stored in the
373 // vectors point_child_infos_, edge_child_infos_ and cell_child_infos_
374 // have been initialized consistently for the finest mesh.
375
376 // This functions will augement these vectors with information about
377 // the indices of child entities on a newly created finest mesh.
378
379 // Retrieve the finest mesh in the hierarchy = parent mesh
380 const mesh::Mesh &parent_mesh(*meshes_.back());
381
382 {
383 // Partly intialized vectors of child information
384 std::vector<PointChildInfo> &pt_child_info(point_child_infos_.back());
385 // ======================================================================
386 // First run through the vertices, create child vertices and register
387 // them with the mesh factory
388 // Store child indices in an auxiliary array
389 size_type new_node_cnt = 0;
391 RefPat::rp_copy);
392 for (const mesh::Entity *node : parent_mesh.Entities(2)) {
393 // Obtain index of node in coarse mesh
394 const lf::base::glb_idx_t node_index = parent_mesh.Index(*node);
395 LF_VERIFY_MSG(node_index < pt_child_info.size(),
396 "Node index " << node_index << " out of range");
397 // Find position of node in physical coordinates
398 const lf::geometry::Geometry &pt_geo(*node->Geometry());
399 if (pt_child_info[node_index].ref_pat != RefPat::rp_nil) {
400 // Generate a node for the fine mesh at the same position
401 std::vector<std::unique_ptr<geometry::Geometry>> pt_child_geo_ptrs(
402 pt_geo.ChildGeometry(rp_copy_node, 0));
403 LF_VERIFY_MSG(pt_child_geo_ptrs.size() == 1,
404 "A point can only have one chile");
405 // Store index of child node
406 pt_child_info[node_index].child_point_idx =
407 mesh_factory_->AddPoint(std::move(pt_child_geo_ptrs[0]));
408 new_node_cnt++;
409 }
410 } // end loop over nodes
411 SPDLOG_LOGGER_DEBUG(Logger(), "{} new nodes added", new_node_cnt);
412
413 // ======================================================================
414
415 // Partly intialized vectors of child information
416 std::vector<EdgeChildInfo> &ed_child_info(edge_child_infos_.back());
417 // ======================================================================
418 // Now traverse the edges. Depending on the refinement pattern,
419 // either copy them or split them.
420 // Supplement the refinement information for edges accordingly.
421 size_type new_edge_cnt = 0;
422 for (const mesh::Entity *edge : parent_mesh.Entities(1)) {
423 // Fetch global index of edge
424 lf::base::glb_idx_t edge_index = parent_mesh.Index(*edge);
425
426 // Get indices of endpoints in parent mesh
427 auto ed_nodes = edge->SubEntities(1);
428 const lf::base::glb_idx_t ed_p0_coarse_idx =
429 parent_mesh.Index(*ed_nodes[0]);
430 const lf::base::glb_idx_t ed_p1_coarse_idx =
431 parent_mesh.Index(*ed_nodes[1]);
432
433 // Obtain indices of the nodes at the same position in the fine mesh
434 const lf::base::glb_idx_t ed_p0_fine_idx =
435 pt_child_info[ed_p0_coarse_idx].child_point_idx;
436 const lf::base::glb_idx_t ed_p1_fine_idx =
437 pt_child_info[ed_p1_coarse_idx].child_point_idx;
438 // Prepare request of geometry after refinement
439 EdgeChildInfo &edge_ci(ed_child_info[edge_index]);
440 const RefPat edge_refpat(edge_ci.ref_pat_);
441 Hybrid2DRefinementPattern rp(edge->RefEl(), edge_refpat);
442
443 // Distinguish between different local refinement patterns
444 switch (edge_refpat) {
445 case RefPat::rp_copy: {
446 // Edge has to be duplicated
447 std::vector<std::unique_ptr<lf::geometry::Geometry>> ed_copy(
448 edge->Geometry()->ChildGeometry(rp, 0));
449 LF_VERIFY_MSG(ed_copy.size() == 1,
450 "Copy may create only a single child!");
451 // Register the new edge
452 SPDLOG_LOGGER_TRACE(Logger(), "Copy edge {} new edge [{},{}]",
453 edge_index, ed_p0_fine_idx, ed_p1_fine_idx);
454
455 // Store index of copy of edge on finer mesh
456 edge_ci.child_edge_idx.push_back(
457 mesh_factory_->AddEntity(edge->RefEl(),
458 std::array<lf::base::glb_idx_t, 2>{
459 {ed_p0_fine_idx, ed_p1_fine_idx}},
460 std::move(ed_copy[0])));
461 break;
462 } // end rp_copy
463 case rp_split: {
464 // Edge has to be split into two halves with a new node created at the
465 // midpoint position. First obtain geometry information about new node
466 // (sub-entity with relative co-dimension 1)
467 std::vector<std::unique_ptr<geometry::Geometry>> edge_nodes_geo_ptrs(
468 edge->Geometry()->ChildGeometry(rp, 1));
469 LF_VERIFY_MSG(edge_nodes_geo_ptrs.size() == 1,
470 "Split edge with " << edge_nodes_geo_ptrs.size()
471 << " child nodes!");
472 // Register midpoint as new node
473 const lf::base::glb_idx_t midpoint_fine_idx =
474 mesh_factory_->AddPoint(std::move(edge_nodes_geo_ptrs[0]));
475 edge_ci.child_point_idx.push_back(midpoint_fine_idx);
476 // Next get the geometry objects for the two child edges (co-dim == 0)
477 std::vector<std::unique_ptr<geometry::Geometry>> edge_child_geo_ptrs(
478 edge->Geometry()->ChildGeometry(rp, 0));
479 LF_VERIFY_MSG(
480 edge_child_geo_ptrs.size() == 2,
481 "Split edge with " << edge_child_geo_ptrs.size() << " parts!");
482 // Register the two new edges
483 // CAREFUL: Assignment of endpoints has to match implementation in
484 // refinement.cc
485 // First child edge adjacent to endpoint #0, second child edge
486 // adjacent to endpoint #1
487 SPDLOG_LOGGER_TRACE(Logger(),
488 "Split Edge {} new edges [{},{}], [{},{}]",
489 edge_index, ed_p0_fine_idx, midpoint_fine_idx,
490 midpoint_fine_idx, ed_p1_fine_idx);
491
492 edge_ci.child_edge_idx.push_back(
493 mesh_factory_->AddEntity(edge->RefEl(),
494 std::array<lf::base::glb_idx_t, 2>{
495 {ed_p0_fine_idx, midpoint_fine_idx}},
496 std::move(edge_child_geo_ptrs[0])));
497 edge_ci.child_edge_idx.push_back(
498 mesh_factory_->AddEntity(edge->RefEl(),
499 std::array<lf::base::glb_idx_t, 2>{
500 {midpoint_fine_idx, ed_p1_fine_idx}},
501 std::move(edge_child_geo_ptrs[1])));
502 break;
503 } // end rp_split
504 default: {
505 LF_VERIFY_MSG(false, "Refinement pattern "
506 << static_cast<int>(edge_refpat)
507 << " illegal for edge");
508 break;
509 }
510 } // end switch refpat
511 new_edge_cnt++;
512 } // end edge loop
513
514 SPDLOG_LOGGER_DEBUG(Logger(), "{} edges added", new_edge_cnt);
515 // ======================================================================
516
517 // Partly intialized vectors of child information
518 std::vector<CellChildInfo> &cell_child_info(cell_child_infos_.back());
519 // ======================================================================
520 // Visit all cells, examine their refinement patterns, retrieve indices of
521 // their sub-entities, and those of the children.
522 LF_VERIFY_MSG(cell_child_info.size() == parent_mesh.NumEntities(0),
523 "Size mismatch for CellChildInfos");
524 for (const mesh::Entity *cell : parent_mesh.Entities(0)) {
525 // type of cell
526 const lf::base::RefEl ref_el(cell->RefEl());
527 const lf::base::size_type num_edges = ref_el.NumSubEntities(1);
528 const lf::base::size_type num_vertices = ref_el.NumSubEntities(2);
529 // fetch index of current cell
530 const lf::base::glb_idx_t cell_index(parent_mesh.Index(*cell));
531
532 // Set up refinement object -> variable rp
533 CellChildInfo &cell_ci(cell_child_info[cell_index]);
534 const RefPat cell_refpat(cell_ci.ref_pat_);
535 const sub_idx_t anchor = cell_ci.anchor_; // anchor edge index
536
537 SPDLOG_LOGGER_TRACE(Logger(), "Cell {} = {}, refpat = {}, anchor = {}",
538 cell_index, ref_el, static_cast<int>(cell_refpat),
539 anchor);
540
541 Hybrid2DRefinementPattern rp(cell->RefEl(), cell_refpat, anchor);
542
543 // Index offsets for refinement patterns requiring an ancchor edge
544 std::array<sub_idx_t, 4> mod{};
545 if (anchor != idx_nil) {
546 for (int k = 0; k < num_vertices; k++) {
547 mod[k] = (k + anchor) % num_vertices;
548 }
549 }
550
551 // Obtain indices of subentities (co-dimension = outer array index)
552 std::array<std::vector<lf::base::glb_idx_t>, 3> cell_subent_idx;
553 cell_subent_idx[0].push_back(cell_index);
554 for (int codim = 1; codim <= 2; codim++) {
555 auto subentities = cell->SubEntities(codim);
556 for (const mesh::Entity *sub_ent : subentities) {
557 cell_subent_idx[codim].push_back(parent_mesh.Index(*sub_ent));
558 }
559 LF_VERIFY_MSG(
560 cell_subent_idx[codim].size() == ref_el.NumSubEntities(codim),
561 ref_el.ToString() << ": only " << cell_subent_idx[codim].size()
562 << " subents of codim = " << codim);
563
564 SPDLOG_LOGGER_TRACE(Logger(), " Subent({}) = [{}], ", codim,
565 cell_subent_idx[codim]);
566 }
567 // Index information for sub-entities with respect to fine mesh
568 // Retrieve indices of vertices of cell on the fine mesh
569 std::array<lf::base::glb_idx_t, 4> vertex_child_idx{
571 for (lf::base::sub_idx_t vt_lidx = 0; vt_lidx < num_vertices; vt_lidx++) {
572 LF_VERIFY_MSG(pt_child_info[cell_subent_idx[2][vt_lidx]].ref_pat ==
573 RefPat::rp_copy,
574 "Vertex must have been copied!");
575 vertex_child_idx[vt_lidx] =
576 pt_child_info[cell_subent_idx[2][vt_lidx]].child_point_idx;
577 }
578
579 // Retrieve indices of midpoints of edges, if they exist
580 std::array<lf::base::glb_idx_t, 4> edge_midpoint_idx{
582 for (lf::base::sub_idx_t ed_lidx = 0; ed_lidx < num_edges; ed_lidx++) {
583 const EdgeChildInfo &ed_ci(ed_child_info[cell_subent_idx[1][ed_lidx]]);
584 if (!ed_ci.child_point_idx.empty()) {
585 LF_VERIFY_MSG(ed_child_info[cell_subent_idx[1][ed_lidx]].ref_pat_ ==
586 RefPat::rp_split,
587 "Edge with a midpoint must have been split");
588 edge_midpoint_idx[ed_lidx] = ed_ci.child_point_idx[0];
589 }
590 } // end loop over local edges
591
592 SPDLOG_LOGGER_TRACE(Logger(), "vt_child_idx = {}, ed_mp_idx = {}",
593 nonstd::span(vertex_child_idx.data(), num_vertices),
594 nonstd::span(edge_midpoint_idx.data(), num_edges));
595
596 // Array of node indices (w.r.t. fine mesh) for sub-cells (triangles or
597 // quadrilaterals)
598 std::vector<std::vector<glb_idx_t>> child_cell_nodes;
599 std::vector<glb_idx_t> tria_ccn_tmp(3);
600 std::vector<glb_idx_t> quad_ccn_tmp(4);
601 // Array of node indices for interior child edges
602 std::vector<std::array<glb_idx_t, 2>> child_edge_nodes;
603 std::array<glb_idx_t, 2> cen_tmp{};
604
605 // Local linking of child entities is very different depending on cell
606 // type and refinement patterns.
607 if (ref_el == lf::base::RefEl::kTria()) {
608 // Case of a triangle
609 switch (cell_refpat) {
610 case RefPat::rp_nil: {
611 LF_VERIFY_MSG(false, "Every triangle must be refined");
612 break;
613 }
614 case RefPat::rp_copy: {
615 // Just copy the parent triangle
616 child_cell_nodes.push_back({vertex_child_idx[0],
617 vertex_child_idx[1],
618 vertex_child_idx[2]});
619 break;
620 }
621 case RefPat::rp_bisect: {
622 LF_VERIFY_MSG(
623 anchor != idx_nil,
624 "Anchor must be set for bisection refinement of triangle");
625 // Splitting a triangle in two by bisecting anchor edge
626 tria_ccn_tmp[0] = vertex_child_idx[mod[0]];
627 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
628 tria_ccn_tmp[2] = vertex_child_idx[mod[2]];
629 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
630 "refpat = " << (int)cell_refpat << ": illegal index");
631 child_cell_nodes.push_back(tria_ccn_tmp);
632
633 tria_ccn_tmp[0] = vertex_child_idx[mod[1]];
634 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
635 tria_ccn_tmp[2] = vertex_child_idx[mod[2]];
636 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
637 "refpat = " << (int)cell_refpat << ": illegal index");
638 child_cell_nodes.push_back(tria_ccn_tmp);
639
640 // edges
641 cen_tmp[0] = edge_midpoint_idx[mod[0]];
642 cen_tmp[1] = vertex_child_idx[mod[2]];
643 child_edge_nodes.push_back(cen_tmp);
644 break;
645 }
646 case RefPat::rp_trisect: {
647 LF_VERIFY_MSG(
648 anchor != idx_nil,
649 "Anchor must be set for trisection refinement of triangle");
650 // Bisect through anchor edge first and then bisect through
651 // edge with the next larger index (mod 3); creates three
652 // child triangles.
653 tria_ccn_tmp[0] = vertex_child_idx[mod[0]];
654 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
655 tria_ccn_tmp[2] = vertex_child_idx[mod[2]];
656 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
657 "refpat = " << (int)cell_refpat << ": illegal index");
658 child_cell_nodes.push_back(tria_ccn_tmp);
659
660 tria_ccn_tmp[0] = vertex_child_idx[mod[1]];
661 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
662 tria_ccn_tmp[2] = edge_midpoint_idx[mod[1]];
663 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
664 "refpat = " << (int)cell_refpat << ": illegal index");
665 child_cell_nodes.push_back(tria_ccn_tmp);
666
667 tria_ccn_tmp[0] = vertex_child_idx[mod[2]];
668 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
669 tria_ccn_tmp[2] = edge_midpoint_idx[mod[1]];
670 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
671 "refpat = " << (int)cell_refpat << ": illegal index");
672 child_cell_nodes.push_back(tria_ccn_tmp);
673
674 // edges
675 cen_tmp[0] = edge_midpoint_idx[mod[0]];
676 cen_tmp[1] = vertex_child_idx[mod[2]];
677 child_edge_nodes.push_back(cen_tmp);
678
679 cen_tmp[0] = edge_midpoint_idx[mod[0]];
680 cen_tmp[1] = edge_midpoint_idx[mod[1]];
681 child_edge_nodes.push_back(cen_tmp);
682 break;
683 }
684 case RefPat::rp_trisect_left: {
685 LF_VERIFY_MSG(
686 anchor != idx_nil,
687 "Anchor must be set for trisection refinement of triangle");
688
689 // Bisect through anchor edge first and then bisect through
690 // edge with the next smaller index (mod 3); creates three
691 // child triangles.
692 tria_ccn_tmp[0] = vertex_child_idx[mod[0]];
693 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
694 tria_ccn_tmp[2] = edge_midpoint_idx[mod[2]];
695 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
696 "refpat = " << (int)cell_refpat << ": illegal index");
697 child_cell_nodes.push_back(tria_ccn_tmp);
698
699 tria_ccn_tmp[0] = vertex_child_idx[mod[1]];
700 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
701 tria_ccn_tmp[2] = vertex_child_idx[mod[2]];
702 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
703 "refpat = " << (int)cell_refpat << ": illegal index");
704 child_cell_nodes.push_back(tria_ccn_tmp);
705
706 tria_ccn_tmp[0] = vertex_child_idx[mod[2]];
707 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
708 tria_ccn_tmp[2] = edge_midpoint_idx[mod[2]];
709 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
710 "refpat = " << (int)cell_refpat << ": illegal index");
711 child_cell_nodes.push_back(tria_ccn_tmp);
712
713 // edges
714 cen_tmp[0] = edge_midpoint_idx[mod[0]];
715 cen_tmp[1] = vertex_child_idx[mod[2]];
716 child_edge_nodes.push_back(cen_tmp);
717
718 cen_tmp[0] = edge_midpoint_idx[mod[0]];
719 cen_tmp[1] = edge_midpoint_idx[mod[2]];
720 child_edge_nodes.push_back(cen_tmp);
721 break;
722 }
723 case RefPat::rp_quadsect: {
724 LF_VERIFY_MSG(
725 anchor != idx_nil,
726 "Anchor must be set for quadsection refinement of triangle");
727 // Bisect through the anchor edge first and then
728 // through the two remaining edges; creates four child
729 // triangles; every edge is split.
730 tria_ccn_tmp[0] = vertex_child_idx[mod[0]];
731 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
732 tria_ccn_tmp[2] = edge_midpoint_idx[mod[2]];
733 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
734 "refpat = " << (int)cell_refpat << ": illegal index");
735 child_cell_nodes.push_back(tria_ccn_tmp);
736
737 tria_ccn_tmp[0] = vertex_child_idx[mod[1]];
738 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
739 tria_ccn_tmp[2] = edge_midpoint_idx[mod[1]];
740 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
741 "refpat = " << (int)cell_refpat << ": illegal index");
742 child_cell_nodes.push_back(tria_ccn_tmp);
743
744 tria_ccn_tmp[0] = vertex_child_idx[mod[2]];
745 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
746 tria_ccn_tmp[2] = edge_midpoint_idx[mod[1]];
747 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
748 "refpat = " << (int)cell_refpat << ": illegal index");
749 child_cell_nodes.push_back(tria_ccn_tmp);
750
751 tria_ccn_tmp[0] = vertex_child_idx[mod[2]];
752 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
753 tria_ccn_tmp[2] = edge_midpoint_idx[mod[2]];
754 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
755 "refpat = " << (int)cell_refpat << ": illegal index");
756 child_cell_nodes.push_back(tria_ccn_tmp);
757
758 // edges
759 cen_tmp[0] = edge_midpoint_idx[mod[0]];
760 cen_tmp[1] = vertex_child_idx[mod[2]];
761 child_edge_nodes.push_back(cen_tmp);
762
763 cen_tmp[0] = edge_midpoint_idx[mod[0]];
764 cen_tmp[1] = edge_midpoint_idx[mod[2]];
765 child_edge_nodes.push_back(cen_tmp);
766
767 cen_tmp[0] = edge_midpoint_idx[mod[0]];
768 cen_tmp[1] = edge_midpoint_idx[mod[1]];
769 child_edge_nodes.push_back(cen_tmp);
770 break;
771 }
772 case RefPat::rp_barycentric: {
773 // Split triangle into 6 smaller triangles by connecting
774 // the center of gravity with the vertices and the midpoints
775 // of the edges.
776 // Create a new interior vertex
777 std::vector<std::unique_ptr<geometry::Geometry>>
778 cell_center_geo_ptrs(cell->Geometry()->ChildGeometry(
779 rp, 2)); // point: co-dim == 2
780 LF_VERIFY_MSG(cell_center_geo_ptrs.size() == 1,
781 "Barycentrically refined triangle with "
782 << cell_center_geo_ptrs.size()
783 << " interior child nodes ??");
784 // Register midpoint as new node
785 const glb_idx_t center_fine_idx =
786 mesh_factory_->AddPoint(std::move(cell_center_geo_ptrs[0]));
787 cell_ci.child_point_idx.push_back(center_fine_idx);
788
789 tria_ccn_tmp[0] = vertex_child_idx[0];
790 tria_ccn_tmp[1] = edge_midpoint_idx[0];
791 tria_ccn_tmp[2] = center_fine_idx;
792 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
793 "refpat = " << (int)cell_refpat << ": illegal index");
794 child_cell_nodes.push_back(tria_ccn_tmp);
795
796 tria_ccn_tmp[0] = vertex_child_idx[1];
797 tria_ccn_tmp[1] = edge_midpoint_idx[0];
798 tria_ccn_tmp[2] = center_fine_idx;
799 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
800 "refpat = " << (int)cell_refpat << ": illegal index");
801 child_cell_nodes.push_back(tria_ccn_tmp);
802
803 tria_ccn_tmp[0] = vertex_child_idx[1];
804 tria_ccn_tmp[1] = edge_midpoint_idx[1];
805 tria_ccn_tmp[2] = center_fine_idx;
806 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
807 "refpat = " << (int)cell_refpat << ": illegal index");
808 child_cell_nodes.push_back(tria_ccn_tmp);
809
810 tria_ccn_tmp[0] = vertex_child_idx[2];
811 tria_ccn_tmp[1] = edge_midpoint_idx[1];
812 tria_ccn_tmp[2] = center_fine_idx;
813 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
814 "refpat = " << (int)cell_refpat << ": illegal index");
815 child_cell_nodes.push_back(tria_ccn_tmp);
816
817 tria_ccn_tmp[0] = vertex_child_idx[2];
818 tria_ccn_tmp[1] = edge_midpoint_idx[2];
819 tria_ccn_tmp[2] = center_fine_idx;
820 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
821 "refpat = " << (int)cell_refpat << ": illegal index");
822 child_cell_nodes.push_back(tria_ccn_tmp);
823
824 tria_ccn_tmp[0] = vertex_child_idx[0];
825 tria_ccn_tmp[1] = edge_midpoint_idx[2];
826 tria_ccn_tmp[2] = center_fine_idx;
827 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
828 "refpat = " << (int)cell_refpat << ": illegal index");
829 child_cell_nodes.push_back(tria_ccn_tmp);
830
831 // edges
832 cen_tmp[0] = vertex_child_idx[0];
833 cen_tmp[1] = center_fine_idx;
834 child_edge_nodes.push_back(cen_tmp);
835
836 cen_tmp[0] = vertex_child_idx[1];
837 cen_tmp[1] = center_fine_idx;
838 child_edge_nodes.push_back(cen_tmp);
839
840 cen_tmp[0] = vertex_child_idx[2];
841 cen_tmp[1] = center_fine_idx;
842 child_edge_nodes.push_back(cen_tmp);
843
844 cen_tmp[0] = edge_midpoint_idx[0];
845 cen_tmp[1] = center_fine_idx;
846 child_edge_nodes.push_back(cen_tmp);
847
848 cen_tmp[0] = edge_midpoint_idx[1];
849 cen_tmp[1] = center_fine_idx;
850 child_edge_nodes.push_back(cen_tmp);
851
852 cen_tmp[0] = edge_midpoint_idx[2];
853 cen_tmp[1] = center_fine_idx;
854 child_edge_nodes.push_back(cen_tmp);
855 break;
856 }
857 case RefPat::rp_regular: {
858 // regular refinement into four congruent triangles
859 // Child cells
860 tria_ccn_tmp[0] = vertex_child_idx[0];
861 tria_ccn_tmp[1] = edge_midpoint_idx[0];
862 tria_ccn_tmp[2] = edge_midpoint_idx[2];
863 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
864 "refpat = " << (int)cell_refpat << ": illegal index");
865 child_cell_nodes.push_back(tria_ccn_tmp);
866
867 tria_ccn_tmp[0] = vertex_child_idx[1];
868 tria_ccn_tmp[1] = edge_midpoint_idx[0];
869 tria_ccn_tmp[2] = edge_midpoint_idx[1];
870 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
871 "refpat = " << (int)cell_refpat << ": illegal index");
872 child_cell_nodes.push_back(tria_ccn_tmp);
873
874 tria_ccn_tmp[0] = vertex_child_idx[2];
875 tria_ccn_tmp[1] = edge_midpoint_idx[2];
876 tria_ccn_tmp[2] = edge_midpoint_idx[1];
877 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
878 "refpat = " << (int)cell_refpat << ": illegal index");
879 child_cell_nodes.push_back(tria_ccn_tmp);
880
881 tria_ccn_tmp[0] = edge_midpoint_idx[0];
882 tria_ccn_tmp[1] = edge_midpoint_idx[1];
883 tria_ccn_tmp[2] = edge_midpoint_idx[2];
884 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
885 "refpat = " << (int)cell_refpat << ": illegal index");
886 child_cell_nodes.push_back(tria_ccn_tmp);
887
888 // Child edges (interior edges)
889 cen_tmp[0] = edge_midpoint_idx[0];
890 cen_tmp[1] = edge_midpoint_idx[2];
891 child_edge_nodes.push_back(cen_tmp);
892
893 cen_tmp[0] = edge_midpoint_idx[0];
894 cen_tmp[1] = edge_midpoint_idx[1];
895 child_edge_nodes.push_back(cen_tmp);
896
897 cen_tmp[0] = edge_midpoint_idx[2];
898 cen_tmp[1] = edge_midpoint_idx[1];
899 child_edge_nodes.push_back(cen_tmp);
900 // No new interior node
901 break;
902 }
903 default: {
904 LF_VERIFY_MSG(
905 false, "Refinement pattern not (yet) implemented for triangle");
906 break;
907 }
908 } // end switch refpat
909 } else if (ref_el == lf::base::RefEl::kQuad()) {
910 // Case of a quadrilateral
911 switch (cell_refpat) {
912 case RefPat::rp_nil: {
913 LF_VERIFY_MSG(false, "Every quadrilateral must be refined");
914 break;
915 }
916 case RefPat::rp_copy: {
917 // Just copy the parent triangle
918 child_cell_nodes.push_back(
919 {vertex_child_idx[0], vertex_child_idx[1], vertex_child_idx[2],
920 vertex_child_idx[3]});
921 break;
922 }
923 case RefPat::rp_trisect: {
924 LF_VERIFY_MSG(
925 anchor != idx_nil,
926 "Anchor must be set for trisection refinement of quad");
927
928 // Partition a quad into three triangle, the anchor edge
929 // being split in the process
930 tria_ccn_tmp[0] = edge_midpoint_idx[mod[0]];
931 tria_ccn_tmp[1] = vertex_child_idx[mod[2]];
932 tria_ccn_tmp[2] = vertex_child_idx[mod[3]];
933 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
934 "refpat = " << (int)cell_refpat << ": illegal index");
935 child_cell_nodes.push_back(tria_ccn_tmp);
936
937 tria_ccn_tmp[0] = edge_midpoint_idx[mod[0]];
938 tria_ccn_tmp[1] = vertex_child_idx[mod[0]];
939 tria_ccn_tmp[2] = vertex_child_idx[mod[3]];
940 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
941 "refpat = " << (int)cell_refpat << ": illegal index");
942 child_cell_nodes.push_back(tria_ccn_tmp);
943
944 tria_ccn_tmp[0] = edge_midpoint_idx[mod[0]];
945 tria_ccn_tmp[1] = vertex_child_idx[mod[1]];
946 tria_ccn_tmp[2] = vertex_child_idx[mod[2]];
947 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
948 "refpat = " << (int)cell_refpat << ": illegal index");
949 child_cell_nodes.push_back(tria_ccn_tmp);
950
951 // edges
952 cen_tmp[0] = edge_midpoint_idx[mod[0]];
953 cen_tmp[1] = vertex_child_idx[mod[2]];
954 child_edge_nodes.push_back(cen_tmp);
955
956 cen_tmp[0] = edge_midpoint_idx[mod[0]];
957 cen_tmp[1] = vertex_child_idx[mod[3]];
958 child_edge_nodes.push_back(cen_tmp);
959 break;
960 }
961 case RefPat::rp_quadsect: {
962 LF_VERIFY_MSG(
963 anchor != idx_nil,
964 "Anchor must be set for quadsection refinement of triangle");
965 // Partition a quad into four triangle, thus
966 // splitting two edges. The one with the smaller sub index is the
967 // anchor edge
968 tria_ccn_tmp[0] = vertex_child_idx[mod[0]];
969 tria_ccn_tmp[1] = vertex_child_idx[mod[3]];
970 tria_ccn_tmp[2] = edge_midpoint_idx[mod[0]];
971 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
972 "refpat = " << (int)cell_refpat << ": illegal index");
973 child_cell_nodes.push_back(tria_ccn_tmp);
974
975 tria_ccn_tmp[0] = vertex_child_idx[mod[1]];
976 tria_ccn_tmp[1] = edge_midpoint_idx[mod[1]];
977 tria_ccn_tmp[2] = edge_midpoint_idx[mod[0]];
978 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
979 "refpat = " << (int)cell_refpat << ": illegal index");
980 child_cell_nodes.push_back(tria_ccn_tmp);
981
982 tria_ccn_tmp[0] = vertex_child_idx[mod[2]];
983 tria_ccn_tmp[1] = vertex_child_idx[mod[3]];
984 tria_ccn_tmp[2] = edge_midpoint_idx[mod[1]];
985 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
986 "refpat = " << (int)cell_refpat << ": illegal index");
987 child_cell_nodes.push_back(tria_ccn_tmp);
988
989 tria_ccn_tmp[0] = edge_midpoint_idx[mod[0]];
990 tria_ccn_tmp[1] = edge_midpoint_idx[mod[1]];
991 tria_ccn_tmp[2] = vertex_child_idx[mod[3]];
992 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
993 "refpat = " << (int)cell_refpat << ": illegal index");
994 child_cell_nodes.push_back(tria_ccn_tmp);
995
996 // edges
997 cen_tmp[0] = vertex_child_idx[mod[3]];
998 cen_tmp[1] = edge_midpoint_idx[mod[0]];
999 child_edge_nodes.push_back(cen_tmp);
1000
1001 cen_tmp[0] = edge_midpoint_idx[mod[1]];
1002 cen_tmp[1] = edge_midpoint_idx[mod[0]];
1003 child_edge_nodes.push_back(cen_tmp);
1004
1005 cen_tmp[0] = vertex_child_idx[mod[3]];
1006 cen_tmp[1] = edge_midpoint_idx[mod[1]];
1007 child_edge_nodes.push_back(cen_tmp);
1008 break;
1009 }
1010 case RefPat::rp_bisect:
1011 case RefPat::rp_split: {
1012 LF_VERIFY_MSG(anchor != idx_nil,
1013 "Anchor must be set for splitting of quad");
1014
1015 // Cut a quadrilateral into two
1016 quad_ccn_tmp[0] = vertex_child_idx[mod[0]];
1017 quad_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
1018 quad_ccn_tmp[2] = edge_midpoint_idx[mod[2]];
1019 quad_ccn_tmp[3] = vertex_child_idx[mod[3]];
1020 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1021 "refpat = " << (int)cell_refpat << ": illegal index");
1022 child_cell_nodes.push_back(quad_ccn_tmp);
1023
1024 quad_ccn_tmp[0] = vertex_child_idx[mod[1]];
1025 quad_ccn_tmp[1] = vertex_child_idx[mod[2]];
1026 quad_ccn_tmp[2] = edge_midpoint_idx[mod[2]];
1027 quad_ccn_tmp[3] = edge_midpoint_idx[mod[0]];
1028 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1029 "refpat = " << (int)cell_refpat << ": illegal index");
1030 child_cell_nodes.push_back(quad_ccn_tmp);
1031
1032 // edges
1033 cen_tmp[0] = edge_midpoint_idx[mod[0]];
1034 cen_tmp[1] = edge_midpoint_idx[mod[2]];
1035 child_edge_nodes.push_back(cen_tmp);
1036 break;
1037 }
1038 case RefPat::rp_threeedge: {
1039 LF_VERIFY_MSG(
1040 anchor != idx_nil,
1041 "Anchor must be set for three edge refinement of a quad");
1042
1043 quad_ccn_tmp[0] = vertex_child_idx[mod[2]];
1044 quad_ccn_tmp[1] = vertex_child_idx[mod[3]];
1045 quad_ccn_tmp[2] = edge_midpoint_idx[mod[3]];
1046 quad_ccn_tmp[3] = edge_midpoint_idx[mod[1]];
1047 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1048 "refpat = " << (int)cell_refpat << ": illegal index");
1049 child_cell_nodes.push_back(quad_ccn_tmp);
1050
1051 tria_ccn_tmp[0] = vertex_child_idx[mod[0]];
1052 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
1053 tria_ccn_tmp[2] = edge_midpoint_idx[mod[3]];
1054 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
1055 "refpat = " << (int)cell_refpat << ": illegal index");
1056 child_cell_nodes.push_back(tria_ccn_tmp);
1057
1058 tria_ccn_tmp[0] = vertex_child_idx[mod[1]];
1059 tria_ccn_tmp[1] = edge_midpoint_idx[mod[0]];
1060 tria_ccn_tmp[2] = edge_midpoint_idx[mod[1]];
1061 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
1062 "refpat = " << (int)cell_refpat << ": illegal index");
1063 child_cell_nodes.push_back(tria_ccn_tmp);
1064
1065 tria_ccn_tmp[0] = edge_midpoint_idx[mod[0]];
1066 tria_ccn_tmp[1] = edge_midpoint_idx[mod[1]];
1067 tria_ccn_tmp[2] = edge_midpoint_idx[mod[3]];
1068 LF_ASSERT_MSG(checkValidIndex(tria_ccn_tmp),
1069 "refpat = " << (int)cell_refpat << ": illegal index");
1070 child_cell_nodes.push_back(tria_ccn_tmp);
1071
1072 // edges
1073 cen_tmp[0] = edge_midpoint_idx[mod[3]];
1074 cen_tmp[1] = edge_midpoint_idx[mod[1]];
1075 child_edge_nodes.push_back(cen_tmp);
1076
1077 cen_tmp[0] = edge_midpoint_idx[mod[0]];
1078 cen_tmp[1] = edge_midpoint_idx[mod[3]];
1079 child_edge_nodes.push_back(cen_tmp);
1080
1081 cen_tmp[0] = edge_midpoint_idx[mod[0]];
1082 cen_tmp[1] = edge_midpoint_idx[mod[1]];
1083 child_edge_nodes.push_back(cen_tmp);
1084 break;
1085 }
1086 case RefPat::rp_barycentric:
1087 case RefPat::rp_regular: {
1088 // Create a new interior vertex
1089 std::vector<std::unique_ptr<geometry::Geometry>>
1090 cell_center_geo_ptrs(cell->Geometry()->ChildGeometry(
1091 rp, 2)); // point: co-dim == 2
1092 LF_VERIFY_MSG(cell_center_geo_ptrs.size() == 1,
1093 "Regularly refined quadrilateral with "
1094 << cell_center_geo_ptrs.size()
1095 << " interior child nodes!");
1096 // Register midpoint as new node
1097 const glb_idx_t center_fine_idx =
1098 mesh_factory_->AddPoint(std::move(cell_center_geo_ptrs[0]));
1099 cell_ci.child_point_idx.push_back(center_fine_idx);
1100
1101 // Set the node indices (w.r.t. fine mesh) of the four sub-quads
1102 quad_ccn_tmp[0] = vertex_child_idx[0];
1103 quad_ccn_tmp[1] = edge_midpoint_idx[0];
1104 quad_ccn_tmp[2] = center_fine_idx;
1105 quad_ccn_tmp[3] = edge_midpoint_idx[3];
1106 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1107 "refpat = " << (int)cell_refpat << ": illegal index");
1108 child_cell_nodes.push_back(quad_ccn_tmp);
1109
1110 quad_ccn_tmp[0] = vertex_child_idx[1];
1111 quad_ccn_tmp[1] = edge_midpoint_idx[1];
1112 quad_ccn_tmp[2] = center_fine_idx;
1113 quad_ccn_tmp[3] = edge_midpoint_idx[0];
1114 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1115 "refpat = " << (int)cell_refpat << ": illegal index");
1116 child_cell_nodes.push_back(quad_ccn_tmp);
1117
1118 quad_ccn_tmp[0] = vertex_child_idx[2];
1119 quad_ccn_tmp[1] = edge_midpoint_idx[1];
1120 quad_ccn_tmp[2] = center_fine_idx;
1121 quad_ccn_tmp[3] = edge_midpoint_idx[2];
1122 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1123 "refpat = " << (int)cell_refpat << ": illegal index");
1124 child_cell_nodes.push_back(quad_ccn_tmp);
1125
1126 quad_ccn_tmp[0] = vertex_child_idx[3];
1127 quad_ccn_tmp[1] = edge_midpoint_idx[2];
1128 quad_ccn_tmp[2] = center_fine_idx;
1129 quad_ccn_tmp[3] = edge_midpoint_idx[3];
1130 LF_ASSERT_MSG(checkValidIndex(quad_ccn_tmp),
1131 "refpat = " << (int)cell_refpat << ": illegal index");
1132 child_cell_nodes.push_back(quad_ccn_tmp);
1133
1134 // set node indices of the four new interior edges
1135 cen_tmp[0] = edge_midpoint_idx[0];
1136 cen_tmp[1] = center_fine_idx;
1137 child_edge_nodes.push_back(cen_tmp);
1138
1139 cen_tmp[0] = edge_midpoint_idx[1];
1140 cen_tmp[1] = center_fine_idx;
1141 child_edge_nodes.push_back(cen_tmp);
1142
1143 cen_tmp[0] = edge_midpoint_idx[2];
1144 cen_tmp[1] = center_fine_idx;
1145 child_edge_nodes.push_back(cen_tmp);
1146
1147 cen_tmp[0] = edge_midpoint_idx[3];
1148 cen_tmp[1] = center_fine_idx;
1149 child_edge_nodes.push_back(cen_tmp);
1150 break;
1151 }
1152 default: {
1153 LF_VERIFY_MSG(
1154 false,
1155 "Refinement pattern not (yet) implemented for quadrilateral");
1156 break;
1157 }
1158 } // end switch cell_refpat
1159 } // end quadrilateral case
1160 else {
1161 LF_VERIFY_MSG(false, "Unknown cell type" << ref_el.ToString());
1162 }
1163 // Register new edges
1164 {
1165 std::vector<std::unique_ptr<geometry::Geometry>> cell_edge_geo_ptrs(
1166 cell->Geometry()->ChildGeometry(rp, 1)); // child edge: co-dim == 1
1167 const size_type num_new_edges = child_edge_nodes.size();
1168 LF_VERIFY_MSG(num_new_edges == rp.NumChildren(1),
1169 "num_new_edges = " << num_new_edges << " <-> "
1170 << rp.NumChildren(1));
1171 for (int k = 0; k < num_new_edges; k++) {
1172 const std::array<glb_idx_t, 2> &cen(child_edge_nodes[k]);
1173 SPDLOG_LOGGER_TRACE(
1174 Logger(), "{}({}), ref_pat = {}: new edge {}[{},{}]", ref_el,
1175 cell_index, (int)cell_refpat, k, cen[0], cen[1]);
1176
1177 const glb_idx_t new_edge_index = mesh_factory_->AddEntity(
1179 std::array<base::glb_idx_t, 2>{{cen[0], cen[1]}},
1180 std::move(cell_edge_geo_ptrs[k]));
1181 cell_ci.child_edge_idx.push_back(new_edge_index);
1182 } // end loop over new edges
1183 } // end register new edges
1184 // Register new cells
1185 {
1186 std::vector<std::unique_ptr<geometry::Geometry>> childcell_geo_ptrs(
1187 cell->Geometry()->ChildGeometry(rp, 0)); // child cell: co-dim == 0
1188 const size_type num_new_cells = child_cell_nodes.size();
1189 LF_VERIFY_MSG(num_new_cells == rp.NumChildren(0),
1190 "num_new_cells = " << num_new_cells << " <-> "
1191 << rp.NumChildren(0));
1192 for (int k = 0; k < num_new_cells; k++) {
1193 const std::vector<glb_idx_t> &ccn(child_cell_nodes[k]);
1194 glb_idx_t new_cell_index;
1195 if (ccn.size() == 3) {
1196 // New cell is a triangle
1197 SPDLOG_LOGGER_TRACE(
1198 Logger(), "{}({}), ref_pat = {}: new triangle {}[{},{},{}]",
1199 ref_el, cell_index, (int)cell_refpat, k, ccn[0], ccn[1],
1200 ccn[2]);
1201
1202 new_cell_index = mesh_factory_->AddEntity(
1204 std::array<base::glb_idx_t, 3>{ccn[0], ccn[1], ccn[2]},
1205 std::move(childcell_geo_ptrs[k]));
1206 } else if (ccn.size() == 4) {
1207 // New cell is a quadrilateral
1208 SPDLOG_LOGGER_TRACE(
1209 Logger(), "{}({}), ref_pat = {}: new quad {}[{},{},{},{}]",
1210 ref_el, cell_index, (int)cell_refpat, k, ccn[0], ccn[1], ccn[2],
1211 ccn[3]);
1212
1213 new_cell_index =
1214 mesh_factory_->AddEntity(lf::base::RefEl::kQuad(),
1215 std::array<base::glb_idx_t, 4>{
1216 {ccn[0], ccn[1], ccn[2], ccn[3]}},
1217 std::move(childcell_geo_ptrs[k]));
1218 } else {
1219 LF_VERIFY_MSG(false,
1220 "Child cells must be either triangles or quads");
1221 }
1222 cell_ci.child_cell_idx.push_back(new_cell_index);
1223 } // end loop over new cells
1224 } // end register new cells
1225 } // end loop over cells
1226 }
1227 // At this point the MeshFactory has complete information to generate the new
1228 // finest mesh
1229 meshes_.push_back(mesh_factory_->Build()); // MESH CONSTRUCTION
1230 mesh::Mesh &child_mesh(*meshes_.back());
1231
1232 SPDLOG_LOGGER_DEBUG(Logger(), "Child mesh {} nodes, {} edges, {} cells.",
1233 child_mesh.NumEntities(2), child_mesh.NumEntities(1),
1234 child_mesh.NumEntities(0));
1235
1236 // Create space for data pertaining to the new mesh
1237 // Note that references to vectors may become invalid
1238 {
1239 // Arrays containing parent information
1240 parent_infos_.push_back(
1241 {std::move(std::vector<ParentInfo>(child_mesh.NumEntities(0))),
1242 std::move(std::vector<ParentInfo>(child_mesh.NumEntities(1))),
1243 std::move(std::vector<ParentInfo>(child_mesh.NumEntities(2)))});
1244
1245 // Initialize (empty) refinement information for newly created fine mesh
1246 // Same code as in the constructor of MeshHierarchy
1247 std::vector<CellChildInfo> fine_cell_child_info(child_mesh.NumEntities(0));
1248 std::vector<EdgeChildInfo> fine_edge_child_info(child_mesh.NumEntities(1));
1249 std::vector<PointChildInfo> fine_point_child_info(
1250 child_mesh.NumEntities(2));
1251 cell_child_infos_.push_back(std::move(fine_cell_child_info));
1252 edge_child_infos_.push_back(std::move(fine_edge_child_info));
1253 point_child_infos_.push_back(std::move(fine_point_child_info));
1254
1255 // Array containing information about refinement edges
1256 refinement_edges_.push_back(
1257 std::move(std::vector<sub_idx_t>(child_mesh.NumEntities(0), idx_nil)));
1258
1259 // Finally set up vector for edge flags
1260 edge_marked_.emplace_back(child_mesh.NumEntities(1), false);
1261 }
1262
1263 // Finally, we have to initialize the parent pointers for the entities of the
1264 // newly created finest mesh.
1265 {
1266 const size_type n_levels = meshes_.size();
1267 LF_VERIFY_MSG(n_levels > 1, "A least two levels after refinement");
1268 // Access parent information for finest level
1269 std::vector<ParentInfo> &fine_node_parent_info(parent_infos_.back()[2]);
1270 std::vector<ParentInfo> &fine_edge_parent_info(parent_infos_.back()[1]);
1271 std::vector<ParentInfo> &fine_cell_parent_info(parent_infos_.back()[0]);
1272
1273 LF_VERIFY_MSG(fine_node_parent_info.size() == child_mesh.NumEntities(2),
1274 "fine_node_parent_info size mismatch");
1275 LF_VERIFY_MSG(fine_edge_parent_info.size() == child_mesh.NumEntities(1),
1276 "fine_edge_parent_info size mismatch");
1277 LF_VERIFY_MSG(fine_cell_parent_info.size() == child_mesh.NumEntities(0),
1278 "fine_edge_parent_info size mismatch");
1279
1280 // Visit all nodes of the parent mesh and retrieve their children by index
1281 std::vector<PointChildInfo> &pt_child_info(
1282 point_child_infos_.at(n_levels - 2));
1283 for (const mesh::Entity *node : parent_mesh.Entities(2)) {
1284 // Obtain index of node in coarse mesh
1285 const glb_idx_t node_index = parent_mesh.Index(*node);
1286 const glb_idx_t child_index = pt_child_info[node_index].child_point_idx;
1287 if (child_index != idx_nil) {
1288 LF_VERIFY_MSG(child_index < fine_node_parent_info.size(),
1289 "index " << child_index << " illegal for child vertex");
1290 fine_node_parent_info[child_index].child_number = 0;
1291 fine_node_parent_info[child_index].parent_ptr = node;
1292 fine_node_parent_info[child_index].parent_index = node_index;
1293 }
1294 } // end loop over nodes
1295
1296 // Traverse edges and set the parent for their interior nodes and child
1297 // edges
1298 std::vector<EdgeChildInfo> &ed_child_info(
1299 edge_child_infos_.at(n_levels - 2));
1300 for (const mesh::Entity *edge : parent_mesh.Entities(1)) {
1301 // Obtain index of edge in coarse mesh
1302 const glb_idx_t edge_index = parent_mesh.Index(*edge);
1303 const EdgeChildInfo &ci_edge(ed_child_info[edge_index]);
1304
1305 // Visit child edges
1306 const size_type num_child_edges = ci_edge.child_edge_idx.size();
1307 for (int l = 0; l < num_child_edges; l++) {
1308 const glb_idx_t edge_child_idx = ci_edge.child_edge_idx[l];
1309 LF_VERIFY_MSG(edge_child_idx < fine_edge_parent_info.size(),
1310 "index " << edge_child_idx << " illegal for child edge");
1311 fine_edge_parent_info[edge_child_idx].child_number = l;
1312 fine_edge_parent_info[edge_child_idx].parent_ptr = edge;
1313 fine_edge_parent_info[edge_child_idx].parent_index = edge_index;
1314 } // end loop over child edges
1315
1316 // Visit child nodes
1317 const size_type num_child_nodes = ci_edge.child_point_idx.size();
1318 for (int l = 0; l < num_child_nodes; l++) {
1319 const glb_idx_t node_child_idx = ci_edge.child_point_idx[l];
1320 LF_VERIFY_MSG(node_child_idx < fine_node_parent_info.size(),
1321 "index " << node_child_idx << " illegal for child point");
1322 fine_node_parent_info[node_child_idx].child_number = l;
1323 fine_node_parent_info[node_child_idx].parent_ptr = edge;
1324 fine_node_parent_info[node_child_idx].parent_index = edge_index;
1325 } // end loop over child points
1326 } // end loop over edges
1327
1328 // Loop over cells
1329 std::vector<CellChildInfo> &cell_child_info(
1330 cell_child_infos_.at(n_levels - 2));
1331 for (const mesh::Entity *cell : parent_mesh.Entities(0)) {
1332 // fetch index of current cell
1333 const glb_idx_t cell_index(parent_mesh.Index(*cell));
1334 // Get infformation about children
1335 CellChildInfo &cell_ci(cell_child_info[cell_index]);
1336
1337 // Visit child cells
1338 const size_type num_child_cells = cell_ci.child_cell_idx.size();
1339 for (int l = 0; l < num_child_cells; l++) {
1340 const glb_idx_t child_cell_idx = cell_ci.child_cell_idx[l];
1341 LF_VERIFY_MSG(child_cell_idx < fine_cell_parent_info.size(),
1342 "index " << child_cell_idx << " illegal for child cell");
1343 fine_cell_parent_info[child_cell_idx].child_number = l;
1344 fine_cell_parent_info[child_cell_idx].parent_ptr = cell;
1345 fine_cell_parent_info[child_cell_idx].parent_index = cell_index;
1346 }
1347
1348 // Visit child edges
1349 const size_type num_child_edges = cell_ci.child_edge_idx.size();
1350 for (int l = 0; l < num_child_edges; l++) {
1351 const glb_idx_t edge_child_idx = cell_ci.child_edge_idx[l];
1352 LF_VERIFY_MSG(edge_child_idx < fine_edge_parent_info.size(),
1353 "index " << edge_child_idx << " illegal for child edge");
1354 fine_edge_parent_info[edge_child_idx].child_number = l;
1355 fine_edge_parent_info[edge_child_idx].parent_ptr = cell;
1356 fine_edge_parent_info[edge_child_idx].parent_index = cell_index;
1357 } // end loop over child edges
1358
1359 // Visit child nodes
1360 const size_type num_child_nodes = cell_ci.child_point_idx.size();
1361 for (int l = 0; l < num_child_nodes; l++) {
1362 const glb_idx_t node_child_idx = cell_ci.child_point_idx[l];
1363 LF_VERIFY_MSG(node_child_idx < fine_node_parent_info.size(),
1364 "index " << node_child_idx << " illegal for child point");
1365 fine_node_parent_info[node_child_idx].child_number = l;
1366 fine_node_parent_info[node_child_idx].parent_ptr = cell;
1367 fine_node_parent_info[node_child_idx].parent_index = cell_index;
1368 } // end loop over child points
1369 } // end loop over cells of parent mesh
1370 }
1371
1372 // Finally set refinement edges for fine mesh
1373 {
1374 size_type n_levels = meshes_.size();
1375 LF_VERIFY_MSG(n_levels > 1, "At least two levels after refinement!");
1376 std::vector<sub_idx_t> &child_ref_edges(refinement_edges_.at(n_levels - 1));
1377 std::vector<ParentInfo> &cell_parent_info(
1378 parent_infos_.at(n_levels - 1)[0]);
1379 std::vector<CellChildInfo> &parent_cell_ci(
1380 cell_child_infos_.at(n_levels - 2));
1381 std::vector<sub_idx_t> &parent_ref_edges(
1382 refinement_edges_.at(n_levels - 2));
1383
1384 // Traverse the cells of the fine mesh
1385 SPDLOG_LOGGER_DEBUG(Logger(), "Setting refinement edges");
1386
1387 for (const mesh::Entity *fine_cell : child_mesh.Entities(0)) {
1388 const glb_idx_t cell_index = child_mesh.Index(*fine_cell);
1389 child_ref_edges[cell_index] = idx_nil;
1390 // Refinement edge relevant for triangles onyl
1391 if (fine_cell->RefEl() == lf::base::RefEl::kTria()) {
1392 // pointer to cell whose refinement has created the current one
1393 const mesh::Entity *parent_ptr =
1394 cell_parent_info[cell_index].parent_ptr;
1395 LF_VERIFY_MSG(parent_ptr != nullptr,
1396 "Cell " << cell_index << " has no parent, paren_index = "
1397 << cell_parent_info[cell_index].parent_index);
1398
1399 if (parent_ptr->RefEl() == lf::base::RefEl::kTria()) {
1400 // Current cell was created by splitting a triangle
1401 // Inheritance rules for refinement edges apply
1402 // Together with refinement pattern allows identification of child
1403 // cell
1404 const sub_idx_t fine_cell_child_number =
1405 (parent_infos_.back())[0][cell_index].child_number;
1406 const glb_idx_t parent_index = parent_mesh.Index(*parent_ptr);
1407 LF_VERIFY_MSG(parent_index < parent_mesh.NumEntities(0),
1408 "parent_index = " << parent_index << " out of range");
1409
1410 SPDLOG_LOGGER_TRACE(Logger(),
1411 "Cell {}: triangle child {} of parent {}",
1412 cell_index, fine_cell_child_number, parent_index);
1413
1414 const CellChildInfo &parent_ci(parent_cell_ci[parent_index]);
1415 LF_VERIFY_MSG(
1416 parent_ci.child_cell_idx[fine_cell_child_number] == cell_index,
1417 "Parent child index mismatch!");
1418 const RefPat parent_ref_pat = parent_ci.ref_pat_;
1419
1420 switch (parent_ref_pat) {
1421 case RefPat::rp_nil: {
1422 LF_VERIFY_MSG(false,
1423 "Parent cannot carry nil refinement pattern");
1424 break;
1425 }
1426 case RefPat::rp_copy: {
1427 // Inherit refinement edge from parent triangle
1428 child_ref_edges[cell_index] = parent_ref_edges[parent_index];
1429 break;
1430 }
1431 case RefPat::rp_bisect: {
1432 // Both children have refinement edge 2
1433 LF_VERIFY_MSG(fine_cell_child_number < 2,
1434 "Only 2 children for rp_bisect");
1435 child_ref_edges[cell_index] = 2;
1436 break;
1437 }
1438 case RefPat::rp_trisect: {
1439 // Refinement edges: 0 -> 2, 1 -> 1, 2 -> 0
1440 LF_VERIFY_MSG(fine_cell_child_number < 3,
1441 "Only 3 children for rp_trisect");
1442 switch (fine_cell_child_number) {
1443 case 0: {
1444 child_ref_edges[cell_index] = 2;
1445 break;
1446 }
1447 case 1: {
1448 child_ref_edges[cell_index] = 1;
1449 break;
1450 }
1451 case 2: {
1452 child_ref_edges[cell_index] = 0;
1453 break;
1454 }
1455 default:
1456 LF_VERIFY_MSG(false,
1457 "invalid value for fine_cell_child_number");
1458 }
1459 break;
1460 }
1461 case RefPat::rp_trisect_left: {
1462 // Refinement edges: 0 -> 2, 1 -> 1, 2 -> 0
1463 LF_VERIFY_MSG(fine_cell_child_number < 4,
1464 "Only 3 children for rp_quadsect");
1465 switch (fine_cell_child_number) {
1466 case 0:
1467 case 1: {
1468 child_ref_edges[cell_index] = 2;
1469 break;
1470 }
1471 case 2: {
1472 child_ref_edges[cell_index] = 0;
1473 break;
1474 }
1475 default:
1476 LF_VERIFY_MSG(false,
1477 "invalid value for fine_cell_child_number");
1478 }
1479 break;
1480 }
1481 case RefPat::rp_quadsect: {
1482 // Refinement edges: 0 -> 2, 1 -> 0, 2 -> 0, 3-> 0
1483 switch (fine_cell_child_number) {
1484 case 0: {
1485 child_ref_edges[cell_index] = 2;
1486 break;
1487 }
1488 case 1:
1489 case 2:
1490 case 3: {
1491 child_ref_edges[cell_index] = 0;
1492 break;
1493 }
1494 default: {
1495 LF_VERIFY_MSG(false, "Illegal child number");
1496 break;
1497 }
1498 }
1499 break;
1500 }
1501 case rp_regular: {
1502 // Inherit the refinement edge of the parent triangle
1503 const sub_idx_t parent_ref_edge_idx =
1504 parent_ref_edges[parent_index];
1505 switch (parent_ref_edge_idx) {
1506 case 0: {
1507 switch (fine_cell_child_number) {
1508 case 0:
1509 case 1: {
1510 child_ref_edges[cell_index] = 0;
1511 break;
1512 }
1513 case 2:
1514 case 3: {
1515 child_ref_edges[cell_index] = 1;
1516 break;
1517 }
1518 default: {
1519 LF_VERIFY_MSG(false, "Illegal child number");
1520 break;
1521 }
1522 }
1523 break;
1524 }
1525 case 1: {
1526 switch (fine_cell_child_number) {
1527 case 0: {
1528 child_ref_edges[cell_index] = 1;
1529 break;
1530 }
1531 case 1:
1532 case 2:
1533 case 3: {
1534 child_ref_edges[cell_index] = 2;
1535 break;
1536 }
1537 default: {
1538 LF_VERIFY_MSG(false, "Illegal child number");
1539 break;
1540 }
1541 }
1542 break;
1543 }
1544 case 2: {
1545 switch (fine_cell_child_number) {
1546 case 0: {
1547 child_ref_edges[cell_index] = 2;
1548 break;
1549 }
1550 case 1: {
1551 child_ref_edges[cell_index] = 1;
1552 break;
1553 }
1554 case 2:
1555 case 3: {
1556 child_ref_edges[cell_index] = 0;
1557 break;
1558 }
1559 default: {
1560 LF_VERIFY_MSG(false, "Illegal child number");
1561 break;
1562 }
1563 }
1564 break;
1565 }
1566 default:
1567 LF_VERIFY_MSG(false, "invalid parent_ref_edge_idx")
1568 } // end switch parent ref_edge_idx
1569 break;
1570 }
1571 case rp_barycentric: {
1572 // In the case of barycentric refinement choose the longest edge
1573 // as refinement edge for every child triangle
1574 child_ref_edges[cell_index] = LongestEdge(*fine_cell);
1575 break;
1576 }
1577 default: {
1578 LF_VERIFY_MSG(false, "Illegal refinement type for a triangle");
1579 break;
1580 }
1581 } // end switch parent_ref_pat
1582
1583 SPDLOG_LOGGER_TRACE(Logger(), "ref_pat = {}({}) ref edge = {}",
1584 (int)parent_ref_pat, parent_ref_pat,
1585 child_ref_edges[cell_index]);
1586
1587 } // end treatment of triangular child cell
1588 else if (parent_ptr->RefEl() == lf::base::RefEl::kQuad()) {
1589 // Parent is a quadrilateral:
1590 // refinement edge will be set to the longest edge
1591 child_ref_edges[cell_index] = LongestEdge(*fine_cell);
1592 } else {
1593 LF_VERIFY_MSG(false, "Unknown parent cell type");
1594 }
1595 }
1596 }
1597 }
1598} // end Perform Refinement
1599
1600// **********************************************************************
1601// Initialization of rel_ref_geo fields of ParentInfo structures
1602// **********************************************************************
1603void MeshHierarchy::initGeometryInParent() {
1604 // number of meshes contained in the hierarchy
1605 const size_type num_levels = NumLevels();
1606 SPDLOG_LOGGER_DEBUG(Logger(),
1607 "Entering MeshHierarchy::initGeometryInParent: {} levels",
1608 num_levels);
1609
1610 // Invoking this function makes sense only if the finest mesh has been
1611 // created by refinement.
1612 LF_ASSERT_MSG(num_levels > 1, "Must have been refined at least once");
1613 // Obtain references to finest and second finest mesh
1614 const lf::mesh::Mesh &parent_mesh{*meshes_.at(num_levels - 2)};
1615 const lf::mesh::Mesh &child_mesh{*meshes_.at(num_levels - 1)};
1616 // Partly intialized vectors of child information
1617 std::vector<PointChildInfo> &pt_child_info{
1618 point_child_infos_.at(num_levels - 2)};
1619 std::vector<EdgeChildInfo> &ed_child_info{
1620 edge_child_infos_.at(num_levels - 2)};
1621 std::vector<CellChildInfo> &cell_child_info{
1622 cell_child_infos_.at(num_levels - 2)};
1623 // Dummy relative geometry for a point in a point
1624 const Eigen::MatrixXd nil_coords(0, 1);
1625
1626 // Visit all entities of the fine mesh. Outer loop covers co-dimensions
1627 // starting with cells (codim = 0)
1628 for (dim_t codim = 0; codim <= 2; ++codim) {
1629 // Reference to ParentInfo vector for entities of co-dimension codim
1630 // of the new mesh
1631 std::vector<ParentInfo> &child_entities_parent_info(
1632 parent_infos_.back()[codim]);
1633 // Loop over all nodes of the new mesh (co-dimension = 2)
1634 for (const lf::mesh::Entity *child_entity : child_mesh.Entities(codim)) {
1635 // Obtain index of the child entity
1636 const glb_idx_t child_idx = child_mesh.Index(*child_entity);
1637 // Obtain ParentInfo for the current child entity
1638 ParentInfo &child_pi{child_entities_parent_info[child_idx]};
1639 LF_ASSERT_MSG(child_pi.rel_ref_geo_ == nullptr,
1640 "No double initialization of rel_ref_geo_");
1641 // Get number of child
1642 const sub_idx_t child_number = child_pi.child_number;
1643 LF_ASSERT_MSG(child_number != idx_nil, "Child number missing");
1644 // Obtain parent entity
1645 LF_ASSERT_MSG(child_pi.parent_ptr != nullptr, "No valid parent pointer");
1646 const lf::mesh::Entity &parent{*child_pi.parent_ptr};
1647 // Obtain type of parent entity
1648 const lf::base::RefEl parent_ref_el(parent.RefEl());
1649 // Obtain co-dimension of parent entity
1650 const dim_t parent_codim = parent.Codim();
1651 // Index of parent entity
1652 const glb_idx_t parent_idx = parent_mesh.Index(parent);
1653 // Difference in co-dimensions
1654 LF_ASSERT_MSG(parent_codim <= codim, "Paren codim > child codim!");
1655 const dim_t child_rel_codim = codim - parent_codim;
1656 // Obtain local geometry of child. To that end we have to do
1657 // different things for different parent types
1658 switch (parent_codim) {
1659 case 0: { // the parent entity is a cell
1660 // Fetch refinement information
1661 const CellChildInfo &parent_child_info{cell_child_info[parent_idx]};
1662 const RefPat parent_ref_pat{parent_child_info.ref_pat_};
1663 const sub_idx_t anchor{parent_child_info.anchor_};
1664 // Obtain geometry of child
1665 const Hybrid2DRefinementPattern rp(parent_ref_el, parent_ref_pat,
1666 anchor);
1667 const std::vector<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>>
1668 child_polygon_vec{rp.ChildPolygons(child_rel_codim)};
1669 LF_ASSERT_MSG(child_number < child_polygon_vec.size(),
1670 "Child number = " << child_number << " >= "
1671 << child_polygon_vec.size());
1672 const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>
1673 &child_polygon{child_polygon_vec[child_number]};
1674 LF_ASSERT_MSG(child_polygon.rows() == 2,
1675 "Need two coordinates in parent cell");
1676 // Matrix containing the relative reference coordinates of the
1677 // child's corners in its columns
1678 const Eigen::MatrixXd child_corners =
1679 child_polygon.cast<double>() /
1680 static_cast<double>(rp.LatticeConst());
1681 switch (codim) {
1682 case 0: { // cell in cell
1683 LF_ASSERT_MSG(parent_child_info.child_cell_idx.at(child_number) ==
1684 child_idx,
1685 "parent_child_info.child_cell_idx.at("
1686 << child_number << " ) !== child_idx");
1687 switch (child_corners.cols()) {
1688 case 3: { // Child is a triangle
1689 LF_ASSERT_MSG(
1690 child_entity->RefEl() == lf::base::RefEl::kTria(),
1691 "Must be triangle!");
1692 SPDLOG_LOGGER_TRACE(Logger(), "Triangle in {}: geo = {}",
1693 parent_ref_el, child_corners);
1694
1695 child_pi.rel_ref_geo_ =
1696 std::make_unique<lf::geometry::TriaO1>(child_corners);
1697 break;
1698 }
1699 case 4: { // Child is a quadrilateral
1700 LF_ASSERT_MSG(
1701 child_entity->RefEl() == lf::base::RefEl::kQuad(),
1702 "Must be quad!");
1703 SPDLOG_LOGGER_TRACE(Logger(), "Quad in {}: geo = {}",
1704 parent_ref_el, child_corners);
1705
1706 child_pi.rel_ref_geo_ =
1707 std::make_unique<lf::geometry::QuadO1>(child_corners);
1708 break;
1709 }
1710 default: {
1711 LF_ASSERT_MSG(false, "Illegal number "
1712 << child_corners.cols()
1713 << " of corners for a child cell");
1714 break;
1715 }
1716 }
1717 break;
1718 }
1719 case 1: { // segment in cell, child_rel_codim = 1
1720 LF_ASSERT_MSG(parent_child_info.child_edge_idx.at(child_number) ==
1721 child_idx,
1722 "parent_child_info.child_edge_idx.at("
1723 << child_number << " ) !== child_idx");
1724 LF_ASSERT_MSG(
1725 child_entity->RefEl() == lf::base::RefEl::kSegment(),
1726 "Must be an edge!");
1727 LF_ASSERT_MSG(child_corners.cols() == 2,
1728 "Segement must have two endpoints");
1729 SPDLOG_LOGGER_TRACE(Logger(), "Segment in {}: geo = {}",
1730 parent_ref_el, child_corners);
1731
1732 child_pi.rel_ref_geo_ =
1733 std::make_unique<lf::geometry::SegmentO1>(child_corners);
1734 break;
1735 }
1736 case 2: { // point in cell, child_rel_codim = 2
1737 LF_ASSERT_MSG(parent_child_info.child_point_idx.at(
1738 child_number) == child_idx,
1739 "parent_child_info.child_point_idx.at("
1740 << child_number << " ) !== child_idx");
1741 LF_ASSERT_MSG(child_entity->RefEl() == lf::base::RefEl::kPoint(),
1742 "Must be a point!");
1743 LF_ASSERT_MSG(child_corners.cols() == 1,
1744 "Only a single coordindate for a point!");
1745 SPDLOG_LOGGER_TRACE(Logger(), "Point in {}: geo = {}",
1746 parent_ref_el, child_corners);
1747
1748 child_pi.rel_ref_geo_ =
1749 std::make_unique<lf::geometry::Point>(child_corners);
1750 break;
1751 }
1752 default:
1753 LF_VERIFY_MSG(false, "unexpected codim " << codim);
1754 } // end switch codim
1755 break;
1756 }
1757 case 1: { // the parent entity is an edge
1758 // Fetch refinement information
1759 const EdgeChildInfo &parent_child_info{ed_child_info[parent_idx]};
1760 const RefPat parent_ref_pat{parent_child_info.ref_pat_};
1761 const sub_idx_t anchor{idx_nil};
1762 // Obtain geometry of child
1763 const Hybrid2DRefinementPattern rp(parent_ref_el, parent_ref_pat,
1764 anchor);
1765 const std::vector<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>>
1766 child_polygon_vec{rp.ChildPolygons(child_rel_codim)};
1767 LF_ASSERT_MSG(child_number < child_polygon_vec.size(),
1768 "Child number = " << child_number << " >= "
1769 << child_polygon_vec.size());
1770 const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>
1771 &child_polygon{child_polygon_vec[child_number]};
1772 LF_ASSERT_MSG(child_polygon.rows() == 1,
1773 "Need one coordinate only in parent segment");
1774 // Row vector containing the relative reference coordinates of the
1775 // child's corners
1776 const Eigen::MatrixXd child_corners =
1777 child_polygon.cast<double>() /
1778 static_cast<double>(rp.LatticeConst());
1779 switch (codim) {
1780 case 1: { // edge in edge, child_rel_codim = 0
1781 LF_ASSERT_MSG(parent_child_info.child_edge_idx.at(child_number) ==
1782 child_idx,
1783 "edge_child_info.child_edge_idx.at("
1784 << child_number << " ) !== child_idx");
1785 LF_ASSERT_MSG(
1786 child_entity->RefEl() == lf::base::RefEl::kSegment(),
1787 "Must be an edge!");
1788 LF_ASSERT_MSG(child_corners.cols() == 2,
1789 "Segement must have two endpoints");
1790 SPDLOG_LOGGER_TRACE(Logger(), "Segment in {}: geo = {}",
1791 parent_ref_el, child_corners);
1792
1793 child_pi.rel_ref_geo_ =
1794 std::make_unique<lf::geometry::SegmentO1>(child_corners);
1795 break;
1796 }
1797 case 2: { // point in edge
1798 LF_ASSERT_MSG(parent_child_info.child_point_idx.at(
1799 child_number) == child_idx,
1800 "edge_child_info.child_point_idx.at("
1801 << child_number << " ) !== child_idx");
1802 LF_ASSERT_MSG(child_entity->RefEl() == lf::base::RefEl::kPoint(),
1803 "Must be a point!");
1804 LF_ASSERT_MSG(child_corners.cols() == 1,
1805 "Only a single coordindate for a point!");
1806 SPDLOG_LOGGER_TRACE(Logger(), "Point in {}: geo = {}",
1807 parent_ref_el, child_corners);
1808
1809 child_pi.rel_ref_geo_ =
1810 std::make_unique<lf::geometry::Point>(child_corners);
1811 break;
1812 }
1813 default: {
1814 LF_VERIFY_MSG(
1815 false, "Child of an edge can only be a point or a segment");
1816 break;
1817 }
1818 } // end switch codim
1819 break;
1820 }
1821 case 2: { // the parent entity is a point
1822 // No relative geometry for a point
1823 SPDLOG_LOGGER_TRACE(Logger(), "point in {}", parent_ref_el);
1824 child_pi.rel_ref_geo_ =
1825 std::make_unique<lf::geometry::Point>(nil_coords);
1826 break;
1827 }
1828 default: {
1829 LF_VERIFY_MSG(false, "Illegal parent co-dimension" << parent_codim);
1830 break;
1831 }
1832 } // end switch(parent_codim)
1833 } // end loop over entities of the fine mesh
1834 } // end loop over codims
1835} // end initGeometryInParent
1836
1837sub_idx_t MeshHierarchy::LongestEdge(const lf::mesh::Entity &T) {
1838 LF_VERIFY_MSG(T.Codim() == 0, "Entity must be a call");
1839 // Obtain iterator over the edges
1840 const size_type num_edges = T.RefEl().NumSubEntities(1);
1841 auto sub_edges = T.SubEntities(1);
1842 double max_len = 0.0;
1843 sub_idx_t idx_longest_edge = 0;
1844 Eigen::MatrixXd mp_refc(1, 1);
1845 mp_refc(0, 0) = 0.5;
1846 for (int k = 0; k < num_edges; k++) {
1847 // Approximate length by "1-point quadrature"
1848 const double approx_length =
1849 (sub_edges[k]->Geometry()->IntegrationElement(mp_refc))[0];
1850 if (max_len < approx_length) {
1851 idx_longest_edge = k;
1852 max_len = approx_length;
1853 }
1854 }
1855 return idx_longest_edge;
1856}
1857
1858const lf::geometry::Geometry *MeshHierarchy::GeometryInParent(
1859 size_type level, const lf::mesh::Entity &e) const {
1860 LF_ASSERT_MSG(level > 0, "level must be that of a child mesh!");
1861 // Obtain reference to fine mesh
1862 const lf::mesh::Mesh &mesh{*getMesh(level)};
1863 // Get index of entity in fine mesh
1864 const lf::base::glb_idx_t idx_e{mesh.Index(e)};
1865 // Access information on parent
1866 const std::vector<ParentInfo> &parent_infos{ParentInfos(level, e.Codim())};
1867 // Fetch ParentInfo structure for entity e
1868 const ParentInfo &e_parent_info{parent_infos[idx_e]};
1869 // Just return the information contained in the relevant ParentInfo
1870 // structure
1871 LF_VERIFY_MSG(e_parent_info.rel_ref_geo_ != nullptr,
1872 "No valid parent information for " << e);
1873 return e_parent_info.rel_ref_geo_.get();
1874}
1875
1876const lf::mesh::Entity *MeshHierarchy::ParentEntity(
1877 size_type level, const lf::mesh::Entity &e) const {
1878 LF_ASSERT_MSG(level > 0, "level > 0 required!");
1879 // Obtain reference to fine mesh
1880 const lf::mesh::Mesh &mesh{*getMesh(level)};
1881 // Get index of entity in fine mesh
1882 const lf::base::glb_idx_t idx_e{mesh.Index(e)};
1883 // Access information about parent entity on next coarser mesh
1884 const std::vector<ParentInfo> &parent_infos{ParentInfos(level, e.Codim())};
1885 // Fetch ParentInfo structure for entity e
1886 const ParentInfo &e_parent_info{parent_infos[idx_e]};
1887 // Just return the information contained in the relevant ParentInfo
1888 // structure
1889 LF_VERIFY_MSG(e_parent_info.parent_ptr != nullptr,
1890 "No valid parent information for " << e);
1891 return e_parent_info.parent_ptr;
1892}
1893
1894std::ostream &MeshHierarchy::PrintInfo(std::ostream &o, unsigned ctrl) const {
1895 o << "MeshHierarchy, " << NumLevels() << " levels: " << std::endl;
1896 for (unsigned level = 0; level < NumLevels(); ++level) {
1897 const lf::mesh::Mesh &mesh{*getMesh(level)};
1898 o << "l=" << level << ": ";
1899 if (ctrl != 0) {
1900 lf::mesh::utils::PrintInfo(o, mesh);
1901 } else {
1902 o << static_cast<int>(mesh.DimMesh()) << "D -> "
1903 << static_cast<int>(mesh.DimWorld()) << "D, " << mesh.NumEntities(0)
1904 << " cells [" << mesh.NumEntities(lf::base::RefEl::kTria()) << " tria, "
1905 << mesh.NumEntities(lf::base::RefEl::kQuad()) << " quad], "
1906 << mesh.NumEntities(1) << " edges, " << mesh.NumEntities(2) << " nodes"
1907 << std::endl;
1908 }
1909 }
1910 return o;
1911}
1912
1913// Utility function for generating a hierarchy of meshes
1914/* SAM_LISTING_BEGIN_1 */
1915std::shared_ptr<MeshHierarchy> GenerateMeshHierarchyByUniformRefinemnt(
1916 const std::shared_ptr<lf::mesh::Mesh> &mesh_p, lf::base::size_type ref_lev,
1917 RefPat ref_pat) {
1918 LF_ASSERT_MSG(mesh_p != nullptr, "No valid mesh supplied!");
1919 // Set up the builder object for mesh entities, here suitable for a 2D
1920 // hybrid mesh comprising triangles and quadrilaterals
1921 std::unique_ptr<lf::mesh::hybrid2d::MeshFactory> mesh_factory_ptr =
1922 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
1923 // Create a mesh hierarchy with a single level
1924 std::shared_ptr<MeshHierarchy> multi_mesh_p =
1925 std::make_shared<MeshHierarchy>(mesh_p, std::move(mesh_factory_ptr));
1926 // Perform the desired number of steps of uniform refinement
1927 for (unsigned refstep = 0; refstep < ref_lev; ++refstep) {
1928 // Conduct regular refinement of all cells of the currently finest mesh.
1929 // This adds another mesh to the sequence of meshes.
1930 multi_mesh_p->RefineRegular(ref_pat);
1931 }
1932 return multi_mesh_p;
1933}
1934/* SAM_LISTING_END_1 */
1935
1936} // namespace lf::refinement
Represents a reference element with all its properties.
Definition: ref_el.h:106
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition: ref_el.h:141
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition: ref_el.h:166
Interface class for shape information on a mesh cell in the spirit of parametric finite element metho...
virtual std::vector< std::unique_ptr< Geometry > > ChildGeometry(const RefinementPattern &ref_pat, lf::base::dim_t codim) const =0
Generate geometry objects for child entities created in the course of refinement.
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
Abstract interface for objects representing a single mesh.
virtual size_type NumEntities(unsigned codim) const =0
The number of Entities that have the given codimension.
virtual nonstd::span< const Entity *const > Entities(unsigned codim) const =0
All entities of a given codimension.
virtual size_type Index(const Entity &e) const =0
Acess to the index of a mesh entity of any co-dimension.
Class containing information about the refinement of a cell.
A hierarchy of nested 2D hybrid meshes created by refinement.
MeshHierarchy(const std::shared_ptr< mesh::Mesh > &base_mesh, std::unique_ptr< mesh::MeshFactory > mesh_factory)
Initialize mesh hierarchy with an existing coarsest mesh.
std::unique_ptr< mesh::MeshFactory > mesh_factory_
The mesh factory to be used to creating a new mesh.
void RefineRegular(RefPat ref_pat=RefPat::rp_regular)
Perform regular or barycentric uniform refinement of the finest mesh in the hierarchy.
void RefineMarked()
Conduct local refinement of the mesh splitting all marked edges.
std::vector< std::shared_ptr< mesh::Mesh > > meshes_
the meshes managed by the MeshHierarchy object
std::vector< std::vector< sub_idx_t > > refinement_edges_
Information about local refinement edges of triangles.
std::vector< std::vector< CellChildInfo > > cell_child_infos_
information about children of cells for each level
std::vector< std::array< std::vector< ParentInfo >, 3 > > parent_infos_
information about parent entities on each level
std::vector< std::vector< bool > > edge_marked_
Information about marked edges.
std::vector< std::vector< PointChildInfo > > point_child_infos_
information about children of nodes for each level
static std::shared_ptr< spdlog::logger > & Logger()
Is used by MeshHierarchy to log additional information for debugging purposes.
void PerformRefinement()
Create new mesh according to refinement pattern provided for entities.
std::vector< std::vector< EdgeChildInfo > > edge_child_infos_
information about children of edges for each level
void initGeometryInParent()
Initialization of rel_ref_geo fields of ParentInfo structures.
static sub_idx_t LongestEdge(const lf::mesh::Entity &T)
Finds the index of the longest edge of a triangle.
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition: base.h:36
unsigned int sub_idx_t
type for local indices of sub-entities
Definition: base.h:32
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
unsigned int glb_idx_t
type for global index of mesh entities (nodes, edges, cells)
Definition: base.h:28
std::shared_ptr< spdlog::logger > InitLogger(const std::string &name)
Create a spdlog logger, register it in the spdlog registry and initialize it with LehrFEM++ specific ...
Definition: spdlog_utils.cc:16
const unsigned int idx_nil
Definition: mesh.h:28
tools for regular or local refinement of 2D hybrid meshes
bool checkValidIndex(const std::vector< glb_idx_t > &idx_vec)
const unsigned int idx_nil
RefPat
(possibly incomplete) list of refinement patterns for triangles/quadrilaterals
span_constexpr std::size_t size(span< T, Extent > const &spn)
Definition: span.h:1463
Information about the refinement status of a cell.
Information about the refinement status of an edge.
std::vector< glb_idx_t > child_edge_idx
global indices of child edges in fine mesh
std::vector< glb_idx_t > child_point_idx
global indices of interior child points in fine mesh
RefPat ref_pat_
type of refinement edge has undergone, see RefPat
Information about possible parent entities.
Information about the refinement status of a point.
RefPat ref_pat
a flag indicating whether the point is to be duplicated (rp_copy)