6#include "mesh_hierarchy.h"
8#include <spdlog/fmt/ostr.h>
9#include <spdlog/spdlog.h>
11#include "lf/mesh/hybrid2d/hybrid2d.h"
12#include "lf/mesh/utils/utils.h"
19 for (
int n = 0; n < n_idx; n++) {
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");
44 for (
const mesh::Entity *cell : base_mesh->Entities(0)) {
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));
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));
65 std::move(edge_parent_info),
66 std::move(point_parent_info)});
69 std::move(std::vector<bool>(base_mesh->NumEntities(1),
false)));
74 ref_pat == RefPat::rp_regular || ref_pat == RefPat::rp_barycentric,
75 "Only regular or barycentric uniform refinement possible");
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");
95 pt_child_info.
ref_pat = RefPat::rp_copy;
101 ed_child_info.
ref_pat_ = RefPat::rp_split;
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");
135 pt_child_info.
ref_pat = RefPat::rp_copy;
141 "Wrong type for an edge");
144 LF_VERIFY_MSG(ed_ci.
ref_pat_ == RefPat::rp_nil,
145 "Edge " << edge_index <<
" already refined!");
158 bool refinement_complete;
160 refinement_complete =
true;
169 std::array<glb_idx_t, 4> cell_edge_indices{};
172 std::array<bool, 4> edge_split{{
false,
false,
false,
false}};
174 std::array<sub_idx_t, 4> split_edge_idx{};
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);
183 for (
int k = 0; k < num_edges; k++) {
185 cell_edge_indices[k] = edge_index;
187 (finest_edge_ci[edge_index].ref_pat_ == RefPat::rp_split);
189 split_edge_idx[split_edge_cnt] = k;
193 switch (cell->RefEl()) {
200 LF_VERIFY_MSG(anchor < 3,
"Illegal anchor = " << anchor);
203 finest_cell_ci[cell_index].anchor_ = anchor;
205 const sub_idx_t mod_1 = (anchor + 1) % 3;
206 const sub_idx_t mod_2 = (anchor + 2) % 3;
208 std::tuple<bool, bool, bool> split_status(
209 {edge_split[mod_0], edge_split[mod_1], edge_split[mod_2]});
219 std::tuple<bool, bool, bool>({
false,
false,
false})) {
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})) {
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})) {
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})) {
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_ =
241 refinement_complete =
false;
242 }
else if (split_status ==
243 std::tuple<bool, bool, bool>({
true,
false,
true})) {
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})) {
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_ =
255 refinement_complete =
false;
256 }
else if (split_status ==
257 std::tuple<bool, bool, bool>({
true,
true,
true})) {
262 LF_VERIFY_MSG(split_edge_cnt == 3,
"Wrong number of split edges");
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})) {
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_ =
274 refinement_complete =
false;
276 LF_VERIFY_MSG(
false,
"Impossible case");
285 switch (split_edge_cnt) {
288 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_copy;
294 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_trisect;
295 finest_cell_ci[cell_index].anchor_ = split_edge_idx[0];
299 if ((split_edge_idx[1] - split_edge_idx[0]) == 2) {
303 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_bisect;
304 finest_cell_ci[cell_index].anchor_ = split_edge_idx[0];
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];
316 "Quad: impossible situation for 2 split edges");
325 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_threeedge;
326 if (!edge_split[0]) {
327 finest_cell_ci[cell_index].anchor_ = 2;
328 }
else if (!edge_split[1]) {
329 finest_cell_ci[cell_index].anchor_ = 3;
330 }
else if (!edge_split[2]) {
331 finest_cell_ci[cell_index].anchor_ = 0;
332 }
else if (!edge_split[3]) {
333 finest_cell_ci[cell_index].anchor_ = 1;
335 LF_VERIFY_MSG(
false,
"Inconsistent split pattern");
341 finest_cell_ci[cell_index].ref_pat_ = RefPat::rp_regular;
345 LF_VERIFY_MSG(
false,
"Illegal number " << split_edge_cnt
346 <<
" of split edges");
353 LF_VERIFY_MSG(
false,
"Illegal cell type");
358 }
while (!refinement_complete);
368 SPDLOG_LOGGER_DEBUG(
Logger(),
369 "Entering MeshHierarchy::PerformRefinement: {} levels",
395 LF_VERIFY_MSG(node_index < pt_child_info.size(),
396 "Node index " << node_index <<
" out of range");
399 if (pt_child_info[node_index].ref_pat != RefPat::rp_nil) {
401 std::vector<std::unique_ptr<geometry::Geometry>> pt_child_geo_ptrs(
403 LF_VERIFY_MSG(pt_child_geo_ptrs.size() == 1,
404 "A point can only have one chile");
406 pt_child_info[node_index].child_point_idx =
411 SPDLOG_LOGGER_DEBUG(
Logger(),
"{} new nodes added", new_node_cnt);
427 auto ed_nodes = edge->SubEntities(1);
429 parent_mesh.
Index(*ed_nodes[0]);
431 parent_mesh.
Index(*ed_nodes[1]);
435 pt_child_info[ed_p0_coarse_idx].child_point_idx;
437 pt_child_info[ed_p1_coarse_idx].child_point_idx;
444 switch (edge_refpat) {
445 case RefPat::rp_copy: {
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!");
452 SPDLOG_LOGGER_TRACE(
Logger(),
"Copy edge {} new edge [{},{}]",
453 edge_index, ed_p0_fine_idx, ed_p1_fine_idx);
458 std::array<lf::base::glb_idx_t, 2>{
459 {ed_p0_fine_idx, ed_p1_fine_idx}},
460 std::move(ed_copy[0])));
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()
477 std::vector<std::unique_ptr<geometry::Geometry>> edge_child_geo_ptrs(
478 edge->Geometry()->ChildGeometry(rp, 0));
480 edge_child_geo_ptrs.size() == 2,
481 "Split edge with " << edge_child_geo_ptrs.size() <<
" parts!");
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);
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])));
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])));
505 LF_VERIFY_MSG(
false,
"Refinement pattern "
506 <<
static_cast<int>(edge_refpat)
507 <<
" illegal for edge");
514 SPDLOG_LOGGER_DEBUG(Logger(),
"{} edges added", new_edge_cnt);
518 std::vector<CellChildInfo> &cell_child_info(cell_child_infos_.back());
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)) {
534 const RefPat cell_refpat(cell_ci.ref_pat_);
535 const sub_idx_t anchor = cell_ci.anchor_;
537 SPDLOG_LOGGER_TRACE(Logger(),
"Cell {} = {}, refpat = {}, anchor = {}",
538 cell_index, ref_el,
static_cast<int>(cell_refpat),
544 std::array<sub_idx_t, 4> mod{};
546 for (
int k = 0; k < num_vertices; k++) {
547 mod[k] = (k + anchor) % num_vertices;
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));
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);
564 SPDLOG_LOGGER_TRACE(Logger(),
" Subent({}) = [{}], ", codim,
565 cell_subent_idx[codim]);
569 std::array<lf::base::glb_idx_t, 4> vertex_child_idx{
572 LF_VERIFY_MSG(pt_child_info[cell_subent_idx[2][vt_lidx]].ref_pat ==
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;
580 std::array<lf::base::glb_idx_t, 4> edge_midpoint_idx{
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_ ==
587 "Edge with a midpoint must have been split");
588 edge_midpoint_idx[ed_lidx] = ed_ci.child_point_idx[0];
592 SPDLOG_LOGGER_TRACE(Logger(),
"vt_child_idx = {}, ed_mp_idx = {}",
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);
602 std::vector<std::array<glb_idx_t, 2>> child_edge_nodes;
603 std::array<glb_idx_t, 2> cen_tmp{};
609 switch (cell_refpat) {
610 case RefPat::rp_nil: {
611 LF_VERIFY_MSG(
false,
"Every triangle must be refined");
614 case RefPat::rp_copy: {
616 child_cell_nodes.push_back({vertex_child_idx[0],
618 vertex_child_idx[2]});
621 case RefPat::rp_bisect: {
624 "Anchor must be set for bisection refinement of triangle");
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]];
630 "refpat = " << (
int)cell_refpat <<
": illegal index");
631 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
637 "refpat = " << (
int)cell_refpat <<
": illegal index");
638 child_cell_nodes.push_back(tria_ccn_tmp);
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);
646 case RefPat::rp_trisect: {
649 "Anchor must be set for trisection refinement of triangle");
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]];
657 "refpat = " << (
int)cell_refpat <<
": illegal index");
658 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
664 "refpat = " << (
int)cell_refpat <<
": illegal index");
665 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
671 "refpat = " << (
int)cell_refpat <<
": illegal index");
672 child_cell_nodes.push_back(tria_ccn_tmp);
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);
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);
684 case RefPat::rp_trisect_left: {
687 "Anchor must be set for trisection refinement of triangle");
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]];
696 "refpat = " << (
int)cell_refpat <<
": illegal index");
697 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
703 "refpat = " << (
int)cell_refpat <<
": illegal index");
704 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
710 "refpat = " << (
int)cell_refpat <<
": illegal index");
711 child_cell_nodes.push_back(tria_ccn_tmp);
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);
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);
723 case RefPat::rp_quadsect: {
726 "Anchor must be set for quadsection refinement of triangle");
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]];
734 "refpat = " << (
int)cell_refpat <<
": illegal index");
735 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
741 "refpat = " << (
int)cell_refpat <<
": illegal index");
742 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
748 "refpat = " << (
int)cell_refpat <<
": illegal index");
749 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
755 "refpat = " << (
int)cell_refpat <<
": illegal index");
756 child_cell_nodes.push_back(tria_ccn_tmp);
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);
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);
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);
772 case RefPat::rp_barycentric: {
777 std::vector<std::unique_ptr<geometry::Geometry>>
778 cell_center_geo_ptrs(cell->Geometry()->ChildGeometry(
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 ??");
786 mesh_factory_->AddPoint(std::move(cell_center_geo_ptrs[0]));
787 cell_ci.child_point_idx.push_back(center_fine_idx);
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;
793 "refpat = " << (
int)cell_refpat <<
": illegal index");
794 child_cell_nodes.push_back(tria_ccn_tmp);
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;
800 "refpat = " << (
int)cell_refpat <<
": illegal index");
801 child_cell_nodes.push_back(tria_ccn_tmp);
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;
807 "refpat = " << (
int)cell_refpat <<
": illegal index");
808 child_cell_nodes.push_back(tria_ccn_tmp);
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;
814 "refpat = " << (
int)cell_refpat <<
": illegal index");
815 child_cell_nodes.push_back(tria_ccn_tmp);
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;
821 "refpat = " << (
int)cell_refpat <<
": illegal index");
822 child_cell_nodes.push_back(tria_ccn_tmp);
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;
828 "refpat = " << (
int)cell_refpat <<
": illegal index");
829 child_cell_nodes.push_back(tria_ccn_tmp);
832 cen_tmp[0] = vertex_child_idx[0];
833 cen_tmp[1] = center_fine_idx;
834 child_edge_nodes.push_back(cen_tmp);
836 cen_tmp[0] = vertex_child_idx[1];
837 cen_tmp[1] = center_fine_idx;
838 child_edge_nodes.push_back(cen_tmp);
840 cen_tmp[0] = vertex_child_idx[2];
841 cen_tmp[1] = center_fine_idx;
842 child_edge_nodes.push_back(cen_tmp);
844 cen_tmp[0] = edge_midpoint_idx[0];
845 cen_tmp[1] = center_fine_idx;
846 child_edge_nodes.push_back(cen_tmp);
848 cen_tmp[0] = edge_midpoint_idx[1];
849 cen_tmp[1] = center_fine_idx;
850 child_edge_nodes.push_back(cen_tmp);
852 cen_tmp[0] = edge_midpoint_idx[2];
853 cen_tmp[1] = center_fine_idx;
854 child_edge_nodes.push_back(cen_tmp);
857 case RefPat::rp_regular: {
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];
864 "refpat = " << (
int)cell_refpat <<
": illegal index");
865 child_cell_nodes.push_back(tria_ccn_tmp);
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];
871 "refpat = " << (
int)cell_refpat <<
": illegal index");
872 child_cell_nodes.push_back(tria_ccn_tmp);
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];
878 "refpat = " << (
int)cell_refpat <<
": illegal index");
879 child_cell_nodes.push_back(tria_ccn_tmp);
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];
885 "refpat = " << (
int)cell_refpat <<
": illegal index");
886 child_cell_nodes.push_back(tria_ccn_tmp);
889 cen_tmp[0] = edge_midpoint_idx[0];
890 cen_tmp[1] = edge_midpoint_idx[2];
891 child_edge_nodes.push_back(cen_tmp);
893 cen_tmp[0] = edge_midpoint_idx[0];
894 cen_tmp[1] = edge_midpoint_idx[1];
895 child_edge_nodes.push_back(cen_tmp);
897 cen_tmp[0] = edge_midpoint_idx[2];
898 cen_tmp[1] = edge_midpoint_idx[1];
899 child_edge_nodes.push_back(cen_tmp);
905 false,
"Refinement pattern not (yet) implemented for triangle");
911 switch (cell_refpat) {
912 case RefPat::rp_nil: {
913 LF_VERIFY_MSG(
false,
"Every quadrilateral must be refined");
916 case RefPat::rp_copy: {
918 child_cell_nodes.push_back(
919 {vertex_child_idx[0], vertex_child_idx[1], vertex_child_idx[2],
920 vertex_child_idx[3]});
923 case RefPat::rp_trisect: {
926 "Anchor must be set for trisection refinement of quad");
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]];
934 "refpat = " << (
int)cell_refpat <<
": illegal index");
935 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
941 "refpat = " << (
int)cell_refpat <<
": illegal index");
942 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
948 "refpat = " << (
int)cell_refpat <<
": illegal index");
949 child_cell_nodes.push_back(tria_ccn_tmp);
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);
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);
961 case RefPat::rp_quadsect: {
964 "Anchor must be set for quadsection refinement of triangle");
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]];
972 "refpat = " << (
int)cell_refpat <<
": illegal index");
973 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
979 "refpat = " << (
int)cell_refpat <<
": illegal index");
980 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
986 "refpat = " << (
int)cell_refpat <<
": illegal index");
987 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
993 "refpat = " << (
int)cell_refpat <<
": illegal index");
994 child_cell_nodes.push_back(tria_ccn_tmp);
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);
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);
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);
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");
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]];
1021 "refpat = " << (
int)cell_refpat <<
": illegal index");
1022 child_cell_nodes.push_back(quad_ccn_tmp);
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]];
1029 "refpat = " << (
int)cell_refpat <<
": illegal index");
1030 child_cell_nodes.push_back(quad_ccn_tmp);
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);
1038 case RefPat::rp_threeedge: {
1041 "Anchor must be set for three edge refinement of a quad");
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]];
1048 "refpat = " << (
int)cell_refpat <<
": illegal index");
1049 child_cell_nodes.push_back(quad_ccn_tmp);
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]];
1055 "refpat = " << (
int)cell_refpat <<
": illegal index");
1056 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
1062 "refpat = " << (
int)cell_refpat <<
": illegal index");
1063 child_cell_nodes.push_back(tria_ccn_tmp);
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]];
1069 "refpat = " << (
int)cell_refpat <<
": illegal index");
1070 child_cell_nodes.push_back(tria_ccn_tmp);
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);
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);
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);
1086 case RefPat::rp_barycentric:
1087 case RefPat::rp_regular: {
1089 std::vector<std::unique_ptr<geometry::Geometry>>
1090 cell_center_geo_ptrs(cell->Geometry()->ChildGeometry(
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!");
1098 mesh_factory_->AddPoint(std::move(cell_center_geo_ptrs[0]));
1099 cell_ci.child_point_idx.push_back(center_fine_idx);
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];
1107 "refpat = " << (
int)cell_refpat <<
": illegal index");
1108 child_cell_nodes.push_back(quad_ccn_tmp);
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];
1115 "refpat = " << (
int)cell_refpat <<
": illegal index");
1116 child_cell_nodes.push_back(quad_ccn_tmp);
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];
1123 "refpat = " << (
int)cell_refpat <<
": illegal index");
1124 child_cell_nodes.push_back(quad_ccn_tmp);
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];
1131 "refpat = " << (
int)cell_refpat <<
": illegal index");
1132 child_cell_nodes.push_back(quad_ccn_tmp);
1135 cen_tmp[0] = edge_midpoint_idx[0];
1136 cen_tmp[1] = center_fine_idx;
1137 child_edge_nodes.push_back(cen_tmp);
1139 cen_tmp[0] = edge_midpoint_idx[1];
1140 cen_tmp[1] = center_fine_idx;
1141 child_edge_nodes.push_back(cen_tmp);
1143 cen_tmp[0] = edge_midpoint_idx[2];
1144 cen_tmp[1] = center_fine_idx;
1145 child_edge_nodes.push_back(cen_tmp);
1147 cen_tmp[0] = edge_midpoint_idx[3];
1148 cen_tmp[1] = center_fine_idx;
1149 child_edge_nodes.push_back(cen_tmp);
1155 "Refinement pattern not (yet) implemented for quadrilateral");
1161 LF_VERIFY_MSG(
false,
"Unknown cell type" << ref_el.ToString());
1165 std::vector<std::unique_ptr<geometry::Geometry>> cell_edge_geo_ptrs(
1166 cell->Geometry()->ChildGeometry(rp, 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]);
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);
1186 std::vector<std::unique_ptr<geometry::Geometry>> childcell_geo_ptrs(
1187 cell->Geometry()->ChildGeometry(rp, 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]);
1195 if (ccn.size() == 3) {
1197 SPDLOG_LOGGER_TRACE(
1198 Logger(),
"{}({}), ref_pat = {}: new triangle {}[{},{},{}]",
1199 ref_el, cell_index, (
int)cell_refpat, k, ccn[0], ccn[1],
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) {
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],
1215 std::array<base::glb_idx_t, 4>{
1216 {ccn[0], ccn[1], ccn[2], ccn[3]}},
1217 std::move(childcell_geo_ptrs[k]));
1219 LF_VERIFY_MSG(
false,
1220 "Child cells must be either triangles or quads");
1222 cell_ci.child_cell_idx.push_back(new_cell_index);
1229 meshes_.push_back(mesh_factory_->Build());
1230 mesh::Mesh &child_mesh(*meshes_.back());
1232 SPDLOG_LOGGER_DEBUG(Logger(),
"Child mesh {} nodes, {} edges, {} cells.",
1233 child_mesh.NumEntities(2), child_mesh.NumEntities(1),
1234 child_mesh.NumEntities(0));
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)))});
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));
1256 refinement_edges_.push_back(
1257 std::move(std::vector<sub_idx_t>(child_mesh.NumEntities(0), idx_nil)));
1260 edge_marked_.emplace_back(child_mesh.NumEntities(1),
false);
1266 const size_type n_levels = meshes_.size();
1267 LF_VERIFY_MSG(n_levels > 1,
"A least two levels after refinement");
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]);
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");
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)) {
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;
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)) {
1302 const glb_idx_t edge_index = parent_mesh.Index(*edge);
1303 const EdgeChildInfo &ci_edge(ed_child_info[edge_index]);
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;
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;
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)) {
1333 const glb_idx_t cell_index(parent_mesh.Index(*cell));
1335 CellChildInfo &cell_ci(cell_child_info[cell_index]);
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;
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;
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;
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));
1385 SPDLOG_LOGGER_DEBUG(Logger(),
"Setting refinement edges");
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;
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);
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");
1410 SPDLOG_LOGGER_TRACE(Logger(),
1411 "Cell {}: triangle child {} of parent {}",
1412 cell_index, fine_cell_child_number, parent_index);
1414 const CellChildInfo &parent_ci(parent_cell_ci[parent_index]);
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_;
1420 switch (parent_ref_pat) {
1421 case RefPat::rp_nil: {
1422 LF_VERIFY_MSG(
false,
1423 "Parent cannot carry nil refinement pattern");
1426 case RefPat::rp_copy: {
1428 child_ref_edges[cell_index] = parent_ref_edges[parent_index];
1431 case RefPat::rp_bisect: {
1433 LF_VERIFY_MSG(fine_cell_child_number < 2,
1434 "Only 2 children for rp_bisect");
1435 child_ref_edges[cell_index] = 2;
1438 case RefPat::rp_trisect: {
1440 LF_VERIFY_MSG(fine_cell_child_number < 3,
1441 "Only 3 children for rp_trisect");
1442 switch (fine_cell_child_number) {
1444 child_ref_edges[cell_index] = 2;
1448 child_ref_edges[cell_index] = 1;
1452 child_ref_edges[cell_index] = 0;
1456 LF_VERIFY_MSG(
false,
1457 "invalid value for fine_cell_child_number");
1461 case RefPat::rp_trisect_left: {
1463 LF_VERIFY_MSG(fine_cell_child_number < 4,
1464 "Only 3 children for rp_quadsect");
1465 switch (fine_cell_child_number) {
1468 child_ref_edges[cell_index] = 2;
1472 child_ref_edges[cell_index] = 0;
1476 LF_VERIFY_MSG(
false,
1477 "invalid value for fine_cell_child_number");
1481 case RefPat::rp_quadsect: {
1483 switch (fine_cell_child_number) {
1485 child_ref_edges[cell_index] = 2;
1491 child_ref_edges[cell_index] = 0;
1495 LF_VERIFY_MSG(
false,
"Illegal child number");
1504 parent_ref_edges[parent_index];
1505 switch (parent_ref_edge_idx) {
1507 switch (fine_cell_child_number) {
1510 child_ref_edges[cell_index] = 0;
1515 child_ref_edges[cell_index] = 1;
1519 LF_VERIFY_MSG(
false,
"Illegal child number");
1526 switch (fine_cell_child_number) {
1528 child_ref_edges[cell_index] = 1;
1534 child_ref_edges[cell_index] = 2;
1538 LF_VERIFY_MSG(
false,
"Illegal child number");
1545 switch (fine_cell_child_number) {
1547 child_ref_edges[cell_index] = 2;
1551 child_ref_edges[cell_index] = 1;
1556 child_ref_edges[cell_index] = 0;
1560 LF_VERIFY_MSG(
false,
"Illegal child number");
1567 LF_VERIFY_MSG(
false,
"invalid parent_ref_edge_idx")
1574 child_ref_edges[cell_index] = LongestEdge(*fine_cell);
1578 LF_VERIFY_MSG(
false,
"Illegal refinement type for a triangle");
1583 SPDLOG_LOGGER_TRACE(Logger(),
"ref_pat = {}({}) ref edge = {}",
1584 (
int)parent_ref_pat, parent_ref_pat,
1585 child_ref_edges[cell_index]);
1591 child_ref_edges[cell_index] = LongestEdge(*fine_cell);
1593 LF_VERIFY_MSG(
false,
"Unknown parent cell type");
1603void MeshHierarchy::initGeometryInParent() {
1605 const size_type num_levels = NumLevels();
1606 SPDLOG_LOGGER_DEBUG(Logger(),
1607 "Entering MeshHierarchy::initGeometryInParent: {} levels",
1612 LF_ASSERT_MSG(num_levels > 1,
"Must have been refined at least once");
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)};
1624 const Eigen::MatrixXd nil_coords(0, 1);
1628 for (
dim_t codim = 0; codim <= 2; ++codim) {
1631 std::vector<ParentInfo> &child_entities_parent_info(
1632 parent_infos_.back()[codim]);
1636 const glb_idx_t child_idx = child_mesh.Index(*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_");
1642 const sub_idx_t child_number = child_pi.child_number;
1643 LF_ASSERT_MSG(child_number != idx_nil,
"Child number missing");
1645 LF_ASSERT_MSG(child_pi.parent_ptr !=
nullptr,
"No valid parent pointer");
1650 const dim_t parent_codim = parent.Codim();
1652 const glb_idx_t parent_idx = parent_mesh.Index(parent);
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,
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());
1682 case 0: { // cell in cell
1683 LF_ASSERT_MSG(parent_child_info.child_cell_idx.at(child_number) ==
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
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);
1695 child_pi.rel_ref_geo_ =
1696 std::make_unique<lf::geometry::TriaO1>(child_corners);
1699 case 4: { // Child is a quadrilateral
1701 child_entity->RefEl() == lf::base::RefEl::kQuad(),
1703 SPDLOG_LOGGER_TRACE(Logger(), "Quad in {}: geo = {}
",
1704 parent_ref_el, child_corners);
1706 child_pi.rel_ref_geo_ =
1707 std::make_unique<lf::geometry::QuadO1>(child_corners);
1711 LF_ASSERT_MSG(false, "Illegal number
"
1712 << child_corners.cols()
1713 << " of corners
for a child cell
");
1719 case 1: { // segment in cell, child_rel_codim = 1
1720 LF_ASSERT_MSG(parent_child_info.child_edge_idx.at(child_number) ==
1722 "parent_child_info.child_edge_idx.at(
"
1723 << child_number << " ) !== child_idx
");
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);
1732 child_pi.rel_ref_geo_ =
1733 std::make_unique<lf::geometry::SegmentO1>(child_corners);
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);
1748 child_pi.rel_ref_geo_ =
1749 std::make_unique<lf::geometry::Point>(child_corners);
1753 LF_VERIFY_MSG(false, "unexpected codim
" << codim);
1754 } // end switch codim
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,
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
1776 const Eigen::MatrixXd child_corners =
1777 child_polygon.cast<double>() /
1778 static_cast<double>(rp.LatticeConst());
1780 case 1: { // edge in edge, child_rel_codim = 0
1781 LF_ASSERT_MSG(parent_child_info.child_edge_idx.at(child_number) ==
1783 "edge_child_info.child_edge_idx.at(
"
1784 << child_number << " ) !== child_idx
");
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);
1793 child_pi.rel_ref_geo_ =
1794 std::make_unique<lf::geometry::SegmentO1>(child_corners);
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);
1809 child_pi.rel_ref_geo_ =
1810 std::make_unique<lf::geometry::Point>(child_corners);
1815 false, "Child of an edge can only be a point or a segment
");
1818 } // end switch codim
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);
1829 LF_VERIFY_MSG(false, "Illegal parent co-dimension
" << parent_codim);
1832 } // end switch(parent_codim)
1833 } // end loop over entities of the fine mesh
1834 } // end loop over codims
1835} // end initGeometryInParent
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;
1855 return idx_longest_edge;
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
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();
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
1889 LF_VERIFY_MSG(e_parent_info.parent_ptr != nullptr,
1890 "No valid parent information
for " << e);
1891 return e_parent_info.parent_ptr;
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 << ":
";
1900 lf::mesh::utils::PrintInfo(o, mesh);
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
"
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,
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);
1932 return multi_mesh_p;
1934/* SAM_LISTING_END_1 */
1936} // namespace lf::refinement
Represents a reference element with all its properties.
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
static constexpr RefEl kTria()
Returns the reference triangle.
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
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
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
unsigned int sub_idx_t
type for local indices of sub-entities
unsigned int size_type
general type for variables related to size of arrays
unsigned int glb_idx_t
type for global index of mesh entities (nodes, edges, cells)
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 ...
const unsigned int idx_nil
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)
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)