https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Classes | Functions
MooseMeshUtils Namespace Reference

Classes

struct  ElemSidePair
 

Functions

void mergeBoundaryIDsWithSameName (MeshBase &mesh)
 Merges the boundary IDs of boundaries that have the same names but different IDs.
 
void changeBoundaryId (MeshBase &mesh, const libMesh::boundary_id_type old_id, const libMesh::boundary_id_type new_id, bool delete_prev)
 Changes the old boundary ID to a new ID in the mesh.
 
void changeSubdomainId (MeshBase &mesh, const subdomain_id_type old_id, const subdomain_id_type new_id)
 Changes the old subdomain ID to a new ID in the mesh.
 
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.
 
std::vector< BoundaryID > getBoundaryIDs (const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown)
 Gets the boundary IDs with their names.
 
std::set< BoundaryID > getBoundaryIDSet (const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown)
 Gets the boundary IDs into a set with their names.
 
BoundaryID getBoundaryID (const BoundaryName &boundary_name, const MeshBase &mesh)
 Gets the boundary ID associated with the given BoundaryName.
 
SubdomainID getSubdomainID (const SubdomainName &subdomain_name, const MeshBase &mesh)
 Gets the subdomain ID associated with the given SubdomainName.
 
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.
 
std::set< subdomain_id_type > getSubdomainIDs (const libMesh::MeshBase &mesh, const std::set< SubdomainName > &subdomain_name)
 
Point meshCentroidCalculator (const MeshBase &mesh)
 Calculates the centroid of a MeshBase.
 
Point boundaryCentroidCalculator (const BoundaryName &boundary, MeshBase &mesh)
 Calculates the centroid of a boundary on a mesh.
 
RealVectorValue boundaryWeightedNormal (const BoundaryName &boundary, MeshBase &mesh)
 Calculates the side-volume weighted (side-vertex) average normal of a boundary on a mesh.
 
template<typename P , typename C >
void coordTransformFactor (const P &point, C &factor, const Moose::CoordinateSystemType coord_type, const unsigned int rz_radial_coord=libMesh::invalid_uint)
 Compute a coordinate transformation volume integration factor.
 
template<typename P , typename C >
C computeDistanceToAxis (const P &point, const Point &origin, const RealVectorValue &direction)
 Computes the distance to a general axis.
 
Real computeMaxDistanceToAxis (const MeshBase &mesh, const Point &origin, const RealVectorValue &direction)
 Computes the maximum distance from all nodes of a mesh to a general axis.
 
template<typename P , typename C >
void coordTransformFactorRZGeneral (const P &point, const std::pair< Point, RealVectorValue > &axis, C &factor)
 Computes a coordinate transformation factor for a general axisymmetric axis.
 
void computeFiniteVolumeCoords (FaceInfo &fi, const Moose::CoordinateSystemType coord_type, const unsigned int rz_radial_coord=libMesh::invalid_uint)
 
std::unordered_map< dof_id_type, dof_id_type > getExtraIDUniqueCombinationMap (const MeshBase &mesh, const std::set< SubdomainID > &block_ids, std::vector< ExtraElementIDName > extra_ids)
 Create a new set of element-wise IDs by finding unique combinations of existing extra ID values.
 
bool isCoPlanar (const std::vector< Point > &vec_pts, const Point plane_nvec, const Point fixed_pt)
 Decides whether all the Points of a vector of Points are in a plane that is defined by a normal vector and an inplane Point.
 
bool isCoPlanar (const std::vector< Point > &vec_pts, const Point plane_nvec)
 Decides whether all the Points of a vector of Points are in a plane with a given normal vector.
 
bool isCoPlanar (const std::vector< Point > &vec_pts)
 Decides whether all the Points of a vector of Points are coplanar.
 
SubdomainID getNextFreeSubdomainID (MeshBase &input_mesh)
 Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in use in the mesh.
 
BoundaryID getNextFreeBoundaryID (MeshBase &input_mesh)
 Checks input mesh and returns the largest boundary ID in the mesh plus one, which is a boundary ID in the mesh that is not currently in use.
 
bool hasSubdomainID (const MeshBase &input_mesh, const SubdomainID &id)
 Whether a particular subdomain ID exists in the mesh.
 
bool hasSubdomainName (const MeshBase &input_mesh, const SubdomainName &name)
 Whether a particular subdomain name exists in the mesh.
 
bool hasBoundaryID (const MeshBase &input_mesh, const BoundaryID id)
 Whether a particular boundary ID exists in the mesh.
 
bool hasBoundaryName (const MeshBase &mesh, const BoundaryName &name)
 Whether a particular boundary name exists in the mesh.
 
bool hasBoundaryNameOrID (const MeshBase &mesh, const BoundaryName &name_or_id)
 Whether a particular boundary name or ID exists in the mesh.
 
void makeOrderedNodeList (std::vector< std::pair< dof_id_type, dof_id_type > > &node_assm, std::vector< dof_id_type > &elem_id_list, std::vector< dof_id_type > &midpoint_node_list, std::vector< dof_id_type > &ordered_node_list, std::vector< dof_id_type > &ordered_elem_id_list)
 Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes based on connectivity.
 
void makeOrderedNodeList (std::vector< std::pair< dof_id_type, dof_id_type > > &node_assm, std::vector< dof_id_type > &elem_id_list, std::vector< dof_id_type > &ordered_node_list, std::vector< dof_id_type > &ordered_elem_id_list)
 Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes based on connectivity.
 
template<typename T , typename Q >
Q getIDFromName (const T &name)
 Converts a given name (BoundaryName or SubdomainName) that is known to only contain digits into a corresponding ID (BoundaryID or SubdomainID) and performs bounds checking to ensure that overflow doesn't happen.
 
void swapNodesInElem (Elem &elem, const unsigned int nd1, const unsigned int nd2)
 Swap two nodes within an element.
 
template<typename T >
void idSwapParametersProcessor (const std::string &class_name, const std::string &id_name, const std::vector< std::vector< T > > &id_swaps, std::vector< std::unordered_map< T, T > > &id_swap_pairs, const unsigned int row_index_shift=0)
 Reprocess the swap related input parameters to make pairs out of them to ease further processing.
 
void extraElemIntegerSwapParametersProcessor (const std::string &class_name, const unsigned int num_sections, const unsigned int num_integers, const std::vector< std::vector< std::vector< dof_id_type > > > &elem_integers_swaps, std::vector< std::unordered_map< dof_id_type, dof_id_type > > &elem_integers_swap_pairs)
 Reprocess the elem_integers_swaps into maps so they are easier to use.
 
std::unique_ptr< ReplicatedMesh > buildBoundaryMesh (const MeshBase &input_mesh, const boundary_id_type boundary_id)
 Build a lower-dimensional mesh from a boundary of an input mesh Note: The lower-dimensional mesh will only have one subdomain and one boundary.
 
std::unique_ptr< ReplicatedMesh > buildLoopBoundaryOf2DMesh (const MeshBase &input_mesh, const boundary_id_type boundary_id)
 Build a loop mesh of edges from the contiguous 2D boundary of 2D input mesh Note: The lower-dimensional mesh will only have one subdomain.
 
std::unordered_map< dof_id_type, std::unordered_set< dof_id_type > > buildBoundaryNodeToElemMap (const MeshBase &input_mesh, const boundary_id_type boundary_id)
 Build a map from the node ids to all element ids they are part of for the nodes on a particular nodeset.
 
std::set< dof_id_type > getBoundaryNodes (const MeshBase &mesh, const BoundaryID boundary_id)
 Get all the nodes on that particular boundary, whether a nodeset or a sideset.
 
void createSubdomainFromSidesets (MeshBase &mesh, std::vector< BoundaryName > boundary_names, const SubdomainID new_subdomain_id, const SubdomainName &new_subdomain_name)
 Create a new subdomain by generating new side elements from a list of sidesets in a given mesh.
 
void convertBlockToMesh (MeshBase &source_mesh, MeshBase &target_mesh, const std::vector< SubdomainName > &target_blocks)
 Convert a list of blocks in a given mesh to a standalone new mesh.
 
void copyIntoMesh (MeshGenerator &mg, UnstructuredMesh &destination, const UnstructuredMesh &source, const bool avoid_merging_subdomains, const bool avoid_merging_boundaries, const Parallel::Communicator &communicator)
 Helper function for copying one mesh into another.
 
void buildPolyLineMesh (MeshBase &mesh, const std::vector< Point > &points, const bool loop, const BoundaryName &start_boundary, const BoundaryName &end_boundary, const std::vector< unsigned int > &nums_edges_between_points)
 Generates meshes from edges connecting a list of points.
 
void buildPolyLineMesh (MeshBase &mesh, const std::vector< Point > &points, const std::vector< Point > &mid_points, const bool loop, const BoundaryName &start_boundary, const BoundaryName &end_boundary, const std::vector< unsigned int > &nums_edges_between_points)
 Generates meshes from edges connecting a list of points, with optional midpoints to produce Edge3 elements so as to enable quadratic meshing.
 
void buildPolyLineMesh (MeshBase &mesh, const std::vector< Point > &points, const bool loop, const BoundaryName &start_boundary, const BoundaryName &end_boundary, const Real max_elem_size)
 Generates meshes from edges connecting a list of points.
 
