12 #include "../config/config.hpp"
17 #include "../fem/fem.hpp"
18 #include "../general/sets.hpp"
19 #include "../general/sort_pairs.hpp"
20 #include "../general/text.hpp"
21 #include "../general/globals.hpp"
31 ParMesh::ParMesh(
const ParMesh &pmesh,
bool copy_nodes)
33 group_svert(pmesh.group_svert),
34 group_sedge(pmesh.group_sedge),
35 group_stria(pmesh.group_stria),
36 group_squad(pmesh.group_squad),
38 glob_offset_sequence(-1),
80 if (pmesh.
Nodes && copy_nodes)
108 : glob_elem_offset(-1)
109 , glob_offset_sequence(-1)
112 int *partitioning = NULL;
123 partitioning = partitioning_;
128 partitioning =
new int[mesh.
GetNE()];
129 for (
int i = 0; i < mesh.
GetNE(); i++)
159 partitioning = partitioning_;
173 Table *edge_element = NULL;
176 activeBdrElem, edge_element);
214 int nsedges =
FindSharedEdges(mesh, partitioning, edge_element, groups);
221 int ngroups = groups.
Size()-1, nstris, nsquads;
228 face_group, vert_global_local);
247 "invalid NURBS mesh");
267 Nodes->MakeOwner(nfec);
273 int element_counter = 0;
274 for (
int i = 0; i < mesh.
GetNE(); i++)
276 if (partitioning[i] ==
MyRank)
279 mesh.
GetNodes()->FESpace()->GetElementVDofs(i, gvdofs);
280 mesh.
GetNodes()->GetSubVector(gvdofs, lnodes);
291 if (partitioning != partitioning_)
293 delete [] partitioning;
301 const int* partitioning,
305 vert_global_local = -1;
307 int vert_counter = 0;
308 for (
int i = 0; i < mesh.
GetNE(); i++)
310 if (partitioning[i] ==
MyRank)
314 for (
int j = 0; j < vert.
Size(); j++)
316 if (vert_global_local[vert[j]] < 0)
318 vert_global_local[vert[j]] = vert_counter++;
326 for (
int i = 0; i < vert_global_local.
Size(); i++)
328 if (vert_global_local[i] >= 0)
330 vert_global_local[i] = vert_counter++;
336 for (
int i = 0; i < vert_global_local.
Size(); i++)
338 if (vert_global_local[i] >= 0)
352 for (
int i = 0; i < mesh.
GetNE(); i++)
354 if (partitioning[i] ==
MyRank) { nelems++; }
362 int element_counter = 0;
363 for (
int i = 0; i < mesh.
GetNE(); i++)
365 if (partitioning[i] ==
MyRank)
368 int *v =
elements[element_counter]->GetVertices();
369 int nv =
elements[element_counter]->GetNVertices();
370 for (
int j = 0; j < nv; j++)
372 v[j] = vert_global_local[v[j]];
378 return element_counter;
384 Table*& edge_element)
391 activeBdrElem =
false;
396 for (
int i = 0; i < mesh.
GetNBE(); i++)
398 int face, o, el1, el2;
401 if (partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2] ==
MyRank)
406 activeBdrElem[i] =
true;
411 int bdrelem_counter = 0;
413 for (
int i = 0; i < mesh.
GetNBE(); i++)
415 int face, o, el1, el2;
418 if (partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2] ==
MyRank)
421 int *v =
boundary[bdrelem_counter]->GetVertices();
422 int nv =
boundary[bdrelem_counter]->GetNVertices();
423 for (
int j = 0; j < nv; j++)
425 v[j] = vert_global_local[v[j]];
433 edge_element =
new Table;
436 for (
int i = 0; i < mesh.
GetNBE(); i++)
439 int el1 = edge_element->
GetRow(edge)[0];
440 if (partitioning[el1] ==
MyRank)
445 activeBdrElem[i] =
true;
450 int bdrelem_counter = 0;
452 for (
int i = 0; i < mesh.
GetNBE(); i++)
455 int el1 = edge_element->
GetRow(edge)[0];
456 if (partitioning[el1] ==
MyRank)
459 int *v =
boundary[bdrelem_counter]->GetVertices();
460 int nv =
boundary[bdrelem_counter]->GetNVertices();
461 for (
int j = 0; j < nv; j++)
463 v[j] = vert_global_local[v[j]];
471 for (
int i = 0; i < mesh.
GetNBE(); i++)
473 int vert = mesh.
boundary[i]->GetVertices()[0];
476 if (partitioning[el1] ==
MyRank)
482 int bdrelem_counter = 0;
484 for (
int i = 0; i < mesh.
GetNBE(); i++)
486 int vert = mesh.
boundary[i]->GetVertices()[0];
489 if (partitioning[el1] ==
MyRank)
492 int *v =
boundary[bdrelem_counter]->GetVertices();
493 v[0] = vert_global_local[v[0]];
510 for (
int i = 0; i < face_group.
Size(); i++)
517 el[0] = partitioning[el[0]];
518 el[1] = partitioning[el[1]];
523 face_group[i] = groups.
Insert(group) - 1;
530 Table*& edge_element,
536 int sedge_counter = 0;
539 edge_element =
new Table;
550 for (
int i = 0; i < edge_element->
Size(); i++)
552 int me = 0, others = 0;
553 for (
int j = edge_element->
GetI()[i]; j < edge_element->
GetI()[i+1]; j++)
555 int k = edge_element->
GetJ()[j];
556 int rank = partitioning[k];
557 edge_element->
GetJ()[j] = rank;
576 edge_element->
GetRow(i)[0] = -1;
580 return sedge_counter;
589 int svert_counter = 0;
590 for (
int i = 0; i < vert_element->
Size(); i++)
592 int me = 0, others = 0;
593 for (
int j = vert_element->
GetI()[i]; j < vert_element->
GetI()[i+1]; j++)
595 vert_element->
GetJ()[j] = partitioning[vert_element->
GetJ()[j]];
610 vert_element->
GetI()[i] = groups.
Insert(group) - 1;
614 vert_element->
GetI()[i] = -1;
617 return svert_counter;
622 int &nstria,
int &nsquad)
628 for (
int i = 0; i < face_group.
Size(); i++)
630 if (face_group[i] >= 0)
647 for (
int i = 0; i < face_group.
Size(); i++)
649 if (face_group[i] >= 0)
670 for (
int i = 0; i < edge_element.
Size(); i++)
672 if (edge_element.
GetRow(i)[0] >= 0)
680 int sedge_counter = 0;
681 for (
int i = 0; i < edge_element.
Size(); i++)
683 if (edge_element.
GetRow(i)[0] >= 0)
696 for (
int i = 0; i < vert_element.
Size(); i++)
698 if (vert_element.
GetI()[i] >= 0)
706 int svert_counter = 0;
707 for (
int i = 0; i < vert_element.
Size(); i++)
709 if (vert_element.
GetI()[i] >= 0)
719 const Mesh& mesh,
int *partitioning,
728 if (
Dim < 3) {
return; }
730 int stria_counter = 0;
731 int squad_counter = 0;
732 for (
int i = 0; i < face_group.
Size(); i++)
734 if (face_group[i] < 0) {
continue; }
744 for (
int j = 0; j < 3; j++)
746 v[j] = vert_global_local[v[j]];
748 const int lface = (*faces_tbl)(v[0], v[1], v[2]);
764 if (
MyRank == partitioning[gl_el2])
766 std::swap(v[0], v[1]);
778 for (
int j = 0; j < 4; j++)
780 v[j] = vert_global_local[v[j]];
783 (*faces_tbl)(v[0], v[1], v[2], v[3]);
789 MFEM_ABORT(
"unknown face type: " << face->
GetType());
797 const Table* edge_element)
809 int sedge_counter = 0;
810 for (
int i = 0; i < edge_element->
Size(); i++)
812 if (edge_element->
GetRow(i)[0] >= 0)
818 new Segment(vert_global_local[vert[0]],
819 vert_global_local[vert[1]], 1);
821 sedge_ledge[sedge_counter] = v_to_v(vert_global_local[vert[0]],
822 vert_global_local[vert[1]]);
824 MFEM_VERIFY(
sedge_ledge[sedge_counter] >= 0,
"Error in v_to_v.");
839 int svert_counter = 0;
840 for (
int i = 0; i < vert_element->
Size(); i++)
842 if (vert_element->
GetI()[i] >= 0)
844 svert_lvert[svert_counter++] = vert_global_local[i];
852 : MyComm(pncmesh.MyComm)
853 , NRanks(pncmesh.NRanks)
854 , MyRank(pncmesh.MyRank)
855 , glob_elem_offset(-1)
856 , glob_offset_sequence(-1)
880 MPI_Allreduce(&loc_meshgen, &
meshgen, 1, MPI_INT, MPI_BOR,
MyComm);
894 const int l_edge = v_to_v(v[0], v[1]);
895 MFEM_ASSERT(l_edge >= 0,
"invalid shared edge");
906 for (
int st = 0; st < nst; st++)
921 : glob_elem_offset(-1)
922 , glob_offset_sequence(-1)
932 const int gen_edges = 1;
934 Load(input, gen_edges, refine,
true);
938 bool fix_orientation)
945 Loader(input, generate_edges,
"mfem_serial_mesh_end");
957 MFEM_ASSERT(
pncmesh,
"internal error");
980 MFEM_VERIFY(ident ==
"communication_groups",
981 "input stream is not a parallel MFEM mesh");
989 input >> ident >> num_sverts;
990 MFEM_VERIFY(ident ==
"total_shared_vertices",
"invalid mesh file");
999 input >> ident >> num_sedges;
1000 MFEM_VERIFY(ident ==
"total_shared_edges",
"invalid mesh file");
1014 input >> ident >> num_sface;
1015 MFEM_VERIFY(ident ==
"total_shared_faces",
"invalid mesh file");
1028 int svert_counter = 0, sedge_counter = 0;
1035 input >> ident >> g;
1038 mfem::err <<
"ParMesh::ParMesh : expecting group " << gr
1039 <<
", read group " << g << endl;
1045 input >> ident >> nv;
1046 MFEM_VERIFY(ident ==
"shared_vertices",
"invalid mesh file");
1047 nv += svert_counter;
1049 "incorrect number of total_shared_vertices");
1051 for ( ; svert_counter < nv; svert_counter++)
1060 input >> ident >> ne;
1061 MFEM_VERIFY(ident ==
"shared_edges",
"invalid mesh file");
1062 ne += sedge_counter;
1064 "incorrect number of total_shared_edges");
1066 for ( ; sedge_counter < ne; sedge_counter++)
1069 input >> v[0] >> v[1];
1076 input >> ident >> nf;
1077 for (
int i = 0; i < nf; i++)
1086 for (
int i = 0; i < 3; i++) { input >> v[i]; }
1091 for (
int i = 0; i < 4; i++) { input >> v[i]; }
1094 MFEM_ABORT(
"invalid shared face geometry: " << geom);
1105 "incorrect number of total_shared_faces");
1139 ref_factors = ref_factor;
1218 for (
int j = 0; j < orig_n_verts; j++)
1225 const int orig_n_edges = orig_mesh.
GroupNEdges(gr);
1226 if (orig_n_edges > 0)
1231 const int *c2h_map = rfec.
GetDofMap(geom, ref_factor);
1233 for (
int e = 0; e < orig_n_edges; e++)
1238 for (
int j = 2; j < rdofs.
Size(); j++)
1246 for (
int k = 0; k < nvert; k++)
1249 v[k] = rdofs[c2h_map[cid]];
1265 const int *c2h_map = rfec.
GetDofMap(geom, ref_factor);
1267 for (
int f = 0;
f < orig_nt;
f++)
1272 for (
int j = rdofs.
Size()-num_int_verts; j < rdofs.
Size(); j++)
1281 for (
int k = 0; k < 2; k++)
1283 v[k] = rdofs[c2h_map[RG.
RefEdges[j+k]]];
1292 for (
int k = 0; k < nvert; k++)
1295 v[k] = rdofs[c2h_map[cid]];
1309 const int *c2h_map = rfec.
GetDofMap(geom, ref_factor);
1311 for (
int f = 0;
f < orig_nq;
f++)
1316 for (
int j = rdofs.
Size()-num_int_verts; j < rdofs.
Size(); j++)
1325 for (
int k = 0; k < 2; k++)
1327 v[k] = rdofs[c2h_map[RG.
RefEdges[j+k]]];
1336 for (
int k = 0; k < nvert; k++)
1339 v[k] = rdofs[c2h_map[cid]];
1386 for (
int iv=0; iv<orig_mesh.
GetNV(); ++iv)
1388 vglobal[iv] = fes.GetGlobalTDofNumber(iv);
1397 for (
int gr = 1; gr < mesh.
GetNGroups(); gr++)
1423 constexpr
int ntris = 2, nv_tri = 3, nv_quad = 4;
1426 for (
int gr = 1; gr < mesh.
GetNGroups(); gr++)
1430 for (
int j = 0; j < orig_n_verts; j++)
1432 fes.GetVertexDofs(orig_mesh.
GroupVertex(gr, j), dofs);
1437 const int orig_n_edges = orig_mesh.
GroupNEdges(gr);
1438 for (
int e = 0; e < orig_n_edges; e++)
1450 for (
int e = 0; e < orig_nt; e++)
1457 for (
int iv=0; iv<nv_tri; ++iv) { v2[iv] = v[iv]; }
1464 static const int trimap[12] =
1470 static const int diagmap[4] = { 0, 2, 1, 3 };
1471 for (
int f = 0;
f < orig_nq; ++
f)
1478 for (
int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
1479 int iv_min = std::min_element(vg, vg+nv_quad) - vg;
1480 int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
1484 v_diag[0] = v[diagmap[0 + isplit*2]];
1485 v_diag[1] = v[diagmap[1 + isplit*2]];
1488 for (
int itri=0; itri<ntris; ++itri)
1492 for (
int iv=0; iv<nv_tri; ++iv)
1494 v2[iv] = v[trimap[itri + isplit*2 + iv*ntris*2]];
1512 const int meshgen_save =
meshgen;
1541 int max_attr = attr.
Size() ? attr.
Max() : 1 ;
1542 int glb_max_attr = -1;
1543 MPI_Allreduce(&max_attr, &glb_max_attr, 1, MPI_INT, MPI_MAX,
MyComm);
1547 bool *attr_marker =
new bool[glb_max_attr];
1548 bool *glb_attr_marker =
new bool[glb_max_attr];
1549 for (
int i = 0; i < glb_max_attr; i++)
1551 attr_marker[i] =
false;
1553 for (
int i = 0; i < attr.
Size(); i++)
1555 attr_marker[attr[i] - 1] =
true;
1557 MPI_Allreduce(attr_marker, glb_attr_marker, glb_max_attr,
1558 MPI_C_BOOL, MPI_LOR,
MyComm);
1559 delete [] attr_marker;
1564 for (
int i = 0; i < glb_max_attr; i++)
1566 if (glb_attr_marker[i])
1571 delete [] glb_attr_marker;
1582 MFEM_WARNING(
"Non-positive boundary element attributes found!");
1588 MFEM_WARNING(
"Non-positive element attributes found!");
1597 o = (v[0] < v[1]) ? (+1) : (-1);
1606 "Expecting a triangular face.");
1617 "Expecting a quadrilateral face.");
1633 gr_sedge.
GetI()[0] = 0;
1652 sedge_ord[k] = order[v_to_v(v[0], v[1])];
1655 sedge_comm.
Bcast<
int>(sedge_ord, 1);
1657 for (
int k = 0, gr = 1; gr <
GetNGroups(); gr++)
1660 if (n == 0) {
continue; }
1661 sedge_ord_map.SetSize(n);
1662 for (
int j = 0; j < n; j++)
1664 sedge_ord_map[j].one = sedge_ord[k+j];
1665 sedge_ord_map[j].two = j;
1667 SortPairs<int, int>(sedge_ord_map, n);
1668 for (
int j = 0; j < n; j++)
1671 const int *v =
shared_edges[sedge_from]->GetVertices();
1672 sedge_ord[k+j] = order[v_to_v(v[0], v[1])];
1674 std::sort(&sedge_ord[k], &sedge_ord[k] + n);
1675 for (
int j = 0; j < n; j++)
1679 order[v_to_v(v[0], v[1])] = sedge_ord[k+j];
1693 ilen_len[j].one = order[j];
1694 ilen_len[j].two =
GetLength(i, it.Column());
1698 SortPairs<int, double>(ilen_len, order.
Size());
1701 for (
int i = 1; i < order.
Size(); i++)
1703 d_max = std::max(d_max, ilen_len[i-1].two-ilen_len[i].two);
1713 MPI_Reduce(&d_max, &glob_d_max, 1, MPI_DOUBLE, MPI_MAX, 0,
MyComm);
1716 mfem::out <<
"glob_d_max = " << glob_d_max << endl;
1728 elements[i]->MarkEdge(v_to_v, order);
1736 boundary[i]->MarkEdge(v_to_v, order);
1755 if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1)
1772 face_stack.
Append(face_t(fv[0], fv[1], fv[2]));
1773 for (
unsigned bit = 0; face_stack.
Size() > 0; bit++)
1775 if (bit == 8*
sizeof(
unsigned))
1781 const face_t &
f = face_stack.
Last();
1782 int mid = v_to_v.
FindId(f.one, f.two);
1792 face_stack.
Append(face_t(f.three, f.one, mid));
1793 face_t &r = face_stack[face_stack.
Size()-2];
1794 r = face_t(r.two, r.three, mid);
1806 bool need_refinement = 0;
1807 face_stack.
Append(face_t(v[0], v[1], v[2]));
1808 for (
unsigned bit = 0, code = codes[pos++]; face_stack.
Size() > 0; bit++)
1810 if (bit == 8*
sizeof(
unsigned))
1812 code = codes[pos++];
1816 if ((code & (1 << bit)) == 0) { face_stack.
DeleteLast();
continue; }
1818 const face_t &
f = face_stack.
Last();
1819 int mid = v_to_v.
FindId(f.one, f.two);
1822 mid = v_to_v.
GetId(f.one, f.two);
1823 int ind[2] = { f.one, f.two };
1826 need_refinement = 1;
1829 face_stack.
Append(face_t(f.three, f.one, mid));
1830 face_t &r = face_stack[face_stack.
Size()-2];
1831 r = face_t(r.two, r.three, mid);
1833 return need_refinement;
1839 if (HYPRE_AssumedPartitionCheck())
1842 MPI_Scan(loc_sizes, temp.
GetData(), N, HYPRE_MPI_BIG_INT, MPI_SUM,
MyComm);
1843 for (
int i = 0; i < N; i++)
1846 (*offsets[i])[0] = temp[i] - loc_sizes[i];
1847 (*offsets[i])[1] = temp[i];
1850 for (
int i = 0; i < N; i++)
1852 (*offsets[i])[2] = temp[i];
1854 MFEM_VERIFY((*offsets[i])[0] >= 0 && (*offsets[i])[1] >= 0,
1855 "overflow in offsets");
1861 MPI_Allgather(loc_sizes, N, HYPRE_MPI_BIG_INT, temp.
GetData(), N,
1862 HYPRE_MPI_BIG_INT,
MyComm);
1863 for (
int i = 0; i < N; i++)
1868 for (
int j = 0; j <
NRanks; j++)
1870 offs[j+1] = offs[j] + temp[i+N*j];
1874 "overflow in offsets");
1898 for (
int j = 0; j < nv; j++)
1917 for (
int j = 0; j < n; j++)
1919 pointmat(k,j) = (pNodes->
FaceNbrData())(vdofs[n*k+j]);
1927 MFEM_ABORT(
"Nodes are not ParGridFunction!");
1960 space_dim = (space_dim == -1) ?
spaceDim : space_dim;
1986 *new_nodes = *
Nodes;
2019 bool del_tables =
false;
2046 gr_sface =
new Table;
2076 if (del_tables) {
delete gr_sface; }
2087 int num_face_nbrs = 0;
2090 if (gr_sface->
RowSize(g-1) > 0)
2098 if (num_face_nbrs == 0)
2108 for (
int g = 1, counter = 0; g <
GetNGroups(); g++)
2110 if (gr_sface->
RowSize(g-1) > 0)
2115 int lproc = (nbs[0]) ? nbs[0] : nbs[1];
2117 rank_group[counter].two = g;
2122 SortPairs<int, int>(rank_group, rank_group.
Size());
2124 for (
int fn = 0; fn < num_face_nbrs; fn++)
2130 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
2131 MPI_Request *send_requests = requests;
2132 MPI_Request *recv_requests = requests + num_face_nbrs;
2133 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
2135 int *nbr_data =
new int[6*num_face_nbrs];
2136 int *nbr_send_data = nbr_data;
2137 int *nbr_recv_data = nbr_data + 3*num_face_nbrs;
2144 Table send_face_nbr_elemdata, send_face_nbr_facedata;
2148 send_face_nbr_elemdata.
MakeI(num_face_nbrs);
2149 send_face_nbr_facedata.
MakeI(num_face_nbrs);
2150 for (
int fn = 0; fn < num_face_nbrs; fn++)
2153 int num_sfaces = gr_sface->
RowSize(nbr_group-1);
2154 int *sface = gr_sface->
GetRow(nbr_group-1);
2155 for (
int i = 0; i < num_sfaces; i++)
2157 int lface = s2l_face[sface[i]];
2159 if (el_marker[el] != fn)
2164 const int nv =
elements[el]->GetNVertices();
2165 const int *v =
elements[el]->GetVertices();
2166 for (
int j = 0; j < nv; j++)
2167 if (vertex_marker[v[j]] != fn)
2169 vertex_marker[v[j]] = fn;
2180 nbr_send_data[3*fn+2] = send_face_nbr_elemdata.
GetI()[fn];
2185 MPI_Isend(&nbr_send_data[3*fn], 3, MPI_INT, nbr_rank, tag,
MyComm,
2186 &send_requests[fn]);
2187 MPI_Irecv(&nbr_recv_data[3*fn], 3, MPI_INT, nbr_rank, tag,
MyComm,
2188 &recv_requests[fn]);
2192 send_face_nbr_elemdata.
MakeJ();
2193 send_face_nbr_facedata.
MakeJ();
2197 for (
int fn = 0; fn < num_face_nbrs; fn++)
2200 int num_sfaces = gr_sface->
RowSize(nbr_group-1);
2201 int *sface = gr_sface->
GetRow(nbr_group-1);
2202 for (
int i = 0; i < num_sfaces; i++)
2204 const int sf = sface[i];
2205 int lface = s2l_face[sf];
2207 if (el_marker[el] != fn)
2212 const int nv =
elements[el]->GetNVertices();
2213 const int *v =
elements[el]->GetVertices();
2214 for (
int j = 0; j < nv; j++)
2215 if (vertex_marker[v[j]] != fn)
2217 vertex_marker[v[j]] = fn;
2232 const int *lf_v =
faces[lface]->GetVertices();
2252 for (
int fn = 0; fn < num_face_nbrs; fn++)
2258 int *elemdata = send_face_nbr_elemdata.
GetRow(fn);
2259 int num_sfaces = send_face_nbr_facedata.
RowSize(fn)/2;
2260 int *facedata = send_face_nbr_facedata.
GetRow(fn);
2262 for (
int i = 0; i < num_verts; i++)
2264 vertex_marker[verts[i]] = i;
2267 for (
int el = 0; el < num_elems; el++)
2269 const int nv =
elements[elems[el]]->GetNVertices();
2271 for (
int j = 0; j < nv; j++)
2273 elemdata[j] = vertex_marker[elemdata[j]];
2277 el_marker[elems[el]] = el;
2280 for (
int i = 0; i < num_sfaces; i++)
2282 facedata[2*i] = el_marker[facedata[2*i]];
2286 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
2289 Table recv_face_nbr_elemdata;
2294 recv_face_nbr_elemdata.
MakeI(num_face_nbrs);
2297 for (
int fn = 0; fn < num_face_nbrs; fn++)
2305 recv_face_nbr_elemdata.
MakeJ();
2307 MPI_Waitall(num_face_nbrs, send_requests, statuses);
2310 for (
int fn = 0; fn < num_face_nbrs; fn++)
2315 MPI_Isend(send_face_nbr_elemdata.
GetRow(fn),
2316 send_face_nbr_elemdata.
RowSize(fn),
2317 MPI_INT, nbr_rank, tag,
MyComm, &send_requests[fn]);
2319 MPI_Irecv(recv_face_nbr_elemdata.
GetRow(fn),
2320 recv_face_nbr_elemdata.
RowSize(fn),
2321 MPI_INT, nbr_rank, tag,
MyComm, &recv_requests[fn]);
2329 MPI_Waitany(num_face_nbrs, recv_requests, &fn, statuses);
2331 if (fn == MPI_UNDEFINED)
2339 int *recv_elemdata = recv_face_nbr_elemdata.
GetRow(fn);
2341 for (
int i = 0; i < num_elems; i++)
2347 for (
int j = 0; j < nv; j++)
2349 recv_elemdata[j] += vert_off;
2352 recv_elemdata += nv;
2357 MPI_Waitall(num_face_nbrs, send_requests, statuses);
2360 recv_face_nbr_facedata.
SetSize(
2362 for (
int fn = 0; fn < num_face_nbrs; fn++)
2367 MPI_Isend(send_face_nbr_facedata.
GetRow(fn),
2368 send_face_nbr_facedata.
RowSize(fn),
2369 MPI_INT, nbr_rank, tag,
MyComm, &send_requests[fn]);
2372 MPI_Irecv(&recv_face_nbr_facedata[send_face_nbr_facedata.
GetI()[fn]],
2373 send_face_nbr_facedata.
RowSize(fn),
2374 MPI_INT, nbr_rank, tag,
MyComm, &recv_requests[fn]);
2381 MPI_Waitany(num_face_nbrs, recv_requests, &fn, statuses);
2383 if (fn == MPI_UNDEFINED)
2390 int num_sfaces = gr_sface->
RowSize(nbr_group-1);
2391 int *sface = gr_sface->
GetRow(nbr_group-1);
2393 &recv_face_nbr_facedata[send_face_nbr_facedata.
GetI()[fn]];
2395 for (
int i = 0; i < num_sfaces; i++)
2397 const int sf = sface[i];
2398 int lface = s2l_face[sf];
2400 face_info.
Elem2No = -1 - (facedata[2*i] + elem_off);
2401 int info = facedata[2*i+1];
2409 int nbr_ori = info%64, nbr_v[4];
2410 const int *lf_v =
faces[lface]->GetVertices();
2417 for (
int j = 0; j < 3; j++)
2419 nbr_v[perm[j]] = sf_v[j];
2429 for (
int j = 0; j < 4; j++)
2431 nbr_v[perm[j]] = sf_v[j];
2437 info = 64*(info/64) + nbr_ori;
2443 MPI_Waitall(num_face_nbrs, send_requests, statuses);
2460 else if (
Nodes == NULL)
2470 if (!num_face_nbrs) {
return; }
2472 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
2473 MPI_Request *send_requests = requests;
2474 MPI_Request *recv_requests = requests + num_face_nbrs;
2475 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
2479 for (
int i = 0; i < send_vertices.Size(); i++)
2485 for (
int fn = 0; fn < num_face_nbrs; fn++)
2492 MPI_DOUBLE, nbr_rank, tag,
MyComm, &send_requests[fn]);
2497 MPI_DOUBLE, nbr_rank, tag, MyComm, &recv_requests[fn]);
2500 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
2501 MPI_Waitall(num_face_nbrs, send_requests, statuses);
2509 MFEM_VERIFY(pNodes != NULL,
"Nodes are not ParGridFunction!");
2520 int nbr_lproc = (nbs[0]) ? nbs[0] : nbs[1];
2562 for (
int i = 0; i < s2l_face->
Size(); i++)
2577 for (
int i = 0; i < s2l_face->
Size(); i++)
2579 int lface = (*s2l_face)[i];
2580 int nbr_elem_idx = -1 -
faces_info[lface].Elem2No;
2605 MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
2606 "Mesh requires nodal Finite Element.");
2608 #if 0 // TODO: handle the case of non-interpolatory Nodes
2617 FETr->
SetFE(face_el);
2639 int local_face = is_ghost ? nc_info->
MasterFace : FaceNo;
2653 Elem2NbrNo = -1 - face_info.
Elem2No;
2697 if (is_ghost || fill2)
2720 mfem::out <<
"\nInternal error: face id = " << FaceNo
2721 <<
", dist = " << dist <<
", rank = " <<
MyRank <<
'\n';
2723 MFEM_ABORT(
"internal error");
2744 MFEM_ASSERT(
Dim > 1,
"");
2763 MFEM_ASSERT(
Dim > 1,
"");
2766 return sface < csize
2768 : shared.
slaves[sface - csize].index;
2775 void Rotate3Indirect(
int &
a,
int &
b,
int &c,
2778 if (order[a] < order[b])
2780 if (order[a] > order[c])
2787 if (order[b] < order[c])
2808 Table *old_elem_vert = NULL;
2822 gr_svert.
GetI()[0] = 0;
2847 svert_comm.
Bcast(svert_master_index);
2861 for (
int i = 0; i <
vertices.Size(); i++)
2863 int s = lvert_svert[i];
2866 glob_vert_order[i] =
2867 (std::int64_t(svert_master_rank[s]) << 32) + svert_master_index[s];
2871 glob_vert_order[i] = (std::int64_t(
MyRank) << 32) + i;
2883 int *v =
elements[i]->GetVertices();
2885 Rotate3Indirect(v[0], v[1], v[2], glob_vert_order);
2887 if (glob_vert_order[v[0]] < glob_vert_order[v[3]])
2889 Rotate3Indirect(v[1], v[2], v[3], glob_vert_order);
2903 int *v =
boundary[i]->GetVertices();
2905 Rotate3Indirect(v[0], v[1], v[2], glob_vert_order);
2909 const bool check_consistency =
true;
2910 if (check_consistency)
2919 gr_stria.
GetI()[0] = 0;
2931 for (
int i = 0; i < stria_flag.Size(); i++)
2934 if (glob_vert_order[v[0]] < glob_vert_order[v[1]])
2936 stria_flag[i] = (glob_vert_order[v[0]] < glob_vert_order[v[2]]) ? 0 : 2;
2940 stria_flag[i] = (glob_vert_order[v[1]] < glob_vert_order[v[2]]) ? 1 : 2;
2945 stria_comm.
Bcast(stria_master_flag);
2946 for (
int i = 0; i < stria_flag.Size(); i++)
2949 MFEM_VERIFY(stria_flag[i] == stria_master_flag[i],
2950 "inconsistent vertex ordering found, shared triangle "
2952 << v[0] <<
", " << v[1] <<
", " << v[2] <<
"), "
2953 <<
"local flag: " << stria_flag[i]
2954 <<
", master flag: " << stria_master_flag[i]);
2963 Rotate3Indirect(v[0], v[1], v[2], glob_vert_order);
2979 delete old_elem_vert;
2992 MFEM_ABORT(
"Local and nonconforming refinements cannot be mixed.");
3001 int uniform_refinement = 0;
3005 uniform_refinement = 1;
3016 for (
int i = 0; i < marked_el.
Size(); i++)
3022 for (
int i = 0; i < marked_el.
Size(); i++)
3031 for (
int i = 0; i < marked_el.
Size(); i++)
3048 int need_refinement;
3049 int max_faces_in_group = 0;
3055 face_splittings[i].
Reserve(faces_in_group);
3056 if (faces_in_group > max_faces_in_group)
3058 max_faces_in_group = faces_in_group;
3064 MPI_Request *requests =
new MPI_Request[
GetNGroups()-1];
3067 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3068 int ref_loops_all = 0, ref_loops_par = 0;
3072 need_refinement = 0;
3075 if (
elements[i]->NeedRefinement(v_to_v))
3077 need_refinement = 1;
3081 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3085 if (uniform_refinement)
3092 if (need_refinement == 0)
3094 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3098 const int tag = 293;
3107 if (faces_in_group == 0) {
continue; }
3109 face_splittings[i].
SetSize(0);
3110 for (
int j = 0; j < faces_in_group; j++)
3113 face_splittings[i]);
3117 MPI_Isend(face_splittings[i], face_splittings[i].Size(),
3118 MPI_UNSIGNED, neighbor, tag,
MyComm,
3119 &requests[req_count++]);
3127 if (faces_in_group == 0) {
continue; }
3131 MPI_Probe(neighbor, tag,
MyComm, &status);
3133 MPI_Get_count(&status, MPI_UNSIGNED, &count);
3135 MPI_Recv(iBuf, count, MPI_UNSIGNED, neighbor, tag,
MyComm,
3138 for (
int j = 0, pos = 0; j < faces_in_group; j++)
3145 int nr = need_refinement;
3146 MPI_Allreduce(&nr, &need_refinement, 1, MPI_INT, MPI_LOR,
MyComm);
3148 MPI_Waitall(req_count, requests, MPI_STATUSES_IGNORE);
3151 while (need_refinement == 1);
3153 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3155 int i = ref_loops_all;
3156 MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0,
MyComm);
3159 mfem::out <<
"\n\nParMesh::LocalRefinement : max. ref_loops_all = "
3160 << ref_loops_all <<
", ref_loops_par = " << ref_loops_par
3168 delete [] face_splittings;
3173 need_refinement = 0;
3176 if (
boundary[i]->NeedRefinement(v_to_v))
3178 need_refinement = 1;
3183 while (need_refinement == 1);
3188 " (NumOfBdrElements != boundary.Size())");
3215 int uniform_refinement = 0;
3219 uniform_refinement = 1;
3228 int *edge1 =
new int[nedges];
3229 int *edge2 =
new int[nedges];
3230 int *middle =
new int[nedges];
3232 for (
int i = 0; i < nedges; i++)
3234 edge1[i] = edge2[i] = middle[i] = -1;
3239 int *v =
elements[i]->GetVertices();
3240 for (
int j = 0; j < 3; j++)
3242 int ind = v_to_v(v[j], v[(j+1)%3]);
3243 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
3248 for (
int i = 0; i < marked_el.
Size(); i++)
3254 int need_refinement;
3255 int edges_in_group, max_edges_in_group = 0;
3257 int **edge_splittings =
new int*[
GetNGroups()-1];
3261 edge_splittings[i] =
new int[edges_in_group];
3262 if (edges_in_group > max_edges_in_group)
3264 max_edges_in_group = edges_in_group;
3267 int neighbor, *iBuf =
new int[max_edges_in_group];
3271 MPI_Request request;
3276 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3277 int ref_loops_all = 0, ref_loops_par = 0;
3281 need_refinement = 0;
3282 for (
int i = 0; i < nedges; i++)
3284 if (middle[i] != -1 && edge1[i] != -1)
3286 need_refinement = 1;
3290 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3294 if (uniform_refinement)
3301 if (need_refinement == 0)
3303 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3312 edges_in_group = group_edges.
Size();
3314 if (edges_in_group != 0)
3316 for (
int j = 0; j < edges_in_group; j++)
3318 edge_splittings[i][j] =
3331 MPI_Isend(edge_splittings[i], edges_in_group, MPI_INT,
3332 neighbor, 0,
MyComm, &request);
3340 edges_in_group = group_edges.
Size();
3341 if (edges_in_group != 0)
3352 MPI_Recv(iBuf, edges_in_group, MPI_INT, neighbor,
3353 MPI_ANY_TAG,
MyComm, &status);
3355 for (
int j = 0; j < edges_in_group; j++)
3357 if (iBuf[j] == 1 && edge_splittings[i][j] == 0)
3360 int ii = v_to_v(v[0], v[1]);
3361 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3362 if (middle[ii] != -1)
3364 mfem_error(
"ParMesh::LocalRefinement (triangles) : "
3368 need_refinement = 1;
3370 for (
int c = 0; c < 2; c++)
3380 int nr = need_refinement;
3381 MPI_Allreduce(&nr, &need_refinement, 1, MPI_INT, MPI_LOR,
MyComm);
3384 while (need_refinement == 1);
3386 #ifdef MFEM_DEBUG_PARMESH_LOCALREF
3388 int i = ref_loops_all;
3389 MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0,
MyComm);
3392 mfem::out <<
"\n\nParMesh::LocalRefinement : max. ref_loops_all = "
3393 << ref_loops_all <<
", ref_loops_par = " << ref_loops_par
3401 delete [] edge_splittings[i];
3403 delete [] edge_splittings;
3408 int v1[2], v2[2], bisect, temp;
3410 for (
int i = 0; i < temp; i++)
3412 int *v =
boundary[i]->GetVertices();
3413 bisect = v_to_v(v[0], v[1]);
3414 if (middle[bisect] != -1)
3419 v1[0] = v[0]; v1[1] = middle[bisect];
3420 v2[0] = middle[bisect]; v2[1] = v[1];
3427 mfem_error(
"Only bisection of segment is implemented for bdr"
3460 for (
int j = 0; j < marked_el.
Size(); j++)
3462 int i = marked_el[j];
3465 int new_v = cnv + j, new_e = cne + j;
3474 static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
3476 UseExternalData(seg_children, 1, 2, 3);
3497 MFEM_ABORT(
"NURBS meshes are not supported. Please project the "
3498 "NURBS to Nodes first with SetCurvature().");
3503 MFEM_ABORT(
"Can't convert conforming ParMesh to nonconforming ParMesh "
3504 "(you need to initialize the ParMesh from a nonconforming "
3545 double threshold,
int nc_limit,
int op)
3547 MFEM_VERIFY(
pncmesh,
"Only supported for non-conforming meshes.");
3548 MFEM_VERIFY(!
NURBSext,
"Derefinement of NURBS meshes is not supported. "
3549 "Project the NURBS to Nodes first.");
3562 for (
int i = 0; i < dt.
Size(); i++)
3564 if (nc_limit > 0 && !level_ok[i]) {
continue; }
3569 if (error < threshold) { derefs.
Append(i); }
3573 if (!glob_size) {
return false; }
3616 MFEM_ABORT(
"Load balancing is currently not supported for conforming"
3623 MFEM_VERIFY(dynamic_cast<ParFiniteElementSpace*>(
Nodes->
FESpace())
3624 != NULL,
"internal error");
3654 MFEM_ASSERT(
Dim == 2 &&
meshgen == 1,
"internal error");
3664 int *I_group_svert, *J_group_svert;
3665 int *I_group_sedge, *J_group_sedge;
3670 I_group_svert[0] = I_group_svert[1] = 0;
3671 I_group_sedge[0] = I_group_sedge[1] = 0;
3678 for (
int group = 0; group <
GetNGroups()-1; group++)
3688 const int ind = middle[v_to_v(v[0], v[1])];
3694 const int attr =
shared_edges[group_edges[i]]->GetAttribute();
3701 I_group_svert[group+1] = I_group_svert[group] + group_verts.
Size();
3702 I_group_sedge[group+1] = I_group_sedge[group] + group_edges.
Size();
3705 J = J_group_svert+I_group_svert[group];
3706 for (
int i = 0; i < group_verts.
Size(); i++)
3708 J[i] = group_verts[i];
3710 J = J_group_sedge+I_group_sedge[group];
3711 for (
int i = 0; i < group_edges.
Size(); i++)
3713 J[i] = group_edges[i];
3727 MFEM_ASSERT(
Dim == 3 &&
meshgen == 1,
"internal error");
3729 Array<int> group_verts, group_edges, group_trias;
3748 I_group_svert[0] = 0;
3749 I_group_sedge[0] = 0;
3750 I_group_stria[0] = 0;
3752 for (
int group = 0; group <
GetNGroups()-1; group++)
3763 int ind = v_to_v.
FindId(v[0], v[1]);
3764 if (ind == -1) {
continue; }
3767 const int attr =
shared_edges[group_edges[i]]->GetAttribute();
3777 ind = v_to_v.
FindId(v[0], ind);
3785 ind = v_to_v.
FindId(v[0], v[1]);
3806 while (sedge_stack.
Size() > 0);
3813 int ind = v_to_v.
FindId(v[0], v[1]);
3814 if (ind == -1) {
continue; }
3817 const int edge_attr = 1;
3826 v[1] = v[0]; v[0] = v[2]; v[2] = ind;
3827 ind = v_to_v.
FindId(v[0], v[1]);
3835 ind = v_to_v.
FindId(v[0], v[1]);
3853 v = sface_stack[sface_stack.
Size()-2].v;
3855 v[0] = v[1]; v[1] = v[2]; v[2] = ind;
3858 while (sface_stack.
Size() > 0);
3864 ind = v_to_v.
FindId(v[0], v[1]);
3885 while (sedge_stack.
Size() > 0);
3888 I_group_svert[group+1] = I_group_svert[group] + group_verts.
Size();
3889 I_group_sedge[group+1] = I_group_sedge[group] + group_edges.
Size();
3890 I_group_stria[group+1] = I_group_stria[group] + group_trias.
Size();
3892 J_group_svert.
Append(group_verts);
3893 J_group_sedge.
Append(group_edges);
3894 J_group_stria.
Append(group_trias);
3911 int *I_group_svert, *J_group_svert;
3912 int *I_group_sedge, *J_group_sedge;
3917 I_group_svert[0] = 0;
3918 I_group_sedge[0] = 0;
3925 for (
int group = 0; group <
GetNGroups()-1; group++)
3939 const int attr =
shared_edges[sedges[i]]->GetAttribute();
3945 I_group_svert[group+1] = I_group_svert[group] + sverts.
Size();
3946 I_group_sedge[group+1] = I_group_sedge[group] + sedges.
Size();
3948 sverts.
CopyTo(J_group_svert + I_group_svert[group]);
3949 sedges.
CopyTo(J_group_sedge + I_group_sedge[group]);
3965 Array<int> group_verts, group_edges, group_trias, group_quads;
3967 int *I_group_svert, *J_group_svert;
3968 int *I_group_sedge, *J_group_sedge;
3969 int *I_group_stria, *J_group_stria;
3970 int *I_group_squad, *J_group_squad;
3977 I_group_svert[0] = 0;
3978 I_group_sedge[0] = 0;
3979 I_group_stria[0] = 0;
3980 I_group_squad[0] = 0;
3992 const int oface = old_nv + old_nedges;
3994 for (
int group = 0; group <
GetNGroups()-1; group++)
4006 const int ind = old_nv + old_v_to_v(v[0], v[1]);
4010 const int attr =
shared_edges[group_edges[i]]->GetAttribute();
4020 const int stria = group_trias[i];
4023 m[0] = old_nv + old_v_to_v(v[0], v[1]);
4024 m[1] = old_nv + old_v_to_v(v[1], v[2]);
4025 m[2] = old_nv + old_v_to_v(v[2], v[0]);
4026 const int edge_attr = 1;
4041 v[1] = m[0]; v[2] = m[2];
4042 group_trias.
Append(nst+0);
4043 group_trias.
Append(nst+1);
4044 group_trias.
Append(nst+2);
4052 const int squad = group_quads[i];
4054 const int olf = old_faces(v[0], v[1], v[2], v[3]);
4056 m[0] = oface + (f2qf ? (*f2qf)[olf] : olf);
4060 m[1] = old_nv + old_v_to_v(v[0], v[1]);
4061 m[2] = old_nv + old_v_to_v(v[1], v[2]);
4062 m[3] = old_nv + old_v_to_v(v[2], v[3]);
4063 m[4] = old_nv + old_v_to_v(v[3], v[0]);
4064 const int edge_attr = 1;
4081 v[1] = m[1]; v[2] = m[0]; v[3] = m[4];
4082 group_quads.
Append(nsq+0);
4083 group_quads.
Append(nsq+1);
4084 group_quads.
Append(nsq+2);
4088 I_group_svert[group+1] = I_group_svert[group] + group_verts.
Size();
4089 I_group_sedge[group+1] = I_group_sedge[group] + group_edges.
Size();
4090 I_group_stria[group+1] = I_group_stria[group] + group_trias.
Size();
4091 I_group_squad[group+1] = I_group_squad[group] + group_quads.
Size();
4093 group_verts.
CopyTo(J_group_svert + I_group_svert[group]);
4094 group_edges.
CopyTo(J_group_sedge + I_group_sedge[group]);
4095 group_trias.
CopyTo(J_group_stria + I_group_stria[group]);
4096 group_quads.
CopyTo(J_group_squad + I_group_squad[group]);
4115 const bool update_nodes =
false;
4145 const bool update_nodes =
false;
4154 f2qf.
Size() ? &f2qf : NULL);
4164 mfem::out <<
"\nParMesh::NURBSUniformRefinement : Not supported yet!\n";
4170 MFEM_ASSERT(
Dim ==
spaceDim,
"2D manifolds not supported");
4176 out <<
"NETGEN_Neutral_Format\n";
4181 for (j = 0; j <
Dim; j++)
4194 out <<
elements[i]->GetAttribute();
4195 for (j = 0; j < nv; j++)
4197 out <<
" " << ind[j]+1;
4209 out <<
boundary[i]->GetAttribute();
4210 for (j = 0; j < nv; j++)
4212 out <<
" " << ind[j]+1;
4223 for (j = 0; j < 3; j++)
4225 out <<
' ' << ind[j]+1;
4239 <<
"0 0 0 1 0 0 0 0 0 0 0\n"
4241 <<
" 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
4242 <<
"0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
4243 <<
"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
4249 <<
" " <<
vertices[i](2) <<
" 0.0\n";
4257 out << i+1 <<
" " <<
elements[i]->GetAttribute();
4258 for (j = 0; j < nv; j++)
4260 out <<
" " << ind[j]+1;
4270 out <<
boundary[i]->GetAttribute();
4271 for (j = 0; j < nv; j++)
4273 out <<
" " << ind[j]+1;
4275 out <<
" 1.0 1.0 1.0 1.0\n";
4286 for (j = 0; j < 4; j++)
4288 out <<
' ' << ind[j]+1;
4290 out <<
" 1.0 1.0 1.0 1.0\n";
4299 out <<
"areamesh2\n\n";
4306 attr =
boundary[i]->GetAttribute();
4309 for (j = 0; j < v.
Size(); j++)
4311 out << v[j] + 1 <<
" ";
4321 for (j = 0; j < v.
Size(); j++)
4323 out << v[j] + 1 <<
" ";
4332 attr =
elements[i]->GetAttribute();
4348 for (j = 0; j < v.
Size(); j++)
4350 out << v[j] + 1 <<
" ";
4359 for (j = 0; j <
Dim; j++)
4384 bool print_shared =
true;
4385 int i, j, shared_bdr_attr;
4402 s2l_face = &nc_shared_faces;
4409 for (
int i = 0; i < sfaces.
conforming.Size(); i++)
4412 if (index < nfaces) { nc_shared_faces.
Append(index); }
4414 for (
int i = 0; i < sfaces.
masters.Size(); i++)
4418 if (index < nfaces) { nc_shared_faces.
Append(index); }
4420 for (
int i = 0; i < sfaces.
slaves.Size(); i++)
4423 if (index < nfaces) { nc_shared_faces.
Append(index); }
4428 out <<
"MFEM mesh v1.0\n";
4432 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
4437 "# TETRAHEDRON = 4\n"
4442 out <<
"\ndimension\n" <<
Dim
4450 if (print_shared &&
Dim > 1)
4452 num_bdr_elems += s2l_face->
Size();
4454 out <<
"\nboundary\n" << num_bdr_elems <<
'\n';
4460 if (print_shared &&
Dim > 1)
4468 shared_bdr_attr =
MyRank + 1;
4470 for (i = 0; i < s2l_face->
Size(); i++)
4473 faces[(*s2l_face)[i]]->SetAttribute(shared_bdr_attr);
4501 ostringstream fname_with_suffix;
4502 fname_with_suffix << fname <<
"." << setfill(
'0') << setw(6) <<
MyRank;
4503 ofstream ofs(fname_with_suffix.str().c_str());
4504 ofs.precision(precision);
4508 #ifdef MFEM_USE_ADIOS2
4521 for (
int i = 0; i < nv; i++)
4529 int i, j, k,
p, nv_ne[2], &nv = nv_ne[0], &ne = nv_ne[1], vc;
4537 out <<
"MFEM mesh v1.0\n";
4541 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
4546 "# TETRAHEDRON = 4\n"
4551 out <<
"\ndimension\n" <<
Dim;
4555 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4558 out <<
"\n\nelements\n" << ne <<
'\n';
4562 out << 1 <<
' ' <<
elements[i]->GetGeometryType();
4566 for (j = 0; j < nv; j++)
4573 for (p = 1; p <
NRanks; p++)
4575 MPI_Recv(nv_ne, 2, MPI_INT, p, 444,
MyComm, &status);
4579 MPI_Recv(&ints[0], ne, MPI_INT, p, 445,
MyComm, &status);
4581 for (i = 0; i < ne; )
4584 out << p+1 <<
' ' << ints[i];
4587 for (j = 0; j < k; j++)
4589 out <<
' ' << vc + ints[i++];
4602 ne += 1 +
elements[i]->GetNVertices();
4605 MPI_Send(nv_ne, 2, MPI_INT, 0, 444,
MyComm);
4613 MFEM_ASSERT(ints.
Size() == ne,
"");
4616 MPI_Send(&ints[0], ne, MPI_INT, 0, 445,
MyComm);
4641 dump_element(
boundary[i], ints); ne++;
4679 MFEM_ABORT(
"invalid dimension: " <<
Dim);
4689 if (index < nfaces) { dump_element(
faces[index], ints); ne++; }
4691 for (i = 0; i < list.
masters.Size(); i++)
4694 if (index < nfaces) { dump_element(
faces[index], ints); ne++; }
4696 for (i = 0; i < list.
slaves.Size(); i++)
4699 if (index < nfaces) { dump_element(
faces[index], ints); ne++; }
4703 MPI_Reduce(&ne, &k, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4706 out <<
"\nboundary\n" << k <<
'\n';
4708 for (p = 0; p <
NRanks; p++)
4712 MPI_Recv(nv_ne, 2, MPI_INT, p, 446,
MyComm, &status);
4724 for (i = 0; i < ne; )
4727 out << p+1 <<
' ' << ints[i];
4730 for (j = 0; j < k; j++)
4732 out <<
' ' << vc + ints[i++];
4743 MPI_Send(nv_ne, 2, MPI_INT, 0, 446,
MyComm);
4754 out <<
"\nvertices\n" << nv <<
'\n';
4770 for (p = 1; p <
NRanks; p++)
4772 MPI_Recv(&nv, 1, MPI_INT, p, 448,
MyComm, &status);
4776 MPI_Recv(&vert[0], nv*spaceDim, MPI_DOUBLE, p, 449,
MyComm, &status);
4778 for (i = 0; i < nv; i++)
4783 out <<
' ' << vert[i*spaceDim+j];
4798 vert[i*spaceDim+j] =
vertices[i](j);
4803 MPI_Send(&vert[0], NumOfVertices*spaceDim, MPI_DOUBLE, 0, 449,
MyComm);
4830 mfem_error(
"ParMesh::PrintAsOne : Nodes have no parallel info!");
4842 ofs.precision(precision);
4849 MFEM_ASSERT(
Dim ==
spaceDim,
"2D Manifolds not supported.");
4852 int i, j, k, nv, ne,
p;
4860 out <<
"NETGEN_Neutral_Format\n";
4863 MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4867 for (j = 0; j <
Dim; j++)
4873 for (p = 1; p <
NRanks; p++)
4875 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
4877 MPI_Recv(&vert[0],
Dim*nv, MPI_DOUBLE, p, 445,
MyComm, &status);
4878 for (i = 0; i < nv; i++)
4880 for (j = 0; j <
Dim; j++)
4882 out <<
" " << vert[Dim*i+j];
4890 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4897 for (j = 0; j < nv; j++)
4899 out <<
" " << ind[j]+1;
4904 for (p = 1; p <
NRanks; p++)
4906 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
4907 MPI_Recv(&ne, 1, MPI_INT, p, 446,
MyComm, &status);
4909 MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447,
MyComm, &status);
4910 for (i = 0; i < ne; i++)
4913 for (j = 0; j < 4; j++)
4915 out <<
" " << k+ints[i*4+j]+1;
4923 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4931 for (j = 0; j < nv; j++)
4933 out <<
" " << ind[j]+1;
4944 for (j = 0; j < 3; j++)
4946 out <<
' ' << ind[j]+1;
4952 for (p = 1; p <
NRanks; p++)
4954 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
4955 MPI_Recv(&ne, 1, MPI_INT, p, 446,
MyComm, &status);
4957 MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447,
MyComm, &status);
4958 for (i = 0; i < ne; i++)
4961 for (j = 0; j < 3; j++)
4963 out <<
' ' << k+ints[i*3+j]+1;
4973 MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4977 for (j = 0; j <
Dim; j++)
4981 MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE,
4985 MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
4986 MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444,
MyComm);
4992 for (j = 0; j < 4; j++)
4997 MPI_Send(&ints[0], 4*NumOfElements, MPI_INT, 0, 447,
MyComm);
5000 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5001 MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444,
MyComm);
5003 MPI_Send(&ne, 1, MPI_INT, 0, 446,
MyComm);
5008 for (j = 0; j < 3; j++)
5013 for ( ; i < ne; i++)
5016 for (j = 0; j < 3; j++)
5021 MPI_Send(&ints[0], 3*ne, MPI_INT, 0, 447,
MyComm);
5027 int i, j, k, nv, ne,
p;
5033 int TG_nv, TG_ne, TG_nbe;
5040 MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5043 <<
"1 " << TG_nv <<
" " << TG_ne <<
" 0 0 0 0 0 0 0\n"
5044 <<
"0 0 0 1 0 0 0 0 0 0 0\n"
5045 <<
"0 0 " << TG_nbe <<
" 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
5046 <<
"0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
5047 <<
"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
5054 <<
" " <<
vertices[i](2) <<
" 0.0\n";
5056 for (p = 1; p <
NRanks; p++)
5058 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
5060 MPI_Recv(&vert[0],
Dim*nv, MPI_DOUBLE, p, 445,
MyComm, &status);
5061 for (i = 0; i < nv; i++)
5063 out << i+1 <<
" 0.0 " << vert[
Dim*i] <<
" " << vert[
Dim*i+1]
5064 <<
" " << vert[
Dim*i+2] <<
" 0.0\n";
5074 out << i+1 <<
" " << 1;
5075 for (j = 0; j < nv; j++)
5077 out <<
" " << ind[j]+1;
5082 for (p = 1; p <
NRanks; p++)
5084 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
5085 MPI_Recv(&ne, 1, MPI_INT, p, 446,
MyComm, &status);
5087 MPI_Recv(&ints[0], 8*ne, MPI_INT, p, 447,
MyComm, &status);
5088 for (i = 0; i < ne; i++)
5090 out << i+1 <<
" " << p+1;
5091 for (j = 0; j < 8; j++)
5093 out <<
" " << k+ints[i*8+j]+1;
5108 for (j = 0; j < nv; j++)
5110 out <<
" " << ind[j]+1;
5112 out <<
" 1.0 1.0 1.0 1.0\n";
5122 for (j = 0; j < 4; j++)
5124 out <<
' ' << ind[j]+1;
5126 out <<
" 1.0 1.0 1.0 1.0\n";
5129 for (p = 1; p <
NRanks; p++)
5131 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
5132 MPI_Recv(&ne, 1, MPI_INT, p, 446,
MyComm, &status);
5134 MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447,
MyComm, &status);
5135 for (i = 0; i < ne; i++)
5138 for (j = 0; j < 4; j++)
5140 out <<
" " << k+ints[i*4+j]+1;
5142 out <<
" 1.0 1.0 1.0 1.0\n";
5152 MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5157 for (j = 0; j <
Dim; j++)
5161 MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE, 0, 445,
MyComm);
5163 MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444,
MyComm);
5169 for (j = 0; j < 8; j++)
5174 MPI_Send(&ints[0], 8*NumOfElements, MPI_INT, 0, 447,
MyComm);
5176 MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444,
MyComm);
5178 MPI_Send(&ne, 1, MPI_INT, 0, 446,
MyComm);
5183 for (j = 0; j < 4; j++)
5188 for ( ; i < ne; i++)
5191 for (j = 0; j < 4; j++)
5196 MPI_Send(&ints[0], 4*ne, MPI_INT, 0, 447,
MyComm);
5202 int i, j, k, attr, nv, ne,
p;
5210 out <<
"areamesh2\n\n";
5214 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5219 attr =
boundary[i]->GetAttribute();
5222 for (j = 0; j < v.
Size(); j++)
5224 out << v[j] + 1 <<
" ";
5234 for (j = 0; j < v.
Size(); j++)
5236 out << v[j] + 1 <<
" ";
5241 for (p = 1; p <
NRanks; p++)
5243 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
5244 MPI_Recv(&ne, 1, MPI_INT, p, 446,
MyComm, &status);
5246 MPI_Recv(&ints[0], 2*ne, MPI_INT, p, 447,
MyComm, &status);
5247 for (i = 0; i < ne; i++)
5250 for (j = 0; j < 2; j++)
5252 out <<
" " << k+ints[i*2+j]+1;
5261 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5267 out << 1 <<
" " << 3 <<
" ";
5268 for (j = 0; j < v.
Size(); j++)
5270 out << v[j] + 1 <<
" ";
5275 for (p = 1; p <
NRanks; p++)
5277 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
5278 MPI_Recv(&ne, 1, MPI_INT, p, 446,
MyComm, &status);
5280 MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447,
MyComm, &status);
5281 for (i = 0; i < ne; i++)
5283 out << p+1 <<
" " << 3;
5284 for (j = 0; j < 3; j++)
5286 out <<
" " << k+ints[i*3+j]+1;
5295 MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5299 for (j = 0; j <
Dim; j++)
5305 for (p = 1; p <
NRanks; p++)
5307 MPI_Recv(&nv, 1, MPI_INT, p, 444,
MyComm, &status);
5309 MPI_Recv(&vert[0],
Dim*nv, MPI_DOUBLE, p, 445,
MyComm, &status);
5310 for (i = 0; i < nv; i++)
5312 for (j = 0; j <
Dim; j++)
5314 out <<
" " << vert[Dim*i+j];
5324 MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5327 MPI_Send(&ne, 1, MPI_INT, 0, 446,
MyComm);
5332 for (j = 0; j < 2; j++)
5337 for ( ; i < ne; i++)
5340 for (j = 0; j < 2; j++)
5345 MPI_Send(&ints[0], 2*ne, MPI_INT, 0, 447,
MyComm);
5348 MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5355 for (j = 0; j < 3; j++)
5360 MPI_Send(&ints[0], 3*NumOfElements, MPI_INT, 0, 447,
MyComm);
5363 MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0,
MyComm);
5367 for (j = 0; j <
Dim; j++)
5371 MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE,
5389 MPI_Allreduce(p_min.
GetData(), gp_min, sdim, MPI_DOUBLE, MPI_MIN,
MyComm);
5390 MPI_Allreduce(p_max.
GetData(), gp_max, sdim, MPI_DOUBLE, MPI_MAX,
MyComm);
5394 double &gk_min,
double &gk_max)
5396 double h_min, h_max, kappa_min, kappa_max;
5400 MPI_Allreduce(&h_min, &gh_min, 1, MPI_DOUBLE, MPI_MIN,
MyComm);
5401 MPI_Allreduce(&h_max, &gh_max, 1, MPI_DOUBLE, MPI_MAX,
MyComm);
5402 MPI_Allreduce(&kappa_min, &gk_min, 1, MPI_DOUBLE, MPI_MIN,
MyComm);
5403 MPI_Allreduce(&kappa_max, &gk_max, 1, MPI_DOUBLE, MPI_MAX,
MyComm);
5410 double h_min, h_max, kappa_min, kappa_max, h,
kappa;
5414 out <<
"Parallel Mesh Stats:" <<
'\n';
5420 h = pow(fabs(J.
Weight()), 1.0/
double(
Dim));
5426 kappa_min = kappa_max =
kappa;
5430 if (h < h_min) { h_min = h; }
5431 if (h > h_max) { h_max = h; }
5432 if (kappa < kappa_min) { kappa_min =
kappa; }
5433 if (kappa > kappa_max) { kappa_max =
kappa; }
5437 double gh_min, gh_max, gk_min, gk_max;
5438 MPI_Reduce(&h_min, &gh_min, 1, MPI_DOUBLE, MPI_MIN, 0,
MyComm);
5439 MPI_Reduce(&h_max, &gh_max, 1, MPI_DOUBLE, MPI_MAX, 0,
MyComm);
5440 MPI_Reduce(&kappa_min, &gk_min, 1, MPI_DOUBLE, MPI_MIN, 0,
MyComm);
5441 MPI_Reduce(&kappa_max, &gk_max, 1, MPI_DOUBLE, MPI_MAX, 0,
MyComm);
5446 long mindata[5], maxdata[5], sumdata[5];
5465 MPI_Reduce(ldata, mindata, 5, MPI_LONG, MPI_MIN, 0,
MyComm);
5466 MPI_Reduce(ldata, sumdata, 5, MPI_LONG, MPI_SUM, 0,
MyComm);
5467 MPI_Reduce(ldata, maxdata, 5, MPI_LONG, MPI_MAX, 0,
MyComm);
5473 << setw(12) <<
"minimum"
5474 << setw(12) <<
"average"
5475 << setw(12) <<
"maximum"
5476 << setw(12) <<
"total" <<
'\n';
5478 << setw(12) << mindata[0]
5479 << setw(12) << sumdata[0]/
NRanks
5480 << setw(12) << maxdata[0]
5481 << setw(12) << sumdata[0] <<
'\n';
5483 << setw(12) << mindata[1]
5484 << setw(12) << sumdata[1]/
NRanks
5485 << setw(12) << maxdata[1]
5486 << setw(12) << sumdata[1] <<
'\n';
5490 << setw(12) << mindata[2]
5491 << setw(12) << sumdata[2]/
NRanks
5492 << setw(12) << maxdata[2]
5493 << setw(12) << sumdata[2] <<
'\n';
5496 << setw(12) << mindata[3]
5497 << setw(12) << sumdata[3]/
NRanks
5498 << setw(12) << maxdata[3]
5499 << setw(12) << sumdata[3] <<
'\n';
5500 out <<
" neighbors "
5501 << setw(12) << mindata[4]
5502 << setw(12) << sumdata[4]/
NRanks
5503 << setw(12) << maxdata[4] <<
'\n';
5506 << setw(12) <<
"minimum"
5507 << setw(12) <<
"maximum" <<
'\n';
5509 << setw(12) << gh_min
5510 << setw(12) << gh_max <<
'\n';
5512 << setw(12) << gk_min
5513 << setw(12) << gk_max <<
'\n';
5520 long local = value, global;
5521 MPI_Allreduce(&local, &global, 1, MPI_LONG, MPI_SUM,
MyComm);
5544 Printer(out,
"mfem_serial_mesh_end");
5552 out <<
"total_shared_edges " <<
shared_edges.Size() <<
'\n';
5563 out <<
"\n# group " << gr <<
"\nshared_vertices " << nv <<
'\n';
5564 for (
int i = 0; i < nv; i++)
5573 out <<
"\nshared_edges " << ne <<
'\n';
5574 for (
int i = 0; i < ne; i++)
5577 out << v[0] <<
' ' << v[1] <<
'\n';
5586 out <<
"\nshared_faces " << nt+nq <<
'\n';
5587 for (
int i = 0; i < nt; i++)
5591 for (
int j = 0; j < 3; j++) { out <<
' ' << v[j]; }
5594 for (
int i = 0; i < nq; i++)
5598 for (
int j = 0; j < 4; j++) { out <<
' ' << v[j]; }
5605 out <<
"\nmfem_mesh_end" << endl;
5610 bool high_order_output,
5611 int compression_level,
5614 int pad_digits_rank = 6;
5617 std::string::size_type pos = pathname.find_last_of(
'/');
5619 = (pos == std::string::npos) ? pathname : pathname.substr(pos+1);
5623 std::string pvtu_name = pathname +
"/" + fname +
".pvtu";
5624 std::ofstream
out(pvtu_name);
5627 std::string data_format = (format ==
VTKFormat::ASCII) ?
"ascii" :
"binary";
5629 out <<
"<?xml version=\"1.0\"?>\n";
5630 out <<
"<VTKFile type=\"PUnstructuredGrid\"";
5631 out <<
" version =\"0.1\" byte_order=\"" <<
VTKByteOrder() <<
"\">\n";
5632 out <<
"<PUnstructuredGrid GhostLevel=\"0\">\n";
5634 out <<
"<PPoints>\n";
5635 out <<
"\t<PDataArray type=\"" << data_type <<
"\" ";
5636 out <<
" Name=\"Points\" NumberOfComponents=\"3\""
5637 <<
" format=\"" << data_format <<
"\"/>\n";
5638 out <<
"</PPoints>\n";
5640 out <<
"<PCells>\n";
5641 out <<
"\t<PDataArray type=\"Int32\" ";
5642 out <<
" Name=\"connectivity\" NumberOfComponents=\"1\""
5643 <<
" format=\"" << data_format <<
"\"/>\n";
5644 out <<
"\t<PDataArray type=\"Int32\" ";
5645 out <<
" Name=\"offsets\" NumberOfComponents=\"1\""
5646 <<
" format=\"" << data_format <<
"\"/>\n";
5647 out <<
"\t<PDataArray type=\"UInt8\" ";
5648 out <<
" Name=\"types\" NumberOfComponents=\"1\""
5649 <<
" format=\"" << data_format <<
"\"/>\n";
5650 out <<
"</PCells>\n";
5652 out <<
"<PCellData>\n";
5653 out <<
"\t<PDataArray type=\"Int32\" Name=\"" <<
"attribute"
5654 <<
"\" NumberOfComponents=\"1\""
5655 <<
" format=\"" << data_format <<
"\"/>\n";
5656 out <<
"</PCellData>\n";
5658 for (
int ii=0; ii<
NRanks; ii++)
5660 std::string piece = fname +
".proc"
5662 out <<
"<Piece Source=\"" << piece <<
"\"/>\n";
5665 out <<
"</PUnstructuredGrid>\n";
5666 out <<
"</VTKFile>\n";
5670 std::string vtu_fname = pathname +
"/" + fname +
".proc"
5672 Mesh::PrintVTU(vtu_fname, format, high_order_output, compression_level, bdr);
5679 const int npts = point_mat.
Width();
5680 if (npts == 0) {
return 0; }
5682 const bool no_warn =
false;
5689 Array<int> my_point_rank(npts), glob_point_rank(npts);
5690 for (
int k = 0; k < npts; k++)
5692 my_point_rank[k] = (elem_id[k] == -1) ?
NRanks :
MyRank;
5695 MPI_Allreduce(my_point_rank.GetData(), glob_point_rank.
GetData(), npts,
5696 MPI_INT, MPI_MIN,
MyComm);
5699 for (
int k = 0; k < npts; k++)
5701 if (glob_point_rank[k] ==
NRanks) { elem_id[k] = -1; }
5705 if (glob_point_rank[k] !=
MyRank) { elem_id[k] = -2; }
5708 if (warn && pts_found != npts &&
MyRank == 0)
5710 MFEM_WARNING((npts-pts_found) <<
" points were not found");
5715 static void PrintVertex(
const Vertex &v,
int space_dim, ostream &
out)
5718 for (
int d = 1; d < space_dim; d++)
5726 stringstream out_name;
5727 out_name << fname_prefix <<
'_' << setw(5) << setfill(
'0') <<
MyRank
5728 <<
".shared_entities";
5729 ofstream
out(out_name.str().c_str());
5737 out <<
"total_shared_edges " <<
shared_edges.Size() <<
'\n';
5748 out <<
"\n# group " << gr <<
"\n\nshared_vertices " << nv <<
'\n';
5749 for (
int i = 0; i < nv; i++)
5761 out <<
"\nshared_edges " << ne <<
'\n';
5762 for (
int i = 0; i < ne; i++)
5778 out <<
"\nshared_faces " << nt+nq <<
'\n';
5779 for (
int i = 0; i < nt; i++)
5784 for (
int j = 0; j < 3; j++) { out <<
' ' << v[j]; }
5787 for (
int j = 0; j < 3; j++)
5790 (j < 2) ? out <<
" | " : out <<
'\n';
5793 for (
int i = 0; i < nq; i++)
5798 for (
int j = 0; j < 4; j++) { out <<
' ' << v[j]; }
5801 for (
int j = 0; j < 4; j++)
5804 (j < 3) ? out <<
" | " : out <<
'\n';
5820 for (
int i=0; i<
GetNV(); ++i)
5845 const int ldof = (dofs[0] >= 0) ? dofs[0] : -1 - dofs[0];
5873 const int ldof = (dofs[0] >= 0) ? dofs[0] : -1 - dofs[0];
5885 for (
int i=0; i<
GetNE(); ++i)
int GetNPoints() const
Returns the number of the points in the integration rule.
Abstract class for all finite elements.
Geometry::Type GetGeometryType() const
int GetGroupMasterRank(int g) const
Return the rank of the group master for group 'g'.
int GetNFaceNeighbors() const
void PrintAsOneXG(std::ostream &out=mfem::out)
Old mesh format (Netgen/Truegrid) version of 'PrintAsOne'.
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Ordering::Type GetOrdering() const
Return the ordering method.
void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
Multiply a matrix A with the transpose of a matrix B: A*Bt.
int Size() const
Return the logical size of the array.
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
void GetConformingSharedStructures(class ParMesh &pmesh)
virtual void Print(std::ostream &out=mfem::out) const
void Recreate(const int n, const int *p)
Create an integer set from C-array 'p' of 'n' integers. Overwrites any existing set data...
void GetGhostFaceTransformation(FaceElementTransformations *FETr, Element::Type face_type, Geometry::Type face_geom)
Class for an integration rule - an Array of IntegrationPoint.
void GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
const double * GetVertex(int i) const
Return pointer to vertex i's coordinates.
void LoadSharedEntities(std::istream &input)
void Bcast(T *ldata, int layout) const
Broadcast within each group where the master is the root.
long glob_offset_sequence
void UniformRefineGroups2D(int old_nv)
void FreeElement(Element *E)
void ExchangeFaceNbrData()
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
ParMesh & operator=(ParMesh &&mesh)
Move assignment operator.
void MakeRefined_(ParMesh &orig_mesh, int ref_factor, int ref_type)
Internal function used in ParMesh::MakeRefined (and related constructor)
virtual Element * Duplicate(Mesh *m) const =0
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
int FindSharedVertices(const int *partition, Table *vertex_element, ListOfIntegerSets &groups)
void AddColumnsInRow(int r, int ncol)
void UniformRefinement3D_base(Array< int > *f2qf=NULL, DSTable *v_to_v_p=NULL, bool update_nodes=true)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
virtual void GetVertices(Array< int > &v) const =0
Returns element's vertices.
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
static ParMesh MakeRefined(ParMesh &orig_mesh, int ref_factor, int ref_type)
Create a uniformly refined (by any factor) version of orig_mesh.
Array< Element * > boundary
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
int * GeneratePartitioning(int nparts, int part_method=1)
int BuildLocalVertices(const Mesh &global_mesh, const int *partitioning, Array< int > &vert_global_local)
Fills out partitioned Mesh::vertices.
void GetBdrElementFace(int i, int *f, int *o) const
Return the index and the orientation of the face of bdr element i. (3D)
CoarseFineTransformations CoarseFineTr
virtual void ReorientTetMesh()
See the remarks for the serial version in mesh.hpp.
void GetGlobalElementIndices(Array< HYPRE_Int > &gi) const
AMR meshes are supported.
void SetSize(int s)
Resize the vector to size s.
int GetNBE() const
Returns number of boundary elements.
IsoparametricTransformation Transformation
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
void GetCharacteristics(double &h_min, double &h_max, double &kappa_min, double &kappa_max, Vector *Vh=NULL, Vector *Vk=NULL)
Array< Element * > face_nbr_elements
static FiniteElement * GetTransformationFEforElementType(Element::Type)
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
void GetFaceNeighbors(class ParMesh &pmesh)
Lists all edges/faces in the nonconforming mesh.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
int GetGroupSize(int g) const
Get the number of processors in a group.
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Element::Type GetElementType(int i) const
Returns the type of element i.
void GetBoundingBox(Vector &min, Vector &max, int ref=2)
Returns the minimum and maximum corners of the mesh bounding box.
void ShiftRight(int &a, int &b, int &c)
void SetDims(int rows, int nnz)
void BuildSharedFaceElems(int ntri_faces, int nquad_faces, const Mesh &mesh, int *partitioning, const STable3D *faces_tbl, const Array< int > &face_group, const Array< int > &vert_global_local)
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor...
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
T * GetData()
Returns the data.
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Data type dense matrix using column-major storage.
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
void ApplyLocalSlaveTransformation(FaceElementTransformations &FT, const FaceInfo &fi, bool is_ghost)
int GetBdrElementEdgeIndex(int i) const
void GetCharacteristics(double &h_min, double &h_max, double &kappa_min, double &kappa_max)
void AverageVertices(const int *indexes, int n, int result)
Averages the vertices with given indexes and saves the result in vertices[result].
int GetNE() const
Returns number of elements.
void SynchronizeDerefinementData(Array< Type > &elem_data, const Table &deref_table)
const Element * GetFace(int i) const
int GetEdgeDofs(int edge, Array< int > &dofs, int variant=0) const
Returns the indices of the degrees of freedom for the specified edge, including the DOFs for the vert...
void EnsureParNodes()
If the mesh is curved, make sure 'Nodes' is ParGridFunction.
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
void UniformRefineGroups3D(int old_nv, int old_nedges, const DSTable &old_v_to_v, const STable3D &old_faces, Array< int > *f2qf)
virtual void Derefine(const Array< int > &derefs)
Abstract parallel finite element space.
void PrintVTU(std::ostream &out, int ref=1, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0, bool bdr_elements=false)
Array< Vert3 > shared_trias
virtual int DofForGeometry(Geometry::Type GeomType) const
Array< int > face_nbr_vertices_offset
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
virtual void Save(const char *fname, int precision=16) const
void SetMeshGen()
Determine the mesh generator bitmask meshgen, see MeshGenerator().
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Parallel version of Mesh::Load().
Array< int > face_nbr_group
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
void GetVertices(Vector &vert_coord) const
virtual void SetAttributes()
void RebalanceImpl(const Array< int > *partition)
void BuildFaceGroup(int ngroups, const Mesh &mesh, const Array< int > &face_group, int &nstria, int &nsquad)
double * GetData() const
Return a pointer to the beginning of the Vector data.
void Swap(GroupTopology &other)
Swap the internal data with another GroupTopology object.
virtual void MarkTetMeshForRefinement(DSTable &v_to_v)
int GroupNQuadrilaterals(int group)
Geometry::Type GetElementBaseGeometry(int i) const
int Size_of_connections() const
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
const NCList & GetSharedEdges()
void GetVertexToVertexTable(DSTable &) const
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
void DeleteAll()
Delete the whole array.
void AddConnections(int r, const int *c, int nc)
void InitRefinementTransforms()
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces ('entity' == 0/1/2 resp.).
void GroupTriangle(int group, int i, int &face, int &o)
void UniformRefinement2D_base(bool update_nodes=true)
Array< NCFaceInfo > nc_faces_info
void GetGlobalEdgeIndices(Array< HYPRE_Int > &gi) const
AMR meshes are not supported.
bool IAmMaster(int g) const
Return true if I am master for group 'g'.
bool WantSkipSharedMaster(const NCMesh::Master &master) const
void OnMeshUpdated(Mesh *mesh)
A parallel extension of the NCMesh class.
void GetSharedEdgeDofs(int group, int ei, Array< int > &dofs) const
Element * NewElement(int geom)
FaceElementTransformations FaceElemTr
Element::Type GetFaceElementType(int Face) const
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
void CopyTo(U *dest)
STL-like copyTo dest from begin to end.
int FindSharedEdges(const Mesh &mesh, const int *partition, Table *&edge_element, ListOfIntegerSets &groups)
long GetGlobalElementNum(int local_element_num) const
Map a local element number to a global element number.
int GroupVertex(int group, int i)
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
void MakeRefined_(Mesh &orig_mesh, const Array< int > ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
void ExchangeFaceNbrData()
void BuildSharedVertMapping(int nvert, const Table *vert_element, const Array< int > &vert_global_local)
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element's vertices.
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
void GetElementJacobian(int i, DenseMatrix &J)
int GetLocalElementNum(long global_element_num) const
void GetVertexDofs(int i, Array< int > &dofs) const
void MarkEdge(DenseMatrix &pmat)
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
bool Nonconforming() const
int BuildLocalBoundary(const Mesh &global_mesh, const int *partitioning, const Array< int > &vert_global_local, Array< bool > &activeBdrElem, Table *&edge_element)
Fills out partitioned Mesh::boundary.
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
const FiniteElement * GetFaceNbrFE(int i) const
Array< int > face_nbr_elements_offset
void GetEdgeOrdering(DSTable &v_to_v, Array< int > &order)
double f(const Vector &xvec)
double GetElementSize(ElementTransformation *T, int type=0)
Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed into the table. Diagonals of any kind are not allowed so the row, column and floor must all be different for each node. Only one node is stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor.
void GetBoundingBox(Vector &p_min, Vector &p_max, int ref=2)
const Table & GetDerefinementTable()
Array< Element * > shared_edges
virtual void SetAttributes()
int Append(const T &el)
Append element 'el' to array, resize if necessary.
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
int GetNumNeighbors() const
Return the number of neighbors including the local processor.
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
std::string to_padded_string(int i, int digits)
Convert an integer to a 0-padded string with the given number of digits.
void BuildSharedEdgeElems(int nedges, Mesh &mesh, const Array< int > &vert_global_local, const Table *edge_element)
void Finalize()
Allocate internal buffers after the GroupLDofTable is defined.
void GetFaceTransformation(int i, IsoparametricTransformation *FTr)
Returns the transformation defining the given face element in a user-defined variable.
static const int NumVerts[NumGeom]
void AddConnection(int r, int c)
STable3D * GetElementToFaceTable(int ret_ftbl=0)
FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2=true)
void LoseData()
NULL-ifies the data.
void GetGlobalVertexIndices(Array< HYPRE_Int > &gi) const
AMR meshes are not supported.
Table send_face_nbr_vertices
Type
Constants for the classes derived from Element.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
int InitialPartition(int index) const
Helper to get the partitioning when the serial mesh gets split initially.
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
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...
virtual void Print(std::ostream &out=mfem::out) const
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
void GetSharedQuadrilateralDofs(int group, int fi, Array< int > &dofs) const
static int create_directory(const std::string &dir_name, const Mesh *mesh, int myid)
GeometryRefiner GlobGeometryRefiner
int GetAttribute() const
Return element's attribute.
int GetElementToEdgeTable(Table &, Array< int > &)
const Element * GetElement(int i) const
int GroupNVertices(int group)
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
void GetLocalFaceTransformation(int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
A helper method that constructs a transformation from the reference space of a face to the reference ...
void GetSharedTriangleDofs(int group, int fi, Array< int > &dofs) const
IsoparametricTransformation Transformation2
FiniteElementCollection * OwnFEC()
int Size() const
Returns the number of TYPE I elements.
int GetVDim() const
Returns vector dimension.
FiniteElementSpace * FESpace()
int Size()
Return the number of integer sets in the list.
Array< Vert4 > shared_quads
void Rebalance(const Array< int > *custom_partition=NULL)
int slaves_end
slave faces
Data type tetrahedron element.
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
void GetGlobalFaceIndices(Array< HYPRE_Int > &gi) const
AMR meshes are not supported.
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
int SpaceDimension() const
void GroupQuadrilateral(int group, int i, int &face, int &o)
void Save(std::ostream &out) const
Save the data in a stream.
int GroupNTriangles(int group)
HYPRE_BigInt GetGlobalTDofNumber(int ldof) const
Returns the global tdof number of the given local degree of freedom.
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
void Swap(Array< T > &, Array< T > &)
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
double p(const Vector &x, double t)
void FindSharedFaces(const Mesh &mesh, const int *partition, Array< int > &face_group, ListOfIntegerSets &groups)
void RefineGroups(const DSTable &v_to_v, int *middle)
Update the groups after triangle refinement.
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Array< Vertex > face_nbr_vertices
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
static void PrintElement(const Element *, std::ostream &)
int GetNeighborRank(int i) const
Return the MPI rank of neighbor 'i'.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
void Swap(ParMesh &other)
void AddAColumnInRow(int r)
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
void PrintSharedEntities(const char *fname_prefix) const
Debugging method.
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
virtual long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
bool IsSlaveFace(const FaceInfo &fi) const
void DeleteLast()
Delete the last entry of the array.
ParMesh()
Default constructor. Create an empty ParMesh.
Table & GroupLDofTable()
Fill-in the returned Table reference to initialize the GroupCommunicator then call Finalize()...
Array< Element * > elements
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
void BuildVertexGroup(int ngroups, const Table &vert_element)
void SaveAsOne(const char *fname, int precision=16) const
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
void GetFaceNbrElementTransformation(int i, IsoparametricTransformation *ElTr)
NURBSExtension * NURBSext
Optional NURBS mesh extension.
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
virtual const char * Name() const
void DistributeAttributes(Array< int > &attr)
Ensure that bdr_attributes and attributes agree across processors.
virtual void Refine(const Array< Refinement > &refinements)
void Swap(Mesh &other, bool non_geometry)
void BuildEdgeGroup(int ngroups, const Table &edge_element)
void GetFaceSplittings(const int *fv, const HashTable< Hashed2 > &v_to_v, Array< unsigned > &codes)
Append codes identifying how the given face has been split to codes.
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
const FiniteElementSpace * GetNodalFESpace() const
void ComputeGlobalElementOffset() const
void ExchangeFaceNbrNodes()
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
static const int Orient[NumOrient][NumVert]
int BuildLocalElements(const Mesh &global_mesh, const int *partitioning, const Array< int > &vert_global_local)
Fills out partitioned Mesh::elements.
virtual int GetFaceDofs(int i, Array< int > &dofs, int variant=0) const
void SetIJ(int *newI, int *newJ, int newsize=-1)
Replace the I and J arrays with the given newI and newJ arrays.
const char * VTKByteOrder()
Table group_svert
Shared objects in each group.
bool DecodeFaceSplittings(HashTable< Hashed2 > &v_to_v, const int *v, const Array< unsigned > &codes, int &pos)
Array< MeshId > conforming
double GetFaceNbrElementSize(int i, int type=0)
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
int index(int i, int j, int nx, int ny)
bool IsGhost(int entity, int index) const
Return true if the specified vertex/edge/face is a ghost.
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Array< FaceInfo > faces_info
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element's attribute.
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
STable3D * GetFacesTable()
NCMesh * ncmesh
Optional non-conforming mesh extension.
T & Last()
Return the last element in the array.
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle)
Return a number(0-1) identifying how the given edge has been split.
Geometry::Type GetFaceGeometryType(int Face) const
int GetNEdges() const
Return the number of edges.
virtual void PrintXG(std::ostream &out=mfem::out) const
double AggregateError(const Array< double > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
void GetMarkedFace(const int face, int *fv)
void GroupEdge(int group, int i, int &edge, int &o)
int GetNFaces() const
Return the number of faces in a 3D mesh.
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Arbitrary order H(curl)-conforming Nedelec finite elements.
const FiniteElementCollection * FEColl() const
void GetNodes(Vector &node_coord) const
int NumberOfEntries() const
static ParMesh MakeSimplicial(ParMesh &orig_mesh)
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
void PrintAsOne(std::ostream &out=mfem::out) const
int GetId(int p1, int p2)
Get id of item whose parents are p1, p2... Create it if it doesn't exist.
Arbitrary order H1-conforming (continuous) finite elements.
Array< int > svert_lvert
Shared to local index mapping.
const NCList & GetSharedFaces()
void SaveAsOne(const char *fname, int precision=16) const
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Class for parallel grid function.
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Table send_face_nbr_elements
virtual void PrintInfo(std::ostream &out=mfem::out)
Print various parallel mesh stats.
Table * GetFaceToAllElementTable() const
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
void Bisection(int i, const DSTable &, int *, int *, int *)
Bisect a triangle: element with index i is bisected.
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn't exist.
void ParPrint(std::ostream &out) const
Save the mesh in a parallel mesh format.
Class for parallel meshes.
Abstract data type element.
int GetAttribute(int i) const
Return the attribute of element i.
int GetFaceNbrRank(int fn) const
const Table & ElementToEdgeTable() const
Data type line segment element.
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
virtual void PrintVTU(std::string pathname, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0, bool bdr=false)
void GenerateNCFaceInfo()
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
void GenerateOffsets(int N, HYPRE_BigInt loc_sizes[], Array< HYPRE_BigInt > *offsets[]) const
virtual Type GetType() const =0
Returns element's type.
virtual void LimitNCLevel(int max_nc_level)
Parallel version of NCMesh::LimitNCLevel.
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
const Element * GetBdrElement(int i) const
static const int Orient[NumOrient][NumVert]
void Load(std::istream &in)
Load the data from a stream.
void UpdateNodes()
Update the nodes of a curved mesh after refinement.
Defines the position of a fine element within a coarse element.
int GroupNEdges(int group)
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Arbitrary order "L2-conforming" discontinuous finite elements.
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
ParFiniteElementSpace * ParFESpace() const
virtual void NURBSUniformRefinement()
Refine NURBS mesh.