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 getMesh(), getMesh().bdr_attribute_sets.GetAttributeSet(_cut_boundary)))),
48 _transition_subdomain_boundary(getParam<BoundaryName>(
"transition_subdomain_boundary")),
49 _transition_subdomain(getParam<SubdomainName>(
"transition_subdomain")),
50 _closed_subdomain(getParam<SubdomainName>(
"closed_subdomain")),
59 _submesh = std::make_shared<mfem::ParSubMesh>(mfem::ParSubMesh::CreateFromDomain(
61 _submesh->attribute_sets.attr_sets =
getMesh().attribute_sets.attr_sets;
62 _submesh->bdr_attribute_sets.attr_sets =
getMesh().bdr_attribute_sets.attr_sets;
65 _submesh->bdr_attribute_sets.SetAttributeSet(
77 const mfem::Array<int> & parent_cut_element_id_map =
_cut_submesh->GetParentElementIDMap();
78 int rank_with_submesh = -1;
79 if (parent_cut_element_id_map.Size() > 0)
81 int reference_face = parent_cut_element_id_map[0];
83 rank_with_submesh = mpi_comm_rank;
85 MPI_Allreduce(MPI_IN_PLACE, &rank_with_submesh, 1, MPI_INT, MPI_MAX,
getMFEMProblem().getComm());
93 mfem::Array<int> transition_els;
94 std::vector<HYPRE_BigInt> global_cut_vert_ids;
95 mfem::Array<HYPRE_BigInt> gi;
96 parent_mesh.GetGlobalVertexIndices(gi);
97 std::unique_ptr<mfem::Table> vert_to_elem(parent_mesh.GetVertexToElementTable());
98 const mfem::Array<int> & cut_to_parent_vertex_id_map =
_cut_submesh->GetParentVertexIDMap();
101 int cut_vert = cut_to_parent_vertex_id_map[i];
102 global_cut_vert_ids.push_back(gi[cut_vert]);
103 int ne = vert_to_elem->RowSize(cut_vert);
104 const int * els_adj_to_cut = vert_to_elem->GetRow(cut_vert);
105 for (
int i = 0; i < ne; i++)
107 const int el_adj_to_cut = els_adj_to_cut[i];
110 transition_els.Append(el_adj_to_cut);
115 int n_cut_vertices = global_cut_vert_ids.size();
116 std::vector<int> cut_vert_sizes(mpi_comm_size);
120 std::vector<int> n_vert_offset(mpi_comm_size);
121 std::exclusive_scan(cut_vert_sizes.begin(), cut_vert_sizes.end(), n_vert_offset.begin(), 0);
122 int global_n_cut_vertices = std::accumulate(cut_vert_sizes.begin(), cut_vert_sizes.end(), 0);
125 std::vector<HYPRE_BigInt> all_cut_verts(global_n_cut_vertices);
126 MPI_Allgatherv(global_cut_vert_ids.data(),
129 all_cut_verts.data(),
130 cut_vert_sizes.data(),
131 n_vert_offset.data(),
136 for (
const auto g :
make_range(1, parent_mesh.GetNGroups()))
137 for (
const auto gv :
make_range(parent_mesh.GroupNVertices(g)))
140 int cut_vert = parent_mesh.GroupVertex(g, gv);
141 for (std::size_t i = 0; i < all_cut_verts.size(); i += 1)
142 if (gi[cut_vert] == all_cut_verts[i])
144 int ne = vert_to_elem->RowSize(cut_vert);
145 const int * els_adj_to_cut =
146 vert_to_elem->GetRow(cut_vert);
147 for (
int i = 0; i < ne; i++)
149 const int el_adj_to_cut = els_adj_to_cut[i];
152 transition_els.Append(el_adj_to_cut);
157 transition_els.Sort();
158 transition_els.Unique();
166 if (
mesh.SpaceDimension() != 3)
167 mooseError(
"MFEMCutTransitionSubMesh only works in 3-dimensional meshes!");
169 mfem::Array<int> face_verts;
170 std::vector<mfem::Vector> v;
171 mesh.GetFaceVertices(face, face_verts);
174 for (
auto vtx : face_verts)
176 mfem::Vector vtx_coords(3);
177 for (
int j = 0; j < 3; ++j)
178 vtx_coords[j] =
mesh.GetVertex(vtx)[j];
179 v.push_back(vtx_coords);
185 v[0].cross3D(v[1], normal);
186 normal /= normal.Norml2();
192 const int & el_vertex_on_cut,
193 mfem::ParMesh & parent_mesh)
195 const int sdim = parent_mesh.SpaceDimension();
196 mfem::Vector el_center(3);
197 parent_mesh.GetElementCenter(el, el_center);
198 mfem::Vector vertex_coords(parent_mesh.GetVertex(el_vertex_on_cut), sdim);
199 mfem::Vector relative_center(sdim);
200 for (
int j = 0; j < sdim; j++)
201 relative_center[j] = el_center[j] - vertex_coords[j];
207 mfem::Array<int> & transition_els)
210 const int old_max_attr = parent_mesh.attributes.Max();
211 mfem::Array<int> new_attrs(old_max_attr);
213 for (
auto const & transition_el : transition_els)
215 const int old_attr = parent_mesh.GetAttribute(transition_el);
216 new_attrs[old_attr - 1] = old_max_attr + old_attr;
218 parent_mesh.SetAttribute(transition_el, new_attrs[old_attr - 1]);
224 MPI_IN_PLACE, new_attrs, old_max_attr, MPI_INT, MPI_MAX,
getMFEMProblem().getComm());
226 mfem::AttributeSets & attr_sets = parent_mesh.attribute_sets;
232 const std::set<std::string> attr_set_names = attr_sets.GetAttributeSetNames();
233 for (
int old_attr = 1; old_attr <= old_max_attr; ++old_attr)
235 int new_attr = new_attrs[old_attr - 1];
240 for (
auto const & attr_set_name : attr_set_names)
242 const mfem::Array<int> & attr_set = attr_sets.GetAttributeSet(attr_set_name);
244 if (attr_set.Find(old_attr) != -1)
245 attr_sets.AddToAttributeSet(attr_set_name, new_attr);
250 parent_mesh.SetAttributes();
255 const mfem::Array<int> & subdomains,
256 const mfem::ParMesh & mesh)
262 for (
const auto & subdomain : subdomains)
263 if (
mesh.GetAttribute(element) == subdomain)
MFEMProblem & getMFEMProblem()
Return the owning MFEM problem.
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.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
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 ...