void addExternalBoundary (MeshBase &mesh, const BoundaryID extern_bid, bool &has_external_bid)
 Adds a sideset for the external boundary of the mesh (e.g.
 
void changeBoundaryId (MeshBase &mesh, const boundary_id_type old_id, const boundary_id_type new_id, bool delete_prev)
 
std::vector< boundary_id_type > getBoundaryIDs (const MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown)
 
std::vector< boundary_id_type > getBoundaryIDs (const MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
 
std::set< BoundaryID > getBoundaryIDSet (const MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown)
 
std::vector< subdomain_id_type > getSubdomainIDs (const MeshBase &mesh, const std::vector< SubdomainName > &subdomain_names)
 
std::set< subdomain_id_type > getSubdomainIDs (const MeshBase &mesh, const std::set< SubdomainName > &subdomain_names)
 

Function Documentation

◆ addExternalBoundary()

void MooseMeshUtils::addExternalBoundary ( MeshBase &  mesh,
const BoundaryID  extern_bid,
bool &  has_external_bid 
)

Adds a sideset for the external boundary of the mesh (e.g.

all element sides with no neighbors)

Parameters
meshthe mesh to modify
extern_bidthe ID to assign to the external boundary
has_external_bidfalse if all elements of the mesh are internal (for example a sphere shell)

Definition at line 1511 of file MooseMeshUtils.C.

1512{
1513 auto & binfo = mesh.get_boundary_info();
1514 for (const auto & elem : mesh.active_element_ptr_range())
1515 for (const auto & i_side : elem->side_index_range())
1516 if (elem->neighbor_ptr(i_side) == nullptr)
1517 {
1518 has_external_bid = true;
1519 binfo.add_side(elem, i_side, extern_bid);
1520 }
1521}
for(PetscInt i=0;i< nvars;++i)
if(!dmm->_nl) SETERRQ(PETSC_COMM_WORLD
MeshBase & mesh

Referenced by SurfaceSubdomainsDelaunayRemesher::generate(), XYDelaunayGenerator::generate(), and XYTriangleBoundaryLayerGenerator::generate().

◆ boundaryCentroidCalculator()

Point MooseMeshUtils::boundaryCentroidCalculator ( const BoundaryName &  boundary,
MeshBase &  mesh 
)

Calculates the centroid of a boundary on a mesh.

Parameters
boundaryboundary to compute the centroid of
meshinput mesh holding the boundary whose centroid needs to be calculated
Returns
a Point corresponding to the boundary centroid

Definition at line 298 of file MooseMeshUtils.C.

299{
300 // Need boundaries to be synchronized
301 if (!mesh.preparation().has_boundary_id_sets)
302 mesh.get_boundary_info().synchronize_global_id_set();
303 BoundaryInfo & mesh_boundary_info = mesh.get_boundary_info();
304 boundary_id_type boundary_id = mesh_boundary_info.get_id_by_name(boundary);
305 const auto side_list = mesh_boundary_info.build_side_list();
306
307 // Initialize sums
308 Real volume_sum = 0;
309 Point volume_weighted_centroid_sum(0, 0, 0);
310
311 for (const auto & [eid, side_i, bid] : side_list)
312 {
313 if (bid != boundary_id)
314 continue;
315
316 // Get the side
317 const auto elem = mesh.elem_ptr(eid);
318 const auto side = elem->side_ptr(side_i);
319
320 volume_sum += side->volume();
321 volume_weighted_centroid_sum += side->volume() * side->true_centroid();
322 }
323 // Sum across processes
324 mesh.comm().sum(volume_weighted_centroid_sum);
325 mesh.comm().sum(volume_sum);
326
327 return volume_weighted_centroid_sum / volume_sum;
328}

Referenced by BSplineCurveGenerator::endPoint(), and BSplineCurveGenerator::startPoint().

◆ boundaryWeightedNormal()

RealVectorValue MooseMeshUtils::boundaryWeightedNormal ( const BoundaryName &  boundary,
MeshBase &  mesh 
)

Calculates the side-volume weighted (side-vertex) average normal of a boundary on a mesh.

Parameters
boundaryboundary to compute the weighted normal of
meshinput mesh holding the boundary whose averaged normal needs to be calculated
Returns
a Point corresponding to the boundary weighted normal

Definition at line 331 of file MooseMeshUtils.C.

332{
333 // Need boundaries to be synchronized
334 if (!mesh.preparation().has_boundary_id_sets)
335 mesh.get_boundary_info().synchronize_global_id_set();
336 BoundaryInfo & mesh_boundary_info = mesh.get_boundary_info();
337 boundary_id_type boundary_id = mesh_boundary_info.get_id_by_name(boundary);
338 const auto side_list = mesh_boundary_info.build_side_list();
339
340 // Initialize sums
341 Real volume_sum = 0;
342 RealVectorValue volume_weighted_normal_sum(0, 0, 0);
343
344 for (const auto & [eid, side_i, bid] : side_list)
345 {
346 if (bid != boundary_id)
347 continue;
348
349 // Get the side
350 const auto elem = mesh.elem_ptr(eid);
351 const auto side = elem->side_ptr(side_i);
352
353 volume_sum += side->volume();
354 volume_weighted_normal_sum += side->volume() * elem->side_vertex_average_normal(side_i);
355 }
356 // Sum across processes
357 mesh.comm().sum(volume_weighted_normal_sum);
358 mesh.comm().sum(volume_sum);
359
360 return volume_weighted_normal_sum / volume_sum;
361}

Referenced by BSplineCurveGenerator::endDirection(), and BSplineCurveGenerator::startDirection().

◆ buildBoundaryMesh()

std::unique_ptr< ReplicatedMesh > MooseMeshUtils::buildBoundaryMesh ( const MeshBase &  input_mesh,
const boundary_id_type  boundary_id 
)

Build a lower-dimensional mesh from a boundary of an input mesh Note: The lower-dimensional mesh will only have one subdomain and one boundary.

Error will be thrown if the mesh does not have the boundary. This function works only with replicated mesh, for similar functionality with distributed meshes, please refer to LowerDBlockFromSidesetGenerator generator.

Parameters
input_meshThe input mesh
boundary_idThe boundary id

Definition at line 706 of file MooseMeshUtils.C.

707{
708 if (!input_mesh.is_serial())
709 ::mooseError("Input mesh should be serialized for extracting the boundary mesh.\nInput mesh:" +
710 input_mesh.get_info());
711 auto poly_mesh = std::make_unique<ReplicatedMesh>(input_mesh.comm());
712
713 auto side_list = input_mesh.get_boundary_info().build_side_list();
714
715 std::unordered_map<dof_id_type, dof_id_type> old_new_node_map;
716 for (const auto & [eid, side_i, bid] : side_list)
717 {
718 if (bid != boundary_id)
719 continue;
720
721 // Get the side
722 const auto elem = input_mesh.elem_ptr(eid);
723 const auto side = elem->side_ptr(side_i);
724 auto side_elem = elem->build_side_ptr(side_i);
725 auto copy = side_elem->build(side_elem->type());
726
727 for (const auto i : side_elem->node_index_range())
728 {
729 auto & n = side_elem->node_ref(i);
730
731 if (old_new_node_map.count(n.id()))
732 copy->set_node(i, poly_mesh->node_ptr(old_new_node_map[n.id()]));
733 else
734 {
735 Node * node = poly_mesh->add_point(side_elem->point(i));
736 copy->set_node(i, node);
737 old_new_node_map[n.id()] = node->id();
738 }
739 }
740 poly_mesh->add_elem(copy.release());
741 }
742 poly_mesh->skip_partitioning(true);
743 poly_mesh->prepare_for_use();
744 if (poly_mesh->n_elem() == 0)
745 mooseError("The input mesh to extract the boundary from does not have a boundary with id ",
746 boundary_id,
747 ".\n",
748 input_mesh);
749
750 return poly_mesh;
751}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311

◆ buildBoundaryNodeToElemMap()

std::unordered_map< dof_id_type, std::unordered_set< dof_id_type > > MooseMeshUtils::buildBoundaryNodeToElemMap ( const MeshBase &  input_mesh,
const boundary_id_type  boundary_id 
)

Build a map from the node ids to all element ids they are part of for the nodes on a particular nodeset.

Parameters
input_meshThe input mesh to get the map for
boundary_idThe boundary id of interest

Definition at line 969 of file MooseMeshUtils.C.

970{
971 if (!input_mesh.is_serial())
973 "Input 2D mesh should be serialized for extracting the loop boundary mesh.\nInput mesh:" +
974 input_mesh.get_info());
975
976 // Get all nodes on that boundary
977 // Boundary ID might be a sideset or a nodeset, get nodes regardless
978 const auto particular_node_ids = getBoundaryNodes(input_mesh, boundary_id);
979
980 std::unordered_map<dof_id_type, std::unordered_set<dof_id_type>> nid_to_eids_map;
981 // Fill the map from looping over elements
982 for (const auto & elem :
983 as_range(input_mesh.active_elements_begin(), input_mesh.active_elements_end()))
984 {
985 for (const auto & nd : elem->node_ref_range())
986 {
987 // Only add the element id if the node is on the boundary
988 if (!particular_node_ids.count(nd.id()))
989 continue;
990
991 auto & elem_ids = nid_to_eids_map[nd.id()];
992 elem_ids.insert(elem->id());
993 }
994 }
995 return nid_to_eids_map;
996}
std::set< dof_id_type > getBoundaryNodes(const MeshBase &mesh, const BoundaryID boundary_id)
Get all the nodes on that particular boundary, whether a nodeset or a sideset.

Referenced by buildLoopBoundaryOf2DMesh().

◆ buildLoopBoundaryOf2DMesh()

std::unique_ptr< ReplicatedMesh > MooseMeshUtils::buildLoopBoundaryOf2DMesh ( const MeshBase &  input_mesh,
const boundary_id_type  boundary_id 
)

Build a loop mesh of edges from the contiguous 2D boundary of 2D input mesh Note: The lower-dimensional mesh will only have one subdomain.

An error will be thrown if the mesh does not have the boundary. Note: currently, the boundary_id must be a nodeset!

Parameters
input_meshThe input mesh
boundary_idThe boundary id

Definition at line 754 of file MooseMeshUtils.C.

755{
756 if (!input_mesh.is_serial())
758 "Input 2D mesh should be serialized for extracting the loop boundary mesh.\nInput mesh:" +
759 input_mesh.get_info());
760 auto edge_mesh = std::make_unique<ReplicatedMesh>(input_mesh.comm());
761 auto side_list = input_mesh.get_boundary_info().build_side_list();
762 std::set<BoundaryInfo::BCTuple> visited;
763 bool already_seen_this_side_tuple = false;
764 BoundaryInfo::BCTuple first_side_visited = {libMesh::invalid_uint, 0, 0};
765
766 // Helps move elem to elem at a given node
767 const auto node_to_elem_map = buildBoundaryNodeToElemMap(input_mesh, boundary_id);
768 // Helps check if a node is part of a boundary
769 const auto & node_to_bids = input_mesh.get_boundary_info().get_nodeset_map();
770
771 // Traverse from the first side (edge) in the side_list that matches the boundary_id
772 for (const auto & bside : side_list)
773 {
774 if (std::get<2>(bside) != boundary_id)
775 continue;
776
777 // Check that we are not starting 'another' loop
778 if (bside != first_side_visited)
779 {
780 if (visited.size() && !visited.count(bside))
782 "Boundary " + std::to_string(boundary_id) +
783 " is not a (contiguous) loop. Boundary side: (" + Moose::stringify(bside) +
784 ") was not visited after a single pass around the boundary. Boundary sides visited: " +
785 Moose::stringify(visited));
786 else if (visited.empty())
787 first_side_visited = bside;
788 else
789 continue;
790 }
791
792 // Form the element to be able to find the side
793 // These three variables will be updated while traversing the loop boundary
794 const Elem * elem = input_mesh.elem_ptr(std::get<0>(bside));
795 auto current_side = std::get<1>(bside);
796 auto side_elem = elem->build_side_ptr(current_side);
797
798 // 3D elements should not be part of this boundary
799 if (elem->dim() != 2)
801 "Finding the loop boundary of a 2D mesh cannot be done with non-2D elements such as ",
802 *elem);
803
804 // Start from node 0 of the side (on the boundary), set the next node as the other node
805 // one that side, and keep going from tht next node
806 bool looped_back = false;
807 const Node * starting_node = side_elem->node_ptr(0);
808 const auto new_mesh_starting_node = edge_mesh->add_point(side_elem->point(0));
809 Node * new_first_node = new_mesh_starting_node;
810 [[maybe_unused]] dof_id_type first_node_index = starting_node->id();
811 dof_id_type second_node_index = input_mesh.node_ptr(side_elem->node_id(1))->id();
812
813 while (!looped_back && !already_seen_this_side_tuple)
814 {
815 if (MooseUtils::absoluteFuzzyEqual(input_mesh.point(second_node_index),
816 Point(*starting_node)))
817 looped_back = true;
818
819 // Get the opposite node (the next node) and add it to the edge mesh
820 Node * new_second_node = looped_back
821 ? new_mesh_starting_node
822 : edge_mesh->add_point(input_mesh.point(second_node_index));
823
824 // Add a copy of the edge side element to the mesh
825 side_elem = elem->build_side_ptr(current_side);
826 auto copy = side_elem->build(side_elem->type());
827 copy->set_node(0, new_first_node);
828 copy->set_node(1, new_second_node);
829 edge_mesh->add_elem(copy.release());
830
831 // Make this side as 'visited'
832 std::tuple<dof_id_type, unsigned short int, boundary_id_type> bc_tuple = {
833 elem->id(), current_side, boundary_id};
834 const auto & visit_iter = visited.insert(bc_tuple);
835 if (!looped_back && !visit_iter.second)
836 already_seen_this_side_tuple = true;
837
838 // Find the next element and side_elem
839 auto & connected_elems = libmesh_map_find(node_to_elem_map, second_node_index);
840 bool found_match = false;
841 const auto current_eid = elem->id();
842
843 for (const auto eid : connected_elems)
844 {
845 mooseAssert(!found_match,
846 "We should only find one node on a connected element on this boundary");
847 if (eid != current_eid)
848 {
849 // Update the element (on the input mesh)
850 elem = input_mesh.elem_ptr(eid);
851
852 // Find the side and the opposite node index in that side
853 for (const auto si : elem->side_index_range())
854 {
855 // Check that second node is on the side
856 const auto local_second_node_index =
857 elem->get_node_index(input_mesh.node_ptr(second_node_index));
858 // 2 sides should match this
859 if (elem->is_node_on_side(local_second_node_index, si))
860 {
861 // Only one side should be on the same boundary (node is connected to two elements)
862 // Form a bc_tuple and check the list of boundary sides
863 std::tuple<dof_id_type, unsigned short int, boundary_id_type> side_bc_tuple = {
864 elem->id(), si, boundary_id};
865
866 if (std::find(side_list.begin(), side_list.end(), side_bc_tuple) == side_list.end())
867 continue;
868
869 // We are on the right boundary, just need to get the other node
870 for (const auto local_side_node_id : elem->nodes_on_side(si))
871 {
872 const auto side_node_id = elem->node_id(local_side_node_id);
873
874 // Skip current node (use global index to compare)
875 if (side_node_id == second_node_index)
876 continue;
877 mooseAssert(side_node_id != first_node_index,
878 "Somehow looped back in a single element");
879
880 current_side = si;
881 second_node_index = side_node_id;
882 found_match = true;
883 break;
884 }
885 }
886 // No need to examine more sides
887 if (found_match)
888 break;
889 }
890
891 // No need to examine more elements
892 if (found_match)
893 break;
894 }
895 // next node could be on the same element, just moving on to the next side
896 else if (connected_elems.size() == 1)
897 {
898 elem = input_mesh.elem_ptr(eid);
899 const auto local_second_node_index =
900 elem->get_node_index(input_mesh.node_ptr(second_node_index));
901
902 // Move on to the next side
903 for (const auto si : elem->side_index_range())
904 if (si != current_side && elem->is_node_on_side(local_second_node_index, si))
905 {
906 // Check all nodes on that next side
907 for (const auto local_side_node_id : elem->nodes_on_side(si))
908 {
909 const auto side_node_id = elem->node_id(local_side_node_id);
910 // Skip current node
911 if (side_node_id == second_node_index)
912 continue;
913 mooseAssert((side_node_id != first_node_index) ||
914 (side_list.size() == elem->n_sides()),
915 "Somehow looped back in a single element");
916
917 // Check all the boundaries the other node (on the edge side) is part of
918 const auto bids_range = node_to_bids.equal_range(input_mesh.node_ptr(side_node_id));
919
920 for (auto iter = bids_range.first; iter != bids_range.second; iter++)
921 if (iter->second == boundary_id)
922 {
923 current_side = si;
924 second_node_index = side_node_id;
925 found_match = true;
926 }
927 }
928
929 // no need to examine other sides
930 if (found_match)
931 break;
932 }
933 }
934 }
935
936 // Set current node to opposite node of new element
937 // NOTE: do not use new_first_node or new_second_node to search in the input mesh!
938 new_first_node = new_second_node;
939 first_node_index = second_node_index;
940
941 // Handle loop ending criterion
942 if (!found_match)
943 {
944 mooseWarning("Search for next element in loop boundary failed. Is boundary '" +
945 std::to_string(boundary_id) + "' of mesh ",
946 input_mesh,
947 " a loop boundary?");
948 break;
949 }
950 }
951 }
952
953 if (already_seen_this_side_tuple)
954 mooseWarning("Boundary " + std::to_string(boundary_id) +
955 " seems to have cycles. A single-cycle loop should be used");
956
957 edge_mesh->skip_partitioning(true);
958 edge_mesh->prepare_for_use();
959 if (edge_mesh->n_elem() == 0)
960 mooseError("The input mesh to extract the boundary from does not have a boundary with id ",
961 boundary_id,
962 "\n",
963 input_mesh);
964
965 return edge_mesh;
966}
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:65
const unsigned int invalid_uint
uint8_t dof_id_type

