29using namespace bin_io;
31static int GetHexEdgeSplit(
const int*
nodes,
int v1,
int v2);
36 constexpr real_t rel_tol = 1.0e-8;
38 constexpr real_t rel_tol = 1.0e-5;
40 return std::abs(
a -
b) <= rel_tol *
41 std::max(
real_t(1.0), std::max(std::abs(
a), std::abs(
b)));
44static real_t DirectedHexEdgeScale(
const int*
nodes,
const Refinement &ref,
47 const int dir = GetHexEdgeSplit(
nodes, v0, v1);
48 static const int split_edges[3][4][2] =
50 {{0, 1}, {3, 2}, {4, 5}, {7, 6}},
51 {{1, 2}, {0, 3}, {5, 6}, {4, 7}},
52 {{0, 4}, {1, 5}, {2, 6}, {3, 7}}
55 for (
int i = 0; i < 4; i++)
57 const int a =
nodes[split_edges[dir][i][0]];
58 const int b =
nodes[split_edges[dir][i][1]];
59 if (
a == v0 &&
b == v1)
63 if (
a == v1 &&
b == v0)
65 return 1.0 - ref.s[dir];
69 MFEM_ABORT(
"Shared face edge does not match the refinement direction.");
74 const int *partitioning)
97 int &curved,
int &is_nc)
98 :
NCMesh(input, version, curved, is_nc)
100 MFEM_VERIFY(version != 11,
"Nonconforming mesh format \"MFEM NC mesh v1.1\""
101 " is supported only in serial.");
107 MPI_Comm_rank(
MyComm, &my_rank);
116 "Parallel mesh file doesn't seem to match current MPI setup. "
117 "Loading a parallel NC mesh with a non-matching communicator "
118 "size is not supported.");
121 MPI_Allreduce(&iso, &
Iso, 1, MFEM_MPI_CXX_BOOL, MPI_LAND,
MyComm);
129 , MyComm(other.MyComm)
130 , NRanks(other.NRanks)
152 for (
int i = 0; i < 3; i++)
178 owner = std::min(owner, el.
rank);
189 el_loc = (el.
index << 4) | local;
242 int e_index =
nodes[enode].edge_index;
245 owner = std::min(owner, el.
rank);
256 el_loc = (el.
index << 4) | local;
308 int V[4], E[4], Eo[4];
310 MFEM_ASSERT(nfv == 4,
"");
313 for (
int i=0; i<nfv; ++i)
324 MFEM_ASSERT(!el.
ref_type,
"not a leaf element.");
329 for (
int j = 0; j < gi.
ne; j++)
332 const int* ev = gi.
edges[j];
333 int node[2] = { el.
node[ev[0]], el.
node[ev[1]] };
335 int enode =
nodes.FindId(node[0], node[1]);
336 MFEM_ASSERT(enode >= 0,
"edge node not found!");
339 MFEM_ASSERT(nd.
HasEdge(),
"edge not found!");
349 MFEM_ASSERT(!el.
ref_type,
"not a leaf element.");
352 for (
int j = 0; j <
faces.Size(); j++)
363 int v_index =
nodes[vnode].vert_index;
366 owner = std::min(owner, el.
rank);
377 el_loc = (el.
index << 4) | local;
416 for (
int i = 0; i < num; i++)
428 for (
int i = 0; i < list.masters.Size(); i++)
430 const Master &master = list.masters[i];
432 char master_old_flag = master_flag;
436 int si = list.slaves[j].index;
440 master_flag |= slave_flag;
441 slave_flag |= master_old_flag;
455 for (
int i = 0; i < list.conforming.Size(); i++)
462 for (
int i = 0; i < list.masters.Size(); i++)
466 shared.
masters.Append(list.masters[i]);
469 for (
int i = 0; i < list.slaves.Size(); i++)
471 int si = list.slaves[i].index;
474 shared.
slaves.Append(list.slaves[i]);
481 if (lhs.size() == rhs.size())
483 for (
unsigned i = 0; i < lhs.size(); i++)
485 if (lhs[i] < rhs[i]) {
return true; }
489 return lhs.size() < rhs.size();
495 for (
unsigned i = 1; i < group.size(); i++)
497 if (group[i] <= group[i-1]) {
return false; }
505 if (group.size() == 1 && group[0] ==
MyRank)
509 MFEM_ASSERT(group_sorted(group),
"invalid group");
521 MFEM_ASSERT(rank != INT_MAX,
"invalid rank");
522 static std::vector<int> group;
532 for (
unsigned i = 0; i < group.size(); i++)
534 if (group[i] == rank) {
return true; }
545 entity_group.
SetSize(nentities);
550 for (
auto begin = index_rank.
begin(); begin != index_rank.
end(); )
552 const auto &
index = begin->from;
553 if (
index >= nentities) {
break; }
556 const auto end = std::find_if(begin, index_rank.
end(),
560 group.resize(std::distance(begin, end));
561 std::transform(begin, end, group.begin(), [](
const mfem::Connection &c) { return c.to; });
571 for (
auto rank : ranks)
584 int v[4], e[4], eo[4];
593 for (
int j = master_edge.slaves_begin; j < master_edge.slaves_end; j++)
604 for (
int j = 0; j < 2; j++)
614 for (
int j = master_face.slaves_begin; j < master_face.slaves_end; j++)
628 for (
int j = 0; j < nfv; j++)
643 for (
int i = 0; i < 3; i++)
656 const Element *
const e[2] = { &e1, &e2 };
657 for (
int i = 0; i < 2; i++)
666 if (local) { local[i] = lf; }
670 for (
int j = 0; j < 4; j++)
672 ids[i][j] = e[i]->
node[fv[j]];
682 if (
Dim < 3) {
return; }
691 for (
const auto &face :
faces)
693 if (face.elem[0] >= 0 && face.elem[1] >= 0 && face.index <
NFaces)
698 if (e1->
rank == e2->
rank) {
continue; }
699 if (e1->
rank > e2->
rank) { std::swap(e1, e2); }
719 for (
int j = mf.slaves_begin; j < mf.slaves_end; j++)
730 bdr_faces.
Append(mf.index);
742 for (
int j = me.slaves_begin; j < me.slaves_end; j++)
748 bdr_edges.
Append(me.index);
755 auto FilterSortUnique = [](
Array<int> &v,
int N)
758 auto local = std::remove_if(v.
begin(), v.
end(), [N](
int i) { return i >= N; });
759 std::sort(v.
begin(), local);
763 FilterSortUnique(bdr_vertices,
NVertices);
764 FilterSortUnique(bdr_edges,
NEdges);
765 FilterSortUnique(bdr_faces,
NFaces);
778 for (
int i = 0; i < nleaves; i++)
793 for (
int i = 0; i < nleaves; i++)
801 else if (boundary_set[i] && etype)
818 for (
int i = 0; i < 8 && el.
child[i] >= 0; i++)
848static void set_to_array(
const std::set<T> &set,
Array<T> &array)
850 array.Reserve(
static_cast<int>(set.size()));
869 set_to_array(ranks, neighbors);
881 group_shared.
MakeI(ngroups-1);
885 for (
int i = 0; i < conf_group.
Size(); i++)
889 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
896 shared_local.
SetSize(num_shared);
897 group_shared.
MakeJ();
900 for (
int i = 0, j = 0; i < conf_group.
Size(); i++)
904 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
914 for (
int i = 0; i < group_shared.
Size(); i++)
916 int size = group_shared.
RowSize(i);
917 int *row = group_shared.
GetRow(i);
920 ref_row.
Sort([&](
const int a,
const int b)
928 if (lsi_a != lsi_b) {
return lsi_a < lsi_b; }
930 return (el_loc_a & 0xf) < (el_loc_b & 0xf);
940 for (
int ent = 0; ent <
Dim; ent++)
944 pmesh.
GetNE() == 0,
"Non empty partitions must be connected");
946 pmesh.
GetNE() == 0,
"Non empty partitions must be connected");
956 for (
unsigned i = 0; i <
groups.size(); i++)
958 if (
groups[i].size() > 1 || !i)
961 group_map[i] = int_groups.
Insert(iset);
968 for (
int ent = 0; ent < 3; ent++)
973 ecg = group_map[ecg];
1007 for (
int i = 0; i < slt.
Size(); i++)
1012 int v[4], e[4], eo[4];
1019 for (
int i = 0; i < slq.
Size(); i++)
1029 for (
int ent = 0; ent <
Dim; ent++)
1045 std::map<int, std::vector<int>> recv_elems;
1050 auto count_slaves = [&](
int i,
const Master& x)
1052 return i + (x.slaves_end - x.slaves_begin);
1055 const int bound = shared.
conforming.Size() + std::accumulate(
1065 bool face_nbr_w_tri_faces =
false;
1068 for (
int i = 0; i < shared.
conforming.Size(); i++)
1072 MFEM_ASSERT(face != NULL,
"");
1074 MFEM_ASSERT(face->
elem[0] >= 0 && face->
elem[1] >= 0,
"");
1077 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
1078 MFEM_ASSERT(e[0]->rank !=
MyRank && e[1]->rank ==
MyRank,
"");
1085 recv_elems[e[0]->
rank].push_back(e[0]->
index);
1088 for (
int i = 0; i < shared.
masters.Size(); i++)
1096 MFEM_ASSERT(mf.
element >= 0,
"");
1106 if (loc0) { std::swap(e[0], e[1]); }
1113 recv_elems[e[0]->
rank].push_back(e[0]->
index);
1117 MFEM_ASSERT(fnbr.
Size() <= bound,
1118 "oops, bad upper bound. fnbr.Size(): " << fnbr.
Size() <<
", bound: " << bound);
1127 return (
a->rank !=
b->rank) ?
a->rank <
b->rank
1128 :
a->index <
b->index;
1132 for (
int i = 0; i < fnbr.
Size(); i++)
1151 std::map<int, int> vert_map;
1152 for (
int i = 0; i < fnbr.
Size(); i++)
1160 for (
int k = 0; k < gi.
nv; k++)
1162 int &v = vert_map[elem->
node[k]];
1163 if (!v) { v =
static_cast<int>(vert_map.size()); }
1167 if (!i || elem->
rank != fnbr[i-1]->rank)
1183 for (
const auto &v : vert_map)
1196 for (
auto &kv : recv_elems)
1198 std::sort(kv.second.begin(), kv.second.end());
1199 kv.second.erase(std::unique(kv.second.begin(), kv.second.end()),
1203 for (
int i = 0, last_rank = -1; i < send_elems.
Size(); i++)
1206 if (c.
from != last_rank)
1214 c.
from = send_elems[i-1].from;
1224 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
1243 bool sharedUpdated =
false;
1244 if (shared.
slaves.Size())
1248 sharedUpdated = (pmesh.
faces_info.Size() == nfaces + nghosts);
1251 if (shared.
slaves.Size() && !sharedUpdated)
1259 for (
int i = nfaces; i < pmesh.
faces_info.Size(); i++)
1270 for (
int i = 0; i < shared.
masters.Size(); i++)
1276 if (sf.
element < 0) {
continue; }
1278 MFEM_ASSERT(mf.
element >= 0,
"");
1319 if (!sloc &&
Dim == 3)
1325 std::swap((*pm2)(0, 1), (*pm2)(0, 3));
1326 std::swap((*pm2)(1, 1), (*pm2)(1, 3));
1330 std::swap((*pm2)(0, 0), (*pm2)(0, 1));
1331 std::swap((*pm2)(1, 0), (*pm2)(1, 1));
1348 else if (!sloc &&
Dim == 2)
1369 if (face_nbr_w_tri_faces)
1373 using RankToOrientation = std::map<int, std::vector<std::array<int, 6>>>;
1374 constexpr std::array<int, 6> unset_ori{{-1,-1,-1,-1,-1,-1}};
1381 RankToOrientation send_rank_to_face_neighbor_orientations;
1386 for (
const auto &se : send_elems)
1392 send_rank_to_face_neighbor_orientations[true_rank].emplace_back(unset_ori);
1395 std::copy(orientations.
begin(), orientations.
end(),
1396 send_rank_to_face_neighbor_orientations[true_rank].back().begin());
1403 auto recv_rank_to_face_neighbor_orientations =
1404 send_rank_to_face_neighbor_orientations;
1405 for (
auto &kv : recv_rank_to_face_neighbor_orientations)
1407 kv.second.resize(recv_elems[kv.first].size());
1412 std::vector<MPI_Request> send_requests, recv_requests;
1413 std::vector<MPI_Status> status(nranks);
1417 send_requests.reserve(nranks);
1418 recv_requests.reserve(nranks);
1425 for (
const auto &kv : send_rank_to_face_neighbor_orientations)
1427 send_requests.emplace_back();
1430 const int send_tag = (rank < kv.first)
1431 ? std::min(rank, kv.first)
1432 : std::max(rank, kv.first);
1433 MPI_Isend(
const_cast<int*
>(&kv.second[0][0]),
int(kv.second.size() * 6),
1434 MPI_INT, kv.first, send_tag, pmesh.
MyComm, &send_requests.back());
1439 for (
auto &kv : recv_rank_to_face_neighbor_orientations)
1441 recv_requests.emplace_back();
1444 const int recv_tag = (rank < kv.first)
1445 ? std::max(rank, kv.first)
1446 : std::min(rank, kv.first);
1447 MPI_Irecv(&kv.second[0][0],
int(kv.second.size() * 6),
1448 MPI_INT, kv.first, recv_tag, pmesh.
MyComm, &recv_requests.back());
1452 MPI_Waitall(
int(recv_requests.size()), recv_requests.data(), status.data());
1456 for (
const auto &kv : recv_rank_to_face_neighbor_orientations)
1459 for (
const auto &eo : kv.second)
1468 MPI_Waitall(
int(send_requests.size()), send_requests.data(), status.data());
1492 bool removeAll =
true;
1495 for (
int i = 0; i < 8; i++)
1498 if (el.
child[i] >= 0)
1501 if (!remove[i]) { removeAll =
false; }
1506 if (removeAll) {
return true; }
1509 for (
int i = 0; i < 8; i++)
1529 MFEM_WARNING(
"Can't prune 3D aniso meshes yet.");
1557 std::set<int> &conflicts)
1559 if (
Dim < 3 ||
NRanks == 1) {
return false; }
1561 for (
int i = 0; i < refinements.
Size() &&
Iso; i++)
1571 bool globalIso =
false;
1572 MPI_Allreduce(&
Iso, &globalIso, 1, MFEM_MPI_CXX_BOOL, MPI_LAND,
MyComm);
1574 if (globalIso) {
return false; }
1582 for (
int i = 0; i < neighbors.
Size(); i++)
1584 send_ref[neighbors[i]].SetNCMesh(
this);
1592 for (
int i = 0; i < refinements.
Size(); i++)
1598 for (
int j = 0; j < ranks.
Size(); j++)
1600 send_ref[ranks[j]].AddRefinement(elem, ref);
1611 std::map<int, int> elemToRef;
1612 for (
int i = 0; i < refinements.
Size(); i++)
1618 for (
int i = 0; i < refinements.
Size(); i++)
1626 for (
int j = 0; j < neighbors.
Size(); j++)
1636 for (
int i = 0; i < msg.
Size(); i++)
1650 const bool conflict = conflicts.size() > 0;
1651 bool globalConflict =
false;
1652 MPI_Allreduce(&conflict, &globalConflict, 1, MFEM_MPI_CXX_BOOL, MPI_LOR,
1654 return globalConflict;
1663 constexpr std::array<int, 6> hexFaceDir = {2, 1, 0, 1, 0, 2};
1664 return hexFaceDir[face];
1670 std::array<int, 2> faceRefDir;
1672 for (
int d=0; d<3; ++d)
1676 faceRefDir[cnt] = refDir[d] ? 1 : 0;
1681 const char ref_type = (char)(faceRefDir[0] + (2 * faceRefDir[1]));
1695 if (mid23 >= 0 && mid41 >= 0)
1697 const int midf =
nodes.FindId(mid23, mid41);
1711 if (level > 0) {
return true; }
1717 const std::map<int, int> &elemToRef,
1718 std::set<int> &conflicts)
1720 MFEM_VERIFY(
Dim == 3,
"");
1723 for (
const auto &mf : faceList.
masters)
1726 if (elemToRef.count(mf.element) == 0) {
continue; }
1728 const int refIndex = elemToRef.at(mf.element);
1729 const Refinement& ref = refinements[refIndex];
1732 for (
int i=0; i<3; ++i)
1733 refDir[i] = ref.
s[i] >
real_t{0};
1736 if (faceRefType == 0) {
continue; }
1738 std::array<int, 4> fv;
1739 for (
int i=0; i<4; ++i)
1745 if (faceRefType != 2)
1750 conflicts.insert(refIndex);
1754 if (faceRefType != 1)
1759 conflicts.insert(refIndex);
1768 v.insert({vn1, vn2, vn3, vn4});
1771 for (
int f=0;
f<6; ++
f)
1773 bool allFound =
true;
1774 for (
int i=0; i<4; ++i)
1777 if (v.count(vi) == 0)
1785 MFEM_ASSERT(face == -1,
"");
1790 MFEM_ASSERT(face >= 0,
"");
1796static int GetHexEdgeSplit(
const int*
nodes,
int v1,
int v2)
1806 for (
int i=0; i<12; ++i)
1808 for (
int j=0; j<2; ++j)
1810 ev[j] =
nodes[Geometry::Constants<Geometry::CUBE>::Edges[i][j]];
1816 MFEM_ASSERT(edge == -1,
"");
1821 MFEM_ASSERT(edge >= 0,
"");
1823 constexpr int edgeDir[12] = {0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2};
1824 return edgeDir[edge];
1827void ParNCMesh::CheckRefAnisoFace(
const Refinement &ref,
int elem,
1828 int vn1,
int vn2,
int vn3,
int vn4,
1830 const std::map<int, int> &elemToRef,
1831 std::set<int> &conflicts)
1833 Face* face = faces.Find(vn1, vn2, vn3, vn4);
1834 if (!face) {
return; }
1837 const int nghbIndex = face->
elem[0] == elem ? face->
elem[1] : face->
elem[0];
1838 if (nghbIndex < 0) {
return; }
1840 Element &nghb = elements[nghbIndex];
1841 MFEM_ASSERT(nghb.
ref_type == 0,
"");
1843 if (elemToRef.count(nghbIndex) > 0)
1845 const int refIndex = elemToRef.at(nghbIndex);
1846 const Refinement& nghb_ref = refinements[refIndex];
1849 for (
int i=0; i<3; ++i)
1850 refDir[i] = nghb_ref.
s[i] >
real_t{0};
1855 const bool faceAniso = face_ref_type == 1 ||
1862 int hexSplitOnFace = -1;
1864 const int firstFaceDir = face_ref_type == 1 ? 0 : 1;
1867 for (
int i=0; i<3; ++i)
1869 if (i == faceDir) {
continue; }
1871 if (firstFaceDir == cnt)
1873 MFEM_ASSERT(hexSplitOnFace == -1,
"");
1879 MFEM_ASSERT(cnt == 2 && hexSplitOnFace >= 0,
"");
1881 const int edgeSplit = GetHexEdgeSplit(nghb.
node, vn1, vn2);
1882 if (edgeSplit != hexSplitOnFace)
1884 conflicts.insert(refIndex);
1888 const real_t elem_scale =
1889 DirectedHexEdgeScale(elements[elem].node, ref, vn1, vn2);
1890 const real_t nghb_scale =
1891 DirectedHexEdgeScale(nghb.
node, nghb_ref, vn1, vn2);
1892 if (!SameSplitScale(elem_scale, nghb_scale))
1894 conflicts.insert(refIndex);
1904 int vn1,
int vn2,
int vn3,
int vn4,
1905 int en1,
int en2,
int en3,
int en4,
1907 const std::map<int, int> &elemToRef,
1908 std::set<int> &conflicts)
1910 CheckRefAnisoFace(ref, elem, vn1, vn2, en2, en4, refinements, elemToRef,
1912 CheckRefAnisoFace(ref, elem, en4, en2, vn3, vn4, refinements, elemToRef,
1914 CheckRefAnisoFace(ref, elem, vn4, vn1, en1, en3, refinements, elemToRef,
1916 CheckRefAnisoFace(ref, elem, en3, en1, vn2, vn3, refinements, elemToRef,
1922 const std::map<int, int> &elemToRef,
1923 std::set<int> &conflicts)
1925 const char ref_type = ref.
GetType();
1926 const Element &el = elements[elem];
1927 MFEM_ASSERT(el.
geom == Geometry::CUBE && el.
ref_type == 0,
1928 "Element must be an unrefined hexahedron");
1930 const int* no = el.
node;
1934 if (ref_type == Refinement::X)
1936 CheckRefAnisoFace(ref, elem, no[0], no[1], no[5], no[4], refinements,
1937 elemToRef, conflicts);
1938 CheckRefAnisoFace(ref, elem, no[2], no[3], no[7], no[6], refinements,
1939 elemToRef, conflicts);
1940 CheckRefAnisoFace(ref, elem, no[4], no[5], no[6], no[7], refinements,
1941 elemToRef, conflicts);
1942 CheckRefAnisoFace(ref, elem, no[3], no[2], no[1], no[0], refinements,
1943 elemToRef, conflicts);
1945 else if (ref_type == Refinement::Y)
1947 CheckRefAnisoFace(ref, elem, no[1], no[2], no[6], no[5], refinements,
1948 elemToRef, conflicts);
1949 CheckRefAnisoFace(ref, elem, no[3], no[0], no[4], no[7], refinements,
1950 elemToRef, conflicts);
1951 CheckRefAnisoFace(ref, elem, no[5], no[6], no[7], no[4], refinements,
1952 elemToRef, conflicts);
1953 CheckRefAnisoFace(ref, elem, no[0], no[3], no[2], no[1], refinements,
1954 elemToRef, conflicts);
1956 else if (ref_type == Refinement::Z)
1958 CheckRefAnisoFace(ref, elem, no[4], no[0], no[1], no[5], refinements,
1959 elemToRef, conflicts);
1960 CheckRefAnisoFace(ref, elem, no[5], no[1], no[2], no[6], refinements,
1961 elemToRef, conflicts);
1962 CheckRefAnisoFace(ref, elem, no[6], no[2], no[3], no[7], refinements,
1963 elemToRef, conflicts);
1964 CheckRefAnisoFace(ref, elem, no[7], no[3], no[0], no[4], refinements,
1965 elemToRef, conflicts);
1967 else if (ref_type == Refinement::XY)
1969 CheckRefAnisoFace(ref, elem, no[0], no[1], no[5], no[4], refinements,
1970 elemToRef, conflicts);
1971 CheckRefAnisoFace(ref, elem, no[1], no[2], no[6], no[5], refinements,
1972 elemToRef, conflicts);
1973 CheckRefAnisoFace(ref, elem, no[2], no[3], no[7], no[6], refinements,
1974 elemToRef, conflicts);
1975 CheckRefAnisoFace(ref, elem, no[3], no[0], no[4], no[7], refinements,
1976 elemToRef, conflicts);
1978 const int mid01 = GetMidEdgeNode(no[0], no[1]);
1979 const int mid12 = GetMidEdgeNode(no[1], no[2]);
1980 const int mid23 = GetMidEdgeNode(no[2], no[3]);
1981 const int mid30 = GetMidEdgeNode(no[3], no[0]);
1983 const int mid45 = GetMidEdgeNode(no[4], no[5]);
1984 const int mid56 = GetMidEdgeNode(no[5], no[6]);
1985 const int mid67 = GetMidEdgeNode(no[6], no[7]);
1986 const int mid74 = GetMidEdgeNode(no[7], no[4]);
1988 CheckRefIsoFace(ref, elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
1989 mid30, refinements, elemToRef, conflicts);
1990 CheckRefIsoFace(ref, elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
1991 mid74, refinements, elemToRef, conflicts);
1993 else if (ref_type == Refinement::XZ)
1995 CheckRefAnisoFace(ref, elem, no[3], no[2], no[1], no[0], refinements,
1996 elemToRef, conflicts);
1997 CheckRefAnisoFace(ref, elem, no[2], no[6], no[5], no[1], refinements,
1998 elemToRef, conflicts);
1999 CheckRefAnisoFace(ref, elem, no[6], no[7], no[4], no[5], refinements,
2000 elemToRef, conflicts);
2001 CheckRefAnisoFace(ref, elem, no[7], no[3], no[0], no[4], refinements,
2002 elemToRef, conflicts);
2004 const int mid01 = GetMidEdgeNode(no[0], no[1]);
2005 const int mid23 = GetMidEdgeNode(no[2], no[3]);
2006 const int mid45 = GetMidEdgeNode(no[4], no[5]);
2007 const int mid67 = GetMidEdgeNode(no[6], no[7]);
2009 const int mid04 = GetMidEdgeNode(no[0], no[4]);
2010 const int mid15 = GetMidEdgeNode(no[1], no[5]);
2011 const int mid26 = GetMidEdgeNode(no[2], no[6]);
2012 const int mid37 = GetMidEdgeNode(no[3], no[7]);
2014 CheckRefIsoFace(ref, elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
2015 mid04, refinements, elemToRef, conflicts);
2016 CheckRefIsoFace(ref, elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
2017 mid26, refinements, elemToRef, conflicts);
2019 else if (ref_type == Refinement::YZ)
2021 const int mid12 = GetMidEdgeNode(no[1], no[2]);
2022 const int mid30 = GetMidEdgeNode(no[3], no[0]);
2023 const int mid56 = GetMidEdgeNode(no[5], no[6]);
2024 const int mid74 = GetMidEdgeNode(no[7], no[4]);
2026 const int mid04 = GetMidEdgeNode(no[0], no[4]);
2027 const int mid15 = GetMidEdgeNode(no[1], no[5]);
2028 const int mid26 = GetMidEdgeNode(no[2], no[6]);
2029 const int mid37 = GetMidEdgeNode(no[3], no[7]);
2031 CheckRefAnisoFace(ref, elem, no[4], no[0], no[1], no[5], refinements,
2032 elemToRef, conflicts);
2033 CheckRefAnisoFace(ref, elem, no[0], no[3], no[2], no[1], refinements,
2034 elemToRef, conflicts);
2035 CheckRefAnisoFace(ref, elem, no[3], no[7], no[6], no[2], refinements,
2036 elemToRef, conflicts);
2037 CheckRefAnisoFace(ref, elem, no[7], no[4], no[5], no[6], refinements,
2038 elemToRef, conflicts);
2040 CheckRefIsoFace(ref, elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
2041 mid15, refinements, elemToRef, conflicts);
2042 CheckRefIsoFace(ref, elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
2043 mid37, refinements, elemToRef, conflicts);
2045 else if (ref_type == Refinement::XYZ)
2047 const int mid01 = GetMidEdgeNode(no[0], no[1]);
2048 const int mid12 = GetMidEdgeNode(no[1], no[2]);
2049 const int mid23 = GetMidEdgeNode(no[2], no[3]);
2050 const int mid30 = GetMidEdgeNode(no[3], no[0]);
2052 const int mid45 = GetMidEdgeNode(no[4], no[5]);
2053 const int mid56 = GetMidEdgeNode(no[5], no[6]);
2054 const int mid67 = GetMidEdgeNode(no[6], no[7]);
2055 const int mid74 = GetMidEdgeNode(no[7], no[4]);
2057 const int mid04 = GetMidEdgeNode(no[0], no[4]);
2058 const int mid15 = GetMidEdgeNode(no[1], no[5]);
2059 const int mid26 = GetMidEdgeNode(no[2], no[6]);
2060 const int mid37 = GetMidEdgeNode(no[3], no[7]);
2062 CheckRefIsoFace(ref, elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
2063 mid30, refinements, elemToRef, conflicts);
2064 CheckRefIsoFace(ref, elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
2065 mid04, refinements, elemToRef, conflicts);
2066 CheckRefIsoFace(ref, elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
2067 mid15, refinements, elemToRef, conflicts);
2068 CheckRefIsoFace(ref, elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
2069 mid26, refinements, elemToRef, conflicts);
2070 CheckRefIsoFace(ref, elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
2071 mid37, refinements, elemToRef, conflicts);
2072 CheckRefIsoFace(ref, elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
2073 mid74, refinements, elemToRef, conflicts);
2077 MFEM_ABORT(
"Invalid refinement type.");
2085 NCMesh::Refine(refinements);
2089 for (
int i = 0; i < refinements.
Size() && Iso; i++)
2092 if (ref.
GetType() != Refinement::XYZ)
2102 NeighborProcessors(neighbors);
2103 for (
int i = 0; i < neighbors.
Size(); i++)
2105 send_ref[neighbors[i]].SetNCMesh(
this);
2113 for (
int i = 0; i < refinements.
Size(); i++)
2116 MFEM_ASSERT(ref.
index < NElements,
"");
2117 const int elem = leaf_elements[ref.
index];
2118 ElementNeighborProcessors(elem, ranks);
2119 for (
int j = 0; j < ranks.
Size(); j++)
2121 send_ref[ranks[j]].AddRefinement(elem, ref);
2126 NeighborRefinementMessage::IsendAll(send_ref, MyComm);
2129 for (
int i = 0; i < refinements.
Size(); i++)
2132 ref_i.
index = leaf_elements[refinements[i].index];
2133 NCMesh::RefineElement(ref_i);
2137 for (
int j = 0; j < neighbors.
Size(); j++)
2140 NeighborRefinementMessage::Probe(rank, size, MyComm);
2144 msg.
Recv(rank, size, MyComm);
2147 for (
int i = 0; i < msg.
Size(); i++)
2151 NCMesh::RefineElement(ghost_ref);
2158 NeighborRefinementMessage::WaitAllSent(send_ref);
2162void ParNCMesh::LimitNCLevel(
int max_nc_level)
2164 MFEM_VERIFY(max_nc_level >= 1,
"'max_nc_level' must be 1 or greater.");
2169 GetLimitRefinements(refinements, max_nc_level);
2171 long long size = refinements.
Size(), glob_size;
2172 MPI_Allreduce(&size, &glob_size, 1, MPI_LONG_LONG, MPI_SUM, MyComm);
2174 if (!glob_size) {
break; }
2176 Refine(refinements);
2180void ParNCMesh::GetFineToCoarsePartitioning(
const Array<int> &derefs,
2183 new_ranks.
SetSize(leaf_elements.Size()-GetNGhostElements());
2184 for (
int i = 0; i < leaf_elements.Size()-GetNGhostElements(); i++)
2186 new_ranks[i] = elements[leaf_elements[i]].rank;
2189 for (
int i = 0; i < derefs.
Size(); i++)
2191 int row = derefs[i];
2192 MFEM_VERIFY(row >= 0 && row < derefinements.Size(),
2193 "invalid derefinement number.");
2195 const int* fine = derefinements.GetRow(row);
2196 int size = derefinements.RowSize(row);
2198 int coarse_rank = INT_MAX;
2199 for (
int j = 0; j < size; j++)
2201 int fine_rank = elements[leaf_elements[fine[j]]].rank;
2202 coarse_rank = std::min(coarse_rank, fine_rank);
2204 for (
int j = 0; j < size; j++)
2206 new_ranks[fine[j]] = coarse_rank;
2213 MFEM_VERIFY(Dim < 3 || Iso,
2214 "derefinement of 3D anisotropic meshes not implemented yet.");
2216 InitDerefTransforms();
2219 old_index_or_rank.SetSize(leaf_elements.Size());
2220 for (
int i = 0; i < leaf_elements.Size(); i++)
2222 old_index_or_rank[i] = elements[leaf_elements[i]].rank;
2227 leaf_elements.
Copy(old_elements);
2232 for (
int i = 0; i < leaf_elements.Size(); i++)
2234 new_ranks[i] = elements[leaf_elements[i]].rank;
2238 for (
int i = 0; i < derefs.
Size(); i++)
2240 int row = derefs[i];
2241 MFEM_VERIFY(row >= 0 && row < derefinements.Size(),
2242 "invalid derefinement number.");
2244 const int* fine = derefinements.GetRow(row);
2245 int size = derefinements.RowSize(row);
2247 int coarse_rank = INT_MAX;
2248 for (
int j = 0; j < size; j++)
2250 int fine_rank = elements[leaf_elements[fine[j]]].rank;
2251 coarse_rank = std::min(coarse_rank, fine_rank);
2253 for (
int j = 0; j < size; j++)
2255 new_ranks[fine[j]] = coarse_rank;
2259 int target_elements = 0;
2260 for (
int i = 0; i < new_ranks.
Size(); i++)
2262 if (new_ranks[i] == MyRank) { target_elements++; }
2267 RedistributeElements(new_ranks, target_elements,
false);
2275 NeighborProcessors(neighbors);
2276 for (
int i = 0; i < neighbors.
Size(); i++)
2278 send_deref[neighbors[i]].SetNCMesh(
this);
2285 for (
int i = 0; i < derefs.
Size(); i++)
2287 const int* fine = derefinements.GetRow(derefs[i]);
2288 int parent = elements[old_elements[fine[0]]].parent;
2291 ElementNeighborProcessors(parent, ranks);
2292 for (
int j = 0; j < ranks.
Size(); j++)
2294 send_deref[ranks[j]].AddDerefinement(parent, new_ranks[fine[0]]);
2297 NeighborDerefinementMessage::IsendAll(send_deref, MyComm);
2300 for (
int i = 0; i < leaf_elements.Size(); i++)
2302 elements[leaf_elements[i]].index = -1;
2304 for (
int i = 0; i < old_elements.
Size(); i++)
2306 elements[old_elements[i]].index = i;
2311 old_elements.
Copy(coarse);
2312 for (
int i = 0; i < derefs.
Size(); i++)
2314 const int* fine = derefinements.GetRow(derefs[i]);
2315 int parent = elements[old_elements[fine[0]]].parent;
2318 SetDerefMatrixCodes(parent, coarse);
2320 NCMesh::DerefineElement(parent);
2324 for (
int j = 0; j < neighbors.
Size(); j++)
2327 NeighborDerefinementMessage::Probe(rank, size, MyComm);
2331 msg.
Recv(rank, size, MyComm);
2334 for (
int i = 0; i < msg.
Size(); i++)
2337 if (elements[elem].ref_type)
2339 SetDerefMatrixCodes(elem, coarse);
2340 NCMesh::DerefineElement(elem);
2342 elements[elem].rank = msg.
values[i];
2352 for (
int i = 0; i < coarse.
Size(); i++)
2354 int index = elements[coarse[i]].index;
2355 if (element_type[
index] == 0)
2360 transforms.embeddings[i].parent =
index;
2363 leaf_elements.Copy(old_elements);
2368 for (
int i = 0; i < coarse.
Size(); i++)
2370 int &
index = transforms.embeddings[i].parent;
2378 NeighborDerefinementMessage::WaitAllSent(send_deref);
2382template<
typename Type>
2384 const Table &deref_table)
2395 elem_data.
SetSize(leaf_elements.Size(), 0);
2397 for (
int i = 0; i < deref_table.
Size(); i++)
2399 const int* fine = deref_table.
GetRow(i);
2400 int size = deref_table.
RowSize(i);
2401 MFEM_ASSERT(size <= 8,
"");
2403 int ranks[8], min_rank = INT_MAX, max_rank = INT_MIN;
2404 for (
int j = 0; j < size; j++)
2406 ranks[j] = elements[leaf_elements[fine[j]]].rank;
2407 min_rank = std::min(min_rank, ranks[j]);
2408 max_rank = std::max(max_rank, ranks[j]);
2412 if (min_rank != max_rank)
2415 for (
int j = 0; j < size; j++)
2417 if (ranks[j] != MyRank) { neigh.
Append(ranks[j]); }
2422 for (
int j = 0; j < size; j++)
2424 Type *data = &elem_data[fine[j]];
2426 int rnk = ranks[j], len = 1;
2432 for (
int k = 0; k < neigh.
Size(); k++)
2434 MPI_Request* req =
new MPI_Request;
2435 MPI_Isend(data, len, datatype, neigh[k], 292, MyComm, req);
2441 MPI_Request* req =
new MPI_Request;
2442 MPI_Irecv(data, len, datatype, rnk, 292, MyComm, req);
2449 for (
int i = 0; i < requests.
Size(); i++)
2451 MPI_Wait(requests[i], MPI_STATUS_IGNORE);
2458ParNCMesh::SynchronizeDerefinementData<int>(
Array<int> &,
const Table &);
2465void ParNCMesh::CheckDerefinementNCLevel(
const Table &deref_table,
2472 for (
int i = 0; i < deref_table.
Size(); i++)
2474 const int *fine = deref_table.
GetRow(i),
2475 size = deref_table.
RowSize(i);
2477 int parent = elements[leaf_elements[fine[0]]].parent;
2478 Element &pa = elements[parent];
2480 for (
int j = 0; j < size; j++)
2482 int child = leaf_elements[fine[j]];
2483 if (elements[child].rank == MyRank)
2486 CountSplits(child, splits);
2488 for (
int k = 0; k < Dim; k++)
2491 splits[k] >= max_nc_level)
2493 leaf_ok[fine[j]] = 0;
break;
2500 SynchronizeDerefinementData(leaf_ok, deref_table);
2505 for (
int i = 0; i < deref_table.
Size(); i++)
2507 const int* fine = deref_table.
GetRow(i),
2508 size = deref_table.
RowSize(i);
2510 for (
int j = 0; j < size; j++)
2512 if (!leaf_ok[fine[j]])
2514 level_ok[i] = 0;
break;
2525 send_rebalance_dofs.clear();
2526 recv_rebalance_dofs.clear();
2529 leaf_elements.
GetSubArray(0, NElements, old_elements);
2531 if (!custom_partition)
2537 long local_elems = NElements, total_elems = 0;
2538 MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM, MyComm);
2540 long first_elem_global = 0;
2541 MPI_Scan(&local_elems, &first_elem_global, 1, MPI_LONG, MPI_SUM, MyComm);
2542 first_elem_global -= local_elems;
2544 for (
int i = 0, j = 0; i < leaf_elements.Size(); i++)
2546 if (elements[leaf_elements[i]].rank == MyRank)
2548 new_ranks[i] = Partition(first_elem_global + (j++), total_elems);
2552 int target_elements = PartitionFirstIndex(MyRank+1, total_elems)
2553 - PartitionFirstIndex(MyRank, total_elems);
2556 RedistributeElements(new_ranks, target_elements,
true);
2560 MFEM_VERIFY(custom_partition->
Size() == NElements,
2561 "Size of the partition array must match the number "
2562 "of local mesh elements (ParMesh::GetNE()).");
2565 custom_partition->
Copy(new_ranks);
2566 new_ranks.
SetSize(leaf_elements.Size(), -1);
2568 RedistributeElements(new_ranks, -1,
true);
2572 old_index_or_rank.SetSize(NElements);
2573 old_index_or_rank = -1;
2574 for (
int i = 0; i < old_elements.
Size(); i++)
2576 Element &el = elements[old_elements[i]];
2577 if (el.
rank == MyRank) { old_index_or_rank[el.
index] = i; }
2584void ParNCMesh::RedistributeElements(
Array<int> &new_ranks,
int target_elements,
2587 bool sfc = (target_elements >= 0);
2595 ghost_layer.Sort([&](
const int a,
const int b)
2597 return elements[
a].rank < elements[
b].rank;
2604 int begin = 0, end = 0;
2605 while (end < ghost_layer.Size())
2608 int rank = elements[ghost_layer[begin]].rank;
2609 while (end < ghost_layer.Size() &&
2610 elements[ghost_layer[end]].rank == rank) { end++; }
2613 rank_elems.
MakeRef(&ghost_layer[begin], end - begin);
2617 NeighborExpand(rank_elems, rank_neighbors, &boundary_layer);
2624 for (
int i = 0; i < rank_neighbors.
Size(); i++)
2626 int elem = rank_neighbors[i];
2627 const Element &el = elements[elem];
2631 msg.
Isend(rank, MyComm);
2635 recv_ghost_ranks[rank].SetNCMesh(
this);
2641 NeighborElementRankMessage::RecvAll(recv_ghost_ranks, MyComm);
2644 for (
auto &kv : recv_ghost_ranks)
2647 for (
int i = 0; i < msg.
Size(); i++)
2649 int ghost_index = elements[msg.
elements[i]].index;
2650 MFEM_ASSERT(element_type[ghost_index] == 2,
"");
2652 new_ranks[ghost_index] = value.
rank;
2657 recv_ghost_ranks.clear();
2668 int received_elements = 0;
2669 for (
int i = 0; i < leaf_elements.Size(); i++)
2671 Element &el = elements[leaf_elements[i]];
2672 if (el.
rank == MyRank && new_ranks[i] == MyRank)
2674 received_elements++;
2676 el.
rank = new_ranks[i];
2679 int nsent = 0, nrecv = 0;
2685 owned_elements.
MakeRef(leaf_elements.GetData(), NElements);
2686 owned_elements.
Sort([&](
const int a,
const int b)
2688 return elements[
a].rank < elements[
b].rank;
2695 int begin = 0, end = 0;
2696 while (end < NElements)
2699 int rank = elements[owned_elements[begin]].rank;
2700 while (end < owned_elements.
Size() &&
2701 elements[owned_elements[end]].rank == rank) { end++; }
2706 rank_elems.
MakeRef(&owned_elements[begin], end - begin);
2710 NeighborExpand(rank_elems, batch);
2717 for (
int i = 0; i < batch.
Size(); i++)
2719 int elem = batch[i];
2722 if ((element_type[el.
index] & 1) || el.
rank != rank)
2733 msg.
Isend(rank, MyComm);
2738 msg.
Issend(rank, MyComm);
2746 send_rebalance_dofs[rank].SetElements(rank_elems,
this);
2765 while (received_elements < target_elements)
2768 RebalanceMessage::Probe(rank, size, MyComm);
2771 msg.
Recv(rank, size, MyComm);
2774 for (
int i = 0; i < msg.
Size(); i++)
2781 if (value.
rank == MyRank) { received_elements++; }
2787 recv_rebalance_dofs[rank].SetNCMesh(
this);
2793 RebalanceMessage::WaitAllSent(send_elems);
2803 MPI_Request barrier = MPI_REQUEST_NULL;
2809 while (RebalanceMessage::IProbe(rank, size, MyComm))
2812 msg.
Recv(rank, size, MyComm);
2815 for (
int i = 0; i < msg.
Size(); i++)
2826 recv_rebalance_dofs[rank].SetNCMesh(
this);
2830 if (barrier != MPI_REQUEST_NULL)
2832 MPI_Test(&barrier, &done, MPI_STATUS_IGNORE);
2836 if (RebalanceMessage::TestAllSent(send_elems))
2838 int mpi_err = MPI_Ibarrier(MyComm, &barrier);
2840 MFEM_VERIFY(mpi_err == MPI_SUCCESS,
"");
2841 MFEM_VERIFY(barrier != MPI_REQUEST_NULL,
"");
2849 NeighborElementRankMessage::WaitAllSent(send_ghost_ranks);
2852 int glob_sent, glob_recv;
2853 MPI_Reduce(&nsent, &glob_sent, 1, MPI_INT, MPI_SUM, 0, MyComm);
2854 MPI_Reduce(&nrecv, &glob_recv, 1, MPI_INT, MPI_SUM, 0, MyComm);
2858 MFEM_ASSERT(glob_sent == glob_recv,
2859 "(glob_sent, glob_recv) = ("
2860 << glob_sent <<
", " << glob_recv <<
")");
2863 MFEM_CONTRACT_VAR(nsent);
2864 MFEM_CONTRACT_VAR(nrecv);
2869void ParNCMesh::SendRebalanceDofs(
int old_ndofs,
2870 const Table &old_element_dofs,
2871 long old_global_offset,
2875 int vdim =
space->GetVDim();
2878 RebalanceDofMessage::Map::iterator it;
2879 for (it = send_rebalance_dofs.begin(); it != send_rebalance_dofs.end(); ++it)
2883 int ne =
static_cast<int>(msg.
elem_ids.size());
2888 for (
int i = 0; i < ne; i++)
2891 space->DofsToVDofs(dofs, old_ndofs);
2898 RebalanceDofMessage::IsendAll(send_rebalance_dofs, MyComm);
2905 RebalanceDofMessage::RecvAll(recv_rebalance_dofs, MyComm);
2909 RebalanceDofMessage::Map::iterator it;
2910 for (it = recv_rebalance_dofs.begin(); it != recv_rebalance_dofs.end(); ++it)
2913 ne +=
static_cast<int>(msg.
elem_ids.size());
2914 nd +=
static_cast<int>(msg.
dofs.size());
2922 for (it = recv_rebalance_dofs.begin(); it != recv_rebalance_dofs.end(); ++it)
2925 for (
unsigned i = 0; i < msg.
elem_ids.size(); i++)
2929 for (
unsigned i = 0; i < msg.
dofs.size(); i++)
2935 RebalanceDofMessage::WaitAllSent(send_rebalance_dofs);
2942 : ncmesh(other.ncmesh), include_ref_types(other.include_ref_types)
2950 data.Append(value & 0xff);
2951 data.Append((value >> 8) & 0xff);
2952 data.Append((value >> 16) & 0xff);
2953 data.Append((value >> 24) & 0xff);
2959 return (
int) data[pos] +
2960 ((int) data[pos+1] << 8) +
2961 ((int) data[pos+2] << 16) +
2962 ((int) data[pos+3] << 24);
2967 for (
int i = 0; i <
elements.Size(); i++)
2972 Element &el = ncmesh->elements[elem];
2973 if (el.
flag == flag) {
break; }
2982 Element &el = ncmesh->elements[elem];
2992 for (
int i = 0; i < 8; i++)
2994 if (el.
child[i] >= 0 && ncmesh->elements[el.
child[i]].flag)
3002 if (include_ref_types)
3007 for (
int i = 0; i < 8; i++)
3009 if (mask & (1 << i))
3011 EncodeTree(el.
child[i]);
3024 for (
int i = 0; i < ncmesh->root_state.Size(); i++)
3026 if (ncmesh->elements[i].flag)
3040 std::ostringstream oss;
3041 for (
int i = 0; i < ref_path.Size(); i++)
3043 oss <<
" elem " << ref_path[i] <<
" (";
3044 const Element &el = ncmesh->elements[ref_path[i]];
3045 for (
int j = 0; j <
GI[el.
Geom()].nv; j++)
3047 if (j) { oss <<
", "; }
3048 oss << ncmesh->RetrieveNode(el, j);
3060 ref_path.Append(elem);
3062 int mask = data[pos++];
3069 Element &el = ncmesh->elements[elem];
3070 if (include_ref_types)
3072 int ref_type = data[pos++];
3075 ncmesh->RefineElement(elem, ref_type);
3077 else { MFEM_ASSERT(ref_type == el.
ref_type,
"") }
3081 MFEM_ASSERT(el.
ref_type != 0,
"Path not found:\n"
3082 << RefPath() <<
" mask = " << mask);
3085 for (
int i = 0; i < 8; i++)
3087 if (mask & (1 << i))
3094 ref_path.DeleteLast();
3101 while ((root = GetInt(pos)) >= 0)
3111 os.write((
const char*) data.GetData(), data.Size());
3117 is.read((
char*) data.GetData(), data.Size());
3133 for (
unsigned i = 0; i <
groups.size(); i++)
3139 for (
int i = 0; i < ids[0].
Size(); i++)
3141 find_v[i].one = ids[0][i].index;
3155 for (
int j = 0; j < 2; j++)
3160 k = find_v[pos].two;
3171 for (
int i = 0; i < ids[1].
Size(); i++)
3173 find_e[i].one = ids[1][i].index;
3184 int v[4], e[4], eo[4], pos, k;
3186 for (
int j = 0; j < nfv; j++)
3190 k = find_v[pos].two;
3196 k = find_e[pos].two;
3211 for (
int i = 0; i < gi.
nv; i++)
3213 if (
nodes[el.
node[i]].vert_index ==
id.index)
3220 MFEM_ABORT(
"Vertex not found.");
3226 const int *old_ev =
GI[old.
Geom()].
edges[(int)
id.local];
3228 MFEM_ASSERT(node != NULL,
"Edge not found.");
3234 for (
int i = 0; i < gi.
ne; i++)
3236 const int* ev = gi.
edges[i];
3237 if ((el.
node[ev[0]] == node->
p1 && el.
node[ev[1]] == node->
p2) ||
3238 (el.
node[ev[1]] == node->
p1 && el.
node[ev[0]] == node->
p2))
3246 MFEM_ABORT(
"Edge not found.");
3252 const MeshId &first = ids[find[pos].two];
3253 while (++pos < find.Size() && ids[find[pos].two].index == first.
index)
3255 MeshId &other = ids[find[pos].two];
3263 std::map<int, int> stream_id;
3269 for (
int type = 0; type < 3; type++)
3271 for (
int i = 0; i < ids[type].
Size(); i++)
3285 for (
int i = 0; i < decoded.
Size(); i++)
3287 stream_id[decoded[i]] = i;
3292 for (
int type = 0; type < 3; type++)
3295 for (
int i = 0; i < ids[type].
Size(); i++)
3297 const MeshId&
id = ids[type][i];
3314 for (
int type = 0; type < 3; type++)
3319 for (
int i = 0; i < ne; i++)
3322 int elem = elems[el_num];
3325 MFEM_VERIFY(!el.
ref_type,
"not a leaf element: " << el_num);
3327 MeshId &
id = ids[type][i];
3337 id.index =
nodes[el.
node[(int)
id.local]].vert_index;
3342 const int* ev = gi.
edges[(int)
id.local];
3344 MFEM_ASSERT(node && node->
HasEdge(),
"edge not found.");
3350 const int* fv = gi.
faces[(int)
id.local];
3353 MFEM_ASSERT(face,
"face not found.");
3354 id.index = face->
index;
3364 std::map<GroupId, GroupId> stream_id;
3365 for (
int i = 0; i < ids.
Size(); i++)
3367 if (i && ids[i] == ids[i-1]) {
continue; }
3368 unsigned size = stream_id.size();
3369 GroupId &sid = stream_id[ids[i]];
3370 if (size != stream_id.size()) { sid = size; }
3375 for (std::map<GroupId, GroupId>::iterator
3376 it = stream_id.begin(); it != stream_id.end(); ++it)
3383 for (
unsigned i = 0; i < group.size(); i++)
3397 for (
int i = 0; i < ids.
Size(); i++)
3411 for (
int i = 0; i < ngroups; i++)
3418 for (
int ii = 0; ii < size; ii++)
3432 for (
int i = 0; i < ids.
Size(); i++)
3441template<
class ValueType,
bool RefTypes,
int Tag>
3444 std::ostringstream ostream;
3450 eset.
Encode(tmp_elements);
3458 std::map<int, int> element_index;
3459 for (
int i = 0; i < decoded.
Size(); i++)
3461 element_index[decoded[i]] = i;
3464 write<int>(ostream,
static_cast<int>(values.size()));
3465 MFEM_ASSERT(
elements.size() == values.size(),
"");
3467 for (
unsigned i = 0; i < values.size(); i++)
3473 ostream.str().swap(data);
3476template<
class ValueType,
bool RefTypes,
int Tag>
3479 std::istringstream istream(data);
3485 eset.
Decode(tmp_elements);
3487 int* el = tmp_elements.
GetData();
3492 for (
int i = 0; i < count; i++)
3495 MFEM_ASSERT(
index >= 0 && (
size_t)
index < values.size(),
"");
3506 eset.SetNCMesh(ncmesh);
3511 eset.Decode(decoded);
3513 elem_ids.resize(decoded.
Size());
3514 for (
int i = 0; i < decoded.
Size(); i++)
3516 elem_ids[i] = eset.GetNCMesh()->elements[decoded[i]].index;
3520static void write_dofs(std::ostream &os,
const std::vector<int> &dofs)
3522 write<int>(os,
static_cast<int>(dofs.size()));
3524 os.write((
const char*) dofs.data(), dofs.size() *
sizeof(
int));
3527static void read_dofs(std::istream &is, std::vector<int> &dofs)
3530 is.read((
char*) dofs.data(), dofs.size() *
sizeof(
int));
3535 std::ostringstream stream;
3539 write_dofs(stream, dofs);
3541 stream.str().swap(data);
3546 std::istringstream stream(data);
3550 read_dofs(stream, dofs);
3557 elem_ids.resize(elems.
Size());
3558 for (
int i = 0; i < elems.
Size(); i++)
3560 elem_ids[i] = eset.GetNCMesh()->elements[elems[i]].index;
3573 for (
int i = 0; i < cle.
Size(); i++)
3575 Element &el = copy->elements[cle[i]];
3581 debug_mesh.
ncmesh = copy;
3592 for (
int i = 0; i < 3; i++)
3609 return (elem_ids.capacity() + dofs.capacity()) *
sizeof(int);
3612template<
typename K,
typename V>
3613static std::size_t map_memory_usage(
const std::map<K, V> &map)
3615 std::size_t result = 0;
3616 for (
typename std::map<K, V>::const_iterator
3617 it = map.begin(); it != map.end(); ++it)
3619 result += it->second.MemoryUsage();
3620 result +=
sizeof(std::pair<K, V>) + 3*
sizeof(
void*) +
sizeof(bool);
3628 for (
unsigned i = 0; i <
groups.size(); i++)
3630 groups_size +=
groups[i].capacity() *
sizeof(int);
3632 const int approx_node_size =
3633 sizeof(std::pair<CommGroup, GroupId>) + 3*
sizeof(
void*) +
sizeof(bool);
3634 return groups_size +
group_id.size() * approx_node_size;
3637template<
typename Type,
int Size>
3638static std::size_t arrays_memory_usage(
const Array<Type> (&arrays)[Size])
3640 std::size_t total = 0;
3641 for (
int i = 0; i < Size; i++)
3643 total += arrays[i].MemoryUsage();
3679 << arrays_memory_usage(
entity_owner) <<
" entity_owner\n"
3721 if (
NRanks == 1) {
return; }
3728 for (
int i = 0; i < neighbors.
Size(); i++)
3730 send_ref[neighbors[i]].SetNCMesh(
this);
3738 for (
int i = 0; i < sendData.
Size(); i++)
3740 MFEM_ASSERT(sendData[i].element < (
unsigned int)
NElements,
"");
3743 for (
int j = 0; j < ranks.
Size(); j++)
3745 send_ref[ranks[j]].AddRefinement(elem, sendData[i].order);
3753 for (
int j = 0; j < neighbors.
Size(); j++)
3763 const int os = recvData.
Size();
3765 for (
int i = 0; i < msg.
Size(); i++)
3767 recvData[os + i].element = msg.
elements[i];
3768 recvData[os + i].order = msg.
values[i];
int FindSorted(const T &el) const
Do bisection search for 'el' in a sorted array; return -1 if not found.
void GetSubArray(int offset, int sa_size, Array< T > &sa) const
Copy sub array starting from offset out to the provided sa.
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
void DeleteAll()
Delete the whole array.
int Find(const T &el) const
Return the first index where 'el' is found; return -1 if not found.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
T * GetData()
Returns the data.
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T.
T * end()
STL-like end. Returns pointer after the last element of the array.
T * begin()
STL-like begin. Returns pointer to the first element of the array.
std::size_t MemoryUsage() const
Returns the number of bytes allocated for the array including any reserve.
T & Last()
Return the last element in the array.
Data type dense matrix using column-major storage.
Abstract data type element.
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
void SetAttribute(const int attr)
Set element's attribute.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
static bool IsTensorProduct(Type geom)
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
int NGroups() const
Return the number of groups.
void Recreate(const int n, const int *p)
Create an integer set from C-array 'p' of 'n' integers. Overwrites any existing set data.
int Insert(const IntegerSet &s)
Check to see if set 's' is in the list. If not append it to the end of the list. Returns the index of...
Array< FaceInfo > faces_info
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Array< NCFaceInfo > nc_faces_info
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
int GetNE() const
Returns number of elements.
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
virtual void SetAttributes(bool elem_attrs_changed=true, bool bdr_face_attrs_changed=true)
Determine the sets of unique attribute values in domain if elem_attrs_changed and boundary elements i...
NCMesh * ncmesh
Optional nonconforming mesh extension.
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
static GeomInfo GI[Geometry::NumGeom]
void FindNeighbors(int elem, Array< int > &neighbors, const Array< int > *search_set=NULL)
virtual void Trim()
Save memory by releasing all non-essential and cached data.
const Face & GetFace(int i) const
Access a Face.
mfem::Element * NewMeshElement(int geom) const
static int find_node(const Element &el, int node)
static int find_element_edge(const Element &el, int vn0, int vn1, bool abort=true)
int PrintMemoryDetail() const
bool HaveTets() const
Return true if the mesh contains tetrahedral elements.
void GetEdgeVertices(const MeshId &edge_id, int vert_index[2], bool oriented=true) const
Return Mesh vertex indices of an edge identified by 'edge_id'.
Array< int > boundary_faces
subset of all faces, set by BuildFaceList
BlockArray< Element > elements
int FindMidEdgeNode(int node1, int node2) const
Array< char > face_geom
face geometry by face index, set by OnMeshUpdated
virtual void BuildFaceList()
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
const real_t * CalcVertexPos(int node) const
int GetFaceVerticesEdges(const MeshId &face_id, int vert_index[4], int edge_index[4], int edge_orientation[4]) const
Array< int > leaf_sfc_index
natural tree ordering of leaf elements
NCList edge_list
lazy-initialized list of edges, see GetEdgeList
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
virtual void BuildEdgeList()
bool Iso
true if the mesh only contains isotropic refinements
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges, Array< int > &bdr_faces)
Get a list of vertices (2D/3D), edges (3D) and faces (3D) that coincide with boundary elements with t...
virtual void BuildVertexList()
Array< real_t > coordinates
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
int MyRank
used in parallel, or when loading a parallel file in serial
int spaceDim
dimensions of the elements and the vertex coordinates
NCList vertex_list
lazy-initialized list of vertices, see GetVertexList
void FindSetNeighbors(const Array< char > &elem_set, Array< int > *neighbors, Array< char > *neighbor_set=NULL)
long MemoryUsage() const
Return total number of bytes allocated.
void DerefineElement(int elem)
Derefine the element elem, does nothing on leaf elements.
NCList face_list
lazy-initialized list of faces, see GetFaceList
static int find_local_face(int geom, int a, int b, int c)
Class for parallel meshes.
Table send_face_nbr_elements
Array< Element * > shared_edges
Table group_svert
Shared objects in each group.
void BuildFaceNbrElementToFaceTable()
Array< Vertex > face_nbr_vertices
Array< Vert4 > shared_quads
Array< int > svert_lvert
Shared to local index mapping.
Array< Element * > face_nbr_elements
Array< int > face_nbr_group
Array< int > face_nbr_elements_offset
Array< Vert3 > shared_trias
std::unique_ptr< Table > face_nbr_el_ori
orientations for each face (from nbr processor)
void DecodeTree(int elem, int &pos, Array< int > &elements) const
Array< unsigned char > data
encoded refinement (sub-)trees
void Encode(const Array< int > &elements)
int GetInt(int pos) const
void Decode(Array< int > &elements) const
void FlagElements(const Array< int > &elements, char flag)
std::string RefPath() const
void EncodeTree(int elem)
void Load(std::istream &is)
void Dump(std::ostream &os) const
void Encode(int) override
std::vector< ValueType > values
void Decode(int) override
std::vector< int > elements
void SetNCMesh(ParNCMesh *pncmesh_)
Set pointer to ParNCMesh (needed to encode the message).
std::map< int, NeighborDerefinementMessage > Map
std::map< int, NeighborElementRankMessage > Map
void AddElement(int elem, int rank, int attribute)
std::map< int, NeighborPRefinementMessage > Map
std::map< int, NeighborRefinementMessage > Map
void Encode(int) override
std::vector< int > elem_ids
void SetElements(const Array< int > &elems, NCMesh *ncmesh)
void Decode(int) override
std::size_t MemoryUsage() const
std::map< int, RebalanceMessage > Map
void AddElement(int elem, int rank, int attribute)
A parallel extension of the NCMesh class.
bool AnisotropicConflict(const Array< Refinement > &refinements, std::set< int > &conflicts)
Array< int > entity_elem_local[3]
void MakeSharedTable(int ngroups, int ent, Array< int > &shared_local, Table &group_shared, Array< char > *entity_geom=NULL, char geom=0)
Array< int > tmp_neighbors
void CheckRefinement(int elem, const Refinement &ref, const Array< Refinement > &refinements, const std::map< int, int > &elemToRef, std::set< int > &conflicts)
Check whether the input refinement would cause a conflict.
Array< Connection > entity_index_rank[3]
RebalanceDofMessage::Map send_rebalance_dofs
void CalcFaceOrientations()
void DecodeGroups(std::istream &is, Array< GroupId > &ids)
bool PruneTree(int elem)
Internal. Recursive part of Prune().
bool CheckElementType(int elem, int type)
void GetGhostElements(Array< int > &gelem)
void Trim() override
Save memory by releasing all non-essential and cached data.
void BuildVertexList() override
void FindEdgesOfGhostElement(int elem, Array< int > &edges)
void FindFacesOfGhostElement(int elem, Array< int > &faces)
Array< int > ghost_layer
list of elements whose 'element_type' == 2.
void BuildFaceList() override
void GetFaceNeighbors(class ParMesh &pmesh)
RebalanceDofMessage::Map recv_rebalance_dofs
void ChangeVertexMeshIdElement(NCMesh::MeshId &id, int elem)
void EncodeGroups(std::ostream &os, const Array< GroupId > &ids)
void FindEdgesOfGhostFace(int face, Array< int > &edges)
Array< GroupId > entity_conf_group[3]
Array< int > boundary_layer
list of type 3 elements
void AdjustMeshIds(Array< MeshId > ids[], int rank)
std::size_t GroupsMemoryUsage() const
const NCList & GetSharedVertices()
void ChangeEdgeMeshIdElement(NCMesh::MeshId &id, int elem)
void GetConformingSharedStructures(class ParMesh &pmesh)
bool CheckRefAnisoFaceSplits(int vn1, int vn2, int vn3, int vn4, int level=0)
void ElementNeighborProcessors(int elem, Array< int > &ranks)
static int get_face_orientation(const Face &face, const Element &e1, const Element &e2, int local[2]=NULL)
void ElementSharesFace(int elem, int local, int face) override
void BuildEdgeList() override
Array< char > tmp_shared_flag
Array< int > old_index_or_rank
std::vector< int > CommGroup
void DecodeMeshIds(std::istream &is, Array< MeshId > ids[])
void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges, Array< int > &bdr_faces) override
void EncodeMeshIds(std::ostream &os, Array< MeshId > ids[])
void CheckRefinementMaster(const Array< Refinement > &refinements, const std::map< int, int > &elemToRef, std::set< int > &conflicts)
Check whether any master face is marked for a conflicting refinement.
Array< DenseMatrix * > aux_pm_store
Stores modified point matrices created by GetFaceNeighbors.
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces ('entity' == 0/1/2 resp.).
GroupId GetSingletonGroup(int rank)
void ChangeRemainingMeshIds(Array< MeshId > &ids, int pos, const Array< Pair< int, int > > &find)
Array< char > face_orient
Array< char > element_type
void InitOwners(int num, Array< GroupId > &entity_owner)
Array< GroupId > entity_owner[3]
void CalculatePMatrixGroups()
void ElementSharesEdge(int elem, int local, int enode) override
const NCList & GetSharedEdges()
void GetDebugMesh(Mesh &debug_mesh) const
bool GroupContains(GroupId id, int rank) const
Return true if group 'id' contains the given rank.
const NCList & GetSharedFaces()
Array< GroupId > entity_pmat_group[3]
void MakeSharedList(const NCList &list, NCList &shared)
void AddConnections(int entity, int index, const Array< int > &ranks)
int InitialPartition(int index) const
Helper to get the partitioning when the serial mesh gets split initially.
void NeighborProcessors(Array< int > &neighbors)
void CreateGroups(int nentities, Array< Connection > &index_rank, Array< GroupId > &entity_group)
GroupId GetGroupId(const CommGroup &group)
void CommunicateGhostData(const Array< VarOrderElemInfo > &sendData, Array< VarOrderElemInfo > &recvData)
void ElementSharesVertex(int elem, int local, int vnode) override
Data type line segment element.
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
void AddConnection(int r, int c)
int Size() const
Returns the number of TYPE I elements.
void MakeFromList(int nrows, const Array< Connection > &list)
Create the table from a list of connections {(from, to)}, where 'from' is a TYPE I index and 'to' is ...
void AddAColumnInRow(int r)
int index(int i, int j, int nx, int ny)
real_t f(const Vector &p)
void write(std::ostream &os, T value)
Write 'value' to stream.
T read(std::istream &is)
Read a value from the stream and return it.
int FindHexFace(const int *no, int vn1, int vn2, int vn3, int vn4)
char GetHexFaceRefType(const bool(&refDir)[3], int face)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
int GetHexFaceDir(int face)
MFEM_HOST_DEVICE int FlipIndexSign(int i)
Signed indices i -> -1 - i are used as a convention to encode orientation.
bool operator<(const Pair< A, B > &p, const Pair< A, B > &q)
Comparison operator for class Pair, based on the first element only.
void Update(Vector &x, int k, DenseMatrix &h, Vector &s, Array< Vector * > &v)
Helper struct for defining a connectivity table, see Table::MakeFromList.
Helper struct to convert a C++ type to an MPI type.
This structure stores the low level information necessary to interpret the configuration of elements ...
int rank
processor number (ParNCMesh), -1 if undefined/unknown
int child[MaxElemChildren]
2-10 children (if ref_type != 0)
char flag
generic flag/marker, can be used by algorithms
int node[MaxElemNodes]
element corners (if ref_type == 0)
char ref_type
bit mask of X,Y,Z refinements (bits 0,1,2 respectively)
char geom
Geometry::Type of the element (char for storage only)
int index
element number in the Mesh, -1 if refined
int parent
parent element, -1 if this is a root element, -2 if free'd
Geometry::Type Geom() const
int elem[2]
up to 2 elements sharing the face
int index
face number in the Mesh
int attribute
boundary element attribute, -1 if internal face
This holds in one place the constants about the geometries we support.
int faces[MaxElemFaces][4]
int edges[MaxElemEdges][2]
int slaves_end
slave faces
Identifies a vertex/edge/face in both Mesh and NCMesh.
int element
NCMesh::Element containing this vertex/edge/face.
signed char geom
Geometry::Type (faces only) (char to save RAM)
signed char local
local number within 'element'
Lists all edges/faces in the nonconforming mesh.
Array< MeshId > conforming
All MeshIds corresponding to conformal faces.
Array< Slave > slaves
All MeshIds corresponding to slave faces.
void Clear()
Erase the contents of the conforming, master and slave arrays.
Array< Master > masters
All MeshIds corresponding to master faces.
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
MeshIdAndType GetMeshIdAndType(int index) const
Return a mesh id and type for a given nc index.
Nonconforming edge/face within a bigger edge/face.
unsigned matrix
index into NCList::point_matrices[geom]
int master
master number (in Mesh numbering)
void SetScaleForType(const real_t *scale)
Set the scale in the directions for the currently set type.
int index
Mesh element number.
char GetType() const
Return the type as char.
void Issend(int rank, MPI_Comm comm)
Non-blocking synchronous send to processor 'rank'. Returns immediately. Completion (MPI_Wait/Test) me...
static void WaitAllSent(MapT &rank_msg)
Helper to wait for all messages in a map container to be sent.
void Isend(int rank, MPI_Comm comm)
Non-blocking send to processor 'rank'. Returns immediately. Completion (as tested by MPI_Wait/Test) d...
static void IsendAll(MapT &rank_msg, MPI_Comm comm)
Helper to send all messages in a rank-to-message map container.
void Recv(int rank, int size, MPI_Comm comm)
Post-probe receive from processor 'rank' of message size 'size'.
static void Probe(int &rank, int &size, MPI_Comm comm)
Blocking probe for incoming message of this type from any rank. Returns the rank and message size.
std::array< int, NCMesh::MaxFaceNodes > nodes