14 #include "libmesh/distributed_mesh.h" 15 #include "libmesh/elem.h" 16 #include "libmesh/partitioner.h" 25 params.
addRequiredParam<MeshGeneratorName>(
"input",
"The mesh we want to modify");
27 "Break the mesh at interfaces between blocks. New nodes will be generated so elements on " 28 "each side of the break are no longer connected. At the moment, this only works on a " 30 params.
addParam<std::vector<SubdomainName>>(
32 "The list of subdomain names surrounding which interfaces will be generated.");
33 params.
addParam<std::vector<std::vector<SubdomainName>>>(
34 "block_pairs",
"The list of subdomain pairs between which interfaces will be generated.");
35 params.
addParam<
bool>(
"add_transition_interface",
37 "If true and block is not empty, a special boundary named " 38 "interface_transition is generate between listed blocks and other blocks.");
40 "split_transition_interface",
false,
"Whether to split the transition interface by blocks.");
41 params.
addParam<
bool>(
"add_interface_on_two_sides",
43 "Whether to add an additional interface boundary at the other side.");
45 "interface_transition_name",
46 "interface_transition",
47 "the name of the interface transition boundary created when blocks are provided");
53 _input(getMesh(
"input")),
54 _block_pairs_restricted(parameters.isParamSetByUser(
"block_pairs")),
55 _surrounding_blocks_restricted(parameters.isParamSetByUser(
"surrounding_blocks")),
56 _add_transition_interface(getParam<bool>(
"add_transition_interface")),
57 _split_transition_interface(getParam<bool>(
"split_transition_interface")),
58 _interface_transition_name(getParam<BoundaryName>(
"interface_transition_name")),
59 _add_interface_on_two_sides(getParam<bool>(
"add_interface_on_two_sides"))
63 "BreakMeshByBlockGenerator: 'surrounding_blocks' and 'block_pairs' can not be used " 68 "BreakMeshByBlockGenerator cannot split the transition interface because " 69 "add_transition_interface is false");
73 "BreakMeshByBlockGenerator cannot split the transition interface when 'block_pairs' " 77 std::unique_ptr<MeshBase>
80 std::unique_ptr<MeshBase>
mesh = std::move(
_input);
81 if (!
mesh->is_replicated())
82 mooseError(
"BreakMeshByBlockGenerator is not implemented for distributed meshes");
85 mesh->prepare_for_use();
87 BoundaryInfo & boundary_info =
mesh->get_boundary_info();
92 for (
const auto & block_name_pair :
93 getParam<std::vector<std::vector<SubdomainName>>>(
"block_pairs"))
95 if (block_name_pair.size() != 2)
97 "Each row of 'block_pairs' must have a size of two (block names).");
100 for (
const auto &
name : block_name_pair)
102 paramError(
"block_pairs",
"The block '",
name,
"' was not found in the mesh");
105 std::pair<SubdomainID, SubdomainID> pair = std::make_pair(
106 std::min(block_pair[0], block_pair[1]),
std::max(block_pair[0], block_pair[1]));
115 for (
const auto &
name :
getParam<std::vector<SubdomainName>>(
"surrounding_blocks"))
117 paramError(
"surrounding_blocks",
"The block '",
name,
"' was not found in the mesh");
120 *
mesh,
getParam<std::vector<SubdomainName>>(
"surrounding_blocks"));
121 std::copy(surrounding_block_ids.begin(),
122 surrounding_block_ids.end(),
130 "BreakMeshByBlockGenerator the specified interface transition boundary name " 134 std::map<dof_id_type, std::vector<dof_id_type>> node_to_elem_map;
135 for (
const auto & elem :
mesh->active_element_ptr_range())
136 for (
unsigned int n = 0; n < elem->n_nodes(); n++)
137 node_to_elem_map[elem->node_id(n)].push_back(elem->id());
139 for (
auto node_it = node_to_elem_map.begin(); node_it != node_to_elem_map.end(); ++node_it)
141 const dof_id_type current_node_id = node_it->first;
142 const Node * current_node =
mesh->node_ptr(current_node_id);
144 if (current_node !=
nullptr)
147 std::set<subdomain_id_type> connected_blocks;
148 for (
auto elem_id = node_it->second.begin(); elem_id != node_it->second.end(); elem_id++)
150 const Elem * current_elem =
mesh->elem_ptr(*elem_id);
153 connected_blocks.insert(block_id);
156 if (block_id != Elem::invalid_subdomain_id)
157 connected_blocks.insert(block_id);
161 unsigned int node_multiplicity = connected_blocks.size();
164 if (node_multiplicity > 1)
167 const std::vector<dof_id_type> & connected_elems = node_it->second;
171 auto subdomain_it = connected_blocks.begin();
173 connected_blocks.find(Elem::invalid_subdomain_id) != connected_blocks.end()
174 ? Elem::invalid_subdomain_id
179 bool should_create_new_node =
true;
182 auto elems = node_to_elem_map[current_node->id()];
183 should_create_new_node =
false;
184 std::set<subdomain_id_type> sets_blocks_for_this_node;
185 for (
auto elem_id = elems.begin(); elem_id != elems.end(); elem_id++)
186 sets_blocks_for_this_node.insert(
188 if (sets_blocks_for_this_node.size() == 2)
190 auto setIt = sets_blocks_for_this_node.begin();
192 should_create_new_node =
true;
197 unsigned int multiplicity_counter = node_multiplicity;
198 for (
auto elem_id : connected_elems)
201 if (multiplicity_counter == 0)
204 Elem * current_elem =
mesh->elem_ptr(elem_id);
211 Node * new_node =
nullptr;
213 std::vector<boundary_id_type> node_boundary_ids;
215 for (
unsigned int node_id = 0; node_id < current_elem->n_nodes(); ++node_id)
216 if (current_elem->node_id(node_id) ==
219 if (should_create_new_node)
222 new_node = Node::build(*current_node,
mesh->n_nodes()).release();
227 new_node->processor_id() = current_elem->processor_id();
228 mesh->add_node(new_node);
229 current_elem->set_node(node_id) = new_node;
231 boundary_info.boundary_ids(current_node, node_boundary_ids);
232 boundary_info.add_node(new_node, node_boundary_ids);
235 multiplicity_counter--;
241 if (should_create_new_node)
243 for (
auto connected_elem_id : connected_elems)
245 Elem * connected_elem =
mesh->elem_ptr(connected_elem_id);
249 if (connected_elem->subdomain_id() == current_elem->subdomain_id() &&
250 connected_elem != current_elem)
252 for (
unsigned int node_id = 0; node_id < connected_elem->n_nodes(); ++node_id)
253 if (connected_elem->node_id(node_id) ==
256 connected_elem->set_node(node_id) = new_node;
266 for (
auto elem_id : connected_elems)
268 for (
auto connected_elem_id : connected_elems)
270 Elem * current_elem =
mesh->elem_ptr(elem_id);
271 Elem * connected_elem =
mesh->elem_ptr(connected_elem_id);
276 if (current_elem != connected_elem && curr_elem_subid < connected_elem_subid)
278 if (current_elem->has_neighbor(connected_elem))
281 dof_id_type connected_elem_id = connected_elem->id();
282 unsigned int side = current_elem->which_neighbor_am_i(connected_elem);
283 unsigned int connected_elem_side =
284 connected_elem->which_neighbor_am_i(current_elem);
289 connected_elem_subid = connected_elem->subdomain_id();
290 if (curr_elem_subid > connected_elem_subid)
292 connected_elem_subid = current_elem->subdomain_id();
293 curr_elem_subid = connected_elem->subdomain_id();
295 elem_id = connected_elem->id();
296 side = connected_elem->which_neighbor_am_i(current_elem);
298 connected_elem_id = current_elem->id();
299 connected_elem_side = current_elem->which_neighbor_am_i(connected_elem);
303 std::pair<subdomain_id_type, subdomain_id_type> blocks_pair =
304 std::make_pair(curr_elem_subid, connected_elem_subid);
306 std::pair<subdomain_id_type, subdomain_id_type> blocks_pair2 =
307 std::make_pair(connected_elem_subid, curr_elem_subid);
317 std::make_pair(connected_elem_id, connected_elem_side));
325 std::make_pair(connected_elem_id, connected_elem_side));
337 Partitioner::set_node_processor_ids(*
mesh);
344 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
350 BoundaryName boundary_name;
362 boundary_side_map.first.first,
363 boundary_side_map.first.second,
372 : boundary_id_interface;
373 boundary_id = boundary_id_interface;
374 boundary_info.sideset_name(boundary_id_interface) = boundary_name;
380 const bool interior_boundary =
388 boundary_side_map.first.first,
389 boundary_side_map.first.second,
394 else if (interior_boundary)
399 : boundary_id_interface;
401 boundary_id = boundary_id_interface;
402 boundary_info.sideset_name(boundary_id_interface) = boundary_name;
406 boundary_id_interface_transition =
409 : boundary_id_interface_transition;
410 boundary_id = boundary_id_interface_transition;
415 for (
auto & element_side : boundary_side_map.second)
416 boundary_info.add_side(element_side.first, element_side.second, boundary_id);
426 elem_subdomain_id = Elem::invalid_subdomain_id;
428 return elem_subdomain_id;
435 if ((block_pair.first == block_one && block_pair.second == block_two) ||
436 (block_pair.first == block_two && block_pair.second == block_one))
registerMooseObject("MooseApp", BreakMeshByBlockGenerator)
void addInterfaceBoundary(MeshBase &mesh)
generate the new boundary interface
std::unordered_set< std::pair< SubdomainID, SubdomainID > > _block_pairs
set of subdomain pairs between which interfaces will be generated.
static InputParameters validParams()
void findBoundaryNameAndInd(MeshBase &mesh, const subdomain_id_type &, const subdomain_id_type &, std::string &, boundary_id_type &, BoundaryInfo &)
given the primary and secondary blocks this method return the appropriate boundary id and name ...
const BoundaryID INVALID_BOUNDARY_ID
const bool _surrounding_blocks_restricted
whether interfaces will be generated surrounding blocks
const bool _split_transition_interface
whether to split the transition boundary between the blocks and the rest of the mesh ...
TestClass subdomain_id_type
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
std::vector< subdomain_id_type > getSubdomainIDs(const libMesh::MeshBase &mesh, const std::vector< SubdomainName > &subdomain_name)
Get the associated subdomainIDs for the subdomain names that are passed in.
virtual const std::string & name() const
Get the name of the class.
const bool _block_pairs_restricted
whether interfaces will be generated between block pairs
bool findBlockPairs(subdomain_id_type block_one, subdomain_id_type block_two)
Return true if block_one and block_two are found in users' provided block_pairs list.
auto max(const L &left, const R &right)
const BoundaryName _interface_transition_name
the name of the transition interface
std::string _interface_name
the name of the new interface
std::unique_ptr< MeshBase > & _input
the mesh to modify
static InputParameters validParams()
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
bool _split_interface
the flag to split the interface by block
bool hasSubdomainName(MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain 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 ...
subdomain_id_type blockRestrictedElementSubdomainID(const Elem *elem)
This is a helper method to avoid recoding the same if everywhere.
std::unordered_set< SubdomainID > _block_set
set of the blocks to split the mesh on
const bool _add_transition_interface
whether to add a boundary when splitting the mesh
BreakMeshByBlockGenerator(const InputParameters ¶meters)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
const bool _add_interface_on_two_sides
whether to add two sides interface boundaries
std::map< std::pair< subdomain_id_type, subdomain_id_type >, std::set< std::pair< dof_id_type, unsigned int > > > _new_boundary_sides_map
auto min(const L &left, const R &right)
BoundaryID findFreeBoundaryId(MeshBase &mesh)
this method finds the first free boundary id
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.