Referenced by SurfaceSubdomainsDelaunayRemesher::General2DDelaunay().

◆ buildPolyLineMesh() [1/3]

void MooseMeshUtils::buildPolyLineMesh ( MeshBase &  mesh,
const std::vector< Point > &  points,
const bool  loop,
const BoundaryName &  start_boundary,
const BoundaryName &  end_boundary,
const Real  max_elem_size 
)

Generates meshes from edges connecting a list of points.

Note that we do not support max_elem_size and quadratic mid points at the same time as we cannot pre-determine the number of mid points needed for quadratic elements when max_elem_size is specified.

Parameters
meshThe mesh to be built
pointsThe list of points defining the polyline
loopWhether the polyline is a closed loop
start_boundaryThe boundary name to assign to the start of the polyline (if not a loop)
end_boundaryThe boundary name to assign to the end of the polyline (if not a loop)
max_elem_sizeThe maximum element size for the mesh

Definition at line 1485 of file MooseMeshUtils.C.

1491{
1492 std::vector<unsigned int> nums_edges_between_points;
1493 const auto n_points = points.size();
1494 for (auto i : make_range(n_points))
1495 {
1496 if (!loop && (i + 1) == n_points)
1497 break;
1498
1499 const auto ip1 = (i + 1) % n_points;
1500 const Real length = (points[ip1] - points[i]).norm();
1501 const unsigned int n_elems = std::max(
1502 static_cast<unsigned int>(std::ceil(length / max_elem_size)), static_cast<unsigned int>(1));
1503 nums_edges_between_points.push_back(n_elems);
1504 }
1505
1506 buildPolyLineMesh(
1507 mesh, points, {}, loop, start_boundary, end_boundary, nums_edges_between_points);
1508}

◆ buildPolyLineMesh() [2/3]

void MooseMeshUtils::buildPolyLineMesh ( MeshBase &  mesh,
const std::vector< Point > &  points,
const bool  loop,
const BoundaryName &  start_boundary,
const BoundaryName &  end_boundary,
const std::vector< unsigned int > &  nums_edges_between_points 
)

Generates meshes from edges connecting a list of points.

Parameters
meshThe mesh to be built
pointsThe list of points defining the polyline
loopWhether the polyline is a closed loop
start_boundaryThe boundary name to assign to the start of the polyline (if not a loop)
end_boundaryThe boundary name to assign to the end of the polyline (if not a loop)
nums_edges_between_pointsThe numbers of edges to create between each pair of points (if only one number is given, it is used for all point pairs)

Definition at line 1473 of file MooseMeshUtils.C.

1479{
1481 mesh, points, {}, loop, start_boundary, end_boundary, nums_edges_between_points);
1482}
void buildPolyLineMesh(MeshBase &mesh, const std::vector< Point > &points, const bool loop, const BoundaryName &start_boundary, const BoundaryName &end_boundary, const std::vector< unsigned int > &nums_edges_between_points)
Generates meshes from edges connecting a list of points.

Referenced by BoundaryLayerUtils::buildBoundaryLayerRing(), buildPolyLineMesh(), buildPolyLineMesh(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), and PolyLineMeshGenerator::generate().

◆ buildPolyLineMesh() [3/3]

void MooseMeshUtils::buildPolyLineMesh ( MeshBase &  mesh,
const std::vector< Point > &  points,
const std::vector< Point > &  mid_points,
const bool  loop,
const BoundaryName &  start_boundary,
const BoundaryName &  end_boundary,
const std::vector< unsigned int > &  nums_edges_between_points 
)

Generates meshes from edges connecting a list of points, with optional midpoints to produce Edge3 elements so as to enable quadratic meshing.

If mid_points is empty, Edge2 elements are produced.

Parameters
meshThe mesh to be built
pointsThe list of points defining the polyline
mid_pointsThe optional list of midpoints corresponding to the segments for quadratic elements. if provided, it must contains exactly one midpoint per segment and nums_edges_between_points must be unity for every segment.
loopWhether the polyline is a closed loop
start_boundaryThe boundary name to assign to the start of the polyline (if not a loop)
end_boundaryThe boundary name to assign to the end of the polyline (if not a loop)
nums_edges_between_pointsThe numbers of edges to create between each pair of points (if only one number is given, it is used for all point pairs)

Definition at line 1365 of file MooseMeshUtils.C.

1372{
1373 mooseAssert(nums_edges_between_points.size() == 1 ||
1374 nums_edges_between_points.size() == points.size() - 1 + loop,
1375 "nums_edges_between_points must be either a single value or have the same number of "
1376 "entries as segments defined by the points.");
1377 mooseAssert(
1378 mid_points.size() == 0 || mid_points.size() == points.size() - (loop ? 0 : 1),
1379 "mid_points must be either empty or have the consistent number of entries as points.");
1380 mooseAssert(
1381 mid_points.size() == 0 ||
1382 (nums_edges_between_points.size() == 1 && nums_edges_between_points.front() == 1) ||
1383 (nums_edges_between_points.size() == points.size() - 1 + loop &&
1384 std::all_of(nums_edges_between_points.begin(),
1385 nums_edges_between_points.end(),
1386 [](unsigned int n) { return n == 1; })),
1387 "mid_points can only be provided if each segment has exactly one edge.");
1388
1389 const auto n_points = points.size();
1390 for (auto i : make_range(n_points))
1391 {
1392 const auto & num_edges_between_points =
1393 (nums_edges_between_points.size() == 1)
1394 ? nums_edges_between_points[0]
1395 : (i == nums_edges_between_points.size() ? 0 : nums_edges_between_points[i]);
1396
1397 Point p = points[i];
1398 const auto pt_counter = (nums_edges_between_points.size() == 1)
1399 ? i
1400 : std::accumulate(nums_edges_between_points.begin(),
1401 nums_edges_between_points.begin() + i,
1402 0);
1403 mesh.add_point(
1404 p, nums_edges_between_points.size() == 1 ? (i * num_edges_between_points) : pt_counter);
1405
1406 if (num_edges_between_points > 1)
1407 {
1408 if (!loop && (i + 1) == n_points)
1409 break;
1410
1411 const auto ip1 = (i + 1) % n_points;
1412 const Point pvec = (points[ip1] - p) / num_edges_between_points;
1413
1414 for (auto j : make_range(1u, num_edges_between_points))
1415 {
1416 p += pvec;
1417 mesh.add_point(
1418 p,
1419 (nums_edges_between_points.size() == 1 ? (i * num_edges_between_points) : pt_counter) +
1420 j);
1421 }
1422 }
1423 }
1424 // Add mid points if applicable. When mid points are provided, each segment has exactly one edge,
1425 // so the midpoint node ids follow the vertex node ids.
1426 for (const auto & i : make_range(mid_points.size()))
1427 mesh.add_point(mid_points[i], n_points + i);
1428
1429 const auto n_segments = loop ? n_points : (n_points - 1);
1430 const auto n_elem =
1431 nums_edges_between_points.size() == 1
1432 ? n_segments * nums_edges_between_points[0]
1433 : std::accumulate(nums_edges_between_points.begin(), nums_edges_between_points.end(), 0);
1434 const auto max_nodes =
1435 (nums_edges_between_points.size() == 1 ? n_segments * nums_edges_between_points[0]
1436 : std::accumulate(nums_edges_between_points.begin(),
1437 nums_edges_between_points.end(),
1438 0)) +
1439 (loop ? 0 : 1);
1440 for (auto i : make_range(n_elem))
1441 {
1442 std::unique_ptr<Elem> elem;
1443 if (mid_points.size())
1444 {
1445 elem = std::make_unique<Edge3>();
1446 elem->set_node(2, mesh.node_ptr(n_points + i));
1447 }
1448 else
1449 elem = Elem::build(EDGE2);
1450 const auto ip1 = (i + 1) % max_nodes;
1451 elem->set_node(0, mesh.node_ptr(i));
1452 elem->set_node(1, mesh.node_ptr(ip1));
1453 elem->set_id() = i;
1454 mesh.add_elem(std::move(elem));
1455 }
1456
1457 if (!loop)
1458 {
1459 BoundaryInfo & bi = mesh.get_boundary_info();
1460 std::vector<BoundaryName> bdy_names{start_boundary, end_boundary};
1461 std::vector<boundary_id_type> ids = MooseMeshUtils::getBoundaryIDs(mesh, bdy_names, true);
1462 bi.add_side(mesh.elem_ptr(0), 0, ids[0]);
1463 bi.add_side(mesh.elem_ptr(n_elem - 1), 1, ids[1]);
1464 }
1465 else
1466 mooseAssert(start_boundary.empty() && end_boundary.empty(),
1467 "Cannot assign start/end boundaries on a looped polyline.");
1468
1469 mesh.prepare_for_use();
1470}
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.
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
IntRange< T > make_range(T beg, T end)

◆ changeBoundaryId() [1/2]

void MooseMeshUtils::changeBoundaryId ( MeshBase &  mesh,
const boundary_id_type  old_id,
const boundary_id_type  new_id,
bool  delete_prev 
)

Definition at line 63 of file MooseMeshUtils.C.

67{
68 // Get a reference to our BoundaryInfo object, we will use it several times below...
69 BoundaryInfo & boundary_info = mesh.get_boundary_info();
70
71 // Container to catch ids passed back from BoundaryInfo
72 std::vector<boundary_id_type> old_ids;
73
74 // Only level-0 elements store BCs. Loop over them.
75 for (auto & elem : as_range(mesh.level_elements_begin(0), mesh.level_elements_end(0)))
76 {
77 unsigned int n_sides = elem->n_sides();
78 for (const auto s : make_range(n_sides))
79 {
80 boundary_info.boundary_ids(elem, s, old_ids);
81 if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
82 {
83 std::vector<boundary_id_type> new_ids(old_ids);
84 std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
85 if (delete_prev)
86 {
87 boundary_info.remove_side(elem, s);
88 boundary_info.add_side(elem, s, new_ids);
89 }
90 else
91 boundary_info.add_side(elem, s, new_ids);
92 }
93 }
94 }
95
96 // Remove any remaining references to the old ID from the
97 // BoundaryInfo object. This prevents things like empty sidesets
98 // from showing up when printing information, etc.
99 if (delete_prev)
100 boundary_info.remove_id(old_id);
101
102 // global information may now be out of sync
103 mesh.unset_is_prepared();
104}

◆ changeBoundaryId() [2/2]

void MooseMeshUtils::changeBoundaryId ( MeshBase &  mesh,
const libMesh::boundary_id_type  old_id,
const libMesh::boundary_id_type  new_id,
bool  delete_prev 
)

Changes the old boundary ID to a new ID in the mesh.

Parameters
meshthe mesh
old_idthe old boundary id
new_idthe new boundary id
delete_prevwhether to delete the previous boundary id from the mesh

Referenced by MeshExtruderGenerator::changeID(), MeshTriangulationUtils::finalizeTriangulation(), FillBetweenSidesetsGenerator::generate(), XYDelaunayGenerator::generate(), and MooseMeshElementConversionUtils::transitionLayerGenerator().

◆ changeSubdomainId()

void MooseMeshUtils::changeSubdomainId ( MeshBase &  mesh,
const subdomain_id_type  old_id,
const subdomain_id_type  new_id 
)

Changes the old subdomain ID to a new ID in the mesh.

Parameters
meshthe mesh
old_idthe old subdomain id
new_idthe new subdomain id

Definition at line 270 of file MooseMeshUtils.C.

271{
272 for (const auto & elem : mesh.element_ptr_range())
273 if (elem->subdomain_id() == old_id)
274 elem->subdomain_id() = new_id;
275
276 // global cached information may now be out of sync
277 mesh.unset_is_prepared();
278}

◆ computeDistanceToAxis()

template<typename P , typename C >
C MooseMeshUtils::computeDistanceToAxis ( const P &  point,
const Point &  origin,
const RealVectorValue &  direction 
)

Computes the distance to a general axis.

Parameters
[in]pointPoint for which to compute distance from axis
[in]originAxis starting point
[in]directionAxis direction

