258 const std::unordered_map<int,int> &lface_to_boundary_attribute)
261 const int num_codim_1 = [&mesh]()
263 auto Dim = mesh.Dimension();
264 if (Dim == 1) {
return mesh.GetNV(); }
265 else if (Dim == 2) {
return mesh.GetNEdges(); }
266 else if (Dim == 3) {
return mesh.GetNFaces(); }
267 else { MFEM_ABORT(
"Invalid dimension.");
return -1; }
270 if (mesh.Dimension() == 3)
274 mesh.DeleteBoundaryElementToEdge();
276 int NumOfBdrElements = 0;
277 for (
int i = 0; i < num_codim_1; i++)
279 if (mesh.GetFaceInformation(i).IsBoundary())
287 boundary.
Reserve(NumOfBdrElements);
288 be_to_face.
Reserve(NumOfBdrElements);
290 const auto &parent = *mesh.GetParent();
291 const auto &parent_face_ids = mesh.GetParentFaceIDMap();
292 const auto &parent_edge_ids = mesh.GetParentEdgeIDMap();
293 const auto &parent_vertex_ids = mesh.GetParentVertexIDMap();
294 const auto &parent_face_to_be = parent.GetFaceToBdrElMap();
295 const auto &face_to_be = mesh.GetFaceToBdrElMap();
296 int max_bdr_attr = parent.bdr_attributes.Max();
297 for (
int i = 0; i < num_codim_1; i++)
299 auto pfid = [&](
int i)
301 switch (mesh.Dimension())
303 case 3:
return parent_face_ids[i];
304 case 2:
return parent_edge_ids[i];
305 case 1:
return parent_vertex_ids[i];
310 if (mesh.GetFaceInformation(i).IsBoundary()
311 && (face_to_be.IsEmpty() || face_to_be[i] == -1))
313 auto * be = mesh.GetFace(i)->Duplicate(&mesh);
317 int pbeid = parent_face_to_be[pfid(i)];
320 be->SetAttribute(parent.GetBdrAttribute(pbeid));
324 auto ghost_attr = lface_to_boundary_attribute.find(pfid(i));
325 int battr = ghost_attr != lface_to_boundary_attribute.end() ?
326 ghost_attr->second : max_bdr_attr + 1;
327 be->SetAttribute(battr);
332 auto ghost_attr = lface_to_boundary_attribute.find(pfid(i));
333 int battr = ghost_attr != lface_to_boundary_attribute.end() ?
334 ghost_attr->second : max_bdr_attr + 1;
335 be->SetAttribute(battr);
345 int InteriorBdrElems = 0;
346 for (
int i=0; i<parent.GetNBE(); i++)
348 const int parentFaceIdx = parent.GetBdrElementFaceIndex(i);
349 const int submeshFaceIdx =
350 mesh.Dimension() == 3 ?
351 mesh.GetSubMeshFaceFromParent(parentFaceIdx) :
352 mesh.GetSubMeshEdgeFromParent(parentFaceIdx);
354 if (submeshFaceIdx == -1) {
continue; }
355 if (mesh.GetFaceInformation(submeshFaceIdx).IsBoundary()) {
continue; }
359 if (InteriorBdrElems > 0)
361 NumOfBdrElements += InteriorBdrElems;
362 boundary.
Reserve(NumOfBdrElements);
363 be_to_face.
Reserve(NumOfBdrElements);
366 for (
int i = 0; i < parent.GetNBE(); i++)
368 const int parentFaceIdx = parent.GetBdrElementFaceIndex(i);
369 const int submeshFaceIdx =
370 mesh.Dimension() == 3 ?
371 mesh.GetSubMeshFaceFromParent(parentFaceIdx) :
372 mesh.GetSubMeshEdgeFromParent(parentFaceIdx);
374 if (submeshFaceIdx == -1) {
continue; }
375 if (mesh.GetFaceInformation(submeshFaceIdx).IsBoundary())
378 auto * be = mesh.GetFace(submeshFaceIdx)->Duplicate(&mesh);
379 be->SetAttribute(parent.GetBdrAttribute(i));
381 be_to_face.
Append(submeshFaceIdx);
385 mesh.AddBdrElements(boundary, be_to_face);
439 auto &parent_node_ids = submesh.parent_node_ids_;
440 auto &parent_element_ids = submesh.parent_element_ids_;
441 auto &parent_to_submesh_node_ids = submesh.parent_to_submesh_node_ids_;
442 auto &parent_to_submesh_element_ids = submesh.parent_to_submesh_element_ids_;
443 const auto &parent = *submesh.GetParent();
448 std::map<FaceNodes, int> pnodes_new_elem;
449 std::set<int> new_nodes;
450 parent_to_submesh_element_ids.reserve(parent.GetNumFaces());
451 parent_element_ids.Reserve(parent.GetNumFaces());
454 const auto &face_list =
const_cast<NCMesh&
>(
static_cast<const NCMesh&
>
458 for (
int i = 0, ipe = 0; ipe < parent.GetNumFaces(); i++)
460 const auto &face = parent.GetFace(i);
461 if (face.Unused()) {
continue; }
467 FaceNodes fn{submesh.parent_->FindFaceNodes(face)};
468 if (pnodes_new_elem.find(fn) != pnodes_new_elem.end()) {
continue; }
474 MFEM_ASSERT(face.elem[0] < 0 || face.elem[1] < 0,
475 "Internal nonconforming boundaries are not reliably supported yet.");
476 auto face_geom = FaceGeomFromNodes(fn.nodes);
477 int new_elem_id = submesh.AddElement(face_geom, face.attribute);
480 submesh.elements[new_elem_id].rank = [&parent, &face]()
482 auto rank0 = face.elem[0] >= 0 ? parent.GetElement(face.elem[0]).rank : -1;
483 auto rank1 = face.elem[1] >= 0 ? parent.GetElement(face.elem[1]).rank : -1;
484 if (rank0 < 0) {
return rank1; }
485 if (rank1 < 0) {
return rank0; }
486 return rank0 < rank1 ? rank0 : rank1;
488 pnodes_new_elem[fn] = new_elem_id;
489 parent_element_ids.Append(i);
490 parent_to_submesh_element_ids[i] = new_elem_id;
494 std::copy(fn.nodes.begin(), fn.nodes.end(), submesh.elements[new_elem_id].node);
495 for (
auto x : fn.nodes)
500 auto &gi = submesh.GI[face_geom];
501 gi.InitGeom(face_geom);
502 for (
int e = 0; e < gi.ne; e++)
504 new_nodes.insert(submesh.ParentNodes().FindId(fn.nodes[gi.edges[e][0]],
505 fn.nodes[gi.edges[e][1]]));
520 bool root_path_is_ambiguous=
false;
524 int child = submesh.parent_->ParentFaceNodes(fn.nodes);
525 if (tri_face && child == 3)
529 root_path_is_ambiguous =
true;
534 submesh.elements[new_elem_id].parent = -1;
537 auto pelem = pnodes_new_elem.find(fn);
538 bool new_parent = pelem == pnodes_new_elem.end();
542 int pelem_id = submesh.AddElement(FaceGeomFromNodes(fn.nodes), face.attribute);
543 pelem = pnodes_new_elem.emplace(fn, pelem_id).first;
544 auto parent_face_id = submesh.ParentFaces().FindId(fn.nodes[0], fn.nodes[1],
547 parent_element_ids.Append(parent_face_id);
560 if (!root_path_is_ambiguous &&
561 !std::equal(fn.nodes.begin(), fn.nodes.end(), pelem->first.nodes.begin()))
564 auto pelem_id = pelem->second;
565 MFEM_ASSERT(!submesh.elements[pelem_id].IsLeaf(), pelem_id);
568 pnodes_new_elem.erase(pelem->first);
569 pelem = pnodes_new_elem.emplace(fn, pelem_id).first;
573 submesh.elements[pelem->second].ref_type = submesh.Dim == 2 ?
Refinement::XY :
575 submesh.elements[new_elem_id].parent = pelem->second;
580 if (!new_parent && !fix_parent) {
break; }
582 new_elem_id = pelem->second;
585 parent_element_ids.ShrinkToFit();
586 MFEM_ASSERT(parent_element_ids.Size() == submesh.elements.Size(),
587 parent_element_ids.Size() <<
' ' << submesh.elements.Size());
592 for (
const auto & fn_elem : pnodes_new_elem)
594 auto fn = fn_elem.first;
595 const auto &child_elem = submesh.elements[fn_elem.second];
596 if (child_elem.parent == -1) {
continue; }
597 int child = submesh.parent_->ParentFaceNodes(fn.nodes);
598 MFEM_ASSERT(pnodes_new_elem[fn] == child_elem.parent,
599 pnodes_new_elem[fn] <<
' ' << child_elem.parent);
600 MFEM_ASSERT(submesh.elements[child_elem.parent].ref_type !=
char(0),
601 int(submesh.elements[child_elem.parent].ref_type));
602 submesh.elements[child_elem.parent].child[child] = fn_elem.second;
617 (pnodes_new_elem.size()));
618 for (
const auto &kv : pnodes_new_elem)
620 new_elem_to_parent_face_nodes[kv.second] = kv.first;
622 pnodes_new_elem.clear();
625 parent_node_ids.Reserve(
static_cast<int>(new_nodes.size()));
626 parent_to_submesh_node_ids.reserve(new_nodes.size());
627 for (
auto n : new_nodes)
630 auto new_node_id = node_ids.
Get(n, new_node);
631 MFEM_ASSERT(new_node,
"!");
632 submesh.nodes.Alloc(new_node_id, new_node_id, new_node_id);
633 parent_node_ids.Append(n);
634 parent_to_submesh_node_ids[n] = new_node_id;
636 parent_node_ids.ShrinkToFit();
641 auto comp_elements = [&](
int l,
int r)
643 const auto &elem_l = submesh.elements[l];
644 const auto &elem_r = submesh.elements[r];
645 if (elem_l.parent == elem_r.parent)
647 const auto &fnl = new_elem_to_parent_face_nodes[l].nodes;
648 const auto &fnr = new_elem_to_parent_face_nodes[r].nodes;
649 return std::lexicographical_compare(fnl.begin(), fnl.end(), fnr.begin(),
654 return elem_l.parent < elem_r.parent;
658 auto parental_sorted = [&]()
660 std::iota(indices.
begin(), indices.
end(), 0);
661 return std::is_sorted(indices.
begin(), indices.
end(), comp_elements);
664 Array<int> new_to_old(submesh.elements.Size()),
665 old_to_new(submesh.elements.Size());
666 while (!parental_sorted())
670 new_to_old.SetSize(submesh.elements.Size()),
671 old_to_new.
SetSize(submesh.elements.Size());
672 std::iota(new_to_old.begin(), new_to_old.end(), 0);
673 std::stable_sort(new_to_old.begin(), new_to_old.end(), comp_elements);
675 for (
int i = 0; i < submesh.elements.Size(); i++)
677 old_to_new[new_to_old[i]] = i;
681 Permute(std::move(new_to_old), submesh.elements, parent_element_ids,
682 new_elem_to_parent_face_nodes);
683 parent_to_submesh_element_ids.clear();
684 for (
int i = 0; i < parent_element_ids.Size(); i++)
686 if (parent_element_ids[i] == -1) {
continue;}
687 parent_to_submesh_element_ids[parent_element_ids[i]] = i;
691 for (
auto &elem : submesh.elements)
696 elem.rank = std::numeric_limits<int>::max();
699 elem.child[c] = old_to_new[elem.child[c]];
700 elem.rank = std::min(elem.rank, submesh.elements[elem.child[c]].rank);
703 elem.parent = elem.parent == -1 ? -1 : old_to_new[elem.parent];
708 for (
auto &elem : submesh.elements)
713 auto &gi = submesh.GI[elem.Geom()];
714 gi.InitGeom(elem.Geom());
715 for (
int e = 0; e < gi.ne; e++)
717 const int pid = submesh.ParentNodes().FindId(
718 elem.node[gi.edges[e][0]], elem.node[gi.edges[e][1]]);
719 MFEM_ASSERT(pid >= 0,
720 elem.node[gi.edges[e][0]] <<
' ' << elem.node[gi.edges[e][1]]);
721 auto submesh_node_id = node_ids.
Get(pid, new_id);
722 MFEM_ASSERT(!new_id,
"!");
723 submesh.nodes[submesh_node_id].edge_refc++;
725 for (
int n = 0; n < gi.nv; n++)
727 MFEM_ASSERT(parent_to_submesh_node_ids.find(elem.node[n]) !=
728 parent_to_submesh_node_ids.end(),
"!");
729 elem.node[n] = parent_to_submesh_node_ids[elem.node[n]];
730 submesh.nodes[elem.node[n]].vert_refc++;
733 for (
int f = 0;
f < gi.nf;
f++)
735 auto *face = submesh.faces.Get(
736 elem.node[gi.faces[
f][0]],
737 elem.node[gi.faces[
f][1]],
738 elem.node[gi.faces[
f][2]],
739 elem.node[gi.faces[
f][3]]);
740 face->attribute = -1;
759 auto &parent_node_ids = submesh.parent_node_ids_;
760 auto &parent_element_ids = submesh.parent_element_ids_;
761 auto &parent_to_submesh_node_ids = submesh.parent_to_submesh_node_ids_;
762 auto &parent_to_submesh_element_ids = submesh.parent_to_submesh_element_ids_;
763 const auto &parent = *submesh.GetParent();
766 parent_to_submesh_element_ids.reserve(parent.GetNumElements());
767 std::set<int> new_nodes;
768 for (
int ipe = 0; ipe < parent.GetNumElements(); ipe++)
770 const auto& pe = parent.GetElement(ipe);
772 const int elem_id = submesh.AddElement(pe);
773 auto &el = submesh.elements[elem_id];
774 parent_element_ids.Append(ipe);
775 parent_to_submesh_element_ids[ipe] = elem_id;
776 if (!pe.IsLeaf()) {
continue; }
777 const auto gi = submesh.GI[pe.Geom()];
778 for (
int n = 0; n < gi.nv; n++)
780 new_nodes.insert(el.node[n]);
782 for (
int e = 0; e < gi.ne; e++)
784 new_nodes.insert(submesh.ParentNodes().FindId(el.node[gi.edges[e][0]],
785 el.node[gi.edges[e][1]]));
789 parent_node_ids.Reserve(
static_cast<int>(new_nodes.size()));
790 parent_to_submesh_node_ids.reserve(new_nodes.size());
791 for (
const auto &n : new_nodes)
794 auto new_node_id = node_ids.
Get(n, new_node);
795 MFEM_ASSERT(new_node,
"!");
796 submesh.nodes.Alloc(new_node_id, new_node_id, new_node_id);
797 parent_node_ids.Append(n);
798 parent_to_submesh_node_ids[n] = new_node_id;
803 for (
auto &el : submesh.elements)
807 const auto gi = submesh.GI[el.Geom()];
810 for (
int n = 0; n < gi.nv; n++)
813 el.node[n] = node_ids.
Get(el.node[n], new_id);
814 MFEM_ASSERT(new_id ==
false,
"Should not be new.");
815 submesh.nodes[el.node[n]].vert_refc++;
817 for (
int e = 0; e < gi.ne; e++)
819 const int pid = submesh.ParentNodes().FindId(
820 parent_node_ids[el.node[gi.edges[e][0]]],
821 parent_node_ids[el.node[gi.edges[e][1]]]);
822 MFEM_ASSERT(pid >= 0,
"Edge not found");
823 auto submesh_node_id = node_ids.
Get(pid, new_id);
824 MFEM_ASSERT(new_id ==
false,
"Should not be new.");
825 submesh.nodes[submesh_node_id].edge_refc++;
827 for (
int f = 0;
f < gi.nf;
f++)
829 const int *fv = gi.faces[
f];
830 const int pid = submesh.ParentFaces().FindId(
831 parent_node_ids[el.node[fv[0]]],
832 parent_node_ids[el.node[fv[1]]],
833 parent_node_ids[el.node[fv[2]]],
834 el.node[fv[3]] >= 0 ? parent_node_ids[el.node[fv[3]]]: - 1);
835 MFEM_ASSERT(pid >= 0,
"Face not found");
836 const int id = submesh.faces.GetId(
837 el.node[fv[0]], el.node[fv[1]], el.node[fv[2]], el.node[fv[3]]);
838 submesh.faces[id].attribute = submesh.ParentFaces()[pid].attribute;
846 el.child[i] = parent_to_submesh_element_ids[el.child[i]];
849 el.parent = el.parent < 0 ? el.parent
850 : parent_to_submesh_element_ids.at(el.parent);