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< BoundaryIDgetBoundaryIDs (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< BoundaryIDgetBoundaryIDs (const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown)
 Gets the boundary IDs with their names.
 
std::set< BoundaryIDgetBoundaryIDSet (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 >
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 >
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, const std::string type_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< BoundaryIDgetBoundaryIDSet (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 1558 of file MooseMeshUtils.C.

1559{
1560 auto & binfo = mesh.get_boundary_info();
1561 for (const auto & elem : mesh.active_element_ptr_range())
1562 for (const auto & i_side : elem->side_index_range())
1563 if (elem->neighbor_ptr(i_side) == nullptr)
1564 {
1565 has_external_bid = true;
1566 binfo.add_side(elem, i_side, extern_bid);
1567 }
1568}
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:64
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 1532 of file MooseMeshUtils.C.

1538{
1539 std::vector<unsigned int> nums_edges_between_points;
1540 const auto n_points = points.size();
1541 for (auto i : make_range(n_points))
1542 {
1543 if (!loop && (i + 1) == n_points)
1544 break;
1545
1546 const auto ip1 = (i + 1) % n_points;
1547 const Real length = (points[ip1] - points[i]).norm();
1548 const unsigned int n_elems = std::max(
1549 static_cast<unsigned int>(std::ceil(length / max_elem_size)), static_cast<unsigned int>(1));
1550 nums_edges_between_points.push_back(n_elems);
1551 }
1552
1553 buildPolyLineMesh(
1554 mesh, points, {}, loop, start_boundary, end_boundary, nums_edges_between_points);
1555}

◆ 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 1520 of file MooseMeshUtils.C.

1526{
1528 mesh, points, {}, loop, start_boundary, end_boundary, nums_edges_between_points);
1529}
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 1412 of file MooseMeshUtils.C.

1419{
1420 mooseAssert(nums_edges_between_points.size() == 1 ||
1421 nums_edges_between_points.size() == points.size() - 1 + loop,
1422 "nums_edges_between_points must be either a single value or have the same number of "
1423 "entries as segments defined by the points.");
1424 mooseAssert(
1425 mid_points.size() == 0 || mid_points.size() == points.size() - (loop ? 0 : 1),
1426 "mid_points must be either empty or have the consistent number of entries as points.");
1427 mooseAssert(
1428 mid_points.size() == 0 ||
1429 (nums_edges_between_points.size() == 1 && nums_edges_between_points.front() == 1) ||
1430 (nums_edges_between_points.size() == points.size() - 1 + loop &&
1431 std::all_of(nums_edges_between_points.begin(),
1432 nums_edges_between_points.end(),
1433 [](unsigned int n) { return n == 1; })),
1434 "mid_points can only be provided if each segment has exactly one edge.");
1435
1436 const auto n_points = points.size();
1437 for (auto i : make_range(n_points))
1438 {
1439 const auto & num_edges_between_points =
1440 (nums_edges_between_points.size() == 1)
1441 ? nums_edges_between_points[0]
1442 : (i == nums_edges_between_points.size() ? 0 : nums_edges_between_points[i]);
1443
1444 Point p = points[i];
1445 const auto pt_counter = (nums_edges_between_points.size() == 1)
1446 ? i
1447 : std::accumulate(nums_edges_between_points.begin(),
1448 nums_edges_between_points.begin() + i,
1449 0);
1450 mesh.add_point(
1451 p, nums_edges_between_points.size() == 1 ? (i * num_edges_between_points) : pt_counter);
1452
1453 if (num_edges_between_points > 1)
1454 {
1455 if (!loop && (i + 1) == n_points)
1456 break;
1457
1458 const auto ip1 = (i + 1) % n_points;
1459 const Point pvec = (points[ip1] - p) / num_edges_between_points;
1460
1461 for (auto j : make_range(1u, num_edges_between_points))
1462 {
1463 p += pvec;
1464 mesh.add_point(
1465 p,
1466 (nums_edges_between_points.size() == 1 ? (i * num_edges_between_points) : pt_counter) +
1467 j);
1468 }
1469 }
1470 }
1471 // Add mid points if applicable. When mid points are provided, each segment has exactly one edge,
1472 // so the midpoint node ids follow the vertex node ids.
1473 for (const auto & i : make_range(mid_points.size()))
1474 mesh.add_point(mid_points[i], n_points + i);
1475
1476 const auto n_segments = loop ? n_points : (n_points - 1);
1477 const auto n_elem =
1478 nums_edges_between_points.size() == 1
1479 ? n_segments * nums_edges_between_points[0]
1480 : std::accumulate(nums_edges_between_points.begin(), nums_edges_between_points.end(), 0);
1481 const auto max_nodes =
1482 (nums_edges_between_points.size() == 1 ? n_segments * nums_edges_between_points[0]
1483 : std::accumulate(nums_edges_between_points.begin(),
1484 nums_edges_between_points.end(),
1485 0)) +
1486 (loop ? 0 : 1);
1487 for (auto i : make_range(n_elem))
1488 {
1489 std::unique_ptr<Elem> elem;
1490 if (mid_points.size())
1491 {
1492 elem = std::make_unique<Edge3>();
1493 elem->set_node(2, mesh.node_ptr(n_points + i));
1494 }
1495 else
1496 elem = Elem::build(EDGE2);
1497 const auto ip1 = (i + 1) % max_nodes;
1498 elem->set_node(0, mesh.node_ptr(i));
1499 elem->set_node(1, mesh.node_ptr(ip1));
1500 elem->set_id() = i;
1501 mesh.add_elem(std::move(elem));
1502 }
1503
1504 if (!loop)
1505 {
1506 BoundaryInfo & bi = mesh.get_boundary_info();
1507 std::vector<BoundaryName> bdy_names{start_boundary, end_boundary};
1508 std::vector<boundary_id_type> ids = MooseMeshUtils::getBoundaryIDs(mesh, bdy_names, true);
1509 bi.add_side(mesh.elem_ptr(0), 0, ids[0]);
1510 bi.add_side(mesh.elem_ptr(n_elem - 1), 1, ids[1]);
1511 }
1512 else
1513 mooseAssert(start_boundary.empty() && end_boundary.empty(),
1514 "Cannot assign start/end boundaries on a looped polyline.");
1515
1516 mesh.prepare_for_use();
1517}
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(), FillBetweenSidesetsGenerator::generate(), XYDelaunayGenerator::generate(), MooseMeshElementConversionUtils::transitionLayerGenerator(), and MeshTriangulationUtils::triangulateWithDelaunay().

◆ 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 1173 of file MooseMeshUtils.C.

1176{
1177 if (!source_mesh.is_replicated())
1178 mooseError("This generator does not support distributed meshes.");
1179
1180 const auto target_block_ids = MooseMeshUtils::getSubdomainIDs(source_mesh, target_blocks);
1181
1182 // Check that the block ids/names exist in the mesh
1183 std::set<SubdomainID> mesh_blocks;
1184 source_mesh.subdomain_ids(mesh_blocks);
1185
1186 for (const auto i : index_range(target_block_ids))
1187 if (target_block_ids[i] == Moose::INVALID_BLOCK_ID || !mesh_blocks.count(target_block_ids[i]))
1188 {
1189 mooseException("The target_block '", target_blocks[i], "' was not found within the mesh.");
1190 }
1191
1192 // know which nodes have already been inserted, by tracking the old mesh's node's ids'
1193 std::unordered_map<dof_id_type, dof_id_type> old_new_node_map;
1194
1195 for (const auto target_block_id : target_block_ids)
1196 {
1197
1198 for (auto elem : source_mesh.active_subdomain_elements_ptr_range(target_block_id))
1199 {
1200 if (elem->level() != 0)
1201 mooseError("Refined blocks are not supported by this generator. "
1202 "Can you re-organize mesh generators to refine after converting the block?");
1203
1204 // make a deep copy so that mutiple meshes' destructors don't segfault at program termination
1205 auto copy = elem->build(elem->type());
1206
1207 // Keep the subdomain id
1208 copy->subdomain_id() = elem->subdomain_id();
1209
1210 // index of node in the copy element must be managed manually as there is no intelligent
1211 // insert method
1212 dof_id_type copy_n_index = 0;
1213
1214 // correctly assign new copies of nodes, loop over nodes
1215 for (dof_id_type i : elem->node_index_range())
1216 {
1217 auto & n = elem->node_ref(i);
1218
1219 if (old_new_node_map.count(n.id()))
1220 {
1221 // case where we have already inserted this particular point before
1222 // then we need to find the already-inserted one and hook it up right
1223 // to it's respective element
1224 copy->set_node(copy_n_index++, target_mesh.node_ptr(old_new_node_map[n.id()]));
1225 }
1226 else
1227 {
1228 // case where we've NEVER inserted this particular point before
1229 // add them both to the element and the mesh
1230
1231 // Nodes' IDs are their indexes in the nodes' respective mesh
1232 // If we set them as invalid they are automatically assigned
1233 // Add to mesh, auto-assigning a new id.
1234 Node * node = target_mesh.add_point(elem->point(i));
1235
1236 // Add to element copy (manually)
1237 copy->set_node(copy_n_index++, node);
1238
1239 // remember the (old) ID
1240 old_new_node_map[n.id()] = node->id();
1241 }
1242 }
1243
1244 // it is ok to release the copy element into the mesh because derived meshes class
1245 // (ReplicatedMesh, DistributedMesh) manage their own elements, will delete them
1246 target_mesh.add_elem(copy.release());
1247 }
1248 }
1249
1250 // Move subdomain names
1251 for (const auto sbd_id : target_block_ids)
1252 target_mesh.set_subdomain_name(sbd_id, source_mesh.subdomain_name(sbd_id));
1253}
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 1256 of file MooseMeshUtils.C.

1262{
1263 dof_id_type node_delta = destination.max_node_id();
1264 dof_id_type elem_delta = destination.max_elem_id();
1265
1266 unique_id_type unique_delta =
1267#ifdef LIBMESH_ENABLE_UNIQUE_ID
1268 destination.parallel_max_unique_id();
1269#else
1270 0;
1271#endif
1272
1273 // Prevent overlaps by offsetting the subdomains in
1274 std::unordered_map<subdomain_id_type, subdomain_id_type> id_remapping;
1275 unsigned int block_offset = 0;
1276 if (avoid_merging_subdomains)
1277 {
1278 // Note: if performance becomes an issue, this is overkill for just getting the max node id
1279 std::set<subdomain_id_type> source_ids;
1280 std::set<subdomain_id_type> dest_ids;
1281
1282 // We need source subdomain ids already cached; libMesh will
1283 // scream otherwise
1284 source.subdomain_ids(source_ids, true);
1285
1286 // Our destination is non-const, so we can fix any missing caches
1287 if (!destination.preparation().has_cached_elem_data)
1288 destination.cache_elem_data();
1289
1290 destination.subdomain_ids(dest_ids, true);
1291
1292 mooseAssert(source_ids.size(), "Should have a subdomain");
1293 mooseAssert(dest_ids.size(), "Should have a subdomain");
1294 unsigned int max_dest_bid = *dest_ids.rbegin();
1295 unsigned int min_source_bid = *source_ids.begin();
1296 communicator.max(max_dest_bid);
1297 communicator.min(min_source_bid);
1298 block_offset = 1 + max_dest_bid - min_source_bid;
1299 for (const auto bid : source_ids)
1300 id_remapping[bid] = block_offset + bid;
1301 }
1302
1303 // Copy mesh data over from the other mesh
1304 destination.copy_nodes_and_elements(source,
1305 // Skipping this should cause the neighbors
1306 // to simply be copied from the other mesh
1307 // (which makes sense and is way faster)
1308 /*skip_find_neighbors = */ true,
1309 elem_delta,
1310 node_delta,
1311 unique_delta,
1312 avoid_merging_subdomains ? &id_remapping : nullptr);
1313
1314 // Get an offset to prevent overlaps / wild merging between boundaries
1315 BoundaryInfo & boundary = destination.get_boundary_info();
1316 const BoundaryInfo & other_boundary = source.get_boundary_info();
1317
1318 unsigned int bid_offset = 0;
1319 if (avoid_merging_boundaries)
1320 {
1321 const auto boundary_ids = boundary.get_boundary_ids();
1322 const auto other_boundary_ids = other_boundary.get_boundary_ids();
1323 unsigned int max_dest_bid = boundary_ids.size() ? *boundary_ids.rbegin() : 0;
1324 unsigned int min_source_bid = other_boundary_ids.size() ? *other_boundary_ids.begin() : 0;
1325 communicator.max(max_dest_bid);
1326 communicator.min(min_source_bid);
1327 bid_offset = 1 + max_dest_bid - min_source_bid;
1328 }
1329
1330 // Note: the code below originally came from ReplicatedMesh::stitch_mesh_helper()
1331 // in libMesh replicated_mesh.C around line 1203
1332
1333 // Copy BoundaryInfo from other_mesh too. We do this via the
1334 // list APIs rather than element-by-element for speed.
1335 for (const auto & t : other_boundary.build_node_list())
1336 boundary.add_node(std::get<0>(t) + node_delta, bid_offset + std::get<1>(t));
1337
1338 for (const auto & t : other_boundary.build_side_list())
1339 boundary.add_side(std::get<0>(t) + elem_delta, std::get<1>(t), bid_offset + std::get<2>(t));
1340
1341 for (const auto & t : other_boundary.build_edge_list())
1342 boundary.add_edge(std::get<0>(t) + elem_delta, std::get<1>(t), bid_offset + std::get<2>(t));
1343
1344 for (const auto & t : other_boundary.build_shellface_list())
1345 boundary.add_shellface(
1346 std::get<0>(t) + elem_delta, std::get<1>(t), bid_offset + std::get<2>(t));
1347
1348 // Check for the case with two block ids sharing the same name
1349 if (avoid_merging_subdomains)
1350 {
1351 mooseAssert(mg.parameters().isParamDefined("avoid_merging_subdomains"),
1352 "Missing parameter in the mesh generator calling this function: "
1353 "avoid_merging_subdomains. Considering setting avoid_merging_subdomains to true.");
1354 for (const auto & [block_id, block_name] : destination.get_subdomain_name_map())
1355 for (const auto & [source_id, source_name] : source.get_subdomain_name_map())
1356 if (block_name == source_name)
1357 mg.paramWarning(
1358 "avoid_merging_subdomains",
1359 "Not merging subdomains is creating two subdomains with the same name '" +
1360 block_name + "' but different ids: " + std::to_string(source_id) + " & " +
1361 std::to_string(block_id + block_offset) +
1362 ".\n We recommend using a RenameBlockGenerator to prevent this as you "
1363 "will get errors reading the Exodus output later.");
1364 }
1365
1366 for (const auto & [block_id, block_name] : source.get_subdomain_name_map())
1367 destination.set_subdomain_name_map().insert(
1368 std::make_pair<SubdomainID, SubdomainName>(block_id + block_offset, block_name));
1369
1370 // Check for the case with two boundary ids sharing the same name
1371 if (avoid_merging_boundaries)
1372 {
1373 mooseAssert(mg.parameters().isParamDefined("avoid_merging_boundaries"),
1374 "Missing parameter in the mesh generator calling this function: "
1375 "avoid_merging_boundaries. Considering setting avoid_merging_boundaries to true.");
1376 for (const auto & [b_id, b_name] : other_boundary.get_sideset_name_map())
1377 for (const auto & [source_id, source_name] : boundary.get_sideset_name_map())
1378 if (b_name == source_name)
1379 mg.paramWarning(
1380 "avoid_merging_boundaries",
1381 "Not merging boundaries is creating two sidesets with the same name '" + b_name +
1382 "' but different ids: " + std::to_string(source_id) + " & " +
1383 std::to_string(b_id + bid_offset) +
1384 ".\n We recommend using a RenameBoundaryGenerator to prevent this as you "
1385 "will get errors reading the Exodus output later.");
1386 for (const auto & [b_id, b_name] : other_boundary.get_nodeset_name_map())
1387 for (const auto & [source_id, source_name] : boundary.get_nodeset_name_map())
1388 if (b_name == source_name)
1389 mg.paramWarning(
1390 "avoid_merging_boundaries",
1391 "Not merging boundaries is creating two nodesets with the same name '" + b_name +
1392 "' but different ids: " + std::to_string(source_id) + " & " +
1393 std::to_string(b_id + bid_offset) +
1394 ".\n We recommend using a RenameBoundaryGenerator to prevent this as you "
1395 "will get errors reading the Exodus output later.");
1396 }
1397
1398 for (const auto & [nodeset_id, nodeset_name] : other_boundary.get_nodeset_name_map())
1399 boundary.set_nodeset_name_map().insert(
1400 std::make_pair<BoundaryID, BoundaryName>(nodeset_id + bid_offset, nodeset_name));
1401
1402 for (const auto & [sideset_id, sideset_name] : other_boundary.get_sideset_name_map())
1403 boundary.set_sideset_name_map().insert(
1404 std::make_pair<BoundaryID, BoundaryName>(sideset_id + bid_offset, sideset_name));
1405
1406 for (const auto & [edgeset_id, edgeset_name] : other_boundary.get_edgeset_name_map())
1407 boundary.set_edgeset_name_map().insert(
1408 std::make_pair<BoundaryID, BoundaryName>(edgeset_id + bid_offset, edgeset_name));
1409}
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,
const std::string  type_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.

1032{
1033 // Generate a new block id if one isn't supplied.
1034 SubdomainID new_block_id = new_subdomain_id;
1035
1036 // Make sure our boundary info and parallel counts are setup
1037 if (!mesh.is_prepared())
1038 {
1039 const bool allow_remote_element_removal = mesh.allow_remote_element_removal();
1040 // We want all of our boundary elements available, so avoid removing them if they haven't
1041 // already been so
1042 mesh.allow_remote_element_removal(false);
1043 mesh.prepare_for_use();
1044 mesh.allow_remote_element_removal(allow_remote_element_removal);
1045 }
1046
1047 // Check that the sidesets are present in the mesh
1048 for (const auto & sideset : boundary_names)
1049 if (!MooseMeshUtils::hasBoundaryNameOrID(mesh, sideset))
1050 mooseException("The sideset '", sideset, "' was not found within the mesh");
1051
1052 auto sideset_ids = MooseMeshUtils::getBoundaryIDs(mesh, boundary_names, true);
1053 std::set<boundary_id_type> sidesets(sideset_ids.begin(), sideset_ids.end());
1054 auto side_list = mesh.get_boundary_info().build_side_list();
1055 if (!mesh.is_serial() && mesh.comm().size() > 1)
1056 {
1057 std::vector<Elem *> elements_to_send;
1058 unsigned short i_need_boundary_elems = 0;
1059 for (const auto & [elem_id, side, bc_id] : side_list)
1060 {
1061 libmesh_ignore(side);
1062 if (sidesets.count(bc_id))
1063 {
1064 // Whether we have this boundary information through our locally owned element or a ghosted
1065 // element, we'll need the boundary elements for parallel consistent addition
1066 i_need_boundary_elems = 1;
1067 auto * elem = mesh.elem_ptr(elem_id);
1068 if (elem->processor_id() == mesh.processor_id())
1069 elements_to_send.push_back(elem);
1070 }
1071 }
1072
1073 std::set<const Elem *, libMesh::CompareElemIdsByLevel> connected_elements(
1074 elements_to_send.begin(), elements_to_send.end());
1075 std::set<const Node *> connected_nodes;
1076 reconnect_nodes(connected_elements, connected_nodes);
1077 std::set<dof_id_type> connected_node_ids;
1078 for (auto * nd : connected_nodes)
1079 connected_node_ids.insert(nd->id());
1080
1081 std::vector<unsigned short> need_boundary_elems(mesh.comm().size());
1082 mesh.comm().allgather(i_need_boundary_elems, need_boundary_elems);
1083 std::unordered_map<processor_id_type, decltype(elements_to_send)> push_element_data;
1084 std::unordered_map<processor_id_type, decltype(connected_nodes)> push_node_data;
1085
1086 for (const auto pid : index_range(mesh.comm()))
1087 // Don't need to send to self
1088 if (pid != mesh.processor_id() && need_boundary_elems[pid])
1089 {
1090 if (elements_to_send.size())
1091 push_element_data[pid] = elements_to_send;
1092 if (connected_nodes.size())
1093 push_node_data[pid] = connected_nodes;
1094 }
1095
1096 auto node_action_functor = [](processor_id_type, const auto &)
1097 {
1098 // Node packing specialization already has unpacked node into mesh, so nothing to do
1099 };
1100 Parallel::push_parallel_packed_range(mesh.comm(), push_node_data, &mesh, node_action_functor);
1101 auto elem_action_functor = [](processor_id_type, const auto &)
1102 {
1103 // Elem packing specialization already has unpacked elem into mesh, so nothing to do
1104 };
1105 TIMPI::push_parallel_packed_range(mesh.comm(), push_element_data, &mesh, elem_action_functor);
1106
1107 // now that we've gathered everything, we need to rebuild the side list
1108 side_list = mesh.get_boundary_info().build_side_list();
1109 }
1110
1111 std::vector<std::pair<dof_id_type, ElemSidePair>> element_sides_on_boundary;
1112 dof_id_type counter = 0;
1113 for (const auto & [eid, side, bid] : side_list)
1114 if (sidesets.count(bid))
1115 {
1116 if (auto elem = mesh.query_elem_ptr(eid))
1117 {
1118 if (!elem->active())
1119 mooseError(
1120 "Only active, level 0 elements can be made interior parents of new level 0 lower-d "
1121 "elements. Make sure that ",
1122 type_name,
1123 "s are run before any refinement generators");
1124 element_sides_on_boundary.push_back(std::make_pair(counter, ElemSidePair(elem, side)));
1125 }
1126 ++counter;
1127 }
1128
1129 dof_id_type max_elem_id = mesh.max_elem_id();
1130 unique_id_type max_unique_id = mesh.parallel_max_unique_id();
1131
1132 // Making an important assumption that at least our boundary elements are the same on all
1133 // processes even in distributed mesh mode (this is reliant on the correct ghosting functors
1134 // existing on the mesh)
1135 for (auto & [i, elem_side] : element_sides_on_boundary)
1136 {
1137 Elem * elem = elem_side.elem;
1138
1139 const auto side = elem_side.side;
1140
1141 // Build a non-proxy element from this side.
1142 std::unique_ptr<Elem> side_elem(elem->build_side_ptr(side));
1143
1144 // The side will be added with the same processor id as the parent.
1145 side_elem->processor_id() = elem->processor_id();
1146
1147 // Add subdomain ID
1148 side_elem->subdomain_id() = new_block_id;
1149
1150 // Also assign the side's interior parent, so it is always
1151 // easy to figure out the Elem we came from.
1152 side_elem->set_interior_parent(elem);
1153
1154 // Add id
1155 side_elem->set_id(max_elem_id + i);
1156 side_elem->set_unique_id(max_unique_id + i);
1157
1158 // Finally, add the lower-dimensional element to the mesh.
1159 mesh.add_elem(side_elem.release());
1160 };
1161
1162 // Assign block name, if provided
1163 if (new_subdomain_name.size())
1164 mesh.set_subdomain_name(new_block_id, new_subdomain_name);
1165
1166 const bool skip_partitioning_old = mesh.skip_partitioning();
1167 mesh.skip_partitioning(true);
1168 mesh.prepare_for_use();
1169 mesh.skip_partitioning(skip_partitioning_old);
1170}
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)
uint8_t unique_id_type
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(), PolyLineMeshFollowingNodeSetGenerator::generate(), RenameBoundaryGenerator::generate(), MooseMesh::getBoundaryID(), hasBoundaryNameOrID(), Moose::PeriodicBCHelper::setupManualPeriodicBoundaries(), MooseMeshElementConversionUtils::transitionLayerGenerator(), and MeshTriangulationUtils::triangulateWithDelaunay().

◆ 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(), 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(), SideSetsGeneratorBase::setup(), and MeshTriangulationUtils::triangulateWithDelaunay().

◆ 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 Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), CutMeshByLevelSetGeneratorBase::generate(), SurfaceSubdomainsDelaunayRemesher::generate(), XYDelaunayGenerator::generate(), XYMeshLineCutter::generate(), XYZDelaunayGenerator::generate(), MooseMeshElementConversionUtils::transitionLayerGenerator(), and MeshTriangulationUtils::triangulateWithDelaunay().

◆ 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 Boundary2DDelaunayGenerator::General2DDelaunay(), SurfaceSubdomainsDelaunayRemesher::General2DDelaunay(), Boundary2DDelaunayGenerator::generate(), BoundaryLayerSubdomainGenerator::generate(), CutMeshByLevelSetGeneratorBase::generate(), LowerDBlockFromSidesetGenerator::generate(), ProjectSideSetOntoLevelSetGenerator::generate(), SurfaceSubdomainsFromAllNormalsGenerator::generate(), XYZDelaunayGenerator::generate(), MeshRepairGenerator::separateSubdomainsByElementType(), MooseMeshElementConversionUtils::transitionLayerGenerator(), and MeshTriangulationUtils::triangulateWithDelaunay().

◆ 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 ManifoldSubdomainGenerator::generate(), ParsedExtraElementIDGenerator::generate(), RenameBlockGenerator::generate(), RenumberBySubdomainGenerator::generate(), SubdomainBoundingBoxGenerator::generate(), SubdomainsFromPartitionerGenerator::generate(), UniqueExtraIDMeshGenerator::generate(), XYZDelaunayGenerator::generate(), MooseMesh::getSubdomainID(), getSubdomainIDs(), hasSubdomainName(), MooseMeshXYCuttingUtils::quadToTriOnLine(), MooseMeshXYCuttingUtils::quasiTriElementsFixer(), and MeshTriangulationUtils::triangulateWithDelaunay().

◆ 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(), 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().