Definition at line 217 of file MooseMeshUtils.h.

218{
219 return (point - origin).cross(direction).norm();
220}

◆ computeFiniteVolumeCoords()

void MooseMeshUtils::computeFiniteVolumeCoords ( FaceInfo &  fi,
const Moose::CoordinateSystemType  coord_type,
const unsigned int  rz_radial_coord = libMesh::invalid_uint 
)
inline

Definition at line 251 of file MooseMeshUtils.h.

254{
255 coordTransformFactor(fi.faceCentroid(), fi.faceCoord(), coord_type, rz_radial_coord);
256}
void coordTransformFactor(const SubProblem &s, SubdomainID sub_id, const P &point, C &factor, SubdomainID neighbor_sub_id=libMesh::Elem::invalid_subdomain_id)
Computes a conversion multiplier for use when computing integraals for the current coordinate system ...
Definition Assembly.C:41
Real & faceCoord()
Sets/gets the coordinate transformation factor (for e.g.
Definition FaceInfo.h:68
const Point & faceCentroid() const
Returns the coordinates of the face centroid.
Definition FaceInfo.h:75

◆ computeMaxDistanceToAxis()

Real MooseMeshUtils::computeMaxDistanceToAxis ( const MeshBase &  mesh,
const Point &  origin,
const RealVectorValue &  direction 
)

Computes the maximum distance from all nodes of a mesh to a general axis.

Parameters
[in]meshmesh to get the distance from
[in]originAxis starting point
[in]directionAxis direction

Definition at line 364 of file MooseMeshUtils.C.

367{
368 Real distance = 0;
369 mooseAssert(MooseUtils::absoluteFuzzyEqual(direction.norm_sq(), 1),
370 "Direction should be normalized");
371 for (const auto & node : mesh.node_ptr_range())
372 if (const auto dist_node = (*node - origin).cross(direction).norm(); dist_node > distance)
373 distance = dist_node;
374 mesh.comm().max(distance);
375 return distance;
376}
Real distance(const Point &p)

Referenced by AdvancedExtruderGenerator::generate().

◆ convertBlockToMesh()

void MooseMeshUtils::convertBlockToMesh ( MeshBase &  source_mesh,
MeshBase &  target_mesh,
const std::vector< SubdomainName > &  target_blocks 
)

Convert a list of blocks in a given mesh to a standalone new mesh.

Parameters
source_meshThe source mesh from which the blocks will be converted
target_meshThe target mesh to which the blocks will be converted
target_blocksThe names of the blocks to be converted to the target mesh

Definition at line 1126 of file MooseMeshUtils.C.

1129{
1130 if (!source_mesh.is_replicated())
1131 mooseError("This generator does not support distributed meshes.");
1132
1133 const auto target_block_ids = MooseMeshUtils::getSubdomainIDs(source_mesh, target_blocks);
1134
1135 // Check that the block ids/names exist in the mesh
1136 std::set<SubdomainID> mesh_blocks;
1137 source_mesh.subdomain_ids(mesh_blocks);
1138
1139 for (const auto i : index_range(target_block_ids))
1140 if (target_block_ids[i] == Moose::INVALID_BLOCK_ID || !mesh_blocks.count(target_block_ids[i]))
1141 {
1142 mooseException("The target_block '", target_blocks[i], "' was not found within the mesh.");
1143 }
1144
1145 // know which nodes have already been inserted, by tracking the old mesh's node's ids'
1146 std::unordered_map<dof_id_type, dof_id_type> old_new_node_map;
1147
1148 for (const auto target_block_id : target_block_ids)
1149 {
1150
1151 for (auto elem : source_mesh.active_subdomain_elements_ptr_range(target_block_id))
1152 {
1153 if (elem->level() != 0)
1154 mooseError("Refined blocks are not supported by this generator. "
1155 "Can you re-organize mesh generators to refine after converting the block?");
1156
1157 // make a deep copy so that mutiple meshes' destructors don't segfault at program termination
1158 auto copy = elem->build(elem->type());
1159
1160 // Keep the subdomain id
1161 copy->subdomain_id() = elem->subdomain_id();
1162
1163 // index of node in the copy element must be managed manually as there is no intelligent
1164 // insert method
1165 dof_id_type copy_n_index = 0;
1166
1167 // correctly assign new copies of nodes, loop over nodes
1168 for (dof_id_type i : elem->node_index_range())
1169 {
1170 auto & n = elem->node_ref(i);
1171
1172 if (old_new_node_map.count(n.id()))
1173 {
1174 // case where we have already inserted this particular point before
1175 // then we need to find the already-inserted one and hook it up right
1176 // to it's respective element
1177 copy->set_node(copy_n_index++, target_mesh.node_ptr(old_new_node_map[n.id()]));
1178 }
1179 else
1180 {
1181 // case where we've NEVER inserted this particular point before
1182 // add them both to the element and the mesh
1183
1184 // Nodes' IDs are their indexes in the nodes' respective mesh
1185 // If we set them as invalid they are automatically assigned
1186 // Add to mesh, auto-assigning a new id.
1187 Node * node = target_mesh.add_point(elem->point(i));
1188
1189 // Add to element copy (manually)
1190 copy->set_node(copy_n_index++, node);
1191
1192 // remember the (old) ID
1193 old_new_node_map[n.id()] = node->id();
1194 }
1195 }
1196
1197 // it is ok to release the copy element into the mesh because derived meshes class
1198 // (ReplicatedMesh, DistributedMesh) manage their own elements, will delete them
1199 target_mesh.add_elem(copy.release());
1200 }
1201 }
1202
1203 // Move subdomain names
1204 for (const auto sbd_id : target_block_ids)
1205 target_mesh.set_subdomain_name(sbd_id, source_mesh.subdomain_name(sbd_id));
1206}
unsigned int count
Definition MortarUtils.C:53
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.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...

Referenced by Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), BlockToMeshConverterGenerator::generate(), Boundary2DDelaunayGenerator::generate(), SubdomainsFromPartitionerGenerator::generate(), and SurfaceSubdomainsDelaunayRemesher::generate().

◆ coordTransformFactor()

template<typename P , typename C >
void MooseMeshUtils::coordTransformFactor ( const P &  point,
C &  factor,
const Moose::CoordinateSystemType  coord_type,
const unsigned int  rz_radial_coord = libMesh::invalid_uint 
)

Compute a coordinate transformation volume integration factor.

Parameters
pointThe libMesh Point in space where we are evaluating the factor
factorThe output of this function. Would be 1 for cartesian coordinate systems, 2*pi*r for cylindrical coordinate systems, and 4*pi*r^2 for spherical coordinate systems
coord_typeThe coordinate system type, e.g. cartesian (COORD_XYZ), cylindrical (COORD_RZ), or spherical (COORD_RSPHERICAL)
rz_radial_coordThe index at which to index point for the radial coordinate when in a cylindrical coordinate system

Definition at line 183 of file MooseMeshUtils.h.

187{
188 switch (coord_type)
189 {
190 case Moose::COORD_XYZ:
191 factor = 1.0;
192 break;
193 case Moose::COORD_RZ:
194 {
195 mooseAssert(rz_radial_coord != libMesh::invalid_uint,
196 "Must pass in a valid rz radial coordinate");
197 factor = 2 * M_PI * point(rz_radial_coord);
198 break;
199 }
201 factor = 4 * M_PI * point(0) * point(0);
202 break;
203 default:
204 mooseError("Unknown coordinate system");
205 }
206}
@ COORD_RZ
Definition MooseTypes.h:866
@ COORD_RSPHERICAL
Definition MooseTypes.h:867
@ COORD_XYZ
Definition MooseTypes.h:865

Referenced by computeFiniteVolumeCoords(), coordTransformFactor(), Moose::FV::greenGaussGradient(), and Moose::FV::loopOverElemFaceInfo().

◆ coordTransformFactorRZGeneral()

template<typename P , typename C >
void MooseMeshUtils::coordTransformFactorRZGeneral ( const P &  point,
const std::pair< Point, RealVectorValue > &  axis,
C &  factor 
)

Computes a coordinate transformation factor for a general axisymmetric axis.

Parameters
[in]pointThe libMesh Point in space where we are evaluating the factor
[in]axisThe pair of values defining the general axisymmetric axis. Respectively, the values are the axis starting point and direction.
[out]factorThe coordinate transformation factor

Definition at line 243 of file MooseMeshUtils.h.

246{
247 factor = 2 * M_PI * computeDistanceToAxis<P, C>(point, axis.first, axis.second);
248}

Referenced by coordTransformFactor().

◆ copyIntoMesh()

void MooseMeshUtils::copyIntoMesh ( MeshGenerator &  mg,
UnstructuredMesh &  destination,
const UnstructuredMesh &  source,
const bool  avoid_merging_subdomains,
const bool  avoid_merging_boundaries,
const Parallel::Communicator &  communicator 
)

Helper function for copying one mesh into another.

Parameters
mgThe mesh generator calling this function
destinationThe mesh to copy into
sourceThe mesh to copy from
avoid_merging_subdomainsIf true, subdomain IDs in the source mesh will be offset to avoid merging with subdomain IDs in the destination mesh
avoid_merging_boundariesIf true, boundary IDs in the source mesh will be offset to avoid merging with boundary IDs in the destination mesh
communicatorThe communicator for parallel operations

Definition at line 1209 of file MooseMeshUtils.C.

