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(&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.");
1516 for (
int i = 0; i < refinements.
Size(); i++)
1520 "anisotropic parallel refinement not supported yet in 3D.");
1522 MFEM_VERIFY(
Iso ||
Dim < 3,
1523 "parallel refinement of 3D aniso meshes not supported yet.");
1530 for (
int i = 0; i < neighbors.
Size(); i++)
1532 send_ref[neighbors[i]].SetNCMesh(
this);
1540 for (
int i = 0; i < refinements.
Size(); i++)
1546 for (
int j = 0; j < ranks.
Size(); j++)
1548 send_ref[ranks[j]].AddRefinement(elem, ref.
GetType());
1556 for (
int i = 0; i < refinements.
Size(); i++)
1563 for (
int j = 0; j < neighbors.
Size(); j++)
1573 for (
int i = 0; i < msg.
Size(); i++)
1588 MFEM_VERIFY(max_nc_level >= 1,
"'max_nc_level' must be 1 or greater.");
1595 long long size = refinements.
Size(), glob_size;
1596 MPI_Allreduce(&size, &glob_size, 1, MPI_LONG_LONG, MPI_SUM,
MyComm);
1598 if (!glob_size) {
break; }
1613 for (
int i = 0; i < derefs.
Size(); i++)
1615 int row = derefs[i];
1617 "invalid derefinement number.");
1622 int coarse_rank = INT_MAX;
1623 for (
int j = 0; j < size; j++)
1626 coarse_rank = std::min(coarse_rank, fine_rank);
1628 for (
int j = 0; j < size; j++)
1630 new_ranks[fine[j]] = coarse_rank;
1637 MFEM_VERIFY(
Dim < 3 ||
Iso,
1638 "derefinement of 3D anisotropic meshes not implemented yet.");
1662 for (
int i = 0; i < derefs.
Size(); i++)
1664 int row = derefs[i];
1666 "invalid derefinement number.");
1671 int coarse_rank = INT_MAX;
1672 for (
int j = 0; j < size; j++)
1675 coarse_rank = std::min(coarse_rank, fine_rank);
1677 for (
int j = 0; j < size; j++)
1679 new_ranks[fine[j]] = coarse_rank;
1683 int target_elements = 0;
1684 for (
int i = 0; i < new_ranks.
Size(); i++)
1686 if (new_ranks[i] ==
MyRank) { target_elements++; }
1700 for (
int i = 0; i < neighbors.
Size(); i++)
1702 send_deref[neighbors[i]].SetNCMesh(
this);
1709 for (
int i = 0; i < derefs.
Size(); i++)
1712 int parent =
elements[old_elements[fine[0]]].parent;
1716 for (
int j = 0; j < ranks.
Size(); j++)
1718 send_deref[ranks[j]].AddDerefinement(parent, new_ranks[fine[0]]);
1728 for (
int i = 0; i < old_elements.
Size(); i++)
1730 elements[old_elements[i]].index = i;
1735 old_elements.
Copy(coarse);
1736 for (
int i = 0; i < derefs.
Size(); i++)
1739 int parent =
elements[old_elements[fine[0]]].parent;
1748 for (
int j = 0; j < neighbors.
Size(); j++)
1758 for (
int i = 0; i < msg.
Size(); i++)
1776 for (
int i = 0; i < coarse.
Size(); i++)
1792 for (
int i = 0; i < coarse.
Size(); i++)
1806template<
typename Type>
1808 const Table &deref_table)
1821 for (
int i = 0; i < deref_table.
Size(); i++)
1823 const int* fine = deref_table.
GetRow(i);
1824 int size = deref_table.
RowSize(i);
1825 MFEM_ASSERT(size <= 8,
"");
1827 int ranks[8], min_rank = INT_MAX, max_rank = INT_MIN;
1828 for (
int j = 0; j < size; j++)
1831 min_rank = std::min(min_rank, ranks[j]);
1832 max_rank = std::max(max_rank, ranks[j]);
1836 if (min_rank != max_rank)
1839 for (
int j = 0; j < size; j++)
1846 for (
int j = 0; j < size; j++)
1848 Type *data = &elem_data[fine[j]];
1850 int rnk = ranks[j], len = 1;
1856 for (
int k = 0; k < neigh.
Size(); k++)
1858 MPI_Request* req =
new MPI_Request;
1859 MPI_Isend(data, len, datatype, neigh[k], 292,
MyComm, req);
1865 MPI_Request* req =
new MPI_Request;
1866 MPI_Irecv(data, len, datatype, rnk, 292,
MyComm, req);
1873 for (
int i = 0; i < requests.
Size(); i++)
1875 MPI_Wait(requests[i], MPI_STATUS_IGNORE);
1896 for (
int i = 0; i < deref_table.
Size(); i++)
1898 const int *fine = deref_table.
GetRow(i),
1899 size = deref_table.
RowSize(i);
1904 for (
int j = 0; j < size; j++)
1912 for (
int k = 0; k <
Dim; k++)
1915 splits[k] >= max_nc_level)
1917 leaf_ok[fine[j]] = 0;
break;
1929 for (
int i = 0; i < deref_table.
Size(); i++)
1931 const int* fine = deref_table.
GetRow(i),
1932 size = deref_table.
RowSize(i);
1934 for (
int j = 0; j < size; j++)
1936 if (!leaf_ok[fine[j]])
1938 level_ok[i] = 0;
break;
1955 if (!custom_partition)
1961 long local_elems =
NElements, total_elems = 0;
1962 MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM,
MyComm);
1964 long first_elem_global = 0;
1965 MPI_Scan(&local_elems, &first_elem_global, 1, MPI_LONG, MPI_SUM,
MyComm);
1966 first_elem_global -= local_elems;
1972 new_ranks[i] =
Partition(first_elem_global + (j++), total_elems);
1985 "Size of the partition array must match the number "
1986 "of local mesh elements (ParMesh::GetNE()).");
1989 custom_partition->
Copy(new_ranks);
1998 for (
int i = 0; i < old_elements.
Size(); i++)
2011 bool sfc = (target_elements >= 0);
2028 int begin = 0, end = 0;
2048 for (
int i = 0; i < rank_neighbors.
Size(); i++)
2050 int elem = rank_neighbors[i];
2058 recv_ghost_ranks[rank].SetNCMesh(
this);
2067 for (
auto &kv : recv_ghost_ranks)
2070 for (
int i = 0; i < msg.
Size(); i++)
2074 new_ranks[ghost_index] = msg.
values[i];
2078 recv_ghost_ranks.clear();
2089 int received_elements = 0;
2095 received_elements++;
2097 el.
rank = new_ranks[i];
2100 int nsent = 0, nrecv = 0;
2107 owned_elements.
Sort([&](
const int a,
const int b)
2116 int begin = 0, end = 0;
2120 int rank =
elements[owned_elements[begin]].rank;
2121 while (end < owned_elements.
Size() &&
2122 elements[owned_elements[end]].rank == rank) { end++; }
2127 rank_elems.
MakeRef(&owned_elements[begin], end - begin);
2138 for (
int i = 0; i < batch.
Size(); i++)
2140 int elem = batch[i];
2186 while (received_elements < target_elements)
2195 for (
int i = 0; i < msg.
Size(); i++)
2197 int elem_rank = msg.
values[i];
2200 if (elem_rank ==
MyRank) { received_elements++; }
2222 MPI_Request barrier = MPI_REQUEST_NULL;
2234 for (
int i = 0; i < msg.
Size(); i++)
2246 if (barrier != MPI_REQUEST_NULL)
2248 MPI_Test(&barrier, &done, MPI_STATUS_IGNORE);
2254 int mpi_err = MPI_Ibarrier(
MyComm, &barrier);
2256 MFEM_VERIFY(mpi_err == MPI_SUCCESS,
"");
2257 MFEM_VERIFY(barrier != MPI_REQUEST_NULL,
"");
2268 int glob_sent, glob_recv;
2269 MPI_Reduce(&nsent, &glob_sent, 1, MPI_INT, MPI_SUM, 0,
MyComm);
2270 MPI_Reduce(&nrecv, &glob_recv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
2274 MFEM_ASSERT(glob_sent == glob_recv,
2275 "(glob_sent, glob_recv) = ("
2276 << glob_sent <<
", " << glob_recv <<
")");
2279 MFEM_CONTRACT_VAR(nsent);
2280 MFEM_CONTRACT_VAR(nrecv);
2286 const Table &old_element_dofs,
2287 long old_global_offset,
2291 int vdim =
space->GetVDim();
2294 RebalanceDofMessage::Map::iterator it;
2299 int ne =
static_cast<int>(msg.
elem_ids.size());
2304 for (
int i = 0; i < ne; i++)
2307 space->DofsToVDofs(dofs, old_ndofs);
2325 RebalanceDofMessage::Map::iterator it;
2329 ne +=
static_cast<int>(msg.
elem_ids.size());
2330 nd +=
static_cast<int>(msg.
dofs.size());
2341 for (
unsigned i = 0; i < msg.
elem_ids.size(); i++)
2345 for (
unsigned i = 0; i < msg.
dofs.size(); i++)
2358 : ncmesh(other.ncmesh), include_ref_types(other.include_ref_types)
2366 data.Append(value & 0xff);
2367 data.Append((value >> 8) & 0xff);
2368 data.Append((value >> 16) & 0xff);
2369 data.Append((value >> 24) & 0xff);
2375 return (
int) data[pos] +
2376 ((int) data[pos+1] << 8) +
2377 ((int) data[pos+2] << 16) +
2378 ((int) data[pos+3] << 24);
2383 for (
int i = 0; i <
elements.Size(); i++)
2388 Element &el = ncmesh->elements[elem];
2389 if (el.
flag == flag) {
break; }
2398 Element &el = ncmesh->elements[elem];
2408 for (
int i = 0; i < 8; i++)
2410 if (el.
child[i] >= 0 && ncmesh->elements[el.
child[i]].flag)
2418 if (include_ref_types)
2423 for (
int i = 0; i < 8; i++)
2425 if (mask & (1 << i))
2427 EncodeTree(el.
child[i]);
2440 for (
int i = 0; i < ncmesh->root_state.Size(); i++)
2442 if (ncmesh->elements[i].flag)
2456 std::ostringstream oss;
2457 for (
int i = 0; i < ref_path.Size(); i++)
2459 oss <<
" elem " << ref_path[i] <<
" (";
2460 const Element &el = ncmesh->elements[ref_path[i]];
2461 for (
int j = 0; j <
GI[el.
Geom()].nv; j++)
2463 if (j) { oss <<
", "; }
2464 oss << ncmesh->RetrieveNode(el, j);
2476 ref_path.Append(elem);
2478 int mask = data[pos++];
2485 Element &el = ncmesh->elements[elem];
2486 if (include_ref_types)
2488 int ref_type = data[pos++];
2491 ncmesh->RefineElement(elem, ref_type);
2493 else { MFEM_ASSERT(ref_type == el.
ref_type,
"") }
2497 MFEM_ASSERT(el.
ref_type != 0,
"Path not found:\n"
2498 << RefPath() <<
" mask = " << mask);
2501 for (
int i = 0; i < 8; i++)
2503 if (mask & (1 << i))
2510 ref_path.DeleteLast();
2517 while ((root = GetInt(pos)) >= 0)
2527 os.write((
const char*) data.GetData(), data.Size());
2533 is.read((
char*) data.GetData(), data.Size());
2549 for (
unsigned i = 0; i <
groups.size(); i++)
2555 for (
int i = 0; i < ids[0].
Size(); i++)
2557 find_v[i].one = ids[0][i].index;
2571 for (
int j = 0; j < 2; j++)
2576 k = find_v[pos].two;
2587 for (
int i = 0; i < ids[1].
Size(); i++)
2589 find_e[i].one = ids[1][i].index;
2600 int v[4], e[4], eo[4], pos, k;
2602 for (
int j = 0; j < nfv; j++)
2606 k = find_v[pos].two;
2612 k = find_e[pos].two;
2627 for (
int i = 0; i < gi.
nv; i++)
2629 if (
nodes[el.
node[i]].vert_index ==
id.index)
2636 MFEM_ABORT(
"Vertex not found.");
2642 const int *old_ev =
GI[old.
Geom()].
edges[(int)
id.local];
2644 MFEM_ASSERT(node != NULL,
"Edge not found.");
2650 for (
int i = 0; i < gi.
ne; i++)
2652 const int* ev = gi.
edges[i];
2653 if ((el.
node[ev[0]] == node->
p1 && el.
node[ev[1]] == node->
p2) ||
2654 (el.
node[ev[1]] == node->
p1 && el.
node[ev[0]] == node->
p2))
2662 MFEM_ABORT(
"Edge not found.");
2668 const MeshId &first = ids[find[pos].two];
2669 while (++pos < find.Size() && ids[find[pos].two].index == first.
index)
2671 MeshId &other = ids[find[pos].two];
2679 std::map<int, int> stream_id;
2685 for (
int type = 0; type < 3; type++)
2687 for (
int i = 0; i < ids[type].
Size(); i++)
2701 for (
int i = 0; i < decoded.
Size(); i++)
2703 stream_id[decoded[i]] = i;
2708 for (
int type = 0; type < 3; type++)
2711 for (
int i = 0; i < ids[type].
Size(); i++)
2713 const MeshId&
id = ids[type][i];
2730 for (
int type = 0; type < 3; type++)
2735 for (
int i = 0; i < ne; i++)
2738 int elem = elems[el_num];
2741 MFEM_VERIFY(!el.
ref_type,
"not a leaf element: " << el_num);
2743 MeshId &
id = ids[type][i];
2753 id.index =
nodes[el.
node[(int)
id.local]].vert_index;
2758 const int* ev = gi.
edges[(int)
id.local];
2760 MFEM_ASSERT(node && node->
HasEdge(),
"edge not found.");
2766 const int* fv = gi.
faces[(int)
id.local];
2769 MFEM_ASSERT(face,
"face not found.");
2770 id.index = face->
index;
2780 std::map<GroupId, GroupId> stream_id;
2781 for (
int i = 0; i < ids.
Size(); i++)
2783 if (i && ids[i] == ids[i-1]) {
continue; }
2784 unsigned size = stream_id.size();
2785 GroupId &sid = stream_id[ids[i]];
2786 if (size != stream_id.size()) { sid = size; }
2791 for (std::map<GroupId, GroupId>::iterator
2792 it = stream_id.begin(); it != stream_id.end(); ++it)
2799 for (
unsigned i = 0; i < group.size(); i++)
2813 for (
int i = 0; i < ids.
Size(); i++)
2827 for (
int i = 0; i < ngroups; i++)
2834 for (
int ii = 0; ii < size; ii++)
2848 for (
int i = 0; i < ids.
Size(); i++)
2857template<
class ValueType,
bool RefTypes,
int Tag>
2860 std::ostringstream ostream;
2866 eset.
Encode(tmp_elements);
2874 std::map<int, int> element_index;
2875 for (
int i = 0; i < decoded.
Size(); i++)
2877 element_index[decoded[i]] = i;
2880 write<int>(ostream,
static_cast<int>(values.size()));
2881 MFEM_ASSERT(
elements.size() == values.size(),
"");
2883 for (
unsigned i = 0; i < values.size(); i++)
2889 ostream.str().swap(data);
2892template<
class ValueType,
bool RefTypes,
int Tag>
2895 std::istringstream istream(data);
2901 eset.
Decode(tmp_elements);
2903 int* el = tmp_elements.
GetData();
2908 for (
int i = 0; i < count; i++)
2911 MFEM_ASSERT(
index >= 0 && (
size_t)
index < values.size(),
"");
2922 eset.SetNCMesh(ncmesh);
2927 eset.Decode(decoded);
2929 elem_ids.resize(decoded.
Size());
2930 for (
int i = 0; i < decoded.
Size(); i++)
2932 elem_ids[i] = eset.GetNCMesh()->elements[decoded[i]].index;
2936static void write_dofs(std::ostream &os,
const std::vector<int> &dofs)
2938 write<int>(os,
static_cast<int>(dofs.size()));
2940 os.write((
const char*) dofs.data(), dofs.size() *
sizeof(
int));
2943static void read_dofs(std::istream &is, std::vector<int> &dofs)
2946 is.read((
char*) dofs.data(), dofs.size() *
sizeof(
int));
2951 std::ostringstream stream;
2955 write_dofs(stream, dofs);
2957 stream.str().swap(data);
2962 std::istringstream stream(data);
2966 read_dofs(stream, dofs);
2973 elem_ids.resize(elems.
Size());
2974 for (
int i = 0; i < elems.
Size(); i++)
2976 elem_ids[i] = eset.GetNCMesh()->elements[elems[i]].index;
2989 for (
int i = 0; i < cle.
Size(); i++)
2997 debug_mesh.
ncmesh = copy;
3008 for (
int i = 0; i < 3; i++)
3025 return (elem_ids.capacity() + dofs.capacity()) *
sizeof(int);
3028template<
typename K,
typename V>
3029static std::size_t map_memory_usage(
const std::map<K, V> &map)
3031 std::size_t result = 0;
3032 for (
typename std::map<K, V>::const_iterator
3033 it = map.begin(); it != map.end(); ++it)
3035 result += it->second.MemoryUsage();
3036 result +=
sizeof(std::pair<K, V>) + 3*
sizeof(
void*) +
sizeof(bool);
3044 for (
unsigned i = 0; i <
groups.size(); i++)
3046 groups_size +=
groups[i].capacity() *
sizeof(int);
3048 const int approx_node_size =
3049 sizeof(std::pair<CommGroup, GroupId>) + 3*
sizeof(
void*) +
sizeof(bool);
3050 return groups_size +
group_id.size() * approx_node_size;
3053template<
typename Type,
int Size>
3054static std::size_t arrays_memory_usage(
const Array<Type> (&arrays)[Size])
3056 std::size_t total = 0;
3057 for (
int i = 0; i < Size; i++)
3059 total += arrays[i].MemoryUsage();
3095 << arrays_memory_usage(
entity_owner) <<
" entity_owner\n"
3137 if (
NRanks == 1) {
return; }
3144 for (
int i = 0; i < neighbors.
Size(); i++)
3146 send_ref[neighbors[i]].SetNCMesh(
this);
3154 for (
int i = 0; i < sendData.
Size(); i++)
3156 MFEM_ASSERT(sendData[i].element < (
unsigned int)
NElements,
"");
3159 for (
int j = 0; j < ranks.
Size(); j++)
3161 send_ref[ranks[j]].AddRefinement(elem, sendData[i].order);
3169 for (
int j = 0; j < neighbors.
Size(); j++)
3179 const int os = recvData.
Size();
3181 for (
int i = 0; i < msg.
Size(); i++)
3183 recvData[os + i].element = msg.
elements[i];
3184 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.
NCMesh * ncmesh
Optional nonconforming mesh extension.
virtual void SetAttributes()
Determine the sets of unique attribute values in domain and boundary elements.
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.
void SetDerefMatrixCodes(int parent, Array< int > &fine_coarse)
const Face & GetFace(int i) const
Access a Face.
mfem::Element * NewMeshElement(int geom) const
void NeighborExpand(const Array< int > &elems, Array< int > &expanded, const Array< int > *search_set=NULL)
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
Table derefinements
possible derefinements, see GetDerefinementTable
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
void InitDerefTransforms()
int GetFaceVerticesEdges(const MeshId &face_id, int vert_index[4], int edge_index[4], int edge_orientation[4]) const
void RefineElement(int elem, char ref_type)
Refine the element elem with the refinement type ref_type.
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()
void GetLimitRefinements(Array< Refinement > &refinements, int max_level)
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
void CountSplits(int elem, int splits[3]) const
int spaceDim
dimensions of the elements and the vertex coordinates
CoarseFineTransformations transforms
storage for data returned by Get[De]RefinementTransforms()
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
virtual void Refine(const Array< Refinement > &refinements)
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)
ElementSet(NCMesh *ncmesh=NULL, bool include_ref_types=false)
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.
Array< int > entity_elem_local[3]
void SendRebalanceDofs(int old_ndofs, const Table &old_element_dofs, long old_global_offset, FiniteElementSpace *space)
Use the communication pattern from last Rebalance() to send element DOFs.
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 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)
void LimitNCLevel(int max_nc_level) override
Parallel version of NCMesh::LimitNCLevel.
RebalanceDofMessage::Map recv_rebalance_dofs
void ChangeVertexMeshIdElement(NCMesh::MeshId &id, int elem)
void EncodeGroups(std::ostream &os, const Array< GroupId > &ids)
void Refine(const Array< Refinement > &refinements) override
void FindEdgesOfGhostFace(int face, Array< int > &edges)
Array< GroupId > entity_conf_group[3]
Array< int > boundary_layer
list of type 3 elements
int Partition(long index, long total_elements) const
Return the processor number for a global element number.
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)
void Derefine(const Array< int > &derefs) override
void Rebalance(const Array< int > *custom_partition=NULL)
int GetNGhostElements() const override
void ElementNeighborProcessors(int elem, Array< int > &ranks)
void RecvRebalanceDofs(Array< int > &elements, Array< long > &dofs)
Receive element DOFs sent by SendRebalanceDofs().
static int get_face_orientation(const Face &face, const Element &e1, const Element &e2, int local[2]=NULL)
void GetFineToCoarsePartitioning(const Array< int > &derefs, Array< int > &new_ranks) const
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[])
Array< DenseMatrix * > aux_pm_store
Stores modified point matrices created by GetFaceNeighbors.
void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level) override
void RedistributeElements(Array< int > &new_ranks, int target_elements, bool record_comm)
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)
void SynchronizeDerefinementData(Array< Type > &elem_data, const Table &deref_table)
GroupId GetGroupId(const CommGroup &group)
void CommunicateGhostData(const Array< VarOrderElemInfo > &sendData, Array< VarOrderElemInfo > &recvData)
long PartitionFirstIndex(int rank, long total_elements) const
Return the global index of the first element owned by processor 'rank'.
void ElementSharesVertex(int elem, int local, int vnode) override
Data type line segment element.
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)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
int Size() const
Returns the number of TYPE I elements.
void MakeFromList(int nrows, const Array< Connection > &list)
void AddAColumnInRow(int r)
int index(int i, int j, int nx, int ny)
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.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
bool operator<(const Pair< A, B > &p, const Pair< A, B > &q)
Comparison operator for class Pair, based on the first element only.
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.
static bool TestAllSent(MapT &rank_msg)
Return true if all messages in the map container were sent, otherwise return false,...
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.
static void RecvAll(MapT &rank_msg, MPI_Comm comm)
Helper to receive all messages in a rank-to-message map container.
static bool IProbe(int &rank, int &size, MPI_Comm comm)
Non-blocking probe for incoming message of this type from any rank. If there is an incoming message,...
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.