10 #ifdef MOOSE_MFEM_ENABLED 23 "Class to construct an MFEMSubMesh formed from the set of elements that have least one " 24 "vertex on the specified cut plane, that lie on one side of the plane, " 25 "and that are restricted to the set of user-specified subdomains.");
27 "The boundary associated with the mesh cut.");
29 "transition_subdomain_boundary",
30 "Name to assign boundary of transition subdomain not shared with cut surface.");
32 "transition_subdomain",
33 "The name of the subdomain to be created on the mesh comprised of the set of elements " 34 "adjacent to the cut surface on one side.");
37 "The name of the subdomain attribute to be created comprised of the set of all elements " 38 "of the closed geometry, including the new transition region.");
45 _cut_boundary(getParam<BoundaryName>(
"cut_boundary")),
46 _cut_submesh(
std::make_shared<
mfem::ParSubMesh>(
mfem::ParSubMesh::CreateFromBoundary(
47 getMFEMProblem().
mesh().getMFEMParMesh(),
48 getMesh().bdr_attribute_sets.GetAttributeSet(_cut_boundary)))),
49 _transition_subdomain_boundary(getParam<BoundaryName>(
"transition_subdomain_boundary")),
50 _transition_subdomain(getParam<SubdomainName>(
"transition_subdomain")),
51 _closed_subdomain(getParam<SubdomainName>(
"closed_subdomain")),
60 _submesh = std::make_shared<mfem::ParSubMesh>(mfem::ParSubMesh::CreateFromDomain(
62 _submesh->attribute_sets.attr_sets =
getMesh().attribute_sets.attr_sets;
63 _submesh->bdr_attribute_sets.attr_sets =
getMesh().bdr_attribute_sets.attr_sets;
74 const mfem::Array<int> & parent_cut_element_id_map =
_cut_submesh->GetParentElementIDMap();
75 int rank_with_submesh = -1;
76 if (parent_cut_element_id_map.Size() > 0)
78 int reference_face = parent_cut_element_id_map[0];
80 rank_with_submesh = mpi_comm_rank;
82 MPI_Allreduce(MPI_IN_PLACE, &rank_with_submesh, 1, MPI_INT, MPI_MAX,
getMFEMProblem().getComm());
90 mfem::Array<int> transition_els;
91 std::vector<HYPRE_BigInt> global_cut_vert_ids;
92 mfem::Array<HYPRE_BigInt> gi;
93 parent_mesh.GetGlobalVertexIndices(gi);
94 std::unique_ptr<mfem::Table> vert_to_elem(parent_mesh.GetVertexToElementTable());
95 const mfem::Array<int> & cut_to_parent_vertex_id_map =
_cut_submesh->GetParentVertexIDMap();
98 int cut_vert = cut_to_parent_vertex_id_map[i];
99 global_cut_vert_ids.push_back(gi[cut_vert]);
100 int ne = vert_to_elem->RowSize(cut_vert);
101 const int * els_adj_to_cut = vert_to_elem->GetRow(cut_vert);
102 for (
int i = 0; i < ne; i++)
104 const int el_adj_to_cut = els_adj_to_cut[i];
107 transition_els.Append(el_adj_to_cut);
112 int n_cut_vertices = global_cut_vert_ids.size();
113 std::vector<int> cut_vert_sizes(mpi_comm_size, 0);
115 &n_cut_vertices, 1, MPI_INT, &cut_vert_sizes[0], 1, MPI_INT,
getMFEMProblem().getComm());
117 std::vector<int> n_vert_offset(mpi_comm_size, 0);
118 for (
int i = 1; i < mpi_comm_size; i++)
119 n_vert_offset[i] = n_vert_offset[i - 1] + cut_vert_sizes[i - 1];
120 int global_n_cut_vertices = 0;
121 for (
int i = 0; i < mpi_comm_size; i++)
122 global_n_cut_vertices += cut_vert_sizes[i];
125 std::vector<HYPRE_BigInt> all_cut_verts(global_n_cut_vertices, 0);
126 MPI_Allgatherv(&global_cut_vert_ids[0],
136 for (
int g = 1, sv = 0; g < parent_mesh.GetNGroups(); g++)
138 for (
int gv = 0; gv < parent_mesh.GroupNVertices(g); gv++, sv++)
141 int cut_vert = parent_mesh.GroupVertex(g, gv);
142 for (std::size_t i = 0; i < all_cut_verts.size(); i += 1)
144 if (gi[cut_vert] == all_cut_verts[i])
146 int ne = vert_to_elem->RowSize(cut_vert);
147 const int * els_adj_to_cut =
148 vert_to_elem->GetRow(cut_vert);
149 for (
int i = 0; i < ne; i++)
151 const int el_adj_to_cut = els_adj_to_cut[i];
154 transition_els.Append(el_adj_to_cut);
161 transition_els.Sort();
162 transition_els.Unique();
170 mooseAssert(
mesh.SpaceDimension() == 3,
171 "MFEMCutTransitionSubMesh only works in 3-dimensional meshes!");
173 mfem::Array<int> face_verts;
174 std::vector<mfem::Vector> v;
175 mesh.GetFaceVertices(face, face_verts);
178 for (
auto vtx : face_verts)
180 mfem::Vector vtx_coords(3);
181 for (
int j = 0; j < 3; ++j)
182 vtx_coords[j] =
mesh.GetVertex(vtx)[j];
183 v.push_back(vtx_coords);
189 v[0].cross3D(v[1], normal);
190 normal /= normal.Norml2();
196 const int & el_vertex_on_cut,
197 mfem::ParMesh & parent_mesh)
199 const int sdim = parent_mesh.SpaceDimension();
200 mfem::Vector el_center(3);
201 parent_mesh.GetElementCenter(el, el_center);
202 mfem::Vector vertex_coords(parent_mesh.GetVertex(el_vertex_on_cut), sdim);
203 mfem::Vector relative_center(sdim);
204 for (
int j = 0; j < sdim; j++)
205 relative_center[j] = el_center[j] - vertex_coords[j];
211 mfem::Array<int> & transition_els)
214 const int old_max_attr = parent_mesh.attributes.Max();
215 mfem::Array<int> new_attrs(old_max_attr);
217 for (
auto const & transition_el : transition_els)
219 const int old_attr = parent_mesh.GetAttribute(transition_el);
220 new_attrs[old_attr - 1] = old_max_attr + old_attr;
222 parent_mesh.SetAttribute(transition_el, new_attrs[old_attr - 1]);
228 MPI_IN_PLACE, new_attrs, old_max_attr, MPI_INT, MPI_MAX,
getMFEMProblem().getComm());
230 mfem::AttributeSets & attr_sets = parent_mesh.attribute_sets;
231 mfem::AttributeSets & bdr_attr_sets = parent_mesh.bdr_attribute_sets;
237 const std::set<std::string> attr_set_names = attr_sets.GetAttributeSetNames();
238 for (
int old_attr = 1; old_attr <= old_max_attr; ++old_attr)
240 int new_attr = new_attrs[old_attr - 1];
245 for (
auto const & attr_set_name : attr_set_names)
247 const mfem::Array<int> & attr_set = attr_sets.GetAttributeSet(attr_set_name);
249 if (attr_set.Find(old_attr) != -1)
250 attr_sets.AddToAttributeSet(attr_set_name, new_attr);
258 mfem::Array<int>({parent_mesh.bdr_attributes.Max() + 1}));
260 parent_mesh.SetAttributes();
265 const mfem::Array<int> & subdomains,
266 const mfem::ParMesh & mesh)
272 for (
const auto & subdomain : subdomains)
273 if (
mesh.GetAttribute(element) == subdomain)
Modifies the MFEM Mesh to label a subdomain consisting of elements adjacent to an interior surface on...
MFEMProblemData & getProblemData()
Method to get the current MFEMProblemData object storing the current data specifying the FE problem...
const SubdomainName & _closed_subdomain
virtual void buildSubMesh() override
Constructs the submesh.
const BoundaryName & _transition_subdomain_boundary
const mfem::Array< int > & getSubdomainAttributes()
void labelMesh(mfem::ParMesh &parent_mesh)
Add attributes to the parent mesh representing the cut transition region.
registerMooseObject("MooseApp", MFEMCutTransitionSubMesh)
static InputParameters validParams()
MFEMCutTransitionSubMesh(const InputParameters ¶meters)
const SubdomainName & _transition_subdomain
Base class for construction of a mfem::ParSubMesh object.
bool isPositiveSideOfCut(const int &el, const int &el_vertex_on_cut, mfem::ParMesh &mesh)
Checks whether an element lies on the positive or negative side of the cut plane. ...
bool isInDomain(const int &el, const mfem::Array< int > &subdomains, const mfem::ParMesh &mesh)
Checks whether a given element is within a certain domain or vector of domains.
MPI_Comm getComm()
Return the MPI communicator associated with this FE problem's mesh.
std::shared_ptr< mfem::ParSubMesh > _cut_submesh
void setAttributes(mfem::ParMesh &parent_mesh, mfem::Array< int > &transition_els)
Set new attributes for the provided transition region elements.
MFEMProblem & getMFEMProblem()
Returns a reference to the MFEMProblem instance.
static InputParameters validParams()
const mfem::ParMesh & getMesh() const
mfem::Vector findFaceNormal(const mfem::ParMesh &mesh, const int &face)
Finds the normal vector of a face in the mesh from its vertices.
std::shared_ptr< mfem::ParSubMesh > _submesh
Stores the constructed submesh.
static InputParameters validParams()
Base class for construction of an object that is restricted to a subset of subdomains of the problem ...