1215{
1216 dof_id_type node_delta = destination.max_node_id();
1217 dof_id_type elem_delta = destination.max_elem_id();
1218
1219 unique_id_type unique_delta =
1220#ifdef LIBMESH_ENABLE_UNIQUE_ID
1221 destination.parallel_max_unique_id();
1222#else
1223 0;
1224#endif
1225
1226 // Prevent overlaps by offsetting the subdomains in
1227 std::unordered_map<subdomain_id_type, subdomain_id_type> id_remapping;
1228 unsigned int block_offset = 0;
1229 if (avoid_merging_subdomains)
1230 {
1231 // Note: if performance becomes an issue, this is overkill for just getting the max node id
1232 std::set<subdomain_id_type> source_ids;
1233 std::set<subdomain_id_type> dest_ids;
1234
1235 // We need source subdomain ids already cached; libMesh will
1236 // scream otherwise
1237 source.subdomain_ids(source_ids, true);
1238
1239 // Our destination is non-const, so we can fix any missing caches
1240 if (!destination.preparation().has_cached_elem_data)
1241 destination.cache_elem_data();
1242
1243 destination.subdomain_ids(dest_ids, true);
1244
1245 mooseAssert(source_ids.size(), "Should have a subdomain");
1246 mooseAssert(dest_ids.size(), "Should have a subdomain");
1247 unsigned int max_dest_bid = *dest_ids.rbegin();
1248 unsigned int min_source_bid = *source_ids.begin();
1249 communicator.max(max_dest_bid);
1250 communicator.min(min_source_bid);
1251 block_offset = 1 + max_dest_bid - min_source_bid;
1252 for (const auto bid : source_ids)
1253 id_remapping[bid] = block_offset + bid;
1254 }
1255
1256 // Copy mesh data over from the other mesh
1257 destination.copy_nodes_and_elements(source,
1258 // Skipping this should cause the neighbors
1259 // to simply be copied from the other mesh
1260 // (which makes sense and is way faster)
1261 /*skip_find_neighbors = */ true,
1262 elem_delta,
1263 node_delta,
1264 unique_delta,
1265 avoid_merging_subdomains ? &id_remapping : nullptr);
1266
1267 // Get an offset to prevent overlaps / wild merging between boundaries
1268 BoundaryInfo & boundary = destination.get_boundary_info();
1269 const BoundaryInfo & other_boundary = source.get_boundary_info();
1270
1271 unsigned int bid_offset = 0;
1272 if (avoid_merging_boundaries)
1273 {
1274 const auto boundary_ids = boundary.get_boundary_ids();
1275 const auto other_boundary_ids = other_boundary.get_boundary_ids();
1276 unsigned int max_dest_bid = boundary_ids.size() ? *boundary_ids.rbegin() : 0;
1277 unsigned int min_source_bid = other_boundary_ids.size() ? *other_boundary_ids.begin() : 0;
1278 communicator.max(max_dest_bid);
1279 communicator.min(min_source_bid);
1280 bid_offset = 1 + max_dest_bid - min_source_bid;
1281 }
1282
1283 // Note: the code below originally came from ReplicatedMesh::stitch_mesh_helper()
1284 // in libMesh replicated_mesh.C around line 1203
1285
1286 // Copy BoundaryInfo from other_mesh too. We do this via the
1287 // list APIs rather than element-by-element for speed.
1288 for (const auto & t : other_boundary.build_node_list())
1289 boundary.add_node(std::get<0>(t) + node_delta, bid_offset + std::get<1>(t));
1290
1291 for (const auto & t : other_boundary.build_side_list())
1292 boundary.add_side(std::get<0>(t) + elem_delta, std::get<1>(t), bid_offset + std::get<2>(t));
1293
1294 for (const auto & t : other_boundary.build_edge_list())
1295 boundary.add_edge(std::get<0>(t) + elem_delta, std::get<1>(t), bid_offset + std::get<2>(t));
1296
1297 for (const auto & t : other_boundary.build_shellface_list())
1298 boundary.add_shellface(
1299 std::get<0>(t) + elem_delta, std::get<1>(t), bid_offset + std::get<2>(t));
1300
1301 // Check for the case with two block ids sharing the same name
1302 if (avoid_merging_subdomains)
1303 {
1304 mooseAssert(mg.parameters().isParamDefined("avoid_merging_subdomains"),
1305 "Missing parameter in the mesh generator calling this function: "
1306 "avoid_merging_subdomains. Considering setting avoid_merging_subdomains to true.");
1307 for (const auto & [block_id, block_name] : destination.get_subdomain_name_map())
1308 for (const auto & [source_id, source_name] : source.get_subdomain_name_map())
1309 if (block_name == source_name)
1310 mg.paramWarning(
1311 "avoid_merging_subdomains",
1312 "Not merging subdomains is creating two subdomains with the same name '" +
1313 block_name + "' but different ids: " + std::to_string(source_id) + " & " +
1314 std::to_string(block_id + block_offset) +
1315 ".\n We recommend using a RenameBlockGenerator to prevent this as you "
1316 "will get errors reading the Exodus output later.");
1317 }
1318
1319 for (const auto & [block_id, block_name] : source.get_subdomain_name_map())
1320 destination.set_subdomain_name_map().insert(
1321 std::make_pair<SubdomainID, SubdomainName>(block_id + block_offset, block_name));
1322
1323 // Check for the case with two boundary ids sharing the same name
1324 if (avoid_merging_boundaries)
1325 {
1326 mooseAssert(mg.parameters().isParamDefined("avoid_merging_boundaries"),
1327 "Missing parameter in the mesh generator calling this function: "
1328 "avoid_merging_boundaries. Considering setting avoid_merging_boundaries to true.");
1329 for (const auto & [b_id, b_name] : other_boundary.get_sideset_name_map())
1330 for (const auto & [source_id, source_name] : boundary.get_sideset_name_map())
1331 if (b_name == source_name)
1332 mg.paramWarning(
1333 "avoid_merging_boundaries",
1334 "Not merging boundaries is creating two sidesets with the same name '" + b_name +
1335 "' but different ids: " + std::to_string(source_id) + " & " +
1336 std::to_string(b_id + bid_offset) +
1337 ".\n We recommend using a RenameBoundaryGenerator to prevent this as you "
1338 "will get errors reading the Exodus output later.");
1339 for (const auto & [b_id, b_name] : other_boundary.get_nodeset_name_map())
1340 for (const auto & [source_id, source_name] : boundary.get_nodeset_name_map())
1341 if (b_name == source_name)
1342 mg.paramWarning(
1343 "avoid_merging_boundaries",
1344 "Not merging boundaries is creating two nodesets with the same name '" + b_name +
1345 "' but different ids: " + std::to_string(source_id) + " & " +
1346 std::to_string(b_id + bid_offset) +
1347 ".\n We recommend using a RenameBoundaryGenerator to prevent this as you "
1348 "will get errors reading the Exodus output later.");
1349 }
1350
1351 for (const auto & [nodeset_id, nodeset_name] : other_boundary.get_nodeset_name_map())
1352 boundary.set_nodeset_name_map().insert(
1353 std::make_pair<BoundaryID, BoundaryName>(nodeset_id + bid_offset, nodeset_name));
1354
1355 for (const auto & [sideset_id, sideset_name] : other_boundary.get_sideset_name_map())
1356 boundary.set_sideset_name_map().insert(
1357 std::make_pair<BoundaryID, BoundaryName>(sideset_id + bid_offset, sideset_name));
1358
1359 for (const auto & [edgeset_id, edgeset_name] : other_boundary.get_edgeset_name_map())
1360 boundary.set_edgeset_name_map().insert(
1361 std::make_pair<BoundaryID, BoundaryName>(edgeset_id + bid_offset, edgeset_name));
1362}
boundary_id_type BoundaryID
subdomain_id_type SubdomainID
bool isParamDefined(const std::string &name) const
Method returns true if the parameter is defined for any type.
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const Elem & get(const ElemType type_in)

Referenced by CombinerGenerator::generate(), and XYZDelaunayGenerator::generate().

◆ createSubdomainFromSidesets()

void MooseMeshUtils::createSubdomainFromSidesets ( MeshBase &  mesh,
std::vector< BoundaryName >  boundary_names,
const SubdomainID  new_subdomain_id,
const SubdomainName &  new_subdomain_name 
)

Create a new subdomain by generating new side elements from a list of sidesets in a given mesh.

Parameters
meshThe mesh to work on
boundary_namesThe names of the sidesets to be used to create the new subdomain
new_subdomain_idThe ID of the new subdomain to be created based on the sidesets
new_subdomain_nameThe name of the new subdomain to be created based on the sidesets
type_nameThe type of the mesh generator that is calling this method, used for error messages and debugging purposes.

Definition at line 1027 of file MooseMeshUtils.C.

1031{
1032 // Generate a new block id if one isn't supplied.
1033 SubdomainID new_block_id = new_subdomain_id;
1034
1035 // Make sure our boundary info and parallel counts are setup
1036 if (!mesh.is_prepared())
1037 {
1038 const bool allow_remote_element_removal = mesh.allow_remote_element_removal();
1039 // We want all of our boundary elements available, so avoid removing them if they haven't
1040 // already been so
1041 mesh.allow_remote_element_removal(false);
1042 mesh.complete_preparation();
1043 mesh.allow_remote_element_removal(allow_remote_element_removal);
1044 }
1045
1046 // Check that the sidesets are present in the mesh
1047 for (const auto & sideset : boundary_names)
1048 if (!MooseMeshUtils::hasBoundaryNameOrID(mesh, sideset))
1049 mooseException("The sideset '", sideset, "' was not found within the mesh");
1050
1051 auto sideset_ids = MooseMeshUtils::getBoundaryIDs(mesh, boundary_names, true);
1052 std::set<boundary_id_type> sidesets(sideset_ids.begin(), sideset_ids.end());
1053 auto side_list = mesh.get_boundary_info().build_side_list();
1054 if (!mesh.is_serial() && mesh.comm().size() > 1)
1055 {
1056 std::vector<Elem *> elements_to_send;
1057 unsigned short i_need_boundary_elems = 0;
1058 for (const auto & [elem_id, side, bc_id] : side_list)
1059 {
1060 libmesh_ignore(side);
1061 if (sidesets.count(bc_id))
1062 {
1063 // Whether we have this boundary information through our locally owned element or a ghosted
1064 // element, we'll need the boundary elements for parallel consistent addition
1065 i_need_boundary_elems = 1;
1066 auto * elem = mesh.elem_ptr(elem_id);
1067 if (elem->processor_id() == mesh.processor_id())
1068 elements_to_send.push_back(elem);
1069 }
1070 }
1071
1072 std::set<const Elem *, libMesh::CompareElemIdsByLevel> connected_elements(
1073 elements_to_send.begin(), elements_to_send.end());
1074 std::set<const Node *> connected_nodes;
1075 reconnect_nodes(connected_elements, connected_nodes);
1076 std::set<dof_id_type> connected_node_ids;
1077 for (auto * nd : connected_nodes)
1078 connected_node_ids.insert(nd->id());
1079
1080 std::vector<unsigned short> need_boundary_elems(mesh.comm().size());
1081 mesh.comm().allgather(i_need_boundary_elems, need_boundary_elems);
1082 std::unordered_map<processor_id_type, decltype(elements_to_send)> push_element_data;
1083 std::unordered_map<processor_id_type, decltype(connected_nodes)> push_node_data;
1084
1085 for (const auto pid : index_range(mesh.comm()))
1086 // Don't need to send to self
1087 if (pid != mesh.processor_id() && need_boundary_elems[pid])
1088 {
1089 if (elements_to_send.size())
1090 push_element_data[pid] = elements_to_send;
1091 if (connected_nodes.size())
1092 push_node_data[pid] = connected_nodes;
1093 }
1094
1095 auto node_action_functor = [](processor_id_type, const auto &)
1096 {
1097 // Node packing specialization already has unpacked node into mesh, so nothing to do
1098 };
1099 Parallel::push_parallel_packed_range(mesh.comm(), push_node_data, &mesh, node_action_functor);
1100 auto elem_action_functor = [](processor_id_type, const auto &)
1101 {
1102 // Elem packing specialization already has unpacked elem into mesh, so nothing to do
1103 };
1104 TIMPI::push_parallel_packed_range(mesh.comm(), push_element_data, &mesh, elem_action_functor);
1105
1106 // now that we've gathered everything, we need to rebuild the side list
1107 side_list = mesh.get_boundary_info().build_side_list();
1108 }
1109
1110 // Use libmesh's BoundaryInfo::add_elements to create lower-d elements with interior_parent
1111 // pointers and subdomain IDs set in one pass.
1112 auto & unstr_mesh = libMesh::cast_ref<UnstructuredMesh &>(mesh);
1113 unstr_mesh.get_boundary_info().add_elements(sidesets, unstr_mesh, false, {new_block_id});
1114
1115 // Assign block name, if provided
1116 if (new_subdomain_name.size())
1117 mesh.set_subdomain_name(new_block_id, new_subdomain_name);
1118
1119 const bool skip_partitioning_old = mesh.skip_partitioning();
1120 mesh.skip_partitioning(true);
1121 mesh.prepare_for_use();
1122 mesh.skip_partitioning(skip_partitioning_old);
1123}
std::set< std::string > sideset
uint8_t processor_id_type
void push_parallel_packed_range(const Communicator &comm, MapToContainers &&data, Context *context, const ActionFunctor &act_on_data)
void reconnect_nodes(connected_elem_set_type &connected_elements, connected_node_set_type &connected_nodes)
auto index_range(const T &sizable)

Referenced by Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), Boundary2DDelaunayGenerator::generate(), and LowerDBlockFromSidesetGenerator::generate().

◆ extraElemIntegerSwapParametersProcessor()

void MooseMeshUtils::extraElemIntegerSwapParametersProcessor ( const std::string &  class_name,
const unsigned int  num_sections,
const unsigned int  num_integers,
const std::vector< std::vector< std::vector< dof_id_type > > > &  elem_integers_swaps,
std::vector< std::unordered_map< dof_id_type, dof_id_type > > &  elem_integers_swap_pairs 
)

Reprocess the elem_integers_swaps into maps so they are easier to use.

Parameters
class_namename of the mesh generator class used for exception messages
num_sectionsnumber of sections in the mesh
num_integersnumber of extra element integers in the mesh
elem_integers_swapsvector of vectors of vectors of extra element ids to be swapped
elem_integers_swap_pairsvector of maps of the swapped pairs

Definition at line 674 of file MooseMeshUtils.C.

680{
681 elem_integers_swap_pairs.reserve(num_sections * num_integers);
682 for (const auto i : make_range(num_integers))
683 {
684 const auto & elem_integer_swaps = elem_integers_swaps[i];
685 std::vector<std::unordered_map<dof_id_type, dof_id_type>> elem_integer_swap_pairs;
686 try
687 {
689 "elem_integers_swaps",
690 elem_integer_swaps,
691 elem_integer_swap_pairs,
692 i * num_sections);
693 }
694 catch (const MooseException & e)
695 {
696 throw MooseException(e.what());
697 }
698
699 elem_integers_swap_pairs.insert(elem_integers_swap_pairs.end(),
700 elem_integer_swap_pairs.begin(),
701 elem_integer_swap_pairs.end());
702 }
703}
Provides a way for users to bail out of the current solve.
virtual const char * what() const
Get out the error message.
void idSwapParametersProcessor(const std::string &class_name, const std::string &id_name, const std::vector< std::vector< T > > &id_swaps, std::vector< std::unordered_map< T, T > > &id_swap_pairs, const unsigned int row_index_shift=0)
Reprocess the swap related input parameters to make pairs out of them to ease further processing.

Referenced by AdvancedExtruderGenerator::AdvancedExtruderGenerator().

◆ getBoundaryID()

BoundaryID MooseMeshUtils::getBoundaryID ( const BoundaryName &  boundary_name,
const MeshBase &  mesh 
)

Gets the boundary ID associated with the given BoundaryName.

This is needed because the BoundaryName can be either an ID or a name. If it is a name, the mesh is queried for the ID associated with said name.

Definition at line 237 of file MooseMeshUtils.C.

238{
240 if (boundary_name.empty())
241 return id;
242
243 if (!MooseUtils::isDigits(boundary_name))
244 id = mesh.get_boundary_info().get_id_by_name(boundary_name);
245 else
246 id = getIDFromName<BoundaryName, BoundaryID>(boundary_name);
247
248 return id;
249}
const BoundaryID INVALID_BOUNDARY_ID
Definition MooseTypes.C:22

Referenced by BoundaryDeletionGenerator::generate(), CutMeshByLevelSetGeneratorBase::generate(), MoveBoundaryNodesToCurveGenerator::generate(), PolyLineMeshFollowingNodeSetGenerator::generate(), RenameBoundaryGenerator::generate(), MooseMesh::getBoundaryID(), hasBoundaryNameOrID(), MeshTriangulationUtils::outerBoundaryIds(), Moose::PeriodicBCHelper::setupManualPeriodicBoundaries(), and MooseMeshElementConversionUtils::transitionLayerGenerator().

◆ getBoundaryIDs() [1/4]

std::vector< BoundaryID > MooseMeshUtils::getBoundaryIDs ( const libMesh::MeshBase &  mesh,
const std::vector< BoundaryName > &  boundary_name,
bool  generate_unknown 
)

Gets the boundary IDs with their names.

The ordering of the returned boundary ID vector matches the vector of the boundary names in boundary_name.

When a boundary name is not available in the mesh, if generate_unknown is true a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id will be returned.

If generate_unknown is true and !mesh.preparation().has_boundary_id_sets, this must be called across all ranks for synchronization.

◆ getBoundaryIDs() [2/4]

std::vector< BoundaryID > MooseMeshUtils::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.

The ordering of the returned boundary ID vector matches the vector of the boundary names in boundary_name.

When a boundary name is not available in the mesh, if generate_unknown is true a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id will be returned.

If generate_unknown is true and !mesh.preparation().has_boundary_id_sets, this must be called across all ranks for synchronization.

Referenced by BoundaryPreservedMarker::BoundaryPreservedMarker(), BoundaryLayerUtils::buildBoundaryLayerRing(), buildPolyLineMesh(), MeshExtruderGenerator::changeID(), createSubdomainFromSidesets(), MeshTriangulationUtils::finalizeTriangulation(), FunctorNodalCorrector::FunctorNodalCorrector(), Boundary2DDelaunayGenerator::General2DDelaunay(), AdvancedExtruderGenerator::generate(), BoundaryLayerSubdomainGenerator::generate(), BoundingBoxNodeSetGenerator::generate(), BreakBoundaryOnSubdomainGenerator::generate(), CircularBoundaryCorrectionGenerator::generate(), CoarsenSurfaceMeshAlongSidesetGenerator::generate(), ElementDeletionGeneratorBase::generate(), ExtraNodesetGenerator::generate(), FillBetweenSidesetsGenerator::generate(), MeshDiagnosticsGenerator::generate(), ParsedGenerateNodeset::generate(), ParsedGenerateSideset::generate(), PolyLineMeshFollowingNodeSetGenerator::generate(), RefineSidesetGenerator::generate(), SideSetsAroundSubdomainGenerator::generate(), SideSetsBetweenSubdomainsGenerator::generate(), SideSetsFromBoundingBoxGenerator::generate(), SideSetsFromNormalsGenerator::generate(), SideSetsFromPointsGenerator::generate(), StackGenerator::generate(), XYDelaunayGenerator::generate(), XYTriangleBoundaryLayerGenerator::generate(), PatternedMeshGenerator::generate(), getBoundaryIDs(), MooseMesh::getBoundaryIDs(), getBoundaryIDSet(), NodeSetsGeneratorBase::setup(), and SideSetsGeneratorBase::setup().

◆ getBoundaryIDs() [3/4]

std::vector< boundary_id_type > MooseMeshUtils::getBoundaryIDs ( const MeshBase &  mesh,
const std::vector< BoundaryName > &  boundary_name,
bool  generate_unknown 
)

Definition at line 107 of file MooseMeshUtils.C.

110{
111 return getBoundaryIDs(
112 mesh, boundary_name, generate_unknown, mesh.get_boundary_info().get_boundary_ids());
113}

◆ getBoundaryIDs() [4/4]

std::vector< boundary_id_type > MooseMeshUtils::getBoundaryIDs ( const MeshBase &  mesh,
const std::vector< BoundaryName > &  boundary_name,
bool  generate_unknown,
const std::set< BoundaryID > &  mesh_boundary_ids 
)

If the conversion from a name to a number fails, that means that this must be a named boundary. We will look in the complete map for this sideset and create a new name/ID pair if requested.

Definition at line 116 of file MooseMeshUtils.C.

120{
121 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
122 const std::map<BoundaryID, std::string> & sideset_map = boundary_info.get_sideset_name_map();
123 const std::map<BoundaryID, std::string> & nodeset_map = boundary_info.get_nodeset_name_map();
124
125 /* It is required to generate a new ID for a given name. It is used often in mesh modifiers such
126 * as SideSetsBetweenSubdomains. Then we need to check the current boundary ids since they are
127 * changing during "mesh modify()", and figure out the right max boundary ID. Most of mesh
128 * modifiers are running in serial, and we won't involve a global communication.
129 */
130 BoundaryID max_boundary_id = 0;
131 if (generate_unknown)
132 {
133 bool has_boundary_id_sets = mesh.preparation().has_boundary_id_sets;
134
135 // Ideally, this requirement should be able to be enforced earlier when we
136 // get the name maps. However, that preparedness check on sideset and
137 // nodeset maps doesn't exist yet.
138 if (!has_boundary_id_sets)
139 libmesh_parallel_only(mesh.comm());
140
141 const auto & bids = has_boundary_id_sets ? boundary_info.get_global_boundary_ids()
142 : boundary_info.get_boundary_ids();
143 if (bids.size())
144 max_boundary_id = *(bids.rbegin());
145 if (!has_boundary_id_sets)
146 mesh.comm().max(max_boundary_id);
147 }
148
149 std::vector<BoundaryID> ids(boundary_name.size());
150 for (const auto i : index_range(boundary_name))
151 {
152 if (boundary_name[i] == "ANY_BOUNDARY_ID")
153 {
154 ids.assign(mesh_boundary_ids.begin(), mesh_boundary_ids.end());
155 if (i)
156 mooseWarning("You passed \"ANY_BOUNDARY_ID\" in addition to other boundary_names. This "
157 "may be a logic error.");
158 break;
159 }
160
161 if (boundary_name[i].empty() && !generate_unknown)
162 mooseError("Incoming boundary name is empty and we are not generating unknown boundary IDs. "
163 "This is invalid.");
164
165 BoundaryID id;
166
167 if (boundary_name[i].empty() || !MooseUtils::isDigits(boundary_name[i]))
168 {
174 if (generate_unknown &&
175 !MooseUtils::doesMapContainValue(sideset_map, std::string(boundary_name[i])) &&
176 !MooseUtils::doesMapContainValue(nodeset_map, std::string(boundary_name[i])))
177 id = ++max_boundary_id;
178 else
179 id = boundary_info.get_id_by_name(boundary_name[i]);
180 }
181 else
182 id = getIDFromName<BoundaryName, BoundaryID>(boundary_name[i]);
183
184 ids[i] = id;
185 }
186
187 return ids;
188}

◆ getBoundaryIDSet() [1/2]

std::set< BoundaryID > MooseMeshUtils::getBoundaryIDSet ( const libMesh::MeshBase &  mesh,
const std::vector< BoundaryName > &  boundary_name,
bool  generate_unknown 
)

Gets the boundary IDs into a set with their names.

Because libMesh allows the same boundary to have multiple different boundary names, the size of the returned boundary ID set may be smaller than the size of the boundary name vector.

When a boundary name is not available in the mesh, if generate_unknown is true a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id will be returned.

If generate_unknown is true and !mesh.preparation().has_boundary_id_sets, this must be called across all ranks for synchronization.

Referenced by DomainUserObject::DomainUserObject().

◆ getBoundaryIDSet() [2/2]

std::set< BoundaryID > MooseMeshUtils::getBoundaryIDSet ( const MeshBase &  mesh,
const std::vector< BoundaryName > &  boundary_name,
bool  generate_unknown 
)

Definition at line 191 of file MooseMeshUtils.C.

194{
195 auto boundaries = getBoundaryIDs(mesh, boundary_name, generate_unknown);
196 return std::set<BoundaryID>(boundaries.begin(), boundaries.end());
197}

◆ getBoundaryNodes()

std::set< dof_id_type > MooseMeshUtils::getBoundaryNodes ( const MeshBase &  mesh,
const BoundaryID  boundary_id 
)

Get all the nodes on that particular boundary, whether a nodeset or a sideset.

Note: if the mesh has both a nodeset and a sideset with the same ID, they will both be considered If this is undesirable, renumber one of them prior to calling this routine

Parameters
input_meshThe input mesh to get the map for
boundary_idThe boundary id of interest

Definition at line 999 of file MooseMeshUtils.C.

1000{
1001 std::set<dof_id_type> boundary_node_ids;
1002 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
1003
1004 // Get all nodes from the sideset with ID of boundary_id
1005 const auto & bc_sides =
1006 boundary_info.build_side_list(libMesh::BoundaryInfo::BCTupleSortBy::BOUNDARY_ID);
1007 for (const auto & [elem_id, side, bc_id] : bc_sides)
1008 {
1009 if (bc_id == boundary_id)
1010 {
1011 const auto elem = mesh.elem_ptr(elem_id);
1012 for (const auto ni : elem->nodes_on_side(side))
1013 boundary_node_ids.insert(elem->node_id(ni));
1014 }
1015 }
1016
1017 // Get all nodes from nodeset with ID of boundary_id
1018 const auto & bc_nodes = boundary_info.build_node_list();
1019 for (const auto & [n_id, bc_id] : bc_nodes)
1020 if (bc_id == boundary_id)
1021 boundary_node_ids.insert(n_id);
1022
1023 return boundary_node_ids;
1024}

Referenced by buildBoundaryNodeToElemMap().

◆ getExtraIDUniqueCombinationMap()

std::unordered_map< dof_id_type, dof_id_type > MooseMeshUtils::getExtraIDUniqueCombinationMap ( const MeshBase &  mesh,
const std::set< SubdomainID > &  block_ids,
std::vector< ExtraElementIDName >  extra_ids 
)

Create a new set of element-wise IDs by finding unique combinations of existing extra ID values.

This function finds the unique combinations by recursively calling itself for extra ID inputs. In the recursive calling, the new unique combinations is determined by combining the extra ID value of current level and the unique combination determined in the previous level in recursion. In the lowest level of recursion, the base combination is set by the unique ID values of the corresponding extra ID.

Parameters
meshinput mesh
block_idsblock ids
extra_idsextra ids
Returns
map of element id to new extra id

Definition at line 379 of file MooseMeshUtils.C.

382{
383 // check block restriction
384 const bool block_restricted = !block_ids.empty();
385 // get element id name of interest in recursive parsing algorithm
386 ExtraElementIDName id_name = extra_ids.back();
387 extra_ids.pop_back();
388 const auto id_index = mesh.get_elem_integer_index(id_name);
389
390 // create base parsed id set
391 if (extra_ids.empty())
392 {
393 // get set of extra id values;
394 std::vector<dof_id_type> ids;
395 {
396 std::set<dof_id_type> ids_set;
397 for (const auto & elem : mesh.active_element_ptr_range())
398 {
399 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
400 continue;
401 const auto id = elem->get_extra_integer(id_index);
402 ids_set.insert(id);
403 }
404 mesh.comm().set_union(ids_set);
405 ids.assign(ids_set.begin(), ids_set.end());
406 }
407
408 // determine new extra id values;
409 std::unordered_map<dof_id_type, dof_id_type> parsed_ids;
410 for (auto & elem : mesh.active_element_ptr_range())
411 {
412 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
413 continue;
414 parsed_ids[elem->id()] = std::distance(
415 ids.begin(), std::lower_bound(ids.begin(), ids.end(), elem->get_extra_integer(id_index)));
416 }
417 return parsed_ids;
418 }
419
420 // if extra_ids is not empty, recursively call getExtraIDUniqueCombinationMap
421 const auto base_parsed_ids =
422 MooseMeshUtils::getExtraIDUniqueCombinationMap(mesh, block_ids, extra_ids);
423 // parsing extra ids based on ref_parsed_ids
424 std::vector<std::pair<dof_id_type, dof_id_type>> unique_ids;
425 {
426 std::set<std::pair<dof_id_type, dof_id_type>> unique_ids_set;
427 for (const auto & elem : mesh.active_element_ptr_range())
428 {
429 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
430 continue;
431 const dof_id_type id1 = libmesh_map_find(base_parsed_ids, elem->id());
432 const dof_id_type id2 = elem->get_extra_integer(id_index);
433 const std::pair<dof_id_type, dof_id_type> ids = std::make_pair(id1, id2);
434 unique_ids_set.insert(ids);
435 }
436 mesh.comm().set_union(unique_ids_set);
437 unique_ids.assign(unique_ids_set.begin(), unique_ids_set.end());
438 }
439
440 std::unordered_map<dof_id_type, dof_id_type> parsed_ids;
441
442 for (const auto & elem : mesh.active_element_ptr_range())
443 {
444 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
445 continue;
446 const dof_id_type id1 = libmesh_map_find(base_parsed_ids, elem->id());
447 const dof_id_type id2 = elem->get_extra_integer(id_index);
448 const dof_id_type new_id = std::distance(
449 unique_ids.begin(),
450 std::lower_bound(unique_ids.begin(), unique_ids.end(), std::make_pair(id1, id2)));
451 parsed_ids[elem->id()] = new_id;
452 }
453
454 return parsed_ids;
455}
std::unordered_map< dof_id_type, dof_id_type > getExtraIDUniqueCombinationMap(const MeshBase &mesh, const std::set< SubdomainID > &block_ids, std::vector< ExtraElementIDName > extra_ids)
Create a new set of element-wise IDs by finding unique combinations of existing extra ID values.

Referenced by ExtraIDIntegralVectorPostprocessor::ExtraIDIntegralVectorPostprocessor(), UniqueExtraIDMeshGenerator::generate(), and getExtraIDUniqueCombinationMap().

◆ getIDFromName()

template<typename T , typename Q >
Q MooseMeshUtils::getIDFromName ( const T &  name)

Converts a given name (BoundaryName or SubdomainName) that is known to only contain digits into a corresponding ID (BoundaryID or SubdomainID) and performs bounds checking to ensure that overflow doesn't happen.

Parameters
nameName that is to be converted into an ID.
Returns
ID type corresponding to the type of name.

Definition at line 395 of file MooseMeshUtils.h.

396{
397 if (!MooseUtils::isDigits(name))
399 "'name' ", name, " should only contain digits that can be converted to a numerical type.");
400 long long id = std::stoll(name);
401 Q id_Q = Q(id);
402 if (id < std::numeric_limits<Q>::min() || id > std::numeric_limits<Q>::max())
403 mooseError(MooseUtils::prettyCppType<T>(&name),
404 " ",
405 name,
406 " is not within the numeric limits of the expected ID type ",
407 MooseUtils::prettyCppType<Q>(&id_Q),
408 ".");
409
410 return id_Q;
411}

◆ getNextFreeBoundaryID()

BoundaryID MooseMeshUtils::getNextFreeBoundaryID ( MeshBase &  input_mesh)

Checks input mesh and returns the largest boundary ID in the mesh plus one, which is a boundary ID in the mesh that is not currently in use.

Parameters
inputmesh over which to compute the next free boundary ID

Definition at line 520 of file MooseMeshUtils.C.

521{
522 if (!input_mesh.preparation().has_boundary_id_sets)
523 input_mesh.get_boundary_info().regenerate_id_sets();
524
525 auto boundary_ids = input_mesh.get_boundary_info().get_boundary_ids();
526 if (boundary_ids.empty())
527 return 0;
528 return (*boundary_ids.rbegin() + 1);
529}

Referenced by MeshTriangulationUtils::finalizeTriangulation(), Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), CutMeshByLevelSetGeneratorBase::generate(), SurfaceSubdomainsDelaunayRemesher::generate(), XYDelaunayGenerator::generate(), XYMeshLineCutter::generate(), XYZDelaunayGenerator::generate(), and MooseMeshElementConversionUtils::transitionLayerGenerator().

◆ getNextFreeSubdomainID()

SubdomainID MooseMeshUtils::getNextFreeSubdomainID ( MeshBase &  input_mesh)

Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in use in the mesh.

Parameters
inputmesh over which to compute the next free block id

Definition at line 500 of file MooseMeshUtils.C.

501{
502 // Call this to get most up to date block id information
503 input_mesh.cache_elem_data();
504
505 std::set<SubdomainID> preexisting_subdomain_ids;
506 input_mesh.subdomain_ids(preexisting_subdomain_ids);
507 if (preexisting_subdomain_ids.empty())
508 return 0;
509 else
510 {
511 const auto highest_subdomain_id =
512 *std::max_element(preexisting_subdomain_ids.begin(), preexisting_subdomain_ids.end());
513 mooseAssert(highest_subdomain_id < std::numeric_limits<SubdomainID>::max(),
514 "A SubdomainID with max possible value was found");
515 return highest_subdomain_id + 1;
516 }
517}

Referenced by MeshTriangulationUtils::finalizeTriangulation(), Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), Boundary2DDelaunayGenerator::generate(), BoundaryLayerSubdomainGenerator::generate(), CutMeshByLevelSetGeneratorBase::generate(), LowerDBlockFromSidesetGenerator::generate(), ProjectSideSetOntoLevelSetGenerator::generate(), SurfaceSubdomainsFromAllNormalsGenerator::generate(), XYZDelaunayGenerator::generate(), TriToQuadConverter::recombine(), MeshRepairGenerator::separateSubdomainsByElementType(), TriToQuadConverter::subdivide(), and MooseMeshElementConversionUtils::transitionLayerGenerator().

◆ getSubdomainID()

SubdomainID MooseMeshUtils::getSubdomainID ( const SubdomainName &  subdomain_name,
const MeshBase &  mesh 
)

Gets the subdomain ID associated with the given SubdomainName.

This is needed because the SubdomainName can be either an ID or a name. If it is a name, the mesh is queried for the ID associated with said name.

Definition at line 252 of file MooseMeshUtils.C.

253{
254 if (subdomain_name == "ANY_BLOCK_ID")
255 mooseError("getSubdomainID() does not work with \"ANY_BLOCK_ID\"");
256
258 if (subdomain_name.empty())
259 return id;
260
261 if (!MooseUtils::isDigits(subdomain_name))
262 id = mesh.get_id_by_name(subdomain_name);
263 else
264 id = getIDFromName<SubdomainName, SubdomainID>(subdomain_name);
265
266 return id;
267}
const SubdomainID INVALID_BLOCK_ID
Definition MooseTypes.C:20

Referenced by MeshTriangulationUtils::finalizeTriangulation(), ManifoldSubdomainGenerator::generate(), ParsedExtraElementIDGenerator::generate(), RenameBlockGenerator::generate(), RenumberBySubdomainGenerator::generate(), SubdomainBoundingBoxGenerator::generate(), SubdomainsFromPartitionerGenerator::generate(), UniqueExtraIDMeshGenerator::generate(), XYZDelaunayGenerator::generate(), MooseMesh::getSubdomainID(), getSubdomainIDs(), hasSubdomainName(), TriToQuadConverter::moveSurvivingTriangles(), MooseMeshXYCuttingUtils::quadToTriOnLine(), and MooseMeshXYCuttingUtils::quasiTriElementsFixer().

◆ getSubdomainIDs() [1/4]

std::set< subdomain_id_type > MooseMeshUtils::getSubdomainIDs ( const libMesh::MeshBase &  mesh,
const std::set< SubdomainName > &  subdomain_name 
)

◆ getSubdomainIDs() [2/4]

std::vector< subdomain_id_type > MooseMeshUtils::getSubdomainIDs ( const libMesh::MeshBase &  mesh,
const std::vector< SubdomainName > &  subdomain_name 
)

◆ getSubdomainIDs() [3/4]

std::set< subdomain_id_type > MooseMeshUtils::getSubdomainIDs ( const MeshBase &  mesh,
const std::set< SubdomainName > &  subdomain_names 
)

Definition at line 229 of file MooseMeshUtils.C.

230{
231 const auto blk_ids = getSubdomainIDs(
232 mesh, std::vector<SubdomainName>(subdomain_names.begin(), subdomain_names.end()));
233 return {blk_ids.begin(), blk_ids.end()};
234}

◆ getSubdomainIDs() [4/4]

std::vector< subdomain_id_type > MooseMeshUtils::getSubdomainIDs ( const MeshBase &  mesh,
const std::vector< SubdomainName > &  subdomain_names 
)

Definition at line 200 of file MooseMeshUtils.C.

201{
202 std::vector<subdomain_id_type> ids;
203
204 // shortcut for "ANY_BLOCK_ID"
205 if (subdomain_names.size() == 1 && subdomain_names[0] == "ANY_BLOCK_ID")
206 {
207 // since get_mesh_subdomains() requires a prepared mesh, we need to check that here
208 mooseAssert(mesh.is_prepared(),
209 "getSubdomainIDs() should only be called on a prepared mesh if ANY_BLOCK_ID is "
210 "used to query all block IDs");
211 ids.assign(mesh.get_mesh_subdomains().begin(), mesh.get_mesh_subdomains().end());
212 return ids;
213 }
214
215 // loop through subdomain names and get IDs (this preserves the order of subdomain_names)
216 ids.resize(subdomain_names.size());
217 for (auto i : index_range(subdomain_names))
218 {
219 if (subdomain_names[i] == "ANY_BLOCK_ID")
220 mooseError("getSubdomainIDs() accepts \"ANY_BLOCK_ID\" if and only if it is the only "
221 "subdomain name being queried.");
222 ids[i] = MooseMeshUtils::getSubdomainID(subdomain_names[i], mesh);
223 }
224
225 return ids;
226}
SubdomainID getSubdomainID(const SubdomainName &subdomain_name, const MeshBase &mesh)
Gets the subdomain ID associated with the given SubdomainName.

◆ hasBoundaryID()

bool MooseMeshUtils::hasBoundaryID ( const MeshBase &  input_mesh,
const BoundaryID  id 
)

Whether a particular boundary ID exists in the mesh.

Parameters
inputmesh over which to determine boundary IDs
boundaryID

Definition at line 553 of file MooseMeshUtils.C.

554{
555 const BoundaryInfo & boundary_info = input_mesh.get_boundary_info();
556 std::set<boundary_id_type> boundary_ids = boundary_info.get_boundary_ids();
557
558 // On a distributed mesh we may have boundary IDs that only exist on
559 // other processors
560 if (!input_mesh.is_replicated())
561 input_mesh.comm().set_union(boundary_ids);
562
563 return boundary_ids.count(id) && (id != Moose::INVALID_BOUNDARY_ID);
564}

Referenced by MooseMeshXYCuttingUtils::boundaryTriElemImprover(), AdvancedExtruderGenerator::generate(), XYMeshLineCutter::generate(), and hasBoundaryNameOrID().

◆ hasBoundaryName()

bool MooseMeshUtils::hasBoundaryName ( const MeshBase &  mesh,
const BoundaryName &  name 
)

Whether a particular boundary name exists in the mesh.

This returns true if name is non-empty and is a name (not ID) that exists.

Parameters
meshmesh over which to determine boundary names
nameboundary name

Definition at line 567 of file MooseMeshUtils.C.

568{
569 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
570 const BoundaryID id = boundary_info.get_id_by_name(name);
571 return id != Moose::INVALID_BOUNDARY_ID;
572}

◆ hasBoundaryNameOrID()

bool MooseMeshUtils::hasBoundaryNameOrID ( const MeshBase &  mesh,
const BoundaryName &  name_or_id 
)

Whether a particular boundary name or ID exists in the mesh.

This returns true if name_or_id is non-empty and either a name or ID that exists.

Parameters
meshmesh over which to determine boundary names
name_or_idboundary name or ID

Definition at line 575 of file MooseMeshUtils.C.

576{
577 const auto id = getBoundaryID(name_or_id, mesh);
578 return hasBoundaryID(mesh, id);
579}
bool hasBoundaryID(const MeshBase &input_mesh, const BoundaryID id)
Whether a particular boundary ID exists in the mesh.
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.

Referenced by createSubdomainFromSidesets(), MultiAppNearestNodeTransfer::execute(), MultiAppUserObjectTransfer::execute(), BreakBoundaryOnSubdomainGenerator::generate(), CircularBoundaryCorrectionGenerator::generate(), CutMeshByLevelSetGeneratorBase::generate(), MeshDiagnosticsGenerator::generate(), MoveBoundaryNodesToCurveGenerator::generate(), MultiAppNearestNodeTransfer::getLocalEntitiesAndComponents(), MultiAppNearestNodeTransfer::getTargetLocalNodes(), MultiAppGeneralFieldTransfer::initialSetup(), and MooseMeshElementConversionUtils::transitionLayerGenerator().

◆ hasSubdomainID()

bool MooseMeshUtils::hasSubdomainID ( const MeshBase &  input_mesh,
const SubdomainID &  id 
)

Whether a particular subdomain ID exists in the mesh.

Parameters
inputmesh over which to determine subdomain IDs
subdomainID

Definition at line 532 of file MooseMeshUtils.C.

533{
534 std::set<SubdomainID> mesh_blocks;
535 input_mesh.subdomain_ids(mesh_blocks);
536
537 // On a distributed mesh we may have sideset IDs that only exist on
538 // other processors
539 if (!input_mesh.is_replicated())
540 input_mesh.comm().set_union(mesh_blocks);
541
542 return mesh_blocks.count(id) && (id != Moose::INVALID_BLOCK_ID);
543}

Referenced by MooseMeshElementConversionUtils::assignConvertedElementsSubdomainNameSuffix(), AdvancedExtruderGenerator::generate(), BlockDeletionGenerator::generate(), BreakMeshByElementGenerator::generate(), CoarsenBlockGenerator::generate(), ManifoldSubdomainGenerator::generate(), MeshExtruderGenerator::generate(), RefineBlockGenerator::generate(), and hasSubdomainName().

◆ hasSubdomainName()

bool MooseMeshUtils::hasSubdomainName ( const MeshBase &  input_mesh,
const SubdomainName &  name 
)

◆ idSwapParametersProcessor()

template<typename T >
void MooseMeshUtils::idSwapParametersProcessor ( const std::string &  class_name,
const std::string &  id_name,
const std::vector< std::vector< T > > &  id_swaps,
std::vector< std::unordered_map< T, T > > &  id_swap_pairs,
const unsigned int  row_index_shift = 0 
)

Reprocess the swap related input parameters to make pairs out of them to ease further processing.

Parameters
class_namename of the mesh generator class used for exception messages
id_namename of the parameter to be swapped used for exception messages
id_swapsvector of vectors of the ids to be swapped
id_swap_pairsvector of maps of the swapped pairs
row_index_shiftshift to be applied to the row index in the exception messages (useful when this method is utilized to process a fraction of a long vector)

Definition at line 432 of file MooseMeshUtils.h.

437{
438 id_swap_pairs.resize(id_swaps.size());
439 for (const auto i : index_range(id_swaps))
440 {
441 const auto & swaps = id_swaps[i];
442 auto & swap_pairs = id_swap_pairs[i];
443
444 if (swaps.size() % 2)
445 throw MooseException("Row ",
446 row_index_shift + i + 1,
447 " of ",
448 id_name,
449 " in ",
450 class_name,
451 " does not contain an even number of entries! Num entries: ",
452 swaps.size());
453
454 swap_pairs.reserve(swaps.size() / 2);
455 for (unsigned int j = 0; j < swaps.size(); j += 2)
456 swap_pairs[swaps[j]] = swaps[j + 1];
457 }
458}

Referenced by AdvancedExtruderGenerator::AdvancedExtruderGenerator(), and extraElemIntegerSwapParametersProcessor().

◆ isCoPlanar() [1/3]

bool MooseMeshUtils::isCoPlanar ( const std::vector< Point > &  vec_pts)

Decides whether all the Points of a vector of Points are coplanar.

Parameters
vec_ptsvector of points to be examined
Returns
whether all the Points are in a same plane

Definition at line 473 of file MooseMeshUtils.C.

474{
475 // Assuming that overlapped Points are allowed, the Points that are overlapped with vec_pts[0] are
476 // removed before further calculation.
477 std::vector<Point> vec_pts_nonzero{vec_pts[0]};
478 for (const auto i : index_range(vec_pts))
479 if (!MooseUtils::absoluteFuzzyEqual((vec_pts[i] - vec_pts[0]).norm(), 0.0))
480 vec_pts_nonzero.push_back(vec_pts[i]);
481 // 3 or fewer points are always coplanar
482 if (vec_pts_nonzero.size() <= 3)
483 return true;
484 else
485 {
486 for (const auto i : make_range(vec_pts_nonzero.size() - 1))
487 {
488 const Point tmp_pt = (vec_pts_nonzero[i] - vec_pts_nonzero[0])
489 .cross(vec_pts_nonzero[i + 1] - vec_pts_nonzero[0]);
490 // if the three points are not collinear, use cross product as the normal vector of the plane
491 if (!MooseUtils::absoluteFuzzyEqual(tmp_pt.norm(), 0.0))
492 return isCoPlanar(vec_pts_nonzero, tmp_pt.unit());
493 }
494 }
495 // If all the points are collinear, they are also coplanar
496 return true;
497}

◆ isCoPlanar() [2/3]

bool MooseMeshUtils::isCoPlanar ( const std::vector< Point > &  vec_pts,
const Point  plane_nvec 
)

Decides whether all the Points of a vector of Points are in a plane with a given normal vector.

Parameters
vec_ptsvector of points to be examined
plane_nvecnormal vector of the plane
Returns
whether all the Points are in the same plane with the given normal vector

Definition at line 467 of file MooseMeshUtils.C.

468{
469 return isCoPlanar(vec_pts, plane_nvec, vec_pts.front());
470}
bool isCoPlanar(const std::vector< Point > &vec_pts, const Point plane_nvec, const Point fixed_pt)
Decides whether all the Points of a vector of Points are in a plane that is defined by a normal vecto...

◆ isCoPlanar() [3/3]

bool MooseMeshUtils::isCoPlanar ( const std::vector< Point > &  vec_pts,
const Point  plane_nvec,
const Point  fixed_pt 
)

Decides whether all the Points of a vector of Points are in a plane that is defined by a normal vector and an inplane Point.

Parameters
vec_ptsvector of points to be examined
plane_nvecnormal vector of the plane
fixed_pta Point in the plane
Returns
whether all the Points are in the given plane

Definition at line 458 of file MooseMeshUtils.C.

459{
460 for (const auto & pt : vec_pts)
461 if (!MooseUtils::absoluteFuzzyEqual((pt - fixed_pt) * plane_nvec, 0.0))
462 return false;
463 return true;
464}

Referenced by Positions::arePositionsCoplanar(), FillBetweenPointVectorsTools::fillBetweenPointVectorsGenerator(), SurfaceMeshGeneratorBase::get2DElemNormal(), isCoPlanar(), and isCoPlanar().

◆ makeOrderedNodeList() [1/2]

void MooseMeshUtils::makeOrderedNodeList ( std::vector< std::pair< dof_id_type, dof_id_type > > &  node_assm,
std::vector< dof_id_type > &  elem_id_list,
std::vector< dof_id_type > &  midpoint_node_list,
std::vector< dof_id_type > &  ordered_node_list,
std::vector< dof_id_type > &  ordered_elem_id_list 
)

Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes based on connectivity.

Parameters
node_assmvector of pairs of node ids that represent the sides
elem_id_listvector of element ids that represent the elements that contain the sides
midpoint_node_listvector of node ids that represent the midpoints of the sides for quadratic sides
ordered_node_listvector of node ids that represent the ordered nodes
ordered_elem_id_listvector of element corresponding to the ordered nodes

Definition at line 582 of file MooseMeshUtils.C.

587{
588 // a flag to indicate if the ordered_node_list has been reversed
589 bool is_flipped = false;
590 // Start from the first element, try to find a chain of nodes
591 mooseAssert(node_assm.size(), "Node list must not be empty");
592 ordered_node_list.push_back(node_assm.front().first);
593 if (midpoint_node_list.front() != DofObject::invalid_id)
594 ordered_node_list.push_back(midpoint_node_list.front());
595 ordered_node_list.push_back(node_assm.front().second);
596 ordered_elem_id_list.push_back(elem_id_list.front());
597 // Remove the element that has just been added to ordered_node_list
598 node_assm.erase(node_assm.begin());
599 midpoint_node_list.erase(midpoint_node_list.begin());
600 elem_id_list.erase(elem_id_list.begin());
601 const unsigned int node_assm_size_0 = node_assm.size();
602 for (unsigned int i = 0; i < node_assm_size_0; i++)
603 {
604 // Find nodes to expand the chain
605 dof_id_type end_node_id = ordered_node_list.back();
606 auto isMatch1 = [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair)
607 { return old_id_pair.first == end_node_id; };
608 auto isMatch2 = [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair)
609 { return old_id_pair.second == end_node_id; };
610 auto result = std::find_if(node_assm.begin(), node_assm.end(), isMatch1);
611 bool match_first;
612 if (result == node_assm.end())
613 {
614 match_first = false;
615 result = std::find_if(node_assm.begin(), node_assm.end(), isMatch2);
616 }
617 else
618 {
619 match_first = true;
620 }
621 // If found, add the node to boundary_ordered_node_list
622 if (result != node_assm.end())
623 {
624 const auto elem_index = std::distance(node_assm.begin(), result);
625 if (midpoint_node_list[elem_index] != DofObject::invalid_id)
626 ordered_node_list.push_back(midpoint_node_list[elem_index]);
627 ordered_node_list.push_back(match_first ? (*result).second : (*result).first);
628 node_assm.erase(result);
629 midpoint_node_list.erase(midpoint_node_list.begin() + elem_index);
630 ordered_elem_id_list.push_back(elem_id_list[elem_index]);
631 elem_id_list.erase(elem_id_list.begin() + elem_index);
632 }
633 // If there are still elements in node_assm and result ==
634 // node_assm.end(), this means the curve is not a loop, the
635 // ordered_node_list is flipped and try the other direction that has not
636 // been examined yet.
637 else
638 {
639 if (is_flipped)
640 // Flipped twice; this means the node list has at least two segments.
641 throw MooseException("The node list provided has more than one segments.");
642
643 // mark the first flip event.
644 is_flipped = true;
645 std::reverse(ordered_node_list.begin(), ordered_node_list.end());
646 std::reverse(midpoint_node_list.begin(), midpoint_node_list.end());
647 std::reverse(ordered_elem_id_list.begin(), ordered_elem_id_list.end());
648 // As this iteration is wasted, set the iterator backward
649 i--;
650 }
651 }
652}

Referenced by MooseMeshXYCuttingUtils::boundaryTriElemImprover(), FillBetweenPointVectorsTools::isClosedLoop(), and makeOrderedNodeList().

◆ makeOrderedNodeList() [2/2]

void MooseMeshUtils::makeOrderedNodeList ( std::vector< std::pair< dof_id_type, dof_id_type > > &  node_assm,
std::vector< dof_id_type > &  elem_id_list,
std::vector< dof_id_type > &  ordered_node_list,
std::vector< dof_id_type > &  ordered_elem_id_list 
)

Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes based on connectivity.

Parameters
node_assmvector of pairs of node ids that represent the sides
elem_id_listvector of element ids that represent the elements that contain the sides
ordered_node_listvector of node ids that represent the ordered nodes
ordered_elem_id_listvector of element corresponding to the ordered nodes

Definition at line 655 of file MooseMeshUtils.C.

659{
660 std::vector<dof_id_type> dummy_midpoint_node_list(node_assm.size(), DofObject::invalid_id);
662 node_assm, elem_id_list, dummy_midpoint_node_list, ordered_node_list, ordered_elem_id_list);
663}
void makeOrderedNodeList(std::vector< std::pair< dof_id_type, dof_id_type > > &node_assm, std::vector< dof_id_type > &elem_id_list, std::vector< dof_id_type > &midpoint_node_list, std::vector< dof_id_type > &ordered_node_list, std::vector< dof_id_type > &ordered_elem_id_list)
Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes bas...

◆ mergeBoundaryIDsWithSameName()

void MooseMeshUtils::mergeBoundaryIDsWithSameName ( MeshBase &  mesh)

Merges the boundary IDs of boundaries that have the same names but different IDs.

Parameters
meshThe input mesh whose boundaries we will modify

Definition at line 36 of file MooseMeshUtils.C.

37{
38 // We check if we have the same boundary name with different IDs. If we do, we assign the
39 // first ID to every occurrence.
40 const auto & side_bd_name_map = mesh.get_boundary_info().get_sideset_name_map();
41 const auto & node_bd_name_map = mesh.get_boundary_info().get_nodeset_name_map();
42 std::map<boundary_id_type, boundary_id_type> same_name_ids;
43
44 auto populate_map = [](const std::map<boundary_id_type, std::string> & map,
45 std::map<boundary_id_type, boundary_id_type> & same_ids)
46 {
47 for (const auto & pair_outer : map)
48 for (const auto & pair_inner : map)
49 // The last condition is needed to make sure we only store one combination
50 if (pair_outer.second == pair_inner.second && pair_outer.first != pair_inner.first &&
51 same_ids.find(pair_inner.first) == same_ids.end())
52 same_ids[pair_outer.first] = pair_inner.first;
53 };
54
55 populate_map(side_bd_name_map, same_name_ids);
56 populate_map(node_bd_name_map, same_name_ids);
57
58 for (const auto & [id1, id2] : same_name_ids)
59 mesh.get_boundary_info().renumber_id(id2, id1);
60}

Referenced by MeshRepairGenerator::generate(), and StitchMeshGenerator::generate().

◆ meshCentroidCalculator()

Point MooseMeshUtils::meshCentroidCalculator ( const MeshBase &  mesh)

Calculates the centroid of a MeshBase.

Parameters
meshinput mesh whose centroid needs to be calculated
Returns
a Point corresponding to the mesh centroid

Definition at line 281 of file MooseMeshUtils.C.

282{
283 Point centroid_pt = Point(0.0, 0.0, 0.0);
284 Real vol_tmp = 0.0;
285 for (const auto & elem : mesh.active_local_element_ptr_range())
286 {
287 Real elem_vol = elem->volume();
288 centroid_pt += (elem->true_centroid()) * elem_vol;
289 vol_tmp += elem_vol;
290 }
291 mesh.comm().sum(centroid_pt);
292 mesh.comm().sum(vol_tmp);
293 centroid_pt /= vol_tmp;
294 return centroid_pt;
295}

Referenced by Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), AdvancedExtruderGenerator::generate(), FillBetweenSidesetsGenerator::generate(), and MultiAppPositions::initialize().

◆ swapNodesInElem()

void MooseMeshUtils::swapNodesInElem ( Elem &  elem,
const unsigned int  nd1,
const unsigned int  nd2 
)

Swap two nodes within an element.

Parameters
elemelement whose nodes need to be swapped
nd1index of the first node to be swapped
nd2index of the second node to be swapped

Definition at line 666 of file MooseMeshUtils.C.

667{
668 Node * n_temp = elem.node_ptr(nd1);
669 elem.set_node(nd1, elem.node_ptr(nd2));
670 elem.set_node(nd2, n_temp);
671}

Referenced by AdvancedExtruderGenerator::generate().