12 #include "../config/config.hpp" 18 #include "../general/binaryio.hpp" 27 using namespace bin_io;
51 int &curved,
int &is_nc)
52 :
NCMesh(input, version, curved, is_nc)
58 MPI_Comm_rank(
MyComm, &my_rank);
67 "Parallel mesh file doesn't seem to match current MPI setup. " 68 "Loading a parallel NC mesh with a non-matching communicator " 69 "size is not supported.");
72 MPI_Allreduce(&iso, &
Iso, 1, MPI_C_BOOL, MPI_LAND,
MyComm);
80 , MyComm(other.MyComm)
81 , NRanks(other.NRanks)
103 for (
int i = 0; i < 3; i++)
124 int f_index =
faces[face].index;
127 owner = std::min(owner, el.
rank);
138 el_loc = (el.
index << 4) | local;
191 int e_index =
nodes[enode].edge_index;
194 owner = std::min(owner, el.
rank);
205 el_loc = (el.
index << 4) | local;
252 int v_index =
nodes[vnode].vert_index;
255 owner = std::min(owner, el.
rank);
266 el_loc = (el.
index << 4) | local;
305 for (
int i = 0; i < num; i++)
317 for (
int i = 0; i < list.
masters.Size(); i++)
321 char master_old_flag = master_flag;
325 int si = list.
slaves[j].index;
329 master_flag |= slave_flag;
330 slave_flag |= master_old_flag;
344 for (
int i = 0; i < list.
conforming.Size(); i++)
351 for (
int i = 0; i < list.
masters.Size(); i++)
358 for (
int i = 0; i < list.
slaves.Size(); i++)
360 int si = list.
slaves[i].index;
370 if (lhs.size() == rhs.size())
372 for (
unsigned i = 0; i < lhs.size(); i++)
374 if (lhs[i] < rhs[i]) {
return true; }
378 return lhs.size() < rhs.size();
384 for (
unsigned i = 1; i < group.size(); i++)
386 if (group[i] <= group[i-1]) {
return false; }
394 if (group.size() == 1 && group[0] ==
MyRank)
398 MFEM_ASSERT(group_sorted(group),
"invalid group");
410 MFEM_ASSERT(rank != INT_MAX,
"invalid rank");
411 static std::vector<int> group;
421 for (
unsigned i = 0; i < group.size(); i++)
423 if (group[i] == rank) {
return true; }
434 entity_group.
SetSize(nentities);
439 for (
auto begin = index_rank.
begin(); begin != index_rank.
end(); )
441 const auto &
index = begin->from;
442 if (
index >= nentities) {
break; }
445 const auto end = std::find_if(begin, index_rank.
end(),
449 group.resize(std::distance(begin, end));
450 std::transform(begin, end, group.begin(), [](
const mfem::Connection &c) {
return c.to; });
460 for (
auto rank : ranks)
473 int v[4], e[4], eo[4];
482 for (
int j = master_edge.slaves_begin; j < master_edge.slaves_end; j++)
493 for (
int j = 0; j < 2; j++)
503 for (
int j = master_face.slaves_begin; j < master_face.slaves_end; j++)
516 for (
int j = 0; j < nfv; j++)
531 for (
int i = 0; i < 3; i++)
544 for (
int i = 0; i < 2; i++)
553 if (local) { local[i] = lf; }
557 for (
int j = 0; j < 4; j++)
559 ids[i][j] = e[i]->
node[fv[j]];
569 if (
Dim < 3) {
return; }
578 for (
auto face =
faces.begin(); face !=
faces.end(); ++face)
580 if (face->elem[0] >= 0 && face->elem[1] >= 0 && face->index <
NFaces)
585 if (e1->
rank == e2->
rank) {
continue; }
586 if (e1->
rank > e2->
rank) { std::swap(e1, e2); }
601 for (i = j = 0; i < bdr_vertices.
Size(); i++)
603 if (bdr_vertices[i] <
NVertices) { bdr_vertices[j++] = bdr_vertices[i]; }
608 for (i = j = 0; i < bdr_edges.
Size(); i++)
610 if (bdr_edges[i] <
NEdges) { bdr_edges[j++] = bdr_edges[i]; }
625 for (
int i = 0; i < nleaves; i++)
640 for (
int i = 0; i < nleaves; i++)
648 else if (boundary_set[i] && etype)
665 for (
int i = 0; i < 8 && el.
child[i] >= 0; i++)
695 static void set_to_array(
const std::set<T> &
set,
Array<T> &array)
699 for (std::set<int>::iterator it =
set.begin(); it !=
set.end(); ++it)
716 set_to_array(ranks, neighbors);
728 group_shared.
MakeI(ngroups-1);
732 for (
int i = 0; i < conf_group.
Size(); i++)
736 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
743 shared_local.
SetSize(num_shared);
744 group_shared.
MakeJ();
747 for (
int i = 0, j = 0; i < conf_group.
Size(); i++)
751 if (entity_geom && (*entity_geom)[i] != geom) {
continue; }
761 for (
int i = 0; i < group_shared.
Size(); i++)
763 int size = group_shared.
RowSize(i);
764 int *row = group_shared.
GetRow(i);
767 ref_row.
Sort([&](
const int a,
const int b)
775 if (lsi_a != lsi_b) {
return lsi_a < lsi_b; }
777 return (el_loc_a & 0xf) < (el_loc_b & 0xf);
787 for (
int ent = 0; ent <
Dim; ent++)
801 for (
unsigned i = 0; i <
groups.size(); i++)
803 if (
groups[i].size() > 1 || !i)
806 group_map[i] = int_groups.
Insert(iset);
813 for (
int ent = 0; ent < 3; ent++)
818 ecg = group_map[ecg];
852 for (
int i = 0; i < slt.
Size(); i++)
857 int v[4], e[4], eo[4];
864 for (
int i = 0; i < slq.
Size(); i++)
874 for (
int ent = 0; ent <
Dim; ent++)
893 auto count_slaves = [&](
int i,
const Master& x)
895 return i + (x.slaves_end - x.slaves_begin);
898 const int bound = shared.
conforming.Size() + std::accumulate(
905 for (
int i = 0; i < shared.
conforming.Size(); i++)
909 MFEM_ASSERT(face != NULL,
"");
911 MFEM_ASSERT(face->
elem[0] >= 0 && face->
elem[1] >= 0,
"");
914 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
915 MFEM_ASSERT(e[0]->rank !=
MyRank && e[1]->rank ==
MyRank,
"");
921 for (
int i = 0; i < shared.
masters.Size(); i++)
927 if (sf.
element < 0) {
continue; }
929 MFEM_ASSERT(mf.
element >= 0,
"");
939 if (loc0) { std::swap(e[0], e[1]); }
946 MFEM_ASSERT(fnbr.
Size() <= bound,
947 "oops, bad upper bound. fnbr.Size(): " << fnbr.
Size() <<
", bound: " << bound);
956 return (
a->rank !=
b->rank) ?
a->rank <
b->rank
957 :
a->index <
b->index;
961 for (
int i = 0; i < fnbr.
Size(); i++)
980 std::map<int, int> vert_map;
981 for (
int i = 0; i < fnbr.
Size(); i++)
989 for (
int k = 0; k < gi.
nv; k++)
991 int &v = vert_map[elem->
node[k]];
992 if (!v) { v = vert_map.size(); }
996 if (!i || elem->
rank != fnbr[i-1]->rank)
1012 for (
const auto &v : vert_map)
1025 for (
int i = 0, last_rank = -1; i < send_elems.
Size(); i++)
1028 if (c.
from != last_rank)
1036 c.
from = send_elems[i-1].from;
1046 if (e[0]->rank ==
MyRank) { std::swap(e[0], e[1]); }
1064 if (shared.
slaves.Size())
1070 MFEM_ASSERT(pmesh.
faces_info.Size() == nfaces,
"");
1073 for (
int i = nfaces; i < pmesh.
faces_info.Size(); i++)
1084 for (
int i = 0; i < shared.
masters.Size(); i++)
1090 if (sf.
element < 0) {
continue; }
1092 MFEM_ASSERT(mf.
element >= 0,
"");
1133 if (!sloc &&
Dim == 3)
1137 if (sf.
geom == Geometry::Type::SQUARE)
1139 std::swap((*pm2)(0, 1), (*pm2)(0, 3));
1140 std::swap((*pm2)(1, 1), (*pm2)(1, 3));
1142 else if (sf.
geom == Geometry::Type::TRIANGLE)
1144 std::swap((*pm2)(0, 0), (*pm2)(0, 1));
1145 std::swap((*pm2)(1, 0), (*pm2)(1, 1));
1162 else if (!sloc &&
Dim == 2)
1171 MFEM_ASSERT(fi.
NCFace < 0,
"fi.NCFace = " << fi.
NCFace);
1200 bool removeAll =
true;
1203 for (
int i = 0; i < 8; i++)
1206 if (el.
child[i] >= 0)
1209 if (!
remove[i]) { removeAll =
false; }
1214 if (removeAll) {
return true; }
1217 for (
int i = 0; i < 8; i++)
1237 MFEM_WARNING(
"Can't prune 3D aniso meshes yet.");
1273 for (
int i = 0; i < refinements.
Size(); i++)
1277 "anisotropic parallel refinement not supported yet in 3D.");
1279 MFEM_VERIFY(
Iso ||
Dim < 3,
1280 "parallel refinement of 3D aniso meshes not supported yet.");
1287 for (
int i = 0; i < neighbors.
Size(); i++)
1289 send_ref[neighbors[i]].SetNCMesh(
this);
1297 for (
int i = 0; i < refinements.
Size(); i++)
1303 for (
int j = 0; j < ranks.
Size(); j++)
1305 send_ref[ranks[j]].AddRefinement(elem, ref.
ref_type);
1313 for (
int i = 0; i < refinements.
Size(); i++)
1320 for (
int j = 0; j < neighbors.
Size(); j++)
1330 for (
int i = 0; i < msg.
Size(); i++)
1345 MFEM_VERIFY(max_nc_level >= 1,
"'max_nc_level' must be 1 or greater.");
1352 long long size = refinements.
Size(), glob_size;
1353 MPI_Allreduce(&size, &glob_size, 1, MPI_LONG_LONG, MPI_SUM,
MyComm);
1355 if (!glob_size) {
break; }
1370 for (
int i = 0; i < derefs.
Size(); i++)
1372 int row = derefs[i];
1374 "invalid derefinement number.");
1379 int coarse_rank = INT_MAX;
1380 for (
int j = 0; j < size; j++)
1383 coarse_rank = std::min(coarse_rank, fine_rank);
1385 for (
int j = 0; j < size; j++)
1387 new_ranks[fine[j]] = coarse_rank;
1394 MFEM_VERIFY(
Dim < 3 ||
Iso,
1395 "derefinement of 3D anisotropic meshes not implemented yet.");
1419 for (
int i = 0; i < derefs.
Size(); i++)
1421 int row = derefs[i];
1423 "invalid derefinement number.");
1428 int coarse_rank = INT_MAX;
1429 for (
int j = 0; j < size; j++)
1432 coarse_rank = std::min(coarse_rank, fine_rank);
1434 for (
int j = 0; j < size; j++)
1436 new_ranks[fine[j]] = coarse_rank;
1440 int target_elements = 0;
1441 for (
int i = 0; i < new_ranks.Size(); i++)
1443 if (new_ranks[i] ==
MyRank) { target_elements++; }
1457 for (
int i = 0; i < neighbors.
Size(); i++)
1459 send_deref[neighbors[i]].SetNCMesh(
this);
1466 for (
int i = 0; i < derefs.
Size(); i++)
1469 int parent =
elements[old_elements[fine[0]]].parent;
1473 for (
int j = 0; j < ranks.
Size(); j++)
1475 send_deref[ranks[j]].AddDerefinement(parent, new_ranks[fine[0]]);
1485 for (
int i = 0; i < old_elements.
Size(); i++)
1487 elements[old_elements[i]].index = i;
1492 old_elements.
Copy(coarse);
1493 for (
int i = 0; i < derefs.
Size(); i++)
1496 int parent =
elements[old_elements[fine[0]]].parent;
1505 for (
int j = 0; j < neighbors.
Size(); j++)
1515 for (
int i = 0; i < msg.
Size(); i++)
1533 for (
int i = 0; i < coarse.
Size(); i++)
1549 for (
int i = 0; i < coarse.
Size(); i++)
1563 template<
typename Type>
1565 const Table &deref_table)
1578 for (
int i = 0; i < deref_table.
Size(); i++)
1580 const int* fine = deref_table.
GetRow(i);
1581 int size = deref_table.
RowSize(i);
1582 MFEM_ASSERT(size <= 8,
"");
1584 int ranks[8], min_rank = INT_MAX, max_rank = INT_MIN;
1585 for (
int j = 0; j < size; j++)
1588 min_rank = std::min(min_rank, ranks[j]);
1589 max_rank = std::max(max_rank, ranks[j]);
1593 if (min_rank != max_rank)
1596 for (
int j = 0; j < size; j++)
1603 for (
int j = 0; j < size; j++)
1605 Type *data = &elem_data[fine[j]];
1607 int rnk = ranks[j], len = 1;
1613 for (
int k = 0; k < neigh.
Size(); k++)
1615 MPI_Request* req =
new MPI_Request;
1616 MPI_Isend(data, len, datatype, neigh[k], 292,
MyComm, req);
1622 MPI_Request* req =
new MPI_Request;
1623 MPI_Irecv(data, len, datatype, rnk, 292,
MyComm, req);
1630 for (
int i = 0; i < requests.
Size(); i++)
1632 MPI_Wait(requests[i], MPI_STATUS_IGNORE);
1639 ParNCMesh::SynchronizeDerefinementData<int>(
Array<int> &,
const Table &);
1651 for (
int i = 0; i < deref_table.
Size(); i++)
1653 const int *fine = deref_table.
GetRow(i),
1654 size = deref_table.
RowSize(i);
1659 for (
int j = 0; j < size; j++)
1667 for (
int k = 0; k <
Dim; k++)
1670 splits[k] >= max_nc_level)
1672 leaf_ok[fine[j]] = 0;
break;
1684 for (
int i = 0; i < deref_table.
Size(); i++)
1686 const int* fine = deref_table.
GetRow(i),
1687 size = deref_table.
RowSize(i);
1689 for (
int j = 0; j < size; j++)
1691 if (!leaf_ok[fine[j]])
1693 level_ok[i] = 0;
break;
1710 if (!custom_partition)
1716 long local_elems =
NElements, total_elems = 0;
1717 MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM,
MyComm);
1719 long first_elem_global = 0;
1720 MPI_Scan(&local_elems, &first_elem_global, 1, MPI_LONG, MPI_SUM,
MyComm);
1721 first_elem_global -= local_elems;
1727 new_ranks[i] =
Partition(first_elem_global + (j++), total_elems);
1740 "Size of the partition array must match the number " 1741 "of local mesh elements (ParMesh::GetNE()).");
1744 custom_partition->
Copy(new_ranks);
1753 for (
int i = 0; i < old_elements.
Size(); i++)
1766 bool sfc = (target_elements >= 0);
1783 int begin = 0, end = 0;
1803 for (
int i = 0; i < rank_neighbors.
Size(); i++)
1805 int elem = rank_neighbors[i];
1813 recv_ghost_ranks[rank].SetNCMesh(
this);
1822 NeighborElementRankMessage::Map::iterator it;
1823 for (it = recv_ghost_ranks.begin(); it != recv_ghost_ranks.end(); ++it)
1826 for (
int i = 0; i < msg.
Size(); i++)
1830 new_ranks[ghost_index] = msg.
values[i];
1834 recv_ghost_ranks.clear();
1845 int received_elements = 0;
1851 received_elements++;
1853 el.
rank = new_ranks[i];
1856 int nsent = 0, nrecv = 0;
1863 owned_elements.
Sort([&](
const int a,
const int b)
1872 int begin = 0, end = 0;
1876 int rank =
elements[owned_elements[begin]].rank;
1877 while (end < owned_elements.
Size() &&
1878 elements[owned_elements[end]].rank == rank) { end++; }
1883 rank_elems.
MakeRef(&owned_elements[begin], end - begin);
1894 for (
int i = 0; i < batch.
Size(); i++)
1896 int elem = batch[i];
1942 while (received_elements < target_elements)
1951 for (
int i = 0; i < msg.
Size(); i++)
1953 int elem_rank = msg.
values[i];
1956 if (elem_rank ==
MyRank) { received_elements++; }
1978 MPI_Request barrier = MPI_REQUEST_NULL;
1990 for (
int i = 0; i < msg.
Size(); i++)
2002 if (barrier != MPI_REQUEST_NULL)
2004 MPI_Test(&barrier, &done, MPI_STATUS_IGNORE);
2010 int mpi_err = MPI_Ibarrier(
MyComm, &barrier);
2012 MFEM_VERIFY(mpi_err == MPI_SUCCESS,
"");
2013 MFEM_VERIFY(barrier != MPI_REQUEST_NULL,
"");
2024 int glob_sent, glob_recv;
2025 MPI_Reduce(&nsent, &glob_sent, 1, MPI_INT, MPI_SUM, 0,
MyComm);
2026 MPI_Reduce(&nrecv, &glob_recv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
2030 MFEM_ASSERT(glob_sent == glob_recv,
2031 "(glob_sent, glob_recv) = (" 2032 << glob_sent <<
", " << glob_recv <<
")");
2035 MFEM_CONTRACT_VAR(nsent);
2036 MFEM_CONTRACT_VAR(nrecv);
2042 const Table &old_element_dofs,
2043 long old_global_offset,
2047 int vdim =
space->GetVDim();
2050 RebalanceDofMessage::Map::iterator it;
2060 for (
int i = 0; i < ne; i++)
2063 space->DofsToVDofs(dofs, old_ndofs);
2081 RebalanceDofMessage::Map::iterator it;
2086 nd += msg.
dofs.size();
2097 for (
unsigned i = 0; i < msg.
elem_ids.size(); i++)
2101 for (
unsigned i = 0; i < msg.
dofs.size(); i++)
2114 : ncmesh(other.ncmesh), include_ref_types(other.include_ref_types)
2122 data.Append(value & 0xff);
2123 data.Append((value >> 8) & 0xff);
2124 data.Append((value >> 16) & 0xff);
2125 data.Append((value >> 24) & 0xff);
2131 return (
int) data[pos] +
2132 ((int) data[pos+1] << 8) +
2133 ((int) data[pos+2] << 16) +
2134 ((int) data[pos+3] << 24);
2139 for (
int i = 0; i <
elements.Size(); i++)
2144 Element &el = ncmesh->elements[elem];
2145 if (el.
flag == flag) {
break; }
2154 Element &el = ncmesh->elements[elem];
2164 for (
int i = 0; i < 8; i++)
2166 if (el.
child[i] >= 0 && ncmesh->elements[el.
child[i]].flag)
2174 if (include_ref_types)
2179 for (
int i = 0; i < 8; i++)
2181 if (mask & (1 << i))
2183 EncodeTree(el.
child[i]);
2196 for (
int i = 0; i < ncmesh->root_state.Size(); i++)
2198 if (ncmesh->elements[i].flag)
2212 std::ostringstream oss;
2213 for (
int i = 0; i < ref_path.Size(); i++)
2215 oss <<
" elem " << ref_path[i] <<
" (";
2216 const Element &el = ncmesh->elements[ref_path[i]];
2217 for (
int j = 0; j <
GI[el.
Geom()].
nv; j++)
2219 if (j) { oss <<
", "; }
2220 oss << ncmesh->RetrieveNode(el, j);
2232 ref_path.Append(elem);
2234 int mask = data[pos++];
2241 Element &el = ncmesh->elements[elem];
2242 if (include_ref_types)
2244 int ref_type = data[pos++];
2247 ncmesh->RefineElement(elem, ref_type);
2249 else { MFEM_ASSERT(ref_type == el.
ref_type,
"") }
2253 MFEM_ASSERT(el.
ref_type != 0,
"Path not found:\n" 2254 << RefPath() <<
" mask = " << mask);
2257 for (
int i = 0; i < 8; i++)
2259 if (mask & (1 << i))
2266 ref_path.DeleteLast();
2273 while ((root = GetInt(pos)) >= 0)
2282 write<int>(os, data.Size());
2283 os.write((
const char*) data.GetData(), data.Size());
2288 data.SetSize(read<int>(is));
2289 is.read((
char*) data.GetData(), data.Size());
2305 for (
unsigned i = 0; i <
groups.size(); i++)
2311 for (
int i = 0; i < ids[0].
Size(); i++)
2313 find_v[i].one = ids[0][i].index;
2327 for (
int j = 0; j < 2; j++)
2332 k = find_v[pos].two;
2343 for (
int i = 0; i < ids[1].
Size(); i++)
2345 find_e[i].one = ids[1][i].index;
2357 int v[4], e[4], eo[4], pos, k;
2359 for (
int j = 0; j < nfv; j++)
2363 k = find_v[pos].two;
2369 k = find_e[pos].two;
2384 for (
int i = 0; i < gi.
nv; i++)
2386 if (
nodes[el.
node[i]].vert_index ==
id.index)
2393 MFEM_ABORT(
"Vertex not found.");
2399 const int *old_ev =
GI[old.
Geom()].
edges[(int)
id.local];
2401 MFEM_ASSERT(node != NULL,
"Edge not found.");
2407 for (
int i = 0; i < gi.
ne; i++)
2409 const int* ev = gi.
edges[i];
2410 if ((el.
node[ev[0]] == node->
p1 && el.
node[ev[1]] == node->
p2) ||
2411 (el.
node[ev[1]] == node->
p1 && el.
node[ev[0]] == node->
p2))
2419 MFEM_ABORT(
"Edge not found.");
2425 const MeshId &first = ids[find[pos].two];
2426 while (++pos < find.Size() && ids[find[pos].two].index == first.
index)
2428 MeshId &other = ids[find[pos].two];
2436 std::map<int, int> stream_id;
2442 for (
int type = 0; type < 3; type++)
2444 for (
int i = 0; i < ids[type].
Size(); i++)
2446 elements.Append(ids[type][i].element);
2458 for (
int i = 0; i < decoded.
Size(); i++)
2460 stream_id[decoded[i]] = i;
2465 for (
int type = 0; type < 3; type++)
2467 write<int>(os, ids[type].
Size());
2468 for (
int i = 0; i < ids[type].
Size(); i++)
2470 const MeshId&
id = ids[type][i];
2471 write<int>(os, stream_id[
id.element]);
2472 write<char>(os,
id.local);
2487 for (
int type = 0; type < 3; type++)
2489 int ne = read<int>(is);
2492 for (
int i = 0; i < ne; i++)
2494 int el_num = read<int>(is);
2495 int elem = elems[el_num];
2498 MFEM_VERIFY(!el.
ref_type,
"not a leaf element: " << el_num);
2500 MeshId &
id = ids[type][i];
2502 id.local = read<char>(is);
2510 id.index =
nodes[el.
node[(int)
id.local]].vert_index;
2515 const int* ev = gi.edges[(int)
id.local];
2517 MFEM_ASSERT(node && node->
HasEdge(),
"edge not found.");
2523 const int* fv = gi.faces[(int)
id.local];
2526 MFEM_ASSERT(face,
"face not found.");
2527 id.index = face->
index;
2537 std::map<GroupId, GroupId> stream_id;
2538 for (
int i = 0; i < ids.
Size(); i++)
2540 if (i && ids[i] == ids[i-1]) {
continue; }
2541 unsigned size = stream_id.size();
2542 GroupId &sid = stream_id[ids[i]];
2543 if (size != stream_id.size()) { sid = size; }
2547 write<short>(os, stream_id.size());
2548 for (std::map<GroupId, GroupId>::iterator
2549 it = stream_id.begin(); it != stream_id.end(); ++it)
2551 write<GroupId>(os, it->second);
2555 write<short>(os, group.size());
2556 for (
unsigned i = 0; i < group.size(); i++)
2558 write<int>(os, group[i]);
2564 write<short>(os, -1);
2569 write<int>(os, ids.
Size());
2570 for (
int i = 0; i < ids.
Size(); i++)
2572 write<GroupId>(os, stream_id[ids[i]]);
2578 int ngroups = read<short>(is);
2584 for (
int i = 0; i < ngroups; i++)
2586 int id = read<GroupId>(is);
2587 int size = read<short>(is);
2591 for (
int ii = 0; ii < size; ii++)
2593 ranks[ii] = read<int>(is);
2605 for (
int i = 0; i < ids.
Size(); i++)
2607 ids[i] = sgroups[read<GroupId>(is)];
2614 template<
class ValueType,
bool RefTypes,
int Tag>
2617 std::ostringstream ostream;
2623 eset.
Encode(tmp_elements);
2631 std::map<int, int> element_index;
2632 for (
int i = 0; i < decoded.
Size(); i++)
2634 element_index[decoded[i]] = i;
2637 write<int>(ostream, values.size());
2638 MFEM_ASSERT(
elements.size() == values.size(),
"");
2640 for (
unsigned i = 0; i < values.size(); i++)
2642 write<int>(ostream, element_index[
elements[i]]);
2643 write<ValueType>(ostream, values[i]);
2646 ostream.str().swap(data);
2649 template<
class ValueType,
bool RefTypes,
int Tag>
2652 std::istringstream istream(data);
2658 eset.
Decode(tmp_elements);
2660 int* el = tmp_elements.
GetData();
2664 int count = read<int>(istream);
2665 for (
int i = 0; i < count; i++)
2667 int index = read<int>(istream);
2668 MFEM_ASSERT(
index >= 0 && (
size_t)
index < values.size(),
"");
2669 values[
index] = read<ValueType>(istream);
2679 eset.SetNCMesh(ncmesh);
2684 eset.Decode(decoded);
2686 elem_ids.resize(decoded.
Size());
2687 for (
int i = 0; i < decoded.
Size(); i++)
2689 elem_ids[i] = eset.GetNCMesh()->elements[decoded[i]].index;
2693 static void write_dofs(std::ostream &os,
const std::vector<int> &dofs)
2695 write<int>(os, dofs.size());
2697 os.write((
const char*) dofs.data(), dofs.size() *
sizeof(int));
2700 static void read_dofs(std::istream &is, std::vector<int> &dofs)
2702 dofs.resize(read<int>(is));
2703 is.read((
char*) dofs.data(), dofs.size() *
sizeof(int));
2708 std::ostringstream stream;
2711 write<long>(stream, dof_offset);
2712 write_dofs(stream, dofs);
2714 stream.str().swap(data);
2719 std::istringstream stream(data);
2722 dof_offset = read<long>(stream);
2723 read_dofs(stream, dofs);
2730 elem_ids.resize(elems.
Size());
2731 for (
int i = 0; i < elems.
Size(); i++)
2733 elem_ids[i] = eset.GetNCMesh()->elements[elems[i]].index;
2746 for (
int i = 0; i < cle.
Size(); i++)
2754 debug_mesh.
ncmesh = copy;
2765 for (
int i = 0; i < 3; i++)
2782 return (elem_ids.capacity() + dofs.capacity()) *
sizeof(
int);
2785 template<
typename K,
typename V>
2786 static std::size_t map_memory_usage(
const std::map<K, V> &map)
2788 std::size_t result = 0;
2789 for (
typename std::map<K, V>::const_iterator
2790 it = map.begin(); it != map.end(); ++it)
2792 result += it->second.MemoryUsage();
2793 result +=
sizeof(std::pair<K, V>) + 3*
sizeof(
void*) +
sizeof(bool);
2801 for (
unsigned i = 0; i <
groups.size(); i++)
2803 groups_size +=
groups[i].capacity() *
sizeof(int);
2805 const int approx_node_size =
2806 sizeof(std::pair<CommGroup, GroupId>) + 3*
sizeof(
void*) +
sizeof(bool);
2807 return groups_size +
group_id.size() * approx_node_size;
2810 template<
typename Type,
int Size>
2811 static std::size_t arrays_memory_usage(
const Array<Type> (&arrays)[Size])
2813 std::size_t total = 0;
2814 for (
int i = 0; i < Size; i++)
2816 total += arrays[i].MemoryUsage();
2852 << arrays_memory_usage(
entity_owner) <<
" entity_owner\n" 2878 #endif // MFEM_USE_MPI NCList face_list
lazy-initialized list of faces, see GetFaceList
NCList edge_list
lazy-initialized list of edges, see GetEdgeList
ElementSet(NCMesh *ncmesh=NULL, bool include_ref_types=false)
void GetFineToCoarsePartitioning(const Array< int > &derefs, Array< int > &new_ranks) const
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 DecodeMeshIds(std::istream &is, Array< MeshId > ids[])
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
std::string RefPath() const
Array< char > element_type
int faces[MaxElemFaces][4]
std::vector< ValueType > values
void GetConformingSharedStructures(class ParMesh &pmesh)
CoarseFineTransformations transforms
storage for data returned by Get[De]RefinementTransforms()
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 elem[2]
up to 2 elements sharing the face
void BuildVertexList() override
void Encode(int) override
char ref_type
refinement XYZ bit mask (7 = full isotropic)
std::vector< int > CommGroup
void CalcFaceOrientations()
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.
void SetDerefMatrixCodes(int parent, Array< int > &fine_coarse)
Helper struct to convert a C++ type to an MPI type.
int child[MaxElemChildren]
2-10 children (if ref_type != 0)
void MakeSharedList(const NCList &list, NCList &shared)
char flag
generic flag/marker, can be used by algorithms
int GetInt(int pos) const
Array< char > face_orient
int GetNGhostElements() const override
This holds in one place the constants about the geometries we support.
void BuildEdgeList() override
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
virtual void GetVertices(Array< int > &v) const =0
Returns element's vertices.
std::vector< int > elem_ids
void ChangeRemainingMeshIds(Array< MeshId > &ids, int pos, const Array< Pair< int, int > > &find)
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
virtual void Trim()
Save memory by releasing all non-essential and cached data.
int index
element number in the Mesh, -1 if refined
void Encode(int) override
Array< Element * > face_nbr_elements
const NCList & GetSharedVertices()
GroupId GetSingletonGroup(int rank)
void GetFaceNeighbors(class ParMesh &pmesh)
Lists all edges/faces in the nonconforming mesh.
std::map< int, NeighborElementRankMessage > Map
long MemoryUsage() const
Return total number of bytes allocated.
unsigned matrix
index into NCList::point_matrices[geom]
std::vector< int > elements
T * GetData()
Returns the data.
void Load(std::istream &is)
void SetNCMesh(ParNCMesh *pncmesh_)
Set pointer to ParNCMesh (needed to encode the message).
Table derefinements
possible derefinements, see GetDerefinementTable
Data type dense matrix using column-major storage.
NCList vertex_list
lazy-initialized list of vertices, see GetVertexList
void InitDerefTransforms()
char geom
Geometry::Type of the element (char for storage only)
int NGroups() const
Return the number of groups.
void SynchronizeDerefinementData(Array< Type > &elem_data, const Table &deref_table)
std::size_t MemoryUsage() const
void SetElements(const Array< int > &elems, NCMesh *ncmesh)
bool operator<(const Pair< A, B > &p, const Pair< A, B > &q)
Comparison operator for class Pair, based on the first element only.
Array< Vert3 > shared_trias
void ChangeEdgeMeshIdElement(NCMesh::MeshId &id, int elem)
Array< int > face_nbr_group
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
void GetLimitRefinements(Array< Refinement > &refinements, int max_level)
int Partition(long index, long total_elements) const
Return the processor number for a global element number.
std::size_t GroupsMemoryUsage() const
void EncodeTree(int elem)
int spaceDim
dimensions of the elements and the vertex coordinates
const NCList & GetSharedEdges()
void DeleteAll()
Delete the whole array.
static int find_element_edge(const Element &el, int vn0, int vn1, bool abort=true)
int index
Mesh element number.
int master
master number (in Mesh numbering)
void Recv(int rank, int size, MPI_Comm comm)
Post-probe receive from processor 'rank' of message size 'size'.
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces ('entity' == 0/1/2 resp.).
Array< NCFaceInfo > nc_faces_info
void Decode(int) override
A parallel extension of the NCMesh class.
void Derefine(const Array< int > &derefs) override
void ElementSharesFace(int elem, int local, int face) override
static int find_local_face(int geom, int a, int b, int c)
RebalanceDofMessage::Map send_rebalance_dofs
void FlagElements(const Array< int > &elements, char flag)
Face * GetFace(Element &elem, int face_no)
void AddElementRank(int elem, int rank)
Array< int > face_nbr_elements_offset
Geometry::Type Geom() const
int index
face number in the Mesh
void MakeFromList(int nrows, const Array< Connection > &list)
Array< Element * > shared_edges
Array< DenseMatrix * > aux_pm_store
Stores modified point matrices created by GetFaceNeighbors.
void Dump(std::ostream &os) const
virtual void SetAttributes()
Determine the sets of unique attribute values in domain and boundary elements.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
void BuildFaceList() override
void RedistributeElements(Array< int > &new_ranks, int target_elements, bool record_comm)
const double * CalcVertexPos(int node) const
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'.
void FindNeighbors(int elem, Array< int > &neighbors, const Array< int > *search_set=NULL)
int Find(const T &el) const
Return the first index where 'el' is found; return -1 if not found.
void ElementNeighborProcessors(int elem, Array< int > &ranks)
void AddConnection(int r, int c)
Array< int > old_index_or_rank
void CreateGroups(int nentities, Array< Connection > &index_rank, Array< GroupId > &entity_group)
RebalanceDofMessage::Map recv_rebalance_dofs
void DecodeTree(int elem, int &pos, Array< int > &elements) const
This structure stores the low level information necessary to interpret the configuration of elements ...
void Refine(const Array< Refinement > &refinements) override
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
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...
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
virtual void BuildEdgeList()
bool GroupContains(GroupId id, int rank) const
Return true if group 'id' contains the given rank.
Identifies a vertex/edge/face in both Mesh and NCMesh.
T * begin()
STL-like begin. Returns pointer to the first element of the array.
int parent
parent element, -1 if this is a root element, -2 if free'd
std::map< int, NeighborRefinementMessage > Map
void GetDebugMesh(Mesh &debug_mesh) const
static void IsendAll(MapT &rank_msg, MPI_Comm comm)
Helper to send all messages in a rank-to-message map container.
signed char local
local number within 'element'
void Trim() override
Save memory by releasing all non-essential and cached data.
bool HaveTets() const
Return true if the mesh contains tetrahedral elements.
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
int MyRank
used in parallel, or when loading a parallel file in serial
void ElementSharesEdge(int elem, int local, int enode) override
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
void GetSubArray(int offset, int sa_size, Array< T > &sa) const
Copy sub array starting from offset out to the provided sa.
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges)
int FindSorted(const T &el) const
Do bisection search for 'el' in a sorted array; return -1 if not found.
int element
NCMesh::Element containing this vertex/edge/face.
Array< Vert4 > shared_quads
void Rebalance(const Array< int > *custom_partition=NULL)
static GeomInfo GI[Geometry::NumGeom]
static bool TestAllSent(MapT &rank_msg)
Return true if all messages in the map container were sent, otherwise return false, without waiting.
int slaves_end
slave faces
void DecodeGroups(std::istream &is, Array< GroupId > &ids)
void AdjustMeshIds(Array< MeshId > ids[], int rank)
int PrintMemoryDetail() const
bool Iso
true if the mesh only contains isotropic refinements
Array< int > tmp_neighbors
std::map< int, NeighborDerefinementMessage > Map
int GetFaceVerticesEdges(const MeshId &face_id, int vert_index[4], int edge_index[4], int edge_orientation[4]) const
Array< Connection > entity_index_rank[3]
Array< GroupId > entity_owner[3]
void Encode(const Array< int > &elements)
Array< char > tmp_shared_flag
Array< Vertex > face_nbr_vertices
virtual void BuildFaceList()
Nonconforming edge/face within a bigger edge/face.
void DerefineElement(int elem)
Derefine the element elem, does nothing on leaf elements.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
void Decode(int) override
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
bool PruneTree(int elem)
Internal. Recursive part of Prune().
void AddAColumnInRow(int r)
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Array< int > leaf_sfc_index
natural tree ordering of leaf elements
static void RecvAll(MapT &rank_msg, MPI_Comm comm)
Helper to receive all messages in a rank-to-message map container.
Helper struct for defining a connectivity table, see Table::MakeFromList.
void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges) override
void Issend(int rank, MPI_Comm comm)
Non-blocking synchronous send to processor 'rank'. Returns immediately. Completion (MPI_Wait/Test) me...
void Decode(Array< int > &elements) const
void RefineElement(int elem, char ref_type)
long PartitionFirstIndex(int rank, long total_elements) const
Return the global index of the first element owned by processor 'rank'.
Array< int > boundary_faces
subset of all faces, set by BuildFaceList
Array< double > coordinates
void RecvRebalanceDofs(Array< int > &elements, Array< long > &dofs)
Receive element DOFs sent by SendRebalanceDofs().
int Size() const
Returns the number of TYPE I elements.
int edges[MaxElemEdges][2]
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
int node[MaxElemNodes]
element corners (if ref_type == 0)
Table group_svert
Shared objects in each group.
Array< int > boundary_layer
list of type 3 elements
Array< MeshId > conforming
signed char geom
Geometry::Type (faces only) (char to save RAM)
void Isend(int rank, MPI_Comm comm)
Non-blocking send to processor 'rank'. Returns immediately. Completion (as tested by MPI_Wait/Test) d...
int index(int i, int j, int nx, int ny)
void AddElementRank(int elem, int rank)
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
void InitOwners(int num, Array< GroupId > &entity_owner)
void ChangeVertexMeshIdElement(NCMesh::MeshId &id, int elem)
Array< FaceInfo > faces_info
void SetAttribute(const int attr)
Set element's attribute.
void EncodeGroups(std::ostream &os, const Array< GroupId > &ids)
void CalculatePMatrixGroups()
NCMesh * ncmesh
Optional nonconforming mesh extension.
Array< int > entity_elem_local[3]
int Size() const
Return the logical size of the array.
T & Last()
Return the last element in the array.
void NeighborExpand(const Array< int > &elems, Array< int > &expanded, const Array< int > *search_set=NULL)
BlockArray< Element > elements
std::size_t MemoryUsage() const
Returns the number of bytes allocated for the array including any reserve.
void FindSetNeighbors(const Array< char > &elem_set, Array< int > *neighbors, Array< char > *neighbor_set=NULL)
Array< int > ghost_layer
list of elements whose 'element_type' == 2.
void MakeRef(T *, int)
Make this Array a reference to a pointer.
int InitialPartition(int index) const
Helper to get the partitioning when the serial mesh gets split initially.
static void WaitAllSent(MapT &rank_msg)
Helper to wait for all messages in a map container to be sent.
void EncodeMeshIds(std::ostream &os, Array< MeshId > ids[])
mfem::Element * NewMeshElement(int geom) const
void AddConnections(int entity, int index, const Array< int > &ranks)
void ElementSharesVertex(int elem, int local, int vnode) override
void MakeSharedTable(int ngroups, int ent, Array< int > &shared_local, Table &group_shared, Array< char > *entity_geom=NULL, char geom=0)
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Array< int > svert_lvert
Shared to local index mapping.
const NCList & GetSharedFaces()
std::map< int, RebalanceMessage > Map
static int get_face_orientation(Face &face, Element &e1, Element &e2, int local[2]=NULL)
virtual void BuildVertexList()
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Array< GroupId > entity_pmat_group[3]
void NeighborProcessors(Array< int > &neighbors)
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...
Table send_face_nbr_elements
char ref_type
bit mask of X,Y,Z refinements (bits 0,1,2 respectively)
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
static int find_node(const Element &el, int node)
bool CheckElementType(int elem, int type)
Class for parallel meshes.
Abstract data type element.
void LimitNCLevel(int max_nc_level) override
Parallel version of NCMesh::LimitNCLevel.
void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level) override
GroupId GetGroupId(const CommGroup &group)
Data type line segment element.
void CountSplits(int elem, int splits[3]) const
int rank
processor number (ParNCMesh), -1 if undefined/unknown
Array< unsigned char > data
encoded refinement (sub-)trees
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...
virtual void Refine(const Array< Refinement > &refinements)
ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part=NULL)
Construct by partitioning a serial NCMesh.
Array< GroupId > entity_conf_group[3]
Array< char > face_geom
face geometry by face index, set by OnMeshUpdated