17#include <unordered_set>
39 Array<int> &attributes) : parent_(parent), from_(from), attributes_(attributes)
43 MFEM_ABORT(
"SubMesh does not support non-conforming meshes");
60 std::tie(parent_vertex_ids_,
68 std::tie(parent_vertex_ids_,
79 parent_to_submesh_vertex_ids_ = -1;
80 for (
int i = 0; i < parent_vertex_ids_.
Size(); i++)
82 parent_to_submesh_vertex_ids_[parent_vertex_ids_[i]] = i;
85 DSTable v2v(parent_.
GetNV());
93 int parent_edge_id = v2v(parent_vertex_ids_[lv[0]],
94 parent_vertex_ids_[lv[1]]);
95 parent_edge_ids_.
Append(parent_edge_id);
99 parent_to_submesh_edge_ids_ = -1;
100 for (
int i = 0; i < parent_edge_ids_.
Size(); i++)
102 parent_to_submesh_edge_ids_[parent_edge_ids_[i]] = i;
108 parent_element_ids_);
111 parent_to_submesh_face_ids_ = -1;
112 for (
int i = 0; i < parent_face_ids_.
Size(); i++)
114 parent_to_submesh_face_ids_[parent_face_ids_[i]] = i;
124 Array<int> sub_par_vert(sub_vert.Size());
125 for (
int j = 0; j < sub_vert.Size(); j++)
127 sub_par_vert[j] = parent_vertex_ids_[sub_vert[j]];
133 if (par_vert.Size() == 3)
152 Array<int> sub_par_vert(sub_vert.Size());
153 for (
int j = 0; j < sub_vert.Size(); j++)
155 sub_par_vert[j] = parent_vertex_ids_[sub_vert[j]];
172 if (par_vert.Size() == 3)
185 ListOfIntegerSets groups;
188 group.Recreate(1, &
MyRank);
189 groups.Insert(group);
196 FindSharedVerticesRanks(rhvtx);
197 AppendSharedVerticesGroups(groups, rhvtx);
200 FindSharedEdgesRanks(rhe);
201 AppendSharedEdgesGroups(groups, rhe);
206 FindSharedFacesRanks(rht, rhq);
207 AppendSharedFacesGroups(groups, rht, rhq);
213 int ngroups = groups.Size()-1;
215 int nsverts, nsedges, nstrias, nsquads;
216 BuildVertexGroup(ngroups, rhvtx, nsverts);
217 BuildEdgeGroup(ngroups, rhe, nsedges);
220 BuildFaceGroup(ngroups, rht, nstrias, rhq, nsquads);
233 BuildSharedVerticesMapping(nsverts, rhvtx);
234 BuildSharedEdgesMapping(nsedges, rhe);
237 BuildSharedFacesMapping(nstrias, rht, nsquads, rhq);
244 const int num_codim_1 = [
this]()
249 else { MFEM_ABORT(
"Invalid dimension.");
return -1; }
261 for (
int i = 0; i < num_codim_1; i++)
274 for (
int i = 0, j = 0; i < num_codim_1; i++)
283 int pbeid =
Dim == 3 ? parent_face_to_be[parent_face_ids_[i]] :
284 parent_face_to_be[parent_edge_ids_[i]];
291 boundary[j]->SetAttribute(max_bdr_attr + 1);
305 int InteriorBdrElems = 0;
306 for (
int i=0; i<parent.
GetNBE(); i++)
309 const int submeshFaceIdx =
311 parent_to_submesh_face_ids_[parentFaceIdx] :
312 parent_to_submesh_edge_ids_[parentFaceIdx];
314 if (submeshFaceIdx == -1) {
continue; }
320 if (InteriorBdrElems > 0)
328 for (
int i=0, j = OldNumOfBdrElements; i<parent.
GetNBE(); i++)
331 const int submeshFaceIdx =
332 parent_to_submesh_face_ids_[parentFaceIdx];
334 if (submeshFaceIdx == -1) {
continue; }
356 const GridFunction *parent_nodes = parent_.
GetNodes();
359 const FiniteElementSpace *parent_fes = parent_nodes->FESpace();
362 parent_fes->FEColl()->GetOrder(),
363 parent_fes->IsDGSpace(),
365 parent_fes->GetOrdering());
367 const ParGridFunction* pn =
dynamic_cast<const ParGridFunction*
>
370 "Internal error. Object is supposed to be ParGridFunction.");
372 ParGridFunction* n =
dynamic_cast<ParGridFunction*
>
375 "Internal error. Object is supposed to be ParGridFunction.");
390 RT_FECollection fec_rt(0,
Dim);
391 ParFiniteElementSpace parent_fes_rt(
const_cast<ParMesh*
>(&parent),
394 ParGridFunction parent_bdr_attr_gf(&parent_fes_rt);
395 parent_bdr_attr_gf = 0.0;
398 DofTransformation doftrans;
404 parent_bdr_attr_gf.HostReadWrite();
405 for (
int i=0; i<parent.
GetNBE(); i++)
409 parent_fes_rt.GetBdrElementDofs(i, vdofs, doftrans);
417 w = faceInfo.IsShared() ? 2.0 : 1.0;
424 Vector parent_bdr_attr(parent_fes_rt.GetTrueVSize());
427 parent_bdr_attr_gf.ParallelAverage(parent_bdr_attr);
429 parent_bdr_attr_gf.Distribute(parent_bdr_attr);
431 ParFiniteElementSpace submesh_fes_rt(
this,
434 ParGridFunction submesh_bdr_attr_gf(&submesh_fes_rt);
438 submesh_bdr_attr_gf);
439 transfer_map.Transfer(parent_bdr_attr_gf, submesh_bdr_attr_gf);
447 submesh_fes_rt.GetBdrElementDofs(i, vdofs, doftrans);
449 attr = (int)std::round(std::abs(submesh_bdr_attr_gf[dof]));
461void ParSubMesh::FindSharedVerticesRanks(Array<int> &rhvtx)
464 GroupCommunicator svert_comm(parent_.
gtopo);
467 int nsvtx = svert_comm.GroupLDofTable().Size_of_connections();
469 rhvtx.SetSize(nsvtx);
474 for (
int g = 1, sv = 0; g < parent_.
GetNGroups(); g++)
477 MFEM_VERIFY((
unsigned int)group_sz <= 8*
sizeof(
int),
478 "Group size too large. Groups with more than 32 ranks are not supported, yet.");
481 const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
482 MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz,
"internal error");
484 const int my_group_id = my_group_id_ptr-group_lproc;
489 int submesh_vertex_id = parent_to_submesh_vertex_ids_[plvtx];
490 if (submesh_vertex_id != -1)
492 rhvtx[sv] |= 1 << my_group_id;
499 svert_comm.Bcast<
int>(rhvtx, 0);
502void ParSubMesh::FindSharedEdgesRanks(Array<int> &rhe)
505 GroupCommunicator sedge_comm(parent_.
gtopo);
508 int nsedges = sedge_comm.GroupLDofTable().Size_of_connections();
511 rhe.SetSize(nsedges);
516 for (
int g = 1, se = 0; g < parent_.
GetNGroups(); g++)
519 MFEM_VERIFY((
unsigned int)group_sz <= 8*
sizeof(
int),
520 "Group size too large. Groups with more than 32 ranks are not supported, yet.");
523 const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
524 MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz,
"internal error");
527 const int my_group_id = my_group_id_ptr-group_lproc;
529 for (
int ge = 0; ge < parent_.
GroupNEdges(g); ge++, se++)
533 int submesh_edge_id = parent_to_submesh_edge_ids_[ple];
534 if (submesh_edge_id != -1)
536 rhe[se] |= 1 << my_group_id;
543 sedge_comm.Bcast<
int>(rhe, 0);
546void ParSubMesh::FindSharedFacesRanks(Array<int>& rht, Array<int> &rhq)
548 GroupCommunicator squad_comm(parent_.
gtopo);
551 int nsquad = squad_comm.GroupLDofTable().Size_of_connections();
564 int submesh_face_id = parent_to_submesh_face_ids_[plq];
565 if (submesh_face_id != -1)
574 squad_comm.Bcast<
int>(rhq, 0);
576 GroupCommunicator stria_comm(parent_.
gtopo);
579 int nstria = stria_comm.GroupLDofTable().Size_of_connections();
584 for (
int g = 1, st = 0; g < parent_.
GetNGroups(); g++)
592 int submesh_face_id = parent_to_submesh_face_ids_[plt];
593 if (submesh_face_id != -1)
602 stria_comm.Bcast<
int>(rht, 0);
606void ParSubMesh::AppendSharedVerticesGroups(ListOfIntegerSets &groups,
611 for (
int g = 1, sv = 0; g < parent_.
GetNGroups(); g++)
614 MFEM_VERIFY((
unsigned int)group_sz <= 8*
sizeof(
int),
615 "Group size too large. Groups with more than 32 ranks are not supported, yet.");
618 const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
619 MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz,
"internal error");
621 const int my_group_id = my_group_id_ptr-group_lproc;
627 int submesh_vtx = parent_to_submesh_vertex_ids_[plvtx];
630 if (submesh_vtx == -1)
635 else if (rhvtx[sv] & ~(1 << my_group_id))
638 MFEM_ASSERT(rhvtx[sv] & (1 << my_group_id),
"error again");
641 Array<int> &ranks = group;
643 for (
int i = 0; i < group_sz; i++)
645 if ((rhvtx[sv] >> i) & 1)
650 MFEM_ASSERT(ranks.Size() >= 2,
"internal error");
652 rhvtx[sv] = groups.Insert(group) - 1;
663void ParSubMesh::AppendSharedEdgesGroups(ListOfIntegerSets &groups,
668 for (
int g = 1, se = 0; g < parent_.
GetNGroups(); g++)
671 MFEM_VERIFY((
unsigned int)group_sz <= 8*
sizeof(
int),
672 "Group size too large. Groups with more than 32 ranks are not supported, yet.");
675 const int* my_group_id_ptr = std::find(group_lproc, group_lproc+group_sz, 0);
676 MFEM_ASSERT(my_group_id_ptr != group_lproc+group_sz,
"internal error");
678 const int my_group_id = my_group_id_ptr-group_lproc;
680 for (
int ge = 0; ge < parent_.
GroupNEdges(g); ge++, se++)
684 int submesh_edge = parent_to_submesh_edge_ids_[ple];
687 if (submesh_edge == -1)
692 else if (rhe[se] & ~(1 << my_group_id))
697 Array<int> &ranks = group;
699 for (
int i = 0; i < group_sz; i++)
701 if ((rhe[se] >> i) & 1)
706 MFEM_ASSERT(ranks.Size() >= 2,
"internal error");
708 rhe[se] = groups.Insert(group) - 1;
719void ParSubMesh::AppendSharedFacesGroups(ListOfIntegerSets &groups,
720 Array<int>& rht, Array<int> &rhq)
722 IntegerSet quad_group;
730 MFEM_ASSERT(group_sz == 2,
"internal error");
734 int submesh_face_id = parent_to_submesh_face_ids_[plq];
737 if (submesh_face_id == -1)
742 else if (rhq[
sq] == group_sz)
748 Array<int> &ranks = quad_group;
753 rhq[
sq] = groups.Insert(quad_group) - 1;
763 IntegerSet tria_group;
765 for (
int g = 1, st = 0; g < parent_.
GetNGroups(); g++)
771 MFEM_ASSERT(group_sz == 2,
"internal error");
775 int submesh_face_id = parent_to_submesh_face_ids_[plt];
778 if (submesh_face_id == -1)
783 else if (rht[st] == group_sz)
789 Array<int> &ranks = tria_group;
794 rht[st] = groups.Insert(tria_group) - 1;
805void ParSubMesh::BuildVertexGroup(
int ngroups,
const Array<int>& rhvtx,
809 for (
int i = 0; i < rhvtx.Size(); i++)
819 for (
int i = 0; i < rhvtx.Size(); i++)
829void ParSubMesh::BuildEdgeGroup(
int ngroups,
const Array<int>& rhe,
833 for (
int i = 0; i < rhe.Size(); i++)
843 for (
int i = 0; i < rhe.Size(); i++)
853void ParSubMesh::BuildFaceGroup(
int ngroups,
const Array<int>& rht,
854 int& nstrias,
const Array<int>& rhq,
int& nsquads)
857 for (
int i = 0; i < rhq.Size(); i++)
867 for (
int i = 0; i < rhq.Size(); i++)
877 for (
int i = 0; i < rht.Size(); i++)
887 for (
int i = 0; i < rht.Size(); i++)
897void ParSubMesh::BuildSharedVerticesMapping(
const int nsverts,
898 const Array<int>& rhvtx)
902 for (
int g = 1, sv = 0; g < parent_.
GetNGroups(); g++)
908 int submesh_vtx_id = parent_to_submesh_vertex_ids_[plvtx];
909 if ((submesh_vtx_id == -1) || (rhvtx[sv] == -1))
921void ParSubMesh::BuildSharedEdgesMapping(
const int sedges_ct,
922 const Array<int>& rhe)
927 for (
int g = 1, se = 0; g < parent_.
GetNGroups(); g++)
929 for (
int ge = 0; ge < parent_.
GroupNEdges(g); ge++, se++)
933 int submesh_edge_id = parent_to_submesh_edge_ids_[ple];
934 if ((submesh_edge_id == -1) || rhe[se] == -1)
943 int v0 = parent_to_submesh_vertex_ids_[vert[(1-o)/2]];
944 int v1 = parent_to_submesh_vertex_ids_[vert[(1+o)/2]];
955void ParSubMesh::BuildSharedFacesMapping(
const int nstrias,
956 const Array<int>& rht,
957 const int nsquads,
const Array<int>& rhq)
966 for (
int g = 1, st = 0; g < parent_.
GetNGroups(); g++)
972 int submesh_face_id = parent_to_submesh_face_ids_[plt];
973 if ((submesh_face_id == -1) || rht[st] == -1)
1016 int submesh_face_id = parent_to_submesh_face_ids_[plq];
1017 if ((submesh_face_id == -1) || rhq[
sq] == -1)
1063 map.Transfer(src, dst);
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
static int DecodeDof(int dof)
Helper to return the DOF associated with a sign encoded DOF.
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int and double.
int GetNeighborRank(int i) const
Return the MPI rank of neighbor 'i'.
void SetComm(MPI_Comm comm)
Set the MPI communicator to 'comm'.
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor.
int GetGroupSize(int g) const
Get the number of processors in a group.
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
int GetElementToEdgeTable(Table &)
int GetNEdges() const
Return the number of edges.
void GetBdrElementFace(int i, int *f, int *o) const
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Array< int > GetFaceToBdrElMap() const
bool Nonconforming() const
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
static int ComposeQuadOrientations(int ori_a_b, int ori_b_c)
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
int GetNFaces() const
Return the number of faces in a 3D mesh.
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
int Dimension() const
Dimension of the reference space used within the elements.
FaceInformation GetFaceInformation(int f) const
STable3D * GetElementToFaceTable(int ret_ftbl=0)
int SpaceDimension() const
Dimension of the physical space containing the mesh.
void GetNodes(Vector &node_coord) const
static int ComposeTriOrientations(int ori_a_b, int ori_b_c)
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
int GetNBE() const
Returns number of boundary elements.
Array< Element * > boundary
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
void GetVertexToVertexTable(DSTable &) const
void SetBdrAttribute(int i, int attr)
Set the attribute of boundary element i.
Class for parallel grid function.
Class for parallel meshes.
int GroupNQuadrilaterals(int group) const
Array< Element * > shared_edges
void GetSharedTriCommunicator(int ordering, GroupCommunicator &stria_comm) const
Get the shared face triangles GroupCommunicator.
void ExchangeFaceNbrData()
Table group_svert
Shared objects in each group.
int GroupVertex(int group, int i) const
void GetSharedEdgeCommunicator(int ordering, GroupCommunicator &sedge_comm) const
Get the shared edges GroupCommunicator.
void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1) override
Set the curvature of the mesh nodes using the given polynomial degree.
void SetAttributes() override
Determine the sets of unique attribute values in domain and boundary elements.
void GetSharedQuadCommunicator(int ordering, GroupCommunicator &squad_comm) const
Get the shared face quadrilaterals GroupCommunicator.
ParMesh()
Default constructor. Create an empty ParMesh.
Array< Vert4 > shared_quads
void Finalize(bool refine=false, bool fix_orientation=false) override
Finalize the construction of a general Mesh.
Array< int > svert_lvert
Shared to local index mapping.
int GroupNTriangles(int group) const
void GetSharedVertexCommunicator(int ordering, GroupCommunicator &svert_comm) const
Get the shared vertices GroupCommunicator.
int GroupNEdges(int group) const
Array< Vert3 > shared_trias
void GroupQuadrilateral(int group, int i, int &face, int &o) const
void GroupTriangle(int group, int i, int &face, int &o) const
void GroupEdge(int group, int i, int &edge, int &o) const
int GroupNVertices(int group) const
Subdomain representation of a topological parent in another ParMesh.
static ParTransferMap CreateTransferMap(const ParGridFunction &src, const ParGridFunction &dst)
Create a Transfer Map object.
static ParSubMesh CreateFromBoundary(const ParMesh &parent, Array< int > &boundary_attributes)
Create a surface ParSubMesh from it's parent.
static ParSubMesh CreateFromDomain(const ParMesh &parent, Array< int > &domain_attributes)
Create a domain ParSubMesh from it's parent.
static void Transfer(const ParGridFunction &src, ParGridFunction &dst)
Transfer the dofs of a ParGridFunction.
ParTransferMap represents a mapping of degrees of freedom from a source ParGridFunction to a destinat...
static const int GENERATED_ATTRIBUTE
From
Indicator from which part of the parent Mesh the SubMesh is created.
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
void AddConnection(int r, int c)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
void AddAColumnInRow(int r)
std::tuple< Array< int >, Array< int > > AddElementsToMesh(const Mesh &parent, Mesh &mesh, const Array< int > &attributes, bool from_boundary)
Given a Mesh parent and another Mesh mesh using the list of attributes in attributes,...
Array< int > BuildFaceMap(const Mesh &pm, const Mesh &sm, const Array< int > &parent_element_ids)
Given two meshes that have a parent to SubMesh relationship create a face map, using a SubMesh to par...
std::function< real_t(const Vector &)> f(real_t mass_coeff)