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);
86 std::set<boundary_id_type> sidesets(sideset_ids.begin(), sideset_ids.end());
88 auto side_list =
mesh->get_boundary_info().build_side_list();
89 if (!
mesh->is_serial() &&
mesh->comm().size() > 1)
91 std::vector<Elem *> elements_to_send;
92 unsigned short i_need_boundary_elems = 0;
93 for (
const auto & [elem_id, side, bc_id] : side_list)
96 if (sidesets.count(bc_id))
100 i_need_boundary_elems = 1;
101 auto * elem =
mesh->elem_ptr(elem_id);
102 if (elem->processor_id() ==
mesh->processor_id())
103 elements_to_send.push_back(elem);
107 std::set<const Elem *, CompareElemIdsByLevel> connected_elements(elements_to_send.begin(),
108 elements_to_send.end());
109 std::set<const Node *> connected_nodes;
111 std::set<dof_id_type> connected_node_ids;
112 for (
auto * nd : connected_nodes)
113 connected_node_ids.insert(nd->id());
115 std::vector<unsigned short> need_boundary_elems(
mesh->comm().size());
116 mesh->comm().allgather(i_need_boundary_elems, need_boundary_elems);
117 std::unordered_map<processor_id_type, decltype(elements_to_send)> push_element_data;
118 std::unordered_map<processor_id_type, decltype(connected_nodes)> push_node_data;
122 if (pid !=
mesh->processor_id() && need_boundary_elems[pid])
124 if (elements_to_send.size())
125 push_element_data[pid] = elements_to_send;
126 if (connected_nodes.size())
127 push_node_data[pid] = connected_nodes;
134 Parallel::push_parallel_packed_range(
135 mesh->comm(), push_node_data,
mesh.get(), node_action_functor);
141 mesh->comm(), push_element_data,
mesh.get(), elem_action_functor);
144 side_list =
mesh->get_boundary_info().build_side_list();
147 std::vector<std::pair<dof_id_type, ElemSideDouble>> element_sides_on_boundary;
149 for (
const auto & triple : side_list)
150 if (sidesets.count(std::get<2>(triple)))
152 if (
auto elem =
mesh->query_elem_ptr(std::get<0>(triple)))
156 "Only active, level 0 elements can be made interior parents of new level 0 lower-d " 157 "elements. Make sure that ",
159 "s are run before any refinement generators");
160 element_sides_on_boundary.push_back(
161 std::make_pair(counter,
ElemSideDouble(elem, std::get<1>(triple))));
172 for (
auto & [i, elem_side] : element_sides_on_boundary)
174 Elem * elem = elem_side.elem;
176 const auto side = elem_side.side;
179 std::unique_ptr<Elem> side_elem(elem->build_side_ptr(side,
false));
182 side_elem->processor_id() = elem->processor_id();
185 side_elem->subdomain_id() = new_block_id;
189 side_elem->set_interior_parent(elem);
192 side_elem->set_id(max_elem_id + i);
193 side_elem->set_unique_id(max_unique_id + i);
196 mesh->add_elem(side_elem.release());
201 mesh->subdomain_name(new_block_id) = getParam<SubdomainName>(
"new_block_name");
203 const bool skip_partitioning_old =
mesh->skip_partitioning();
204 mesh->skip_partitioning(
true);
205 mesh->prepare_for_use();
206 mesh->skip_partitioning(skip_partitioning_old);
std::unique_ptr< MeshBase > & _input
static InputParameters validParams()
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
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()
void reconnect_nodes(const std::set< const Elem *, CompareElemIdsByLevel > &connected_elements, connected_node_set_type &connected_nodes)
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.
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)