156 std::unique_ptr<MeshBase>
mesh = std::move(
_input);
159 if (!
mesh->preparation().has_cached_elem_data)
160 mesh->cache_elem_data();
163 auto max_node_id =
mesh->max_node_id();
166 if (!
mesh->is_replicated() && !
mesh->is_prepared())
167 mesh->comm().max(max_node_id);
168#if LIBMESH_ENABLE_UNIQUE_ID
169 const auto max_unique_id =
mesh->parallel_max_unique_id();
172 BoundaryInfo & boundary_info =
mesh->get_boundary_info();
177 for (
const auto & block_name_pair :
178 getParam<std::vector<std::vector<SubdomainName>>>(
"block_pairs"))
180 if (block_name_pair.size() != 2)
182 "Each row of 'block_pairs' must have a size of two (block names).");
185 for (
const auto &
name : block_name_pair)
187 paramError(
"block_pairs",
"The block '",
name,
"' was not found in the mesh");
190 std::pair<SubdomainID, SubdomainID> pair = std::make_pair(
191 std::min(block_pair[0], block_pair[1]), std::max(block_pair[0], block_pair[1]));
202 for (
const auto &
name : getParam<std::vector<SubdomainName>>(
"surrounding_blocks"))
204 paramError(
"surrounding_blocks",
"The block '",
name,
"' was not found in the mesh");
207 *
mesh,
getParam<std::vector<SubdomainName>>(
"surrounding_blocks"));
208 std::copy(surrounding_block_ids.begin(),
209 surrounding_block_ids.end(),
217 "BreakMeshByBlockGenerator the specified interface transition boundary name "
221 std::unordered_map<dof_id_type, std::vector<dof_id_type>> node_to_elem_map;
222 for (
const auto & elem :
mesh->active_element_ptr_range())
223 for (
const auto n : make_range(elem->n_nodes()))
224 node_to_elem_map[elem->node_id(n)].push_back(elem->id());
231 for (
const auto & [current_node_id, connected_elems] : node_to_elem_map)
233 const auto * current_node =
mesh->node_ptr(current_node_id);
238 auto it = nodeid_to_connected_blocks.find(current_node_id);
239 if (it == nodeid_to_connected_blocks.end())
246 auto connected_blocks = it->second;
250 connected_blocks.erase(Elem::invalid_subdomain_id);
252 const unsigned int node_multiplicity = connected_blocks.size();
255 if (node_multiplicity > 1)
259 auto subdomain_it = connected_blocks.begin();
260 subdomain_id_type reference_subdomain_id =
262 connected_blocks.find(Elem::invalid_subdomain_id) != connected_blocks.end()
263 ? Elem::invalid_subdomain_id
268 bool should_create_new_node =
true;
272 should_create_new_node =
false;
276 const auto & sets_blocks_for_this_node = it->second;
282 if (sets_blocks_for_this_node.size() == 2)
285 auto set_blocks_for_this_node_it = sets_blocks_for_this_node.begin();
286 subdomain_id_type block1 = *set_blocks_for_this_node_it;
287 subdomain_id_type block2 = *std::next(set_blocks_for_this_node_it);
291 should_create_new_node =
true;
296 unsigned int multiplicity_counter = node_multiplicity;
297 for (
auto elem_id : connected_elems)
300 if (multiplicity_counter == 0)
303 Elem * current_elem =
mesh->elem_ptr(elem_id);
307 if ((block_id != reference_subdomain_id) ||
311 Node * new_node =
nullptr;
313 std::vector<boundary_id_type> node_boundary_ids;
315 for (
const auto local_node_id : make_range(current_elem->n_nodes()))
316 if (current_elem->node_id(local_node_id) ==
319 if (should_create_new_node)
326 new_node = Node::build(*current_node,
327 mesh->is_replicated()
329 : (current_elem->subdomain_id() + 1) * max_node_id +
332#if LIBMESH_ENABLE_UNIQUE_ID
333 new_node->set_unique_id((current_elem->subdomain_id() + 1) * max_unique_id +
334 current_node->unique_id());
339 new_node->processor_id() = current_elem->processor_id();
340 mesh->add_node(new_node);
341 current_elem->set_node(local_node_id, new_node);
343 boundary_info.boundary_ids(current_node, node_boundary_ids);
344 boundary_info.add_node(new_node, node_boundary_ids);
346 multiplicity_counter--;
351 if (should_create_new_node)
353 for (
auto connected_elem_id : connected_elems)
355 Elem * connected_elem =
mesh->elem_ptr(connected_elem_id);
359 if (connected_elem->subdomain_id() == current_elem->subdomain_id() &&
360 connected_elem != current_elem)
362 for (
const auto local_node_id : make_range(connected_elem->n_nodes()))
363 if (connected_elem->node_id(local_node_id) ==
366 connected_elem->set_node(local_node_id, new_node);
376 for (
auto elem_id : connected_elems)
378 for (
auto connected_elem_id : connected_elems)
380 Elem * current_elem =
mesh->elem_ptr(elem_id);
381 Elem * connected_elem =
mesh->elem_ptr(connected_elem_id);
384 if (current_elem == connected_elem)
388 subdomain_id_type connected_elem_subid =
391 if (curr_elem_subid < connected_elem_subid)
393 if (current_elem->has_neighbor(connected_elem))
395 unsigned int side = current_elem->which_neighbor_am_i(connected_elem);
396 unsigned int connected_elem_side = connected_elem->which_neighbor_am_i(current_elem);
400 bool need_to_switch =
false;
403 connected_elem_subid = connected_elem->subdomain_id();
404 if (curr_elem_subid > connected_elem_subid)
406 connected_elem_subid = current_elem->subdomain_id();
407 curr_elem_subid = connected_elem->subdomain_id();
409 side = connected_elem->which_neighbor_am_i(current_elem);
411 connected_elem_side = current_elem->which_neighbor_am_i(connected_elem);
412 need_to_switch =
true;
416 std::pair<subdomain_id_type, subdomain_id_type> blocks_pair =
417 std::make_pair(curr_elem_subid, connected_elem_subid);
419 std::pair<subdomain_id_type, subdomain_id_type> blocks_pair2 =
420 std::make_pair(connected_elem_subid, curr_elem_subid);
422 auto add_boundary_sides =
423 [&](
const std::pair<subdomain_id_type, subdomain_id_type> & blocks_pair,
424 const std::pair<subdomain_id_type, subdomain_id_type> & blocks_pair2,
426 Elem * connected_elem,
428 unsigned int connected_elem_side,
433 !need_to_switch ? current_elem : connected_elem, side);
438 !need_to_switch ? connected_elem : current_elem, connected_elem_side);
446 add_boundary_sides(blocks_pair,
455 add_boundary_sides(blocks_pair,
480 if (!
mesh->is_serial())
481 mesh->remove_orphaned_nodes();
482 Partitioner::set_node_processor_ids(*
mesh);
484 mesh->unset_is_prepared();
486 return dynamic_pointer_cast<MeshBase>(
mesh);
492 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
494 boundary_id_type boundary_id;
498 BoundaryName boundary_name;
500 const std::set<boundary_id_type> & ids = boundary_info.get_boundary_ids();
501 boundary_id_type new_boundaryID = ids.empty() ? 0 : *ids.rbegin() + 1;
505 mesh.comm().max(new_boundaryID);
506 mooseAssert(new_boundaryID >= 0,
"Invalid new boundary ID computed.");
510 std::vector<std::pair<subdomain_id_type, subdomain_id_type>> sorted_pairs(
513 for (
auto & boundary_side : sorted_pairs)
522 boundary_id = new_boundaryID;
525 boundary_side.second,
538 : boundary_id_interface;
539 boundary_id = boundary_id_interface;
540 boundary_info.sideset_name(boundary_id_interface) = boundary_name;
552 boundary_id = new_boundaryID;
555 boundary_side.second,
560 else if (interior_boundary)
566 : boundary_id_interface;
568 boundary_id = boundary_id_interface;
569 boundary_info.sideset_name(boundary_id_interface) = boundary_name;
574 boundary_id_interface_transition =
577 : boundary_id_interface_transition;
578 boundary_id = boundary_id_interface_transition;
589 for (
const auto & [elem, side] : boundary_side_map->second)
590 boundary_info.add_side(elem, side, boundary_id);
595 boundary_info.parallel_sync_side_ids();
596 boundary_info.parallel_sync_node_ids();
601 const auto rev_pair = std::make_pair(sub_pair.second, sub_pair.first);
602 const bool has_reverse =
606 mesh.add_disjoint_neighbor_boundary_pairs(
634 const std::unordered_map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map,
635 const MeshBase & mesh)
637 std::unordered_map<dof_id_type, std::set<subdomain_id_type>> nodeid_to_connected_blocks;
640 for (
const auto & [node_id, elem_ids] : node_to_elem_map)
642 std::set<subdomain_id_type> connected_blocks;
643 for (
const dof_id_type elem_id : elem_ids)
645 const Elem * current_elem =
mesh.elem_ptr(elem_id);
647 nodeid_to_connected_blocks[node_id].insert(block_id);
652 if (
mesh.is_replicated())
653 return nodeid_to_connected_blocks;
656 const auto mesh_pid =
mesh.processor_id();
661 using NodeConnectedBlocksTuple =
662 std::tuple<dof_id_type, std::vector<subdomain_id_type>, processor_id_type>;
663 std::map<processor_id_type, std::vector<NodeConnectedBlocksTuple>> to_owner;
664 for (
const auto & [node_id,
blocks] : nodeid_to_connected_blocks)
666 const Node * node =
mesh.node_ptr(node_id);
667 if (node && node->processor_id() != mesh_pid)
668 to_owner[node->processor_id()].emplace_back(
669 node_id, std::vector<subdomain_id_type>(
blocks.begin(),
blocks.end()), mesh_pid);
673 std::unordered_map<dof_id_type, std::set<processor_id_type>> subscribers;
674 Parallel::push_parallel_vector_data(
677 [&](processor_id_type,
const std::vector<NodeConnectedBlocksTuple> & recv_data)
679 for (
const auto & [node_id, blocks_vec, ghost_pid] : recv_data)
681 subscribers[node_id].insert(ghost_pid);
682 nodeid_to_connected_blocks[node_id].insert(blocks_vec.begin(), blocks_vec.end());
687 std::map<processor_id_type, std::vector<NodeConnectedBlocksPair>> from_owner;
688 for (
const auto & [node_id, sub_pids] : subscribers)
690 const Node * node =
mesh.node_ptr(node_id);
691 if (node && node->processor_id() == mesh_pid)
693 const auto & blocks_set = libmesh_map_find(nodeid_to_connected_blocks, node_id);
694 for (
const auto pid : sub_pids)
695 from_owner[pid].emplace_back(
696 node_id, std::vector<subdomain_id_type>(blocks_set.begin(), blocks_set.end()));
700 Parallel::push_parallel_vector_data(
703 [&](processor_id_type,
const std::vector<NodeConnectedBlocksPair> & recv_data)
705 for (
const auto & [node_id, blocks_vec] : recv_data)
706 nodeid_to_connected_blocks[node_id].insert(blocks_vec.begin(), blocks_vec.end());
708 return nodeid_to_connected_blocks;