29using namespace bin_io;
32 const int *partitioning)
55 int &curved,
int &is_nc)
56 :
NCMesh(input, version, curved, is_nc)
58 MFEM_VERIFY(version != 11,
"Nonconforming mesh format \"MFEM NC mesh v1.1\""
59 " is supported only in serial.");
65 MPI_Comm_rank(
MyComm, &my_rank);
74 "Parallel mesh file doesn't seem to match current MPI setup. "
75 "Loading a parallel NC mesh with a non-matching communicator "
76 "size is not supported.");
79 MPI_Allreduce(&iso, &
Iso, 1, MFEM_MPI_CXX_BOOL, MPI_LAND,
MyComm);
87 , MyComm(other.MyComm)
88 , NRanks(other.NRanks)
110 for (
int i = 0; i < 3; i++)
136 owner = std::min(owner, el.
rank);
147 el_loc = (el.
index << 4) | local;
200 int e_index =
nodes[enode].edge_index;
203 owner = std::min(owner, el.
rank);
214 el_loc = (el.
index << 4) | local;
266 int V[4], E[4], Eo[4];
268 MFEM_ASSERT(nfv == 4,
"");
271 for (
int i=0; i<nfv; ++i)
282 MFEM_ASSERT(!el.
ref_type,
"not a leaf element.");
287 for (
int j = 0; j < gi.
ne; j++)
290 const int* ev = gi.
edges[j];
291 int node[2] = { el.
node[ev[0]], el.
node[ev[1]] };
293 int enode =
nodes.FindId(node[0], node[1]);
294 MFEM_ASSERT(enode >= 0,
"edge node not found!");
297 MFEM_ASSERT(nd.
HasEdge(),
"edge not found!");
307 MFEM_ASSERT(!el.
ref_type,
"not a leaf element.");
310 for (
int j = 0; j <
faces.Size(); j++)
321 int v_index =
nodes[vnode].vert_index;
324 owner = std::min(owner, el.
rank);
335 el_loc = (el.
index << 4) | local;
374 for (
int i = 0; i < num; i++)
386 for (
int i = 0; i < list.masters.Size(); i++)
388 const Master &master = list.masters[i];
390 char master_old_flag = master_flag;
394 int si = list.slaves[j].index;
398 master_flag |= slave_flag;
399 slave_flag |= master_old_flag;
413 for (
int i = 0; i < list.conforming.Size(); i++)
420 for (
int i = 0; i < list.masters.Size(); i++)
424 shared.
masters.Append(list.masters[i]);
427 for (
int i = 0; i < list.slaves.Size(); i++)
429 int si = list.slaves[i].index;
432 shared.
slaves.Append(list.slaves[i]);
439 if (lhs.size() == rhs.size())
441 for (
unsigned i = 0; i < lhs.size(); i++)
443 if (lhs[i] < rhs[i]) {
return true; }
447 return lhs.size() < rhs.size();
453 for (
unsigned i = 1; i < group.size(); i++)
455 if (group[i] <= group[i-1]) {
return false; }
463 if (group.size() == 1 && group[0] ==
MyRank)
467 MFEM_ASSERT(group_sorted(group),
"invalid group");
479 MFEM_ASSERT(rank != INT_MAX,
"invalid rank");
480 static std::vector<int> group;
490 for (
unsigned i = 0; i < group.size(); i++)
492 if (group[i] == rank) {
return true; }
503 entity_group.
SetSize(nentities);
508 for (
auto begin = index_rank.
begin(); begin != index_rank.
end(); )
510 const auto &
index = begin->from;
511 if (
index >= nentities) {
break; }
514 const auto end = std::find_if(begin, index_rank.
end(),
518 group.resize(std::distance(begin, end));
519 std::transform(begin, end, group.begin(), [](
const mfem::Connection &c) { return c.to; });
529 for (
auto rank : ranks)
542 int v[4], e[4], eo[4];
551 for (
int j = master_edge.slaves_begin; j < master_edge.slaves_end; j++)
562 for (
int j = 0; j < 2; j++)
572 for (
int j = master_face.slaves_begin; j < master_face.slaves_end; j++)
585 for (
int j = 0; j < nfv; j++)
600 for (
int i = 0; i < 3; i++)
613 const Element *
const e[2] = { &e1, &e2 };
614 for (
int i = 0; i < 2; i++)
623 if (local) { local[i] = lf; }
627 for (
int j = 0; j < 4; j++)
629 ids[i][j] = e[i]->
node[fv[j]];
639 if (
Dim < 3) {
return; }
648 for (
const auto &face :
faces)
650 if (face.elem[0] >= 0 && face.elem[1] >= 0 && face.index <
NFaces)
655 if (e1->
rank == e2->
rank) {
continue; }
656 if (e1->
rank > e2->
rank) { std::swap(e1, e2); }
676 for (
int j = mf.slaves_begin; j < mf.slaves_end; j++)
687 bdr_faces.
Append(mf.index);
699 for (
int j = me.slaves_begin; j < me.slaves_end; j++)
705 bdr_edges.
Append(me.index);
712 auto FilterSortUnique = [](
Array<int> &v,
int N)
715 auto local = std::remove_if(v.
begin(), v.
end(), [N](
int i) { return i >= N; });
716 std::sort(v.
begin(), local);
720 FilterSortUnique(bdr_vertices,
NVertices);
721 FilterSortUnique(bdr_edges,
NEdges);
722 FilterSortUnique(bdr_faces,
NFaces);
735 for (
int i = 0; i < nleaves; i++)
750 for (
int i = 0; i < nleaves; i++)
758 else if (boundary_set[i] && etype)
775 for (
int i = 0; i < 8 && el.
child[i] >= 0; i++)
805static void set_to_array(
const std::set<T> &set,
Array<T> &array)
807 array.Reserve(
static_cast<int>(set.size()));
826 set_to_array(ranks, neighbors);
838 group_shared.
MakeI(ngroups-1);
842 for (
int i = 0; i < conf_group.
Size(); i++)
846 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
853 shared_local.
SetSize(num_shared);
854 group_shared.
MakeJ();
857 for (
int i = 0, j = 0; i < conf_group.
Size(); i++)
861 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
871 for (
int i = 0; i < group_shared.
Size(); i++)
873 int size = group_shared.
RowSize(i);
874 int *row = group_shared.
GetRow(i);
877 ref_row.
Sort([&](
const int a,
const int b)
885 if (lsi_a != lsi_b) {
return lsi_a < lsi_b; }
887 return (el_loc_a & 0xf) < (el_loc_b & 0xf);
897 for (
int ent = 0; ent <
Dim; ent++)
901 pmesh.
GetNE() == 0,
"Non empty partitions must be connected");
903 pmesh.
GetNE() == 0,
"Non empty partitions must be connected");
913 for (
unsigned i = 0; i <
groups.size(); i++)
915 if (
groups[i].size() > 1 || !i)
918 group_map[i] = int_groups.
Insert(iset);
925 for (
int ent = 0; ent < 3; ent++)
930 ecg = group_map[ecg];
964 for (
int i = 0; i < slt.
Size(); i++)
969 int v[4], e[4], eo[4];
976 for (
int i = 0; i < slq.
Size(); i++)
986 for (
int ent = 0; ent <
Dim; ent++)
1002 std::map<int, std::vector<int>> recv_elems;
1007 auto count_slaves = [&](
int i,
const Master& x)
1009 return i + (x.slaves_end - x.slaves_begin);
1012 const int bound = shared.
conforming.Size() + std::accumulate(
1022 bool face_nbr_w_tri_faces =
false;
1025 for (
int i = 0; i < shared.
conforming.Size(); i++)
1029 MFEM_ASSERT(face != NULL,
"");
1031 MFEM_ASSERT(face->
elem[0] >= 0 && face->
elem[1] >= 0,
"");
1034 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
1035 MFEM_ASSERT(e[0]->rank !=
MyRank && e[1]->rank ==
MyRank,
"");
1042 recv_elems[e[0]->
rank].push_back(e[0]->
index);
1045 for (
int i = 0; i < shared.
masters.Size(); i++)
1053 MFEM_ASSERT(mf.
element >= 0,
"");
1063 if (loc0) { std::swap(e[0], e[1]); }
1070 recv_elems[e[0]->
rank].push_back(e[0]->
index);
1074 MFEM_ASSERT(fnbr.
Size() <= bound,
1075 "oops, bad upper bound. fnbr.Size(): " << fnbr.
Size() <<
", bound: " << bound);
1084 return (
a->rank !=
b->rank) ?
a->rank <
b->rank
1085 :
a->index <
b->index;
1089 for (
int i = 0; i < fnbr.
Size(); i++)
1108 std::map<int, int> vert_map;
1109 for (
int i = 0; i < fnbr.
Size(); i++)
1117 for (
int k = 0; k < gi.
nv; k++)
1119 int &v = vert_map[elem->
node[k]];
1120 if (!v) { v =
static_cast<int>(vert_map.size()); }
1124 if (!i || elem->
rank != fnbr[i-1]->rank)
1140 for (
const auto &v : vert_map)
1153 for (
auto &kv : recv_elems)
1155 std::sort(kv.second.begin(), kv.second.end());
1156 kv.second.erase(std::unique(kv.second.begin(), kv.second.end()),
1160 for (
int i = 0, last_rank = -1; i < send_elems.
Size(); i++)
1163 if (c.
from != last_rank)
1171 c.
from = send_elems[i-1].from;
1181 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
1199 if (shared.
slaves.Size())
1205 MFEM_ASSERT(pmesh.
faces_info.Size() == nfaces,
"");
1208 for (
int i = nfaces; i < pmesh.
faces_info.Size(); i++)
1219 for (
int i = 0; i < shared.
masters.Size(); i++)
1225 if (sf.
element < 0) {
continue; }
1227 MFEM_ASSERT(mf.
element >= 0,
"");
1268 if (!sloc &&
Dim == 3)
1274 std::swap((*pm2)(0, 1), (*pm2)(0, 3));
1275 std::swap((*pm2)(1, 1), (*pm2)(1, 3));
1279 std::swap((*pm2)(0, 0), (*pm2)(0, 1));
1280 std::swap((*pm2)(1, 0), (*pm2)(1, 1));
1297 else if (!sloc &&
Dim == 2)
1306 MFEM_ASSERT(fi.
NCFace < 0,
"fi.NCFace = " << fi.
NCFace);
1320 if (face_nbr_w_tri_faces)
1324 using RankToOrientation = std::map<int, std::vector<std::array<int, 6>>>;
1325 constexpr std::array<int, 6> unset_ori{{-1,-1,-1,-1,-1,-1}};
1332 RankToOrientation send_rank_to_face_neighbor_orientations;
1337 for (
const auto &se : send_elems)
1343 send_rank_to_face_neighbor_orientations[true_rank].emplace_back(unset_ori);
1346 std::copy(orientations.
begin(), orientations.
end(),
1347 send_rank_to_face_neighbor_orientations[true_rank].back().begin());
1354 auto recv_rank_to_face_neighbor_orientations =
1355 send_rank_to_face_neighbor_orientations;
1356 for (
auto &kv : recv_rank_to_face_neighbor_orientations)
1358 kv.second.resize(recv_elems[kv.first].size());
1363 std::vector<MPI_Request> send_requests, recv_requests;
1364 std::vector<MPI_Status> status(nranks);
1368 send_requests.reserve(nranks);
1369 recv_requests.reserve(nranks);
1376 for (
const auto &kv : send_rank_to_face_neighbor_orientations)
1378 send_requests.emplace_back();
1381 const int send_tag = (rank < kv.first)
1382 ? std::min(rank, kv.first)
1383 : std::max(rank, kv.first);
1384 MPI_Isend(
const_cast<int*
>(&kv.second[0][0]),
int(kv.second.size() * 6),
1385 MPI_INT, kv.first, send_tag, pmesh.
MyComm, &send_requests.back());
1390 for (
auto &kv : recv_rank_to_face_neighbor_orientations)
1392 recv_requests.emplace_back();
1395 const int recv_tag = (rank < kv.first)
1396 ? std::max(rank, kv.first)
1397 : std::min(rank, kv.first);
1398 MPI_Irecv(&kv.second[0][0],
int(kv.second.size() * 6),
1399 MPI_INT, kv.first, recv_tag, pmesh.
MyComm, &recv_requests.back());
1403 MPI_Waitall(
int(recv_requests.size()), recv_requests.data(), status.data());
1407 for (
const auto &kv : recv_rank_to_face_neighbor_orientations)
1410 for (
const auto &eo : kv.second)
1419 MPI_Waitall(
int(send_requests.size()), send_requests.data(), status.data());
1443 bool removeAll =
true;
1446 for (
int i = 0; i < 8; i++)
1449 if (el.
child[i] >= 0)
1452 if (!remove[i]) { removeAll =
false; }
1457 if (removeAll) {
return true; }
1460 for (
int i = 0; i < 8; i++)
1480 MFEM_WARNING(
"Can't prune 3D aniso meshes yet.");
1508 std::set<int> &conflicts)
1510 if (
Dim < 3 ||
NRanks == 1) {
return false; }
1512 for (
int i = 0; i < refinements.
Size() &&
Iso; i++)
1522 bool globalIso =
false;
1523 MPI_Allreduce(&
Iso, &globalIso, 1, MFEM_MPI_CXX_BOOL, MPI_LAND,
MyComm);
1525 if (globalIso) {
return false; }
1533 for (
int i = 0; i < neighbors.
Size(); i++)
1535 send_ref[neighbors[i]].SetNCMesh(
this);
1543 for (
int i = 0; i < refinements.
Size(); i++)
1549 for (
int j = 0; j < ranks.
Size(); j++)
1551 send_ref[ranks[j]].AddRefinement(elem, ref.
GetType());
1562 std::map<int, int> elemToRef;
1563 for (
int i = 0; i < refinements.
Size(); i++)
1569 for (
int i = 0; i < refinements.
Size(); i++)
1573 elemToRef, conflicts);
1577 for (
int j = 0; j < neighbors.
Size(); j++)
1587 for (
int i = 0; i < msg.
Size(); i++)
1599 const bool conflict = conflicts.size() > 0;
1600 bool globalConflict =
false;
1601 MPI_Allreduce(&conflict, &globalConflict, 1, MFEM_MPI_CXX_BOOL, MPI_LOR,
1603 return globalConflict;
1612 constexpr std::array<int, 6> hexFaceDir = {2, 1, 0, 1, 0, 2};
1613 return hexFaceDir[face];
1619 std::array<int, 2> faceRefDir;
1621 for (
int d=0; d<3; ++d)
1625 faceRefDir[cnt] = refDir[d] ? 1 : 0;
1630 const char ref_type = (char)(faceRefDir[0] + (2 * faceRefDir[1]));
1644 if (mid23 >= 0 && mid41 >= 0)
1646 const int midf =
nodes.FindId(mid23, mid41);
1660 if (level > 0) {
return true; }
1666 const std::map<int, int> &elemToRef,
1667 std::set<int> &conflicts)
1669 MFEM_VERIFY(
Dim == 3,
"");
1672 for (
const auto &mf : faceList.
masters)
1675 if (elemToRef.count(mf.element) == 0) {
continue; }
1677 const int refIndex = elemToRef.at(mf.element);
1678 const Refinement& ref = refinements[refIndex];
1681 for (
int i=0; i<3; ++i)
1682 refDir[i] = ref.
s[i] >
real_t{0};
1685 if (faceRefType == 0) {
continue; }
1687 std::array<int, 4> fv;
1688 for (
int i=0; i<4; ++i)
1694 if (faceRefType != 2)
1699 conflicts.insert(refIndex);
1703 if (faceRefType != 1)
1708 conflicts.insert(refIndex);
1717 v.insert({vn1, vn2, vn3, vn4});
1720 for (
int f=0;
f<6; ++
f)
1722 bool allFound =
true;
1723 for (
int i=0; i<4; ++i)
1726 if (v.count(vi) == 0)
1734 MFEM_ASSERT(face == -1,
"");
1739 MFEM_ASSERT(face >= 0,
"");
1755 for (
int i=0; i<12; ++i)
1757 for (
int j=0; j<2; ++j)
1765 MFEM_ASSERT(edge == -1,
"");
1770 MFEM_ASSERT(edge >= 0,
"");
1772 constexpr int edgeDir[12] = {0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2};
1773 return edgeDir[edge];
1776void ParNCMesh::CheckRefAnisoFace(
int elem,
int vn1,
int vn2,
int vn3,
int vn4,
1778 const std::map<int, int> &elemToRef,
1779 std::set<int> &conflicts)
1781 Face* face = faces.Find(vn1, vn2, vn3, vn4);
1782 if (!face) {
return; }
1785 const int nghbIndex = face->
elem[0] == elem ? face->
elem[1] : face->
elem[0];
1786 if (nghbIndex < 0) {
return; }
1788 Element &nghb = elements[nghbIndex];
1789 MFEM_ASSERT(nghb.
ref_type == 0,
"");
1791 if (elemToRef.count(nghbIndex) > 0)
1793 const int refIndex = elemToRef.at(nghbIndex);
1794 const Refinement& ref = refinements[refIndex];
1797 for (
int i=0; i<3; ++i)
1798 refDir[i] = ref.
s[i] >
real_t{0};
1803 const bool faceAniso = face_ref_type == 1 ||
1810 int hexSplitOnFace = -1;
1812 const int firstFaceDir = face_ref_type == 1 ? 0 : 1;
1815 for (
int i=0; i<3; ++i)
1817 if (i == faceDir) {
continue; }
1819 if (firstFaceDir == cnt)
1821 MFEM_ASSERT(hexSplitOnFace == -1,
"");
1827 MFEM_ASSERT(cnt == 2 && hexSplitOnFace >= 0,
"");
1830 if (edgeSplit != hexSplitOnFace) { conflicts.insert(refIndex); }
1837void ParNCMesh::CheckRefIsoFace(
int elem,
int vn1,
int vn2,
int vn3,
int vn4,
1838 int en1,
int en2,
int en3,
int en4,
1840 const std::map<int, int> &elemToRef,
1841 std::set<int> &conflicts)
1843 CheckRefAnisoFace(elem, vn1, vn2, en2, en4, refinements, elemToRef, conflicts);
1844 CheckRefAnisoFace(elem, en4, en2, vn3, vn4, refinements, elemToRef, conflicts);
1845 CheckRefAnisoFace(elem, vn4, vn1, en1, en3, refinements, elemToRef, conflicts);
1846 CheckRefAnisoFace(elem, en3, en1, vn2, vn3, refinements, elemToRef, conflicts);
1849void ParNCMesh::CheckRefinement(
int elem,
char ref_type,
1851 const std::map<int, int> &elemToRef,
1852 std::set<int> &conflicts)
1854 const Element &el = elements[elem];
1855 MFEM_ASSERT(el.
geom == Geometry::CUBE && el.
ref_type == 0,
1856 "Element must be an unrefined hexahedron");
1858 const int* no = el.
node;
1862 if (ref_type == Refinement::X)
1864 CheckRefAnisoFace(elem, no[0], no[1], no[5], no[4], refinements,
1865 elemToRef, conflicts);
1866 CheckRefAnisoFace(elem, no[2], no[3], no[7], no[6], refinements,
1867 elemToRef, conflicts);
1868 CheckRefAnisoFace(elem, no[4], no[5], no[6], no[7], refinements,
1869 elemToRef, conflicts);
1870 CheckRefAnisoFace(elem, no[3], no[2], no[1], no[0], refinements,
1871 elemToRef, conflicts);
1873 else if (ref_type == Refinement::Y)
1875 CheckRefAnisoFace(elem, no[1], no[2], no[6], no[5], refinements,
1876 elemToRef, conflicts);
1877 CheckRefAnisoFace(elem, no[3], no[0], no[4], no[7], refinements,
1878 elemToRef, conflicts);
1879 CheckRefAnisoFace(elem, no[5], no[6], no[7], no[4], refinements,
1880 elemToRef, conflicts);
1881 CheckRefAnisoFace(elem, no[0], no[3], no[2], no[1], refinements,
1882 elemToRef, conflicts);
1884 else if (ref_type == Refinement::Z)
1886 CheckRefAnisoFace(elem, no[4], no[0], no[1], no[5], refinements,
1887 elemToRef, conflicts);
1888 CheckRefAnisoFace(elem, no[5], no[1], no[2], no[6], refinements,
1889 elemToRef, conflicts);
1890 CheckRefAnisoFace(elem, no[6], no[2], no[3], no[7], refinements,
1891 elemToRef, conflicts);
1892 CheckRefAnisoFace(elem, no[7], no[3], no[0], no[4], refinements,
1893 elemToRef, conflicts);
1895 else if (ref_type == Refinement::XY)
1897 CheckRefAnisoFace(elem, no[0], no[1], no[5], no[4], refinements,
1898 elemToRef, conflicts);
1899 CheckRefAnisoFace(elem, no[1], no[2], no[6], no[5], refinements,
1900 elemToRef, conflicts);
1901 CheckRefAnisoFace(elem, no[2], no[3], no[7], no[6], refinements,
1902 elemToRef, conflicts);
1903 CheckRefAnisoFace(elem, no[3], no[0], no[4], no[7], refinements,
1904 elemToRef, conflicts);
1906 const int mid01 = GetMidEdgeNode(no[0], no[1]);
1907 const int mid12 = GetMidEdgeNode(no[1], no[2]);
1908 const int mid23 = GetMidEdgeNode(no[2], no[3]);
1909 const int mid30 = GetMidEdgeNode(no[3], no[0]);
1911 const int mid45 = GetMidEdgeNode(no[4], no[5]);
1912 const int mid56 = GetMidEdgeNode(no[5], no[6]);
1913 const int mid67 = GetMidEdgeNode(no[6], no[7]);
1914 const int mid74 = GetMidEdgeNode(no[7], no[4]);
1916 CheckRefIsoFace(elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
1917 mid30, refinements, elemToRef, conflicts);
1918 CheckRefIsoFace(elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
1919 mid74, refinements, elemToRef, conflicts);
1921 else if (ref_type == Refinement::XZ)
1923 CheckRefAnisoFace(elem, no[3], no[2], no[1], no[0], refinements,
1924 elemToRef, conflicts);
1925 CheckRefAnisoFace(elem, no[2], no[6], no[5], no[1], refinements,
1926 elemToRef, conflicts);
1927 CheckRefAnisoFace(elem, no[6], no[7], no[4], no[5], refinements,
1928 elemToRef, conflicts);
1929 CheckRefAnisoFace(elem, no[7], no[3], no[0], no[4], refinements,
1930 elemToRef, conflicts);
1932 const int mid01 = GetMidEdgeNode(no[0], no[1]);
1933 const int mid23 = GetMidEdgeNode(no[2], no[3]);
1934 const int mid45 = GetMidEdgeNode(no[4], no[5]);
1935 const int mid67 = GetMidEdgeNode(no[6], no[7]);
1937 const int mid04 = GetMidEdgeNode(no[0], no[4]);
1938 const int mid15 = GetMidEdgeNode(no[1], no[5]);
1939 const int mid26 = GetMidEdgeNode(no[2], no[6]);
1940 const int mid37 = GetMidEdgeNode(no[3], no[7]);
1942 CheckRefIsoFace(elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
1943 mid04, refinements, elemToRef, conflicts);
1944 CheckRefIsoFace(elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
1945 mid26, refinements, elemToRef, conflicts);
1947 else if (ref_type == Refinement::YZ)
1949 const int mid12 = GetMidEdgeNode(no[1], no[2]);
1950 const int mid30 = GetMidEdgeNode(no[3], no[0]);
1951 const int mid56 = GetMidEdgeNode(no[5], no[6]);
1952 const int mid74 = GetMidEdgeNode(no[7], no[4]);
1954 const int mid04 = GetMidEdgeNode(no[0], no[4]);
1955 const int mid15 = GetMidEdgeNode(no[1], no[5]);
1956 const int mid26 = GetMidEdgeNode(no[2], no[6]);
1957 const int mid37 = GetMidEdgeNode(no[3], no[7]);
1959 CheckRefAnisoFace(elem, no[4], no[0], no[1], no[5], refinements,
1960 elemToRef, conflicts);
1961 CheckRefAnisoFace(elem, no[0], no[3], no[2], no[1], refinements,
1962 elemToRef, conflicts);
1963 CheckRefAnisoFace(elem, no[3], no[7], no[6], no[2], refinements,
1964 elemToRef, conflicts);
1965 CheckRefAnisoFace(elem, no[7], no[4], no[5], no[6], refinements,
1966 elemToRef, conflicts);
1968 CheckRefIsoFace(elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
1969 mid15, refinements, elemToRef, conflicts);
1970 CheckRefIsoFace(elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
1971 mid37, refinements, elemToRef, conflicts);
1973 else if (ref_type == Refinement::XYZ)
1975 const int mid01 = GetMidEdgeNode(no[0], no[1]);
1976 const int mid12 = GetMidEdgeNode(no[1], no[2]);
1977 const int mid23 = GetMidEdgeNode(no[2], no[3]);
1978 const int mid30 = GetMidEdgeNode(no[3], no[0]);
1980 const int mid45 = GetMidEdgeNode(no[4], no[5]);
1981 const int mid56 = GetMidEdgeNode(no[5], no[6]);
1982 const int mid67 = GetMidEdgeNode(no[6], no[7]);
1983 const int mid74 = GetMidEdgeNode(no[7], no[4]);
1985 const int mid04 = GetMidEdgeNode(no[0], no[4]);
1986 const int mid15 = GetMidEdgeNode(no[1], no[5]);
1987 const int mid26 = GetMidEdgeNode(no[2], no[6]);
1988 const int mid37 = GetMidEdgeNode(no[3], no[7]);
1990 CheckRefIsoFace(elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
1991 mid30, refinements, elemToRef, conflicts);
1992 CheckRefIsoFace(elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
1993 mid04, refinements, elemToRef, conflicts);
1994 CheckRefIsoFace(elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
1995 mid15, refinements, elemToRef, conflicts);
1996 CheckRefIsoFace(elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
1997 mid26, refinements, elemToRef, conflicts);
1998 CheckRefIsoFace(elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
1999 mid37, refinements, elemToRef, conflicts);
2000 CheckRefIsoFace(elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
2001 mid74, refinements, elemToRef, conflicts);
2005 MFEM_ABORT(
"Invalid refinement type.");
2013 NCMesh::Refine(refinements);
2017 for (
int i = 0; i < refinements.
Size() && Iso; i++)
2020 if (ref.
GetType() != Refinement::XYZ)
2030 NeighborProcessors(neighbors);
2031 for (
int i = 0; i < neighbors.
Size(); i++)
2033 send_ref[neighbors[i]].SetNCMesh(
this);
2041 for (
int i = 0; i < refinements.
Size(); i++)
2044 MFEM_ASSERT(ref.
index < NElements,
"");
2045 const int elem = leaf_elements[ref.
index];
2046 ElementNeighborProcessors(elem, ranks);
2047 for (
int j = 0; j < ranks.
Size(); j++)
2049 send_ref[ranks[j]].AddRefinement(elem, ref.
GetType());
2054 NeighborRefinementMessage::IsendAll(send_ref, MyComm);
2057 for (
int i = 0; i < refinements.
Size(); i++)
2060 NCMesh::RefineElement(leaf_elements[ref.
index], ref.
GetType());
2064 for (
int j = 0; j < neighbors.
Size(); j++)
2067 NeighborRefinementMessage::Probe(rank, size, MyComm);
2071 msg.
Recv(rank, size, MyComm);
2074 for (
int i = 0; i < msg.
Size(); i++)
2083 NeighborRefinementMessage::WaitAllSent(send_ref);
2087void ParNCMesh::LimitNCLevel(
int max_nc_level)
2089 MFEM_VERIFY(max_nc_level >= 1,
"'max_nc_level' must be 1 or greater.");
2094 GetLimitRefinements(refinements, max_nc_level);
2096 long long size = refinements.
Size(), glob_size;
2097 MPI_Allreduce(&size, &glob_size, 1, MPI_LONG_LONG, MPI_SUM, MyComm);
2099 if (!glob_size) {
break; }
2101 Refine(refinements);
2105void ParNCMesh::GetFineToCoarsePartitioning(
const Array<int> &derefs,
2108 new_ranks.
SetSize(leaf_elements.Size()-GetNGhostElements());
2109 for (
int i = 0; i < leaf_elements.Size()-GetNGhostElements(); i++)
2111 new_ranks[i] = elements[leaf_elements[i]].rank;
2114 for (
int i = 0; i < derefs.
Size(); i++)
2116 int row = derefs[i];
2117 MFEM_VERIFY(row >= 0 && row < derefinements.Size(),
2118 "invalid derefinement number.");
2120 const int* fine = derefinements.GetRow(row);
2121 int size = derefinements.RowSize(row);
2123 int coarse_rank = INT_MAX;
2124 for (
int j = 0; j < size; j++)
2126 int fine_rank = elements[leaf_elements[fine[j]]].rank;
2127 coarse_rank = std::min(coarse_rank, fine_rank);
2129 for (
int j = 0; j < size; j++)
2131 new_ranks[fine[j]] = coarse_rank;
2138 MFEM_VERIFY(Dim < 3 || Iso,
2139 "derefinement of 3D anisotropic meshes not implemented yet.");
2141 InitDerefTransforms();
2144 old_index_or_rank.SetSize(leaf_elements.Size());
2145 for (
int i = 0; i < leaf_elements.Size(); i++)
2147 old_index_or_rank[i] = elements[leaf_elements[i]].rank;
2152 leaf_elements.
Copy(old_elements);
2157 for (
int i = 0; i < leaf_elements.Size(); i++)
2159 new_ranks[i] = elements[leaf_elements[i]].rank;
2163 for (
int i = 0; i < derefs.
Size(); i++)
2165 int row = derefs[i];
2166 MFEM_VERIFY(row >= 0 && row < derefinements.Size(),
2167 "invalid derefinement number.");
2169 const int* fine = derefinements.GetRow(row);
2170 int size = derefinements.RowSize(row);
2172 int coarse_rank = INT_MAX;
2173 for (
int j = 0; j < size; j++)
2175 int fine_rank = elements[leaf_elements[fine[j]]].rank;
2176 coarse_rank = std::min(coarse_rank, fine_rank);
2178 for (
int j = 0; j < size; j++)
2180 new_ranks[fine[j]] = coarse_rank;
2184 int target_elements = 0;
2185 for (
int i = 0; i < new_ranks.
Size(); i++)
2187 if (new_ranks[i] == MyRank) { target_elements++; }
2192 RedistributeElements(new_ranks, target_elements,
false);
2200 NeighborProcessors(neighbors);
2201 for (
int i = 0; i < neighbors.
Size(); i++)
2203 send_deref[neighbors[i]].SetNCMesh(
this);
2210 for (
int i = 0; i < derefs.
Size(); i++)
2212 const int* fine = derefinements.GetRow(derefs[i]);
2213 int parent = elements[old_elements[fine[0]]].parent;
2216 ElementNeighborProcessors(parent, ranks);
2217 for (
int j = 0; j < ranks.
Size(); j++)
2219 send_deref[ranks[j]].AddDerefinement(parent, new_ranks[fine[0]]);
2222 NeighborDerefinementMessage::IsendAll(send_deref, MyComm);
2225 for (
int i = 0; i < leaf_elements.Size(); i++)
2227 elements[leaf_elements[i]].index = -1;
2229 for (
int i = 0; i < old_elements.
Size(); i++)
2231 elements[old_elements[i]].index = i;
2236 old_elements.
Copy(coarse);
2237 for (
int i = 0; i < derefs.
Size(); i++)
2239 const int* fine = derefinements.GetRow(derefs[i]);
2240 int parent = elements[old_elements[fine[0]]].parent;
2243 SetDerefMatrixCodes(parent, coarse);
2245 NCMesh::DerefineElement(parent);
2249 for (
int j = 0; j < neighbors.
Size(); j++)
2252 NeighborDerefinementMessage::Probe(rank, size, MyComm);
2256 msg.
Recv(rank, size, MyComm);
2259 for (
int i = 0; i < msg.
Size(); i++)
2262 if (elements[elem].ref_type)
2264 SetDerefMatrixCodes(elem, coarse);
2265 NCMesh::DerefineElement(elem);
2267 elements[elem].rank = msg.
values[i];
2277 for (
int i = 0; i < coarse.
Size(); i++)
2279 int index = elements[coarse[i]].index;
2280 if (element_type[
index] == 0)
2283 index = -1 - elements[coarse[i]].rank;
2285 transforms.embeddings[i].parent =
index;
2288 leaf_elements.Copy(old_elements);
2293 for (
int i = 0; i < coarse.
Size(); i++)
2295 int &
index = transforms.embeddings[i].parent;
2303 NeighborDerefinementMessage::WaitAllSent(send_deref);
2307template<
typename Type>
2309 const Table &deref_table)
2320 elem_data.
SetSize(leaf_elements.Size(), 0);
2322 for (
int i = 0; i < deref_table.
Size(); i++)
2324 const int* fine = deref_table.
GetRow(i);
2325 int size = deref_table.
RowSize(i);
2326 MFEM_ASSERT(size <= 8,
"");
2328 int ranks[8], min_rank = INT_MAX, max_rank = INT_MIN;
2329 for (
int j = 0; j < size; j++)
2331 ranks[j] = elements[leaf_elements[fine[j]]].rank;
2332 min_rank = std::min(min_rank, ranks[j]);
2333 max_rank = std::max(max_rank, ranks[j]);
2337 if (min_rank != max_rank)
2340 for (
int j = 0; j < size; j++)
2342 if (ranks[j] != MyRank) { neigh.
Append(ranks[j]); }
2347 for (
int j = 0; j < size; j++)
2349 Type *data = &elem_data[fine[j]];
2351 int rnk = ranks[j], len = 1;
2357 for (
int k = 0; k < neigh.
Size(); k++)
2359 MPI_Request* req =
new MPI_Request;
2360 MPI_Isend(data, len, datatype, neigh[k], 292, MyComm, req);
2366 MPI_Request* req =
new MPI_Request;
2367 MPI_Irecv(data, len, datatype, rnk, 292, MyComm, req);
2374 for (
int i = 0; i < requests.
Size(); i++)
2376 MPI_Wait(requests[i], MPI_STATUS_IGNORE);
2383ParNCMesh::SynchronizeDerefinementData<int>(
Array<int> &,
const Table &);
2390void ParNCMesh::CheckDerefinementNCLevel(
const Table &deref_table,
2397 for (
int i = 0; i < deref_table.
Size(); i++)
2399 const int *fine = deref_table.
GetRow(i),
2400 size = deref_table.
RowSize(i);
2402 int parent = elements[leaf_elements[fine[0]]].parent;
2403 Element &pa = elements[parent];
2405 for (
int j = 0; j < size; j++)
2407 int child = leaf_elements[fine[j]];
2408 if (elements[child].rank == MyRank)
2411 CountSplits(child, splits);
2413 for (
int k = 0; k < Dim; k++)
2416 splits[k] >= max_nc_level)
2418 leaf_ok[fine[j]] = 0;
break;
2425 SynchronizeDerefinementData(leaf_ok, deref_table);
2430 for (
int i = 0; i < deref_table.
Size(); i++)
2432 const int* fine = deref_table.
GetRow(i),
2433 size = deref_table.
RowSize(i);
2435 for (
int j = 0; j < size; j++)
2437 if (!leaf_ok[fine[j]])
2439 level_ok[i] = 0;
break;
2450 send_rebalance_dofs.clear();
2451 recv_rebalance_dofs.clear();
2454 leaf_elements.
GetSubArray(0, NElements, old_elements);
2456 if (!custom_partition)
2462 long local_elems = NElements, total_elems = 0;
2463 MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM, MyComm);
2465 long first_elem_global = 0;
2466 MPI_Scan(&local_elems, &first_elem_global, 1, MPI_LONG, MPI_SUM, MyComm);
2467 first_elem_global -= local_elems;
2469 for (
int i = 0, j = 0; i < leaf_elements.Size(); i++)
2471 if (elements[leaf_elements[i]].rank == MyRank)
2473 new_ranks[i] = Partition(first_elem_global + (j++), total_elems);
2477 int target_elements = PartitionFirstIndex(MyRank+1, total_elems)
2478 - PartitionFirstIndex(MyRank, total_elems);
2481 RedistributeElements(new_ranks, target_elements,
true);
2485 MFEM_VERIFY(custom_partition->
Size() == NElements,
2486 "Size of the partition array must match the number "
2487 "of local mesh elements (ParMesh::GetNE()).");
2490 custom_partition->
Copy(new_ranks);
2491 new_ranks.
SetSize(leaf_elements.Size(), -1);
2493 RedistributeElements(new_ranks, -1,
true);
2497 old_index_or_rank.SetSize(NElements);
2498 old_index_or_rank = -1;
2499 for (
int i = 0; i < old_elements.
Size(); i++)
2501 Element &el = elements[old_elements[i]];
2502 if (el.
rank == MyRank) { old_index_or_rank[el.
index] = i; }
2509void ParNCMesh::RedistributeElements(
Array<int> &new_ranks,
int target_elements,
2512 bool sfc = (target_elements >= 0);
2520 ghost_layer.Sort([&](
const int a,
const int b)
2522 return elements[
a].rank < elements[
b].rank;
2529 int begin = 0, end = 0;
2530 while (end < ghost_layer.Size())
2533 int rank = elements[ghost_layer[begin]].rank;
2534 while (end < ghost_layer.Size() &&
2535 elements[ghost_layer[end]].rank == rank) { end++; }
2538 rank_elems.
MakeRef(&ghost_layer[begin], end - begin);
2542 NeighborExpand(rank_elems, rank_neighbors, &boundary_layer);
2549 for (
int i = 0; i < rank_neighbors.
Size(); i++)
2551 int elem = rank_neighbors[i];
2555 msg.
Isend(rank, MyComm);
2559 recv_ghost_ranks[rank].SetNCMesh(
this);
2565 NeighborElementRankMessage::RecvAll(recv_ghost_ranks, MyComm);
2568 for (
auto &kv : recv_ghost_ranks)
2571 for (
int i = 0; i < msg.
Size(); i++)
2573 int ghost_index = elements[msg.
elements[i]].index;
2574 MFEM_ASSERT(element_type[ghost_index] == 2,
"");
2575 new_ranks[ghost_index] = msg.
values[i];
2579 recv_ghost_ranks.clear();
2590 int received_elements = 0;
2591 for (
int i = 0; i < leaf_elements.Size(); i++)
2593 Element &el = elements[leaf_elements[i]];
2594 if (el.
rank == MyRank && new_ranks[i] == MyRank)
2596 received_elements++;
2598 el.
rank = new_ranks[i];
2601 int nsent = 0, nrecv = 0;
2607 owned_elements.
MakeRef(leaf_elements.GetData(), NElements);
2608 owned_elements.
Sort([&](
const int a,
const int b)
2610 return elements[
a].rank < elements[
b].rank;
2617 int begin = 0, end = 0;
2618 while (end < NElements)
2621 int rank = elements[owned_elements[begin]].rank;
2622 while (end < owned_elements.
Size() &&
2623 elements[owned_elements[end]].rank == rank) { end++; }
2628 rank_elems.
MakeRef(&owned_elements[begin], end - begin);
2632 NeighborExpand(rank_elems, batch);
2639 for (
int i = 0; i < batch.
Size(); i++)
2641 int elem = batch[i];
2644 if ((element_type[el.
index] & 1) || el.
rank != rank)
2655 msg.
Isend(rank, MyComm);
2660 msg.
Issend(rank, MyComm);
2668 send_rebalance_dofs[rank].SetElements(rank_elems,
this);
2687 while (received_elements < target_elements)
2690 RebalanceMessage::Probe(rank, size, MyComm);
2693 msg.
Recv(rank, size, MyComm);
2696 for (
int i = 0; i < msg.
Size(); i++)
2698 int elem_rank = msg.
values[i];
2699 elements[msg.
elements[i]].rank = elem_rank;
2701 if (elem_rank == MyRank) { received_elements++; }
2707 recv_rebalance_dofs[rank].SetNCMesh(
this);
2713 RebalanceMessage::WaitAllSent(send_elems);
2723 MPI_Request barrier = MPI_REQUEST_NULL;
2729 while (RebalanceMessage::IProbe(rank, size, MyComm))
2732 msg.
Recv(rank, size, MyComm);
2735 for (
int i = 0; i < msg.
Size(); i++)
2743 recv_rebalance_dofs[rank].SetNCMesh(
this);
2747 if (barrier != MPI_REQUEST_NULL)
2749 MPI_Test(&barrier, &done, MPI_STATUS_IGNORE);
2753 if (RebalanceMessage::TestAllSent(send_elems))
2755 int mpi_err = MPI_Ibarrier(MyComm, &barrier);
2757 MFEM_VERIFY(mpi_err == MPI_SUCCESS,
"");
2758 MFEM_VERIFY(barrier != MPI_REQUEST_NULL,
"");
2766 NeighborElementRankMessage::WaitAllSent(send_ghost_ranks);
2769 int glob_sent, glob_recv;
2770 MPI_Reduce(&nsent, &glob_sent, 1, MPI_INT, MPI_SUM, 0, MyComm);
2771 MPI_Reduce(&nrecv, &glob_recv, 1, MPI_INT, MPI_SUM, 0, MyComm);
2775 MFEM_ASSERT(glob_sent == glob_recv,
2776 "(glob_sent, glob_recv) = ("
2777 << glob_sent <<
", " << glob_recv <<
")");
2780 MFEM_CONTRACT_VAR(nsent);
2781 MFEM_CONTRACT_VAR(nrecv);
2786void ParNCMesh::SendRebalanceDofs(
int old_ndofs,
2787 const Table &old_element_dofs,
2788 long old_global_offset,
2792 int vdim =
space->GetVDim();
2795 RebalanceDofMessage::Map::iterator it;
2796 for (it = send_rebalance_dofs.begin(); it != send_rebalance_dofs.end(); ++it)
2800 int ne =
static_cast<int>(msg.
elem_ids.size());
2805 for (
int i = 0; i < ne; i++)
2808 space->DofsToVDofs(dofs, old_ndofs);
2815 RebalanceDofMessage::IsendAll(send_rebalance_dofs, MyComm);
2822 RebalanceDofMessage::RecvAll(recv_rebalance_dofs, MyComm);
2826 RebalanceDofMessage::Map::iterator it;
2827 for (it = recv_rebalance_dofs.begin(); it != recv_rebalance_dofs.end(); ++it)
2830 ne +=
static_cast<int>(msg.
elem_ids.size());
2831 nd +=
static_cast<int>(msg.
dofs.size());
2839 for (it = recv_rebalance_dofs.begin(); it != recv_rebalance_dofs.end(); ++it)
2842 for (
unsigned i = 0; i < msg.
elem_ids.size(); i++)
2846 for (
unsigned i = 0; i < msg.
dofs.size(); i++)
2852 RebalanceDofMessage::WaitAllSent(send_rebalance_dofs);
2859 : ncmesh(other.ncmesh), include_ref_types(other.include_ref_types)
2867 data.Append(value & 0xff);
2868 data.Append((value >> 8) & 0xff);
2869 data.Append((value >> 16) & 0xff);
2870 data.Append((value >> 24) & 0xff);
2876 return (
int) data[pos] +
2877 ((int) data[pos+1] << 8) +
2878 ((int) data[pos+2] << 16) +
2879 ((int) data[pos+3] << 24);
2884 for (
int i = 0; i <
elements.Size(); i++)
2889 Element &el = ncmesh->elements[elem];
2890 if (el.
flag == flag) {
break; }
2899 Element &el = ncmesh->elements[elem];
2909 for (
int i = 0; i < 8; i++)
2911 if (el.
child[i] >= 0 && ncmesh->elements[el.
child[i]].flag)
2919 if (include_ref_types)
2924 for (
int i = 0; i < 8; i++)
2926 if (mask & (1 << i))
2928 EncodeTree(el.
child[i]);
2941 for (
int i = 0; i < ncmesh->root_state.Size(); i++)
2943 if (ncmesh->elements[i].flag)
2957 std::ostringstream oss;
2958 for (
int i = 0; i < ref_path.Size(); i++)
2960 oss <<
" elem " << ref_path[i] <<
" (";
2961 const Element &el = ncmesh->elements[ref_path[i]];
2962 for (
int j = 0; j <
GI[el.
Geom()].nv; j++)
2964 if (j) { oss <<
", "; }
2965 oss << ncmesh->RetrieveNode(el, j);
2977 ref_path.Append(elem);
2979 int mask = data[pos++];
2986 Element &el = ncmesh->elements[elem];
2987 if (include_ref_types)
2989 int ref_type = data[pos++];
2992 ncmesh->RefineElement(elem, ref_type);
2994 else { MFEM_ASSERT(ref_type == el.
ref_type,
"") }
2998 MFEM_ASSERT(el.
ref_type != 0,
"Path not found:\n"
2999 << RefPath() <<
" mask = " << mask);
3002 for (
int i = 0; i < 8; i++)
3004 if (mask & (1 << i))
3011 ref_path.DeleteLast();
3018 while ((root = GetInt(pos)) >= 0)
3028 os.write((
const char*) data.GetData(), data.Size());
3034 is.read((
char*) data.GetData(), data.Size());
3050 for (
unsigned i = 0; i <
groups.size(); i++)
3056 for (
int i = 0; i < ids[0].
Size(); i++)
3058 find_v[i].one = ids[0][i].index;
3072 for (
int j = 0; j < 2; j++)
3077 k = find_v[pos].two;
3088 for (
int i = 0; i < ids[1].
Size(); i++)
3090 find_e[i].one = ids[1][i].index;
3101 int v[4], e[4], eo[4], pos, k;
3103 for (
int j = 0; j < nfv; j++)
3107 k = find_v[pos].two;
3113 k = find_e[pos].two;
3128 for (
int i = 0; i < gi.
nv; i++)
3130 if (
nodes[el.
node[i]].vert_index ==
id.index)
3137 MFEM_ABORT(
"Vertex not found.");
3143 const int *old_ev =
GI[old.
Geom()].
edges[(int)
id.local];
3145 MFEM_ASSERT(node != NULL,
"Edge not found.");
3151 for (
int i = 0; i < gi.
ne; i++)
3153 const int* ev = gi.
edges[i];
3154 if ((el.
node[ev[0]] == node->
p1 && el.
node[ev[1]] == node->
p2) ||
3155 (el.
node[ev[1]] == node->
p1 && el.
node[ev[0]] == node->
p2))
3163 MFEM_ABORT(
"Edge not found.");
3169 const MeshId &first = ids[find[pos].two];
3170 while (++pos < find.Size() && ids[find[pos].two].index == first.
index)
3172 MeshId &other = ids[find[pos].two];
3180 std::map<int, int> stream_id;
3186 for (
int type = 0; type < 3; type++)
3188 for (
int i = 0; i < ids[type].
Size(); i++)
3202 for (
int i = 0; i < decoded.
Size(); i++)
3204 stream_id[decoded[i]] = i;
3209 for (
int type = 0; type < 3; type++)
3212 for (
int i = 0; i < ids[type].
Size(); i++)
3214 const MeshId&
id = ids[type][i];
3231 for (
int type = 0; type < 3; type++)
3236 for (
int i = 0; i < ne; i++)
3239 int elem = elems[el_num];
3242 MFEM_VERIFY(!el.
ref_type,
"not a leaf element: " << el_num);
3244 MeshId &
id = ids[type][i];
3254 id.index =
nodes[el.
node[(int)
id.local]].vert_index;
3259 const int* ev = gi.
edges[(int)
id.local];
3261 MFEM_ASSERT(node && node->
HasEdge(),
"edge not found.");
3267 const int* fv = gi.
faces[(int)
id.local];
3270 MFEM_ASSERT(face,
"face not found.");
3271 id.index = face->
index;
3281 std::map<GroupId, GroupId> stream_id;
3282 for (
int i = 0; i < ids.
Size(); i++)
3284 if (i && ids[i] == ids[i-1]) {
continue; }
3285 unsigned size = stream_id.size();
3286 GroupId &sid = stream_id[ids[i]];
3287 if (size != stream_id.size()) { sid = size; }
3292 for (std::map<GroupId, GroupId>::iterator
3293 it = stream_id.begin(); it != stream_id.end(); ++it)
3300 for (
unsigned i = 0; i < group.size(); i++)
3314 for (
int i = 0; i < ids.
Size(); i++)
3328 for (
int i = 0; i < ngroups; i++)
3335 for (
int ii = 0; ii < size; ii++)
3349 for (
int i = 0; i < ids.
Size(); i++)
3358template<
class ValueType,
bool RefTypes,
int Tag>
3361 std::ostringstream ostream;
3367 eset.
Encode(tmp_elements);
3375 std::map<int, int> element_index;
3376 for (
int i = 0; i < decoded.
Size(); i++)
3378 element_index[decoded[i]] = i;
3381 write<int>(ostream,
static_cast<int>(values.size()));
3382 MFEM_ASSERT(
elements.size() == values.size(),
"");
3384 for (
unsigned i = 0; i < values.size(); i++)
3390 ostream.str().swap(data);
3393template<
class ValueType,
bool RefTypes,
int Tag>
3396 std::istringstream istream(data);
3402 eset.
Decode(tmp_elements);
3404 int* el = tmp_elements.
GetData();
3409 for (
int i = 0; i < count; i++)
3412 MFEM_ASSERT(
index >= 0 && (
size_t)
index < values.size(),
"");
3423 eset.SetNCMesh(ncmesh);
3428 eset.Decode(decoded);
3430 elem_ids.resize(decoded.
Size());
3431 for (
int i = 0; i < decoded.
Size(); i++)
3433 elem_ids[i] = eset.GetNCMesh()->elements[decoded[i]].index;
3437static void write_dofs(std::ostream &os,
const std::vector<int> &dofs)
3439 write<int>(os,
static_cast<int>(dofs.size()));
3441 os.write((
const char*) dofs.data(), dofs.size() *
sizeof(
int));
3444static void read_dofs(std::istream &is, std::vector<int> &dofs)
3447 is.read((
char*) dofs.data(), dofs.size() *
sizeof(
int));
3452 std::ostringstream stream;
3456 write_dofs(stream, dofs);
3458 stream.str().swap(data);
3463 std::istringstream stream(data);
3467 read_dofs(stream, dofs);
3474 elem_ids.resize(elems.
Size());
3475 for (
int i = 0; i < elems.
Size(); i++)
3477 elem_ids[i] = eset.GetNCMesh()->elements[elems[i]].index;
3490 for (
int i = 0; i < cle.
Size(); i++)
3492 Element &el = copy->elements[cle[i]];
3498 debug_mesh.
ncmesh = copy;
3509 for (
int i = 0; i < 3; i++)
3526 return (elem_ids.capacity() + dofs.capacity()) *
sizeof(int);
3529template<
typename K,
typename V>
3530static std::size_t map_memory_usage(
const std::map<K, V> &map)
3532 std::size_t result = 0;
3533 for (
typename std::map<K, V>::const_iterator
3534 it = map.begin(); it != map.end(); ++it)
3536 result += it->second.MemoryUsage();
3537 result +=
sizeof(std::pair<K, V>) + 3*
sizeof(
void*) +
sizeof(bool);
3545 for (
unsigned i = 0; i <
groups.size(); i++)
3547 groups_size +=
groups[i].capacity() *
sizeof(int);
3549 const int approx_node_size =
3550 sizeof(std::pair<CommGroup, GroupId>) + 3*
sizeof(
void*) +
sizeof(bool);
3551 return groups_size +
group_id.size() * approx_node_size;
3554template<
typename Type,
int Size>
3555static std::size_t arrays_memory_usage(
const Array<Type> (&arrays)[Size])
3557 std::size_t total = 0;
3558 for (
int i = 0; i < Size; i++)
3560 total += arrays[i].MemoryUsage();
3596 << arrays_memory_usage(
entity_owner) <<
" entity_owner\n"
3638 if (
NRanks == 1) {
return; }
3645 for (
int i = 0; i < neighbors.
Size(); i++)
3647 send_ref[neighbors[i]].SetNCMesh(
this);
3655 for (
int i = 0; i < sendData.
Size(); i++)
3657 MFEM_ASSERT(sendData[i].element < (
unsigned int)
NElements,
"");
3660 for (
int j = 0; j < ranks.
Size(); j++)
3662 send_ref[ranks[j]].AddRefinement(elem, sendData[i].order);
3670 for (
int j = 0; j < neighbors.
Size(); j++)
3680 const int os = recvData.
Size();
3682 for (
int i = 0; i < msg.
Size(); i++)
3684 recvData[os + i].element = msg.
elements[i];
3685 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
void AddElementRank(int elem, int rank)
std::map< int, NeighborElementRankMessage > Map
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 AddElementRank(int elem, int rank)
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
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 CheckRefinement(int elem, char ref_type, const Array< Refinement > &refinements, const std::map< int, int > &elemToRef, std::set< int > &conflicts)
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)
int GetHexEdgeSplit(const int *nodes, int v1, int v2)
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)
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