29using namespace bin_io;
53 int &curved,
int &is_nc)
54 :
NCMesh(input, version, curved, is_nc)
60 MPI_Comm_rank(
MyComm, &my_rank);
69 "Parallel mesh file doesn't seem to match current MPI setup. "
70 "Loading a parallel NC mesh with a non-matching communicator "
71 "size is not supported.");
74 MPI_Allreduce(&iso, &
Iso, 1, MPI_C_BOOL, MPI_LAND,
MyComm);
82 , MyComm(other.MyComm)
83 , NRanks(other.NRanks)
105 for (
int i = 0; i < 3; i++)
131 owner = std::min(owner, el.
rank);
142 el_loc = (el.
index << 4) | local;
195 int e_index =
nodes[enode].edge_index;
198 owner = std::min(owner, el.
rank);
209 el_loc = (el.
index << 4) | local;
256 int v_index =
nodes[vnode].vert_index;
259 owner = std::min(owner, el.
rank);
270 el_loc = (el.
index << 4) | local;
309 for (
int i = 0; i < num; i++)
321 for (
int i = 0; i < list.masters.Size(); i++)
323 const Master &master = list.masters[i];
325 char master_old_flag = master_flag;
329 int si = list.slaves[j].index;
333 master_flag |= slave_flag;
334 slave_flag |= master_old_flag;
348 for (
int i = 0; i < list.conforming.Size(); i++)
355 for (
int i = 0; i < list.masters.Size(); i++)
359 shared.
masters.Append(list.masters[i]);
362 for (
int i = 0; i < list.slaves.Size(); i++)
364 int si = list.slaves[i].index;
367 shared.
slaves.Append(list.slaves[i]);
374 if (lhs.size() == rhs.size())
376 for (
unsigned i = 0; i < lhs.size(); i++)
378 if (lhs[i] < rhs[i]) {
return true; }
382 return lhs.size() < rhs.size();
388 for (
unsigned i = 1; i < group.size(); i++)
390 if (group[i] <= group[i-1]) {
return false; }
398 if (group.size() == 1 && group[0] ==
MyRank)
402 MFEM_ASSERT(group_sorted(group),
"invalid group");
414 MFEM_ASSERT(rank != INT_MAX,
"invalid rank");
415 static std::vector<int> group;
425 for (
unsigned i = 0; i < group.size(); i++)
427 if (group[i] == rank) {
return true; }
438 entity_group.
SetSize(nentities);
443 for (
auto begin = index_rank.
begin(); begin != index_rank.
end(); )
445 const auto &
index = begin->from;
446 if (
index >= nentities) {
break; }
449 const auto end = std::find_if(begin, index_rank.
end(),
453 group.resize(std::distance(begin, end));
454 std::transform(begin, end, group.begin(), [](
const mfem::Connection &c) { return c.to; });
464 for (
auto rank : ranks)
477 int v[4], e[4], eo[4];
486 for (
int j = master_edge.slaves_begin; j < master_edge.slaves_end; j++)
497 for (
int j = 0; j < 2; j++)
507 for (
int j = master_face.slaves_begin; j < master_face.slaves_end; j++)
520 for (
int j = 0; j < nfv; j++)
535 for (
int i = 0; i < 3; i++)
548 const Element *
const e[2] = { &e1, &e2 };
549 for (
int i = 0; i < 2; i++)
558 if (local) { local[i] = lf; }
562 for (
int j = 0; j < 4; j++)
564 ids[i][j] = e[i]->
node[fv[j]];
574 if (
Dim < 3) {
return; }
583 for (
const auto &face :
faces)
585 if (face.elem[0] >= 0 && face.elem[1] >= 0 && face.index <
NFaces)
590 if (e1->
rank == e2->
rank) {
continue; }
591 if (e1->
rank > e2->
rank) { std::swap(e1, e2); }
611 for (
int j = mf.slaves_begin; j < mf.slaves_end; j++)
622 bdr_faces.
Append(mf.index);
634 for (
int j = me.slaves_begin; j < me.slaves_end; j++)
640 bdr_edges.
Append(me.index);
647 auto FilterSortUnique = [](
Array<int> &v,
int N)
650 auto local = std::remove_if(v.
begin(), v.
end(), [N](
int i) { return i >= N; });
651 std::sort(v.
begin(), local);
655 FilterSortUnique(bdr_vertices,
NVertices);
656 FilterSortUnique(bdr_edges,
NEdges);
657 FilterSortUnique(bdr_faces,
NFaces);
670 for (
int i = 0; i < nleaves; i++)
685 for (
int i = 0; i < nleaves; i++)
693 else if (boundary_set[i] && etype)
710 for (
int i = 0; i < 8 && el.
child[i] >= 0; i++)
740static void set_to_array(
const std::set<T> &set,
Array<T> &array)
742 array.Reserve(set.size());
761 set_to_array(ranks, neighbors);
773 group_shared.
MakeI(ngroups-1);
777 for (
int i = 0; i < conf_group.
Size(); i++)
781 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
788 shared_local.
SetSize(num_shared);
789 group_shared.
MakeJ();
792 for (
int i = 0, j = 0; i < conf_group.
Size(); i++)
796 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
806 for (
int i = 0; i < group_shared.
Size(); i++)
808 int size = group_shared.
RowSize(i);
809 int *row = group_shared.
GetRow(i);
812 ref_row.
Sort([&](
const int a,
const int b)
820 if (lsi_a != lsi_b) {
return lsi_a < lsi_b; }
822 return (el_loc_a & 0xf) < (el_loc_b & 0xf);
832 for (
int ent = 0; ent <
Dim; ent++)
836 pmesh.
GetNE() == 0,
"Non empty partitions must be connected");
838 pmesh.
GetNE() == 0,
"Non empty partitions must be connected");
848 for (
unsigned i = 0; i <
groups.size(); i++)
850 if (
groups[i].size() > 1 || !i)
853 group_map[i] = int_groups.
Insert(iset);
860 for (
int ent = 0; ent < 3; ent++)
865 ecg = group_map[ecg];
899 for (
int i = 0; i < slt.
Size(); i++)
904 int v[4], e[4], eo[4];
911 for (
int i = 0; i < slq.
Size(); i++)
921 for (
int ent = 0; ent <
Dim; ent++)
937 std::map<int, std::vector<int>> recv_elems;
941 auto count_slaves = [&](
int i,
const Master& x)
943 return i + (x.slaves_end - x.slaves_begin);
946 const int bound = shared.
conforming.Size() + std::accumulate(
955 bool face_nbr_w_tri_faces =
false;
958 for (
int i = 0; i < shared.
conforming.Size(); i++)
962 MFEM_ASSERT(face != NULL,
"");
964 MFEM_ASSERT(face->
elem[0] >= 0 && face->
elem[1] >= 0,
"");
967 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
968 MFEM_ASSERT(e[0]->rank !=
MyRank && e[1]->rank ==
MyRank,
"");
975 recv_elems[e[0]->
rank].push_back(e[0]->
index);
978 for (
int i = 0; i < shared.
masters.Size(); i++)
986 MFEM_ASSERT(mf.
element >= 0,
"");
996 if (loc0) { std::swap(e[0], e[1]); }
1003 recv_elems[e[0]->
rank].push_back(e[0]->
index);
1007 MFEM_ASSERT(fnbr.
Size() <= bound,
1008 "oops, bad upper bound. fnbr.Size(): " << fnbr.
Size() <<
", bound: " << bound);
1017 return (
a->rank !=
b->rank) ?
a->rank <
b->rank
1018 :
a->index <
b->index;
1022 for (
int i = 0; i < fnbr.
Size(); i++)
1041 std::map<int, int> vert_map;
1042 for (
int i = 0; i < fnbr.
Size(); i++)
1050 for (
int k = 0; k < gi.
nv; k++)
1052 int &v = vert_map[elem->
node[k]];
1053 if (!v) { v = vert_map.size(); }
1057 if (!i || elem->
rank != fnbr[i-1]->rank)
1073 for (
const auto &v : vert_map)
1086 for (
auto &kv : recv_elems)
1088 std::sort(kv.second.begin(), kv.second.end());
1089 kv.second.erase(std::unique(kv.second.begin(), kv.second.end()),
1093 for (
int i = 0, last_rank = -1; i < send_elems.
Size(); i++)
1096 if (c.
from != last_rank)
1104 c.
from = send_elems[i-1].from;
1114 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
1132 if (shared.
slaves.Size())
1138 MFEM_ASSERT(pmesh.
faces_info.Size() == nfaces,
"");
1141 for (
int i = nfaces; i < pmesh.
faces_info.Size(); i++)
1152 for (
int i = 0; i < shared.
masters.Size(); i++)
1158 if (sf.
element < 0) {
continue; }
1160 MFEM_ASSERT(mf.
element >= 0,
"");
1201 if (!sloc &&
Dim == 3)
1207 std::swap((*pm2)(0, 1), (*pm2)(0, 3));
1208 std::swap((*pm2)(1, 1), (*pm2)(1, 3));
1212 std::swap((*pm2)(0, 0), (*pm2)(0, 1));
1213 std::swap((*pm2)(1, 0), (*pm2)(1, 1));
1230 else if (!sloc &&
Dim == 2)
1239 MFEM_ASSERT(fi.
NCFace < 0,
"fi.NCFace = " << fi.
NCFace);
1253 if (face_nbr_w_tri_faces)
1257 using RankToOrientation = std::map<int, std::vector<std::array<int, 6>>>;
1258 constexpr std::array<int, 6> unset_ori{{-1,-1,-1,-1,-1,-1}};
1265 RankToOrientation send_rank_to_face_neighbor_orientations;
1270 for (
const auto &se : send_elems)
1276 send_rank_to_face_neighbor_orientations[true_rank].emplace_back(unset_ori);
1279 std::copy(orientations.
begin(), orientations.
end(),
1280 send_rank_to_face_neighbor_orientations[true_rank].back().begin());
1287 auto recv_rank_to_face_neighbor_orientations =
1288 send_rank_to_face_neighbor_orientations;
1289 for (
auto &kv : recv_rank_to_face_neighbor_orientations)
1291 kv.second.resize(recv_elems[kv.first].size());
1296 std::vector<MPI_Request> send_requests, recv_requests;
1297 std::vector<MPI_Status> status(nranks);
1301 send_requests.reserve(nranks);
1302 recv_requests.reserve(nranks);
1309 for (
const auto &kv : send_rank_to_face_neighbor_orientations)
1311 send_requests.emplace_back();
1314 const int send_tag = (rank < kv.first)
1315 ? std::min(rank, kv.first)
1316 : std::max(rank, kv.first);
1317 MPI_Isend(&kv.second[0][0],
int(kv.second.size() * 6),
1318 MPI_INT, kv.first, send_tag, pmesh.
MyComm, &send_requests.back());
1323 for (
auto &kv : recv_rank_to_face_neighbor_orientations)
1325 recv_requests.emplace_back();
1328 const int recv_tag = (rank < kv.first)
1329 ? std::max(rank, kv.first)
1330 : std::min(rank, kv.first);
1331 MPI_Irecv(&kv.second[0][0],
int(kv.second.size() * 6),
1332 MPI_INT, kv.first, recv_tag, pmesh.
MyComm, &recv_requests.back());
1336 MPI_Waitall(
int(recv_requests.size()), recv_requests.data(), status.data());
1340 for (
const auto &kv : recv_rank_to_face_neighbor_orientations)
1343 for (
const auto &eo : kv.second)
1352 MPI_Waitall(
int(send_requests.size()), send_requests.data(), status.data());
1376 bool removeAll =
true;
1379 for (
int i = 0; i < 8; i++)
1382 if (el.
child[i] >= 0)
1385 if (!remove[i]) { removeAll =
false; }
1390 if (removeAll) {
return true; }
1393 for (
int i = 0; i < 8; i++)
1413 MFEM_WARNING(
"Can't prune 3D aniso meshes yet.");
1449 for (
int i = 0; i < refinements.
Size(); i++)
1453 "anisotropic parallel refinement not supported yet in 3D.");
1455 MFEM_VERIFY(
Iso ||
Dim < 3,
1456 "parallel refinement of 3D aniso meshes not supported yet.");
1463 for (
int i = 0; i < neighbors.
Size(); i++)
1465 send_ref[neighbors[i]].SetNCMesh(
this);
1473 for (
int i = 0; i < refinements.
Size(); i++)
1479 for (
int j = 0; j < ranks.
Size(); j++)
1481 send_ref[ranks[j]].AddRefinement(elem, ref.
ref_type);
1489 for (
int i = 0; i < refinements.
Size(); i++)
1496 for (
int j = 0; j < neighbors.
Size(); j++)
1506 for (
int i = 0; i < msg.
Size(); i++)
1521 MFEM_VERIFY(max_nc_level >= 1,
"'max_nc_level' must be 1 or greater.");
1528 long long size = refinements.
Size(), glob_size;
1529 MPI_Allreduce(&size, &glob_size, 1, MPI_LONG_LONG, MPI_SUM,
MyComm);
1531 if (!glob_size) {
break; }
1546 for (
int i = 0; i < derefs.
Size(); i++)
1548 int row = derefs[i];
1550 "invalid derefinement number.");
1555 int coarse_rank = INT_MAX;
1556 for (
int j = 0; j < size; j++)
1559 coarse_rank = std::min(coarse_rank, fine_rank);
1561 for (
int j = 0; j < size; j++)
1563 new_ranks[fine[j]] = coarse_rank;
1570 MFEM_VERIFY(
Dim < 3 ||
Iso,
1571 "derefinement of 3D anisotropic meshes not implemented yet.");
1595 for (
int i = 0; i < derefs.
Size(); i++)
1597 int row = derefs[i];
1599 "invalid derefinement number.");
1604 int coarse_rank = INT_MAX;
1605 for (
int j = 0; j < size; j++)
1608 coarse_rank = std::min(coarse_rank, fine_rank);
1610 for (
int j = 0; j < size; j++)
1612 new_ranks[fine[j]] = coarse_rank;
1616 int target_elements = 0;
1617 for (
int i = 0; i < new_ranks.
Size(); i++)
1619 if (new_ranks[i] ==
MyRank) { target_elements++; }
1633 for (
int i = 0; i < neighbors.
Size(); i++)
1635 send_deref[neighbors[i]].SetNCMesh(
this);
1642 for (
int i = 0; i < derefs.
Size(); i++)
1645 int parent =
elements[old_elements[fine[0]]].parent;
1649 for (
int j = 0; j < ranks.
Size(); j++)
1651 send_deref[ranks[j]].AddDerefinement(parent, new_ranks[fine[0]]);
1661 for (
int i = 0; i < old_elements.
Size(); i++)
1663 elements[old_elements[i]].index = i;
1668 old_elements.
Copy(coarse);
1669 for (
int i = 0; i < derefs.
Size(); i++)
1672 int parent =
elements[old_elements[fine[0]]].parent;
1681 for (
int j = 0; j < neighbors.
Size(); j++)
1691 for (
int i = 0; i < msg.
Size(); i++)
1709 for (
int i = 0; i < coarse.
Size(); i++)
1725 for (
int i = 0; i < coarse.
Size(); i++)
1739template<
typename Type>
1741 const Table &deref_table)
1754 for (
int i = 0; i < deref_table.
Size(); i++)
1756 const int* fine = deref_table.
GetRow(i);
1757 int size = deref_table.
RowSize(i);
1758 MFEM_ASSERT(size <= 8,
"");
1760 int ranks[8], min_rank = INT_MAX, max_rank = INT_MIN;
1761 for (
int j = 0; j < size; j++)
1764 min_rank = std::min(min_rank, ranks[j]);
1765 max_rank = std::max(max_rank, ranks[j]);
1769 if (min_rank != max_rank)
1772 for (
int j = 0; j < size; j++)
1779 for (
int j = 0; j < size; j++)
1781 Type *data = &elem_data[fine[j]];
1783 int rnk = ranks[j], len = 1;
1789 for (
int k = 0; k < neigh.
Size(); k++)
1791 MPI_Request* req =
new MPI_Request;
1792 MPI_Isend(data, len, datatype, neigh[k], 292,
MyComm, req);
1798 MPI_Request* req =
new MPI_Request;
1799 MPI_Irecv(data, len, datatype, rnk, 292,
MyComm, req);
1806 for (
int i = 0; i < requests.
Size(); i++)
1808 MPI_Wait(requests[i], MPI_STATUS_IGNORE);
1829 for (
int i = 0; i < deref_table.
Size(); i++)
1831 const int *fine = deref_table.
GetRow(i),
1832 size = deref_table.
RowSize(i);
1837 for (
int j = 0; j < size; j++)
1845 for (
int k = 0; k <
Dim; k++)
1848 splits[k] >= max_nc_level)
1850 leaf_ok[fine[j]] = 0;
break;
1862 for (
int i = 0; i < deref_table.
Size(); i++)
1864 const int* fine = deref_table.
GetRow(i),
1865 size = deref_table.
RowSize(i);
1867 for (
int j = 0; j < size; j++)
1869 if (!leaf_ok[fine[j]])
1871 level_ok[i] = 0;
break;
1888 if (!custom_partition)
1894 long local_elems =
NElements, total_elems = 0;
1895 MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM,
MyComm);
1897 long first_elem_global = 0;
1898 MPI_Scan(&local_elems, &first_elem_global, 1, MPI_LONG, MPI_SUM,
MyComm);
1899 first_elem_global -= local_elems;
1905 new_ranks[i] =
Partition(first_elem_global + (j++), total_elems);
1918 "Size of the partition array must match the number "
1919 "of local mesh elements (ParMesh::GetNE()).");
1922 custom_partition->
Copy(new_ranks);
1931 for (
int i = 0; i < old_elements.
Size(); i++)
1944 bool sfc = (target_elements >= 0);
1961 int begin = 0, end = 0;
1981 for (
int i = 0; i < rank_neighbors.
Size(); i++)
1983 int elem = rank_neighbors[i];
1991 recv_ghost_ranks[rank].SetNCMesh(
this);
2000 for (
auto &kv : recv_ghost_ranks)
2003 for (
int i = 0; i < msg.
Size(); i++)
2007 new_ranks[ghost_index] = msg.
values[i];
2011 recv_ghost_ranks.clear();
2022 int received_elements = 0;
2028 received_elements++;
2030 el.
rank = new_ranks[i];
2033 int nsent = 0, nrecv = 0;
2040 owned_elements.
Sort([&](
const int a,
const int b)
2049 int begin = 0, end = 0;
2053 int rank =
elements[owned_elements[begin]].rank;
2054 while (end < owned_elements.
Size() &&
2055 elements[owned_elements[end]].rank == rank) { end++; }
2060 rank_elems.
MakeRef(&owned_elements[begin], end - begin);
2071 for (
int i = 0; i < batch.
Size(); i++)
2073 int elem = batch[i];
2119 while (received_elements < target_elements)
2128 for (
int i = 0; i < msg.
Size(); i++)
2130 int elem_rank = msg.
values[i];
2133 if (elem_rank ==
MyRank) { received_elements++; }
2155 MPI_Request barrier = MPI_REQUEST_NULL;
2167 for (
int i = 0; i < msg.
Size(); i++)
2179 if (barrier != MPI_REQUEST_NULL)
2181 MPI_Test(&barrier, &done, MPI_STATUS_IGNORE);
2187 int mpi_err = MPI_Ibarrier(
MyComm, &barrier);
2189 MFEM_VERIFY(mpi_err == MPI_SUCCESS,
"");
2190 MFEM_VERIFY(barrier != MPI_REQUEST_NULL,
"");
2201 int glob_sent, glob_recv;
2202 MPI_Reduce(&nsent, &glob_sent, 1, MPI_INT, MPI_SUM, 0,
MyComm);
2203 MPI_Reduce(&nrecv, &glob_recv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
2207 MFEM_ASSERT(glob_sent == glob_recv,
2208 "(glob_sent, glob_recv) = ("
2209 << glob_sent <<
", " << glob_recv <<
")");
2212 MFEM_CONTRACT_VAR(nsent);
2213 MFEM_CONTRACT_VAR(nrecv);
2219 const Table &old_element_dofs,
2220 long old_global_offset,
2224 int vdim =
space->GetVDim();
2227 RebalanceDofMessage::Map::iterator it;
2237 for (
int i = 0; i < ne; i++)
2240 space->DofsToVDofs(dofs, old_ndofs);
2258 RebalanceDofMessage::Map::iterator it;
2263 nd += msg.
dofs.size();
2274 for (
unsigned i = 0; i < msg.
elem_ids.size(); i++)
2278 for (
unsigned i = 0; i < msg.
dofs.size(); i++)
2291 : ncmesh(other.ncmesh), include_ref_types(other.include_ref_types)
2299 data.Append(value & 0xff);
2300 data.Append((value >> 8) & 0xff);
2301 data.Append((value >> 16) & 0xff);
2302 data.Append((value >> 24) & 0xff);
2308 return (
int) data[pos] +
2309 ((int) data[pos+1] << 8) +
2310 ((int) data[pos+2] << 16) +
2311 ((int) data[pos+3] << 24);
2316 for (
int i = 0; i <
elements.Size(); i++)
2321 Element &el = ncmesh->elements[elem];
2322 if (el.
flag == flag) {
break; }
2331 Element &el = ncmesh->elements[elem];
2341 for (
int i = 0; i < 8; i++)
2343 if (el.
child[i] >= 0 && ncmesh->elements[el.
child[i]].flag)
2351 if (include_ref_types)
2356 for (
int i = 0; i < 8; i++)
2358 if (mask & (1 << i))
2360 EncodeTree(el.
child[i]);
2373 for (
int i = 0; i < ncmesh->root_state.Size(); i++)
2375 if (ncmesh->elements[i].flag)
2389 std::ostringstream oss;
2390 for (
int i = 0; i < ref_path.Size(); i++)
2392 oss <<
" elem " << ref_path[i] <<
" (";
2393 const Element &el = ncmesh->elements[ref_path[i]];
2394 for (
int j = 0; j <
GI[el.
Geom()].nv; j++)
2396 if (j) { oss <<
", "; }
2397 oss << ncmesh->RetrieveNode(el, j);
2409 ref_path.Append(elem);
2411 int mask = data[pos++];
2418 Element &el = ncmesh->elements[elem];
2419 if (include_ref_types)
2421 int ref_type = data[pos++];
2424 ncmesh->RefineElement(elem, ref_type);
2426 else { MFEM_ASSERT(ref_type == el.
ref_type,
"") }
2430 MFEM_ASSERT(el.
ref_type != 0,
"Path not found:\n"
2431 << RefPath() <<
" mask = " << mask);
2434 for (
int i = 0; i < 8; i++)
2436 if (mask & (1 << i))
2443 ref_path.DeleteLast();
2450 while ((root = GetInt(pos)) >= 0)
2460 os.write((
const char*) data.GetData(), data.Size());
2466 is.read((
char*) data.GetData(), data.Size());
2482 for (
unsigned i = 0; i <
groups.size(); i++)
2488 for (
int i = 0; i < ids[0].
Size(); i++)
2490 find_v[i].one = ids[0][i].index;
2504 for (
int j = 0; j < 2; j++)
2509 k = find_v[pos].two;
2520 for (
int i = 0; i < ids[1].
Size(); i++)
2522 find_e[i].one = ids[1][i].index;
2533 int v[4], e[4], eo[4], pos, k;
2535 for (
int j = 0; j < nfv; j++)
2539 k = find_v[pos].two;
2545 k = find_e[pos].two;
2560 for (
int i = 0; i < gi.
nv; i++)
2562 if (
nodes[el.
node[i]].vert_index ==
id.index)
2569 MFEM_ABORT(
"Vertex not found.");
2575 const int *old_ev =
GI[old.
Geom()].
edges[(int)
id.local];
2577 MFEM_ASSERT(node != NULL,
"Edge not found.");
2583 for (
int i = 0; i < gi.
ne; i++)
2585 const int* ev = gi.
edges[i];
2586 if ((el.
node[ev[0]] == node->
p1 && el.
node[ev[1]] == node->
p2) ||
2587 (el.
node[ev[1]] == node->
p1 && el.
node[ev[0]] == node->
p2))
2595 MFEM_ABORT(
"Edge not found.");
2601 const MeshId &first = ids[find[pos].two];
2602 while (++pos < find.Size() && ids[find[pos].two].index == first.
index)
2604 MeshId &other = ids[find[pos].two];
2612 std::map<int, int> stream_id;
2618 for (
int type = 0; type < 3; type++)
2620 for (
int i = 0; i < ids[type].
Size(); i++)
2634 for (
int i = 0; i < decoded.
Size(); i++)
2636 stream_id[decoded[i]] = i;
2641 for (
int type = 0; type < 3; type++)
2644 for (
int i = 0; i < ids[type].
Size(); i++)
2646 const MeshId&
id = ids[type][i];
2663 for (
int type = 0; type < 3; type++)
2668 for (
int i = 0; i < ne; i++)
2671 int elem = elems[el_num];
2674 MFEM_VERIFY(!el.
ref_type,
"not a leaf element: " << el_num);
2676 MeshId &
id = ids[type][i];
2686 id.index =
nodes[el.
node[(int)
id.local]].vert_index;
2691 const int* ev = gi.
edges[(int)
id.local];
2693 MFEM_ASSERT(node && node->
HasEdge(),
"edge not found.");
2699 const int* fv = gi.
faces[(int)
id.local];
2702 MFEM_ASSERT(face,
"face not found.");
2703 id.index = face->
index;
2713 std::map<GroupId, GroupId> stream_id;
2714 for (
int i = 0; i < ids.
Size(); i++)
2716 if (i && ids[i] == ids[i-1]) {
continue; }
2717 unsigned size = stream_id.size();
2718 GroupId &sid = stream_id[ids[i]];
2719 if (size != stream_id.size()) { sid = size; }
2724 for (std::map<GroupId, GroupId>::iterator
2725 it = stream_id.begin(); it != stream_id.end(); ++it)
2732 for (
unsigned i = 0; i < group.size(); i++)
2746 for (
int i = 0; i < ids.
Size(); i++)
2760 for (
int i = 0; i < ngroups; i++)
2767 for (
int ii = 0; ii < size; ii++)
2781 for (
int i = 0; i < ids.
Size(); i++)
2790template<
class ValueType,
bool RefTypes,
int Tag>
2793 std::ostringstream ostream;
2799 eset.
Encode(tmp_elements);
2807 std::map<int, int> element_index;
2808 for (
int i = 0; i < decoded.
Size(); i++)
2810 element_index[decoded[i]] = i;
2814 MFEM_ASSERT(
elements.size() == values.size(),
"");
2816 for (
unsigned i = 0; i < values.size(); i++)
2822 ostream.str().swap(data);
2825template<
class ValueType,
bool RefTypes,
int Tag>
2828 std::istringstream istream(data);
2834 eset.
Decode(tmp_elements);
2836 int* el = tmp_elements.
GetData();
2841 for (
int i = 0; i < count; i++)
2844 MFEM_ASSERT(
index >= 0 && (
size_t)
index < values.size(),
"");
2855 eset.SetNCMesh(ncmesh);
2860 eset.Decode(decoded);
2862 elem_ids.resize(decoded.
Size());
2863 for (
int i = 0; i < decoded.
Size(); i++)
2865 elem_ids[i] = eset.GetNCMesh()->elements[decoded[i]].index;
2869static void write_dofs(std::ostream &os,
const std::vector<int> &dofs)
2873 os.write((
const char*) dofs.data(), dofs.size() *
sizeof(
int));
2876static void read_dofs(std::istream &is, std::vector<int> &dofs)
2879 is.read((
char*) dofs.data(), dofs.size() *
sizeof(
int));
2884 std::ostringstream stream;
2888 write_dofs(stream, dofs);
2890 stream.str().swap(data);
2895 std::istringstream stream(data);
2899 read_dofs(stream, dofs);
2906 elem_ids.resize(elems.
Size());
2907 for (
int i = 0; i < elems.
Size(); i++)
2909 elem_ids[i] = eset.GetNCMesh()->elements[elems[i]].index;
2922 for (
int i = 0; i < cle.
Size(); i++)
2930 debug_mesh.
ncmesh = copy;
2941 for (
int i = 0; i < 3; i++)
2958 return (elem_ids.capacity() + dofs.capacity()) *
sizeof(int);
2961template<
typename K,
typename V>
2962static std::size_t map_memory_usage(
const std::map<K, V> &map)
2964 std::size_t result = 0;
2965 for (
typename std::map<K, V>::const_iterator
2966 it = map.begin(); it != map.end(); ++it)
2968 result += it->second.MemoryUsage();
2969 result +=
sizeof(std::pair<K, V>) + 3*
sizeof(
void*) +
sizeof(bool);
2977 for (
unsigned i = 0; i <
groups.size(); i++)
2979 groups_size +=
groups[i].capacity() *
sizeof(int);
2981 const int approx_node_size =
2982 sizeof(std::pair<CommGroup, GroupId>) + 3*
sizeof(
void*) +
sizeof(bool);
2983 return groups_size +
group_id.size() * approx_node_size;
2986template<
typename Type,
int Size>
2987static std::size_t arrays_memory_usage(
const Array<Type> (&arrays)[Size])
2989 std::size_t total = 0;
2990 for (
int i = 0; i < Size; i++)
2992 total += arrays[i].MemoryUsage();
3028 << arrays_memory_usage(
entity_owner) <<
" entity_owner\n"
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(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)
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)
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
Face * GetFace(Element &elem, int face_no)
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, 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 Trim() override
Save memory by releasing all non-essential and cached data.
void BuildVertexList() override
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
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)
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.
Nonconforming edge/face within a bigger edge/face.
unsigned matrix
index into NCList::point_matrices[geom]
int master
master number (in Mesh numbering)
char ref_type
refinement XYZ bit mask (7 = full isotropic)
int index
Mesh element number.
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.