16 #include "libmesh/distributed_mesh.h" 17 #include "libmesh/elem.h" 18 #include "libmesh/parallel_elem.h" 19 #include "libmesh/parallel_node.h" 20 #include "libmesh/compare_elems_by_level.h" 21 #include "libmesh/mesh_communication.h" 35 params.
addRequiredParam<MeshGeneratorName>(
"input",
"The mesh we want to modify");
37 params.
addParam<SubdomainName>(
"new_block_name",
38 "The lower dimensional block name to create (optional)");
40 "sidesets",
"The sidesets from which to create the new block");
49 _input(getMesh(
"input")),
50 _sideset_names(getParam<
std::vector<BoundaryName>>(
"sidesets"))
64 std::unique_ptr<MeshBase>
67 std::unique_ptr<MeshBase>
mesh = std::move(
_input);
71 ? getParam<SubdomainID>(
"new_block_id")
75 if (!
mesh->is_prepared())
77 const bool allow_remote_element_removal =
mesh->allow_remote_element_removal();
80 mesh->allow_remote_element_removal(
false);
81 mesh->prepare_for_use();
82 mesh->allow_remote_element_removal(allow_remote_element_removal);
88 paramError(
"sidesets",
"The sideset '",
sideset,
"' was not found within the mesh");
91 std::set<boundary_id_type> sidesets(sideset_ids.begin(), sideset_ids.end());
92 auto side_list =
mesh->get_boundary_info().build_side_list();
93 if (!
mesh->is_serial() &&
mesh->comm().size() > 1)
95 std::vector<Elem *> elements_to_send;
96 unsigned short i_need_boundary_elems = 0;
97 for (
const auto & [elem_id, side, bc_id] : side_list)
100 if (sidesets.count(bc_id))
104 i_need_boundary_elems = 1;
105 auto * elem =
mesh->elem_ptr(elem_id);
106 if (elem->processor_id() ==
mesh->processor_id())
107 elements_to_send.push_back(elem);
111 std::set<const Elem *, libMesh::CompareElemIdsByLevel> connected_elements(
112 elements_to_send.begin(), elements_to_send.end());
113 std::set<const Node *> connected_nodes;
115 std::set<dof_id_type> connected_node_ids;
116 for (
auto * nd : connected_nodes)
117 connected_node_ids.insert(nd->id());
119 std::vector<unsigned short> need_boundary_elems(
mesh->comm().size());
120 mesh->comm().allgather(i_need_boundary_elems, need_boundary_elems);
121 std::unordered_map<processor_id_type, decltype(elements_to_send)> push_element_data;
122 std::unordered_map<processor_id_type, decltype(connected_nodes)> push_node_data;
126 if (pid !=
mesh->processor_id() && need_boundary_elems[pid])
128 if (elements_to_send.size())
129 push_element_data[pid] = elements_to_send;
130 if (connected_nodes.size())
131 push_node_data[pid] = connected_nodes;
138 Parallel::push_parallel_packed_range(
139 mesh->comm(), push_node_data,
mesh.get(), node_action_functor);
145 mesh->comm(), push_element_data,
mesh.get(), elem_action_functor);
148 side_list =
mesh->get_boundary_info().build_side_list();
151 std::vector<std::pair<dof_id_type, ElemSideDouble>> element_sides_on_boundary;
153 for (
const auto & triple : side_list)
154 if (sidesets.count(std::get<2>(triple)))
156 if (
auto elem =
mesh->query_elem_ptr(std::get<0>(triple)))
160 "Only active, level 0 elements can be made interior parents of new level 0 lower-d " 161 "elements. Make sure that ",
163 "s are run before any refinement generators");
164 element_sides_on_boundary.push_back(
165 std::make_pair(counter,
ElemSideDouble(elem, std::get<1>(triple))));
176 for (
auto & [i, elem_side] : element_sides_on_boundary)
178 Elem * elem = elem_side.elem;
180 const auto side = elem_side.side;
183 std::unique_ptr<Elem> side_elem(elem->build_side_ptr(side));
186 side_elem->processor_id() = elem->processor_id();
189 side_elem->subdomain_id() = new_block_id;
193 side_elem->set_interior_parent(elem);
196 side_elem->set_id(max_elem_id + i);
197 side_elem->set_unique_id(max_unique_id + i);
200 mesh->add_elem(side_elem.release());
205 mesh->subdomain_name(new_block_id) = getParam<SubdomainName>(
"new_block_name");
207 const bool skip_partitioning_old =
mesh->skip_partitioning();
208 mesh->skip_partitioning(
true);
209 mesh->prepare_for_use();
210 mesh->skip_partitioning(skip_partitioning_old);
std::unique_ptr< MeshBase > & _input
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the mesh.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
void reconnect_nodes(connected_elem_set_type &connected_elements, connected_node_set_type &connected_nodes)
std::set< std::string > sideset
static InputParameters validParams()
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
uint8_t processor_id_type
void libmesh_ignore(const Args &...)
registerMooseObject("MooseApp", LowerDBlockFromSidesetGenerator)
void push_parallel_packed_range(const Communicator &comm, MapToContainers &&data, Context *context, const ActionFunctor &act_on_data)
LowerDBlockFromSidesetGenerator(const InputParameters ¶meters)
const std::string & type() const
Get the type of this class.
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
static InputParameters validParams()
ElemSideDouble(Elem *elem_in, unsigned short int side_in)
Creates lower-dimensional elements on the specified sidesets.
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...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
const std::vector< BoundaryName > _sideset_names
a vector of the names of the sidesets to add the lower-D elements to
MeshGenerators are objects that can modify or add to an existing mesh.
auto index_range(const T &sizable)