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

Classes

struct  ElemSidePair
 

Functions

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

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

1549{
1550 auto & binfo = mesh.get_boundary_info();
1551 for (const auto & elem : mesh.active_element_ptr_range())
1552 for (const auto & i_side : elem->side_index_range())
1553 if (elem->neighbor_ptr(i_side) == nullptr)
1554 {
1555 has_external_bid = true;
1556 binfo.add_side(elem, i_side, extern_bid);
1557 }
1558}
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 326 of file MooseMeshUtils.C.

327{
328 // Need boundaries to be synchronized
329 if (!mesh.preparation().has_boundary_id_sets)
330 mesh.get_boundary_info().synchronize_global_id_set();
331 BoundaryInfo & mesh_boundary_info = mesh.get_boundary_info();
332 boundary_id_type boundary_id = mesh_boundary_info.get_id_by_name(boundary);
333 const auto side_list = mesh_boundary_info.build_side_list();
334
335 // Initialize sums
336 Real volume_sum = 0;
337 Point volume_weighted_centroid_sum(0, 0, 0);
338
339 for (const auto & [eid, side_i, bid] : side_list)
340 {
341 if (bid != boundary_id)
342 continue;
343
344 // Get the side
345 const auto elem = mesh.elem_ptr(eid);
346 const auto side = elem->side_ptr(side_i);
347
348 volume_sum += side->volume();
349 volume_weighted_centroid_sum += side->volume() * side->true_centroid();
350 }
351 // Sum across processes
352 mesh.comm().sum(volume_weighted_centroid_sum);
353 mesh.comm().sum(volume_sum);
354
355 if (volume_sum == 0)
356 {
357 mooseWarning("Boundary centroid was requested but boundary '" + boundary + "' is empty.");
358 return Point(0.);
359 }
360 return volume_weighted_centroid_sum / volume_sum;
361}
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345

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

365{
366 // Need boundaries to be synchronized
367 if (!mesh.preparation().has_boundary_id_sets)
368 mesh.get_boundary_info().synchronize_global_id_set();
369 BoundaryInfo & mesh_boundary_info = mesh.get_boundary_info();
370 boundary_id_type boundary_id = mesh_boundary_info.get_id_by_name(boundary);
371 const auto side_list = mesh_boundary_info.build_side_list();
372
373 // Initialize sums
374 Real volume_sum = 0;
375 RealVectorValue volume_weighted_normal_sum(0, 0, 0);
376
377 for (const auto & [eid, side_i, bid] : side_list)
378 {
379 if (bid != boundary_id)
380 continue;
381
382 // Get the side
383 const auto elem = mesh.elem_ptr(eid);
384 const auto side = elem->side_ptr(side_i);
385
386 volume_sum += side->volume();
387 volume_weighted_normal_sum += side->volume() * elem->side_vertex_average_normal(side_i);
388 }
389 // Sum across processes
390 mesh.comm().sum(volume_weighted_normal_sum);
391 mesh.comm().sum(volume_sum);
392
393 return volume_weighted_normal_sum / volume_sum;
394}

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

740{
741 if (!input_mesh.is_serial())
742 ::mooseError("Input mesh should be serialized for extracting the boundary mesh.\nInput mesh:" +
743 input_mesh.get_info());
744 auto poly_mesh = std::make_unique<ReplicatedMesh>(input_mesh.comm());
745
746 auto side_list = input_mesh.get_boundary_info().build_side_list();
747
748 std::unordered_map<dof_id_type, dof_id_type> old_new_node_map;
749 for (const auto & [eid, side_i, bid] : side_list)
750 {
751 if (bid != boundary_id)
752 continue;
753
754 // Get the side
755 const auto elem = input_mesh.elem_ptr(eid);
756 const auto side = elem->side_ptr(side_i);
757 auto side_elem = elem->build_side_ptr(side_i);
758 auto copy = side_elem->build(side_elem->type());
759
760 for (const auto i : side_elem->node_index_range())
761 {
762 auto & n = side_elem->node_ref(i);
763
764 if (old_new_node_map.count(n.id()))
765 copy->set_node(i, poly_mesh->node_ptr(old_new_node_map[n.id()]));
766 else
767 {
768 Node * node = poly_mesh->add_point(side_elem->point(i));
769 copy->set_node(i, node);
770 old_new_node_map[n.id()] = node->id();
771 }
772 }
773 poly_mesh->add_elem(copy.release());
774 }
775 poly_mesh->skip_partitioning(true);
776 poly_mesh->prepare_for_use();
777 if (poly_mesh->n_elem() == 0)
778 mooseError("The input mesh to extract the boundary from does not have a boundary with id ",
779 boundary_id,
780 ".\n",
781 input_mesh);
782
783 return poly_mesh;
784}
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 1002 of file MooseMeshUtils.C.

1003{
1004 if (!input_mesh.is_serial())
1006 "Input 2D mesh should be serialized for extracting the loop boundary mesh.\nInput mesh:" +
1007 input_mesh.get_info());
1008
1009 // Get all nodes on that boundary
1010 // Boundary ID might be a sideset or a nodeset, get nodes regardless
1011 const auto particular_node_ids = getBoundaryNodes(input_mesh, boundary_id);
1012
1013 std::unordered_map<dof_id_type, std::unordered_set<dof_id_type>> nid_to_eids_map;
1014 // Fill the map from looping over elements
1015 for (const auto & elem :
1016 as_range(input_mesh.active_elements_begin(), input_mesh.active_elements_end()))
1017 {
1018 for (const auto & nd : elem->node_ref_range())
1019 {
1020 // Only add the element id if the node is on the boundary
1021 if (!particular_node_ids.count(nd.id()))
1022 continue;
1023
1024 auto & elem_ids = nid_to_eids_map[nd.id()];
1025 elem_ids.insert(elem->id());
1026 }
1027 }
1028 return nid_to_eids_map;
1029}
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 787 of file MooseMeshUtils.C.

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

Referenced by SurfaceSubdomainsDelaunayRemesher::General2DDelaunay().

◆ buildPolyLineMesh() [1/3]

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

Generates meshes from edges connecting a list of points.

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

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

Definition at line 1522 of file MooseMeshUtils.C.

1528{
1529 std::vector<unsigned int> nums_edges_between_points;
1530 const auto n_points = points.size();
1531 for (auto i : make_range(n_points))
1532 {
1533 if (!loop && (i + 1) == n_points)
1534 break;
1535
1536 const auto ip1 = (i + 1) % n_points;
1537 const Real length = (points[ip1] - points[i]).norm();
1538 const unsigned int n_elems = std::max(
1539 static_cast<unsigned int>(std::ceil(length / max_elem_size)), static_cast<unsigned int>(1));
1540 nums_edges_between_points.push_back(n_elems);
1541 }
1542
1543 buildPolyLineMesh(
1544 mesh, points, {}, loop, start_boundary, end_boundary, nums_edges_between_points);
1545}

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

1516{
1518 mesh, points, {}, loop, start_boundary, end_boundary, nums_edges_between_points);
1519}
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 1402 of file MooseMeshUtils.C.

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

◆ changeBoundaryId() [1/2]

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

Definition at line 63 of file MooseMeshUtils.C.

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

◆ changeBoundaryId() [2/2]

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

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

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

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

◆ changeSubdomainId()

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

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

Parameters
meshthe mesh
old_idthe old subdomain id
new_idthe new subdomain id

Definition at line 298 of file MooseMeshUtils.C.

299{
300 for (const auto & elem : mesh.element_ptr_range())
301 if (elem->subdomain_id() == old_id)
302 elem->subdomain_id() = new_id;
303
304 // global cached information may now be out of sync
305 mesh.unset_is_prepared();
306}

◆ 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 233 of file MooseMeshUtils.h.

234{
235 return (point - origin).cross(direction).norm();
236}

◆ computeFiniteVolumeCoords()

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

Definition at line 267 of file MooseMeshUtils.h.

270{
271 coordTransformFactor(fi.faceCentroid(), fi.faceCoord(), coord_type, rz_radial_coord);
272}
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 397 of file MooseMeshUtils.C.

400{
401 Real distance = 0;
402 mooseAssert(MooseUtils::absoluteFuzzyEqual(direction.norm_sq(), 1),
403 "Direction should be normalized");
404 for (const auto & node : mesh.node_ptr_range())
405 if (const auto dist_node = (*node - origin).cross(direction).norm(); dist_node > distance)
406 distance = dist_node;
407 mesh.comm().max(distance);
408 return distance;
409}
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 1159 of file MooseMeshUtils.C.

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

203{
204 switch (coord_type)
205 {
206 case Moose::COORD_XYZ:
207 factor = 1.0;
208 break;
209 case Moose::COORD_RZ:
210 {
211 mooseAssert(rz_radial_coord != libMesh::invalid_uint,
212 "Must pass in a valid rz radial coordinate");
213 factor = 2 * M_PI * point(rz_radial_coord);
214 break;
215 }
217 factor = 4 * M_PI * point(0) * point(0);
218 break;
219 default:
220 mooseError("Unknown coordinate system");
221 }
222}
@ COORD_RZ
Definition MooseTypes.h:870
@ COORD_RSPHERICAL
Definition MooseTypes.h:871
@ COORD_XYZ
Definition MooseTypes.h:869

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 259 of file MooseMeshUtils.h.

262{
263 factor = 2 * M_PI * computeDistanceToAxis<P, C>(point, axis.first, axis.second);
264}

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

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

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

◆ createSubdomainFromSidesets()

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

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

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

Definition at line 1060 of file MooseMeshUtils.C.

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

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

◆ extraElemIntegerSwapParametersProcessor()

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

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

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

Definition at line 707 of file MooseMeshUtils.C.

713{
714 elem_integers_swap_pairs.reserve(num_sections * num_integers);
715 for (const auto i : make_range(num_integers))
716 {
717 const auto & elem_integer_swaps = elem_integers_swaps[i];
718 std::vector<std::unordered_map<dof_id_type, dof_id_type>> elem_integer_swap_pairs;
719 try
720 {
722 "elem_integers_swaps",
723 elem_integer_swaps,
724 elem_integer_swap_pairs,
725 i * num_sections);
726 }
727 catch (const MooseException & e)
728 {
729 throw MooseException(e.what());
730 }
731
732 elem_integers_swap_pairs.insert(elem_integers_swap_pairs.end(),
733 elem_integer_swap_pairs.begin(),
734 elem_integer_swap_pairs.end());
735 }
736}
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().

◆ getAllBoundaryNamesAndIDs() [1/2]

std::set< std::pair< BoundaryName, BoundaryID > > MooseMeshUtils::getAllBoundaryNamesAndIDs ( const libMesh::MeshBase &  mesh)

Get all boundary names and IDs from a mesh.

Parameters
meshthe mesh of interest
Returns
a set of pairs of boundary names and ids

Referenced by AdvancedExtruderGenerator::generate(), and LowerDBlockFromSidesetGenerator::generate().

◆ getAllBoundaryNamesAndIDs() [2/2]

std::set< std::pair< BoundaryName, BoundaryID > > MooseMeshUtils::getAllBoundaryNamesAndIDs ( const MeshBase &  mesh)

Definition at line 200 of file MooseMeshUtils.C.

201{
202 std::set<std::pair<BoundaryName, BoundaryID>> boundaries;
203 const auto & binfo = mesh.get_boundary_info();
204 const auto & boundary_ids = binfo.get_boundary_ids();
205 for (const auto id : boundary_ids)
206 {
207 // if neither a sideset or nodeset, then empty
208 if (binfo.get_sideset_name(id).size())
209 boundaries.insert(std::make_pair(binfo.get_sideset_name(id), id));
210 else
211 boundaries.insert(std::make_pair(binfo.get_nodeset_name(id), id));
212 }
213 return boundaries;
214}

◆ getAllSubdomainNamesAndIDs() [1/2]

std::set< std::pair< SubdomainName, SubdomainID > > MooseMeshUtils::getAllSubdomainNamesAndIDs ( const libMesh::MeshBase &  mesh)

Get all subdomain names and ids from a mesh.

Parameters
meshthe mesh of interest
Returns
a set of pairs of subdomain names and ids

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

◆ getAllSubdomainNamesAndIDs() [2/2]

std::set< std::pair< SubdomainName, SubdomainID > > MooseMeshUtils::getAllSubdomainNamesAndIDs ( const MeshBase &  mesh)

Definition at line 254 of file MooseMeshUtils.C.

255{
256 std::set<std::pair<SubdomainName, SubdomainID>> subdomains;
257 std::set<subdomain_id_type> subdomain_ids;
258 mesh.subdomain_ids(subdomain_ids, /*global*/ true);
259 for (const auto id : subdomain_ids)
260 subdomains.insert(std::make_pair(mesh.subdomain_name(id), id));
261 return subdomains;
262}

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

266{
268 if (boundary_name.empty())
269 return id;
270
271 if (!MooseUtils::isDigits(boundary_name))
272 id = mesh.get_boundary_info().get_id_by_name(boundary_name);
273 else
274 id = getIDFromName<BoundaryName, BoundaryID>(boundary_name);
275
276 return id;
277}
const BoundaryID INVALID_BOUNDARY_ID
Definition MooseTypes.C:22

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

◆ getBoundaryIDs() [1/4]

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

Gets the boundary IDs with their names.

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

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

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

◆ getBoundaryIDs() [2/4]

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

Gets the boundary IDs with their names.

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

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

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

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

◆ getBoundaryIDs() [3/4]

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

Definition at line 107 of file MooseMeshUtils.C.

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

◆ getBoundaryIDs() [4/4]

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

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

Definition at line 116 of file MooseMeshUtils.C.

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

◆ getBoundaryIDSet() [1/2]

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

Gets the boundary IDs into a set with their names.

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

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

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

Referenced by DomainUserObject::DomainUserObject().

◆ getBoundaryIDSet() [2/2]

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

Definition at line 191 of file MooseMeshUtils.C.

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

◆ getBoundaryNodes()

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

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

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

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

Definition at line 1032 of file MooseMeshUtils.C.

1033{
1034 std::set<dof_id_type> boundary_node_ids;
1035 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
1036
1037 // Get all nodes from the sideset with ID of boundary_id
1038 const auto & bc_sides =
1039 boundary_info.build_side_list(libMesh::BoundaryInfo::BCTupleSortBy::BOUNDARY_ID);
1040 for (const auto & [elem_id, side, bc_id] : bc_sides)
1041 {
1042 if (bc_id == boundary_id)
1043 {
1044 const auto elem = mesh.elem_ptr(elem_id);
1045 for (const auto ni : elem->nodes_on_side(side))
1046 boundary_node_ids.insert(elem->node_id(ni));
1047 }
1048 }
1049
1050 // Get all nodes from nodeset with ID of boundary_id
1051 const auto & bc_nodes = boundary_info.build_node_list();
1052 for (const auto & [n_id, bc_id] : bc_nodes)
1053 if (bc_id == boundary_id)
1054 boundary_node_ids.insert(n_id);
1055
1056 return boundary_node_ids;
1057}

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

415{
416 // check block restriction
417 const bool block_restricted = !block_ids.empty();
418 // get element id name of interest in recursive parsing algorithm
419 ExtraElementIDName id_name = extra_ids.back();
420 extra_ids.pop_back();
421 const auto id_index = mesh.get_elem_integer_index(id_name);
422
423 // create base parsed id set
424 if (extra_ids.empty())
425 {
426 // get set of extra id values;
427 std::vector<dof_id_type> ids;
428 {
429 std::set<dof_id_type> ids_set;
430 for (const auto & elem : mesh.active_element_ptr_range())
431 {
432 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
433 continue;
434 const auto id = elem->get_extra_integer(id_index);
435 ids_set.insert(id);
436 }
437 mesh.comm().set_union(ids_set);
438 ids.assign(ids_set.begin(), ids_set.end());
439 }
440
441 // determine new extra id values;
442 std::unordered_map<dof_id_type, dof_id_type> parsed_ids;
443 for (auto & elem : mesh.active_element_ptr_range())
444 {
445 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
446 continue;
447 parsed_ids[elem->id()] = std::distance(
448 ids.begin(), std::lower_bound(ids.begin(), ids.end(), elem->get_extra_integer(id_index)));
449 }
450 return parsed_ids;
451 }
452
453 // if extra_ids is not empty, recursively call getExtraIDUniqueCombinationMap
454 const auto base_parsed_ids =
455 MooseMeshUtils::getExtraIDUniqueCombinationMap(mesh, block_ids, extra_ids);
456 // parsing extra ids based on ref_parsed_ids
457 std::vector<std::pair<dof_id_type, dof_id_type>> unique_ids;
458 {
459 std::set<std::pair<dof_id_type, dof_id_type>> unique_ids_set;
460 for (const auto & elem : mesh.active_element_ptr_range())
461 {
462 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
463 continue;
464 const dof_id_type id1 = libmesh_map_find(base_parsed_ids, elem->id());
465 const dof_id_type id2 = elem->get_extra_integer(id_index);
466 const std::pair<dof_id_type, dof_id_type> ids = std::make_pair(id1, id2);
467 unique_ids_set.insert(ids);
468 }
469 mesh.comm().set_union(unique_ids_set);
470 unique_ids.assign(unique_ids_set.begin(), unique_ids_set.end());
471 }
472
473 std::unordered_map<dof_id_type, dof_id_type> parsed_ids;
474
475 for (const auto & elem : mesh.active_element_ptr_range())
476 {
477 if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
478 continue;
479 const dof_id_type id1 = libmesh_map_find(base_parsed_ids, elem->id());
480 const dof_id_type id2 = elem->get_extra_integer(id_index);
481 const dof_id_type new_id = std::distance(
482 unique_ids.begin(),
483 std::lower_bound(unique_ids.begin(), unique_ids.end(), std::make_pair(id1, id2)));
484 parsed_ids[elem->id()] = new_id;
485 }
486
487 return parsed_ids;
488}
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 411 of file MooseMeshUtils.h.

412{
413 if (!MooseUtils::isDigits(name))
415 "'name' ", name, " should only contain digits that can be converted to a numerical type.");
416 long long id = std::stoll(name);
417 Q id_Q = Q(id);
418 if (id < std::numeric_limits<Q>::min() || id > std::numeric_limits<Q>::max())
419 mooseError(MooseUtils::prettyCppType<T>(&name),
420 " ",
421 name,
422 " is not within the numeric limits of the expected ID type ",
423 MooseUtils::prettyCppType<Q>(&id_Q),
424 ".");
425
426 return id_Q;
427}

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

554{
555 if (!input_mesh.preparation().has_boundary_id_sets)
556 input_mesh.get_boundary_info().regenerate_id_sets();
557
558 auto boundary_ids = input_mesh.get_boundary_info().get_boundary_ids();
559 if (boundary_ids.empty())
560 return 0;
561 return (*boundary_ids.rbegin() + 1);
562}

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

◆ getNextFreeSubdomainID()

SubdomainID MooseMeshUtils::getNextFreeSubdomainID ( MeshBase &  input_mesh)

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

Parameters
inputmesh over which to compute the next free block id

Definition at line 533 of file MooseMeshUtils.C.

534{
535 // Call this to get most up to date block id information
536 input_mesh.cache_elem_data();
537
538 std::set<SubdomainID> preexisting_subdomain_ids;
539 input_mesh.subdomain_ids(preexisting_subdomain_ids);
540 if (preexisting_subdomain_ids.empty())
541 return 0;
542 else
543 {
544 const auto highest_subdomain_id =
545 *std::max_element(preexisting_subdomain_ids.begin(), preexisting_subdomain_ids.end());
546 mooseAssert(highest_subdomain_id < std::numeric_limits<SubdomainID>::max(),
547 "A SubdomainID with max possible value was found");
548 return highest_subdomain_id + 1;
549 }
550}

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

◆ getSubdomainID()

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

Gets the subdomain ID associated with the given SubdomainName.

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

Definition at line 280 of file MooseMeshUtils.C.

281{
282 if (subdomain_name == "ANY_BLOCK_ID")
283 mooseError("getSubdomainID() does not work with \"ANY_BLOCK_ID\"");
284
286 if (subdomain_name.empty())
287 return id;
288
289 if (!MooseUtils::isDigits(subdomain_name))
290 id = mesh.get_id_by_name(subdomain_name);
291 else
292 id = getIDFromName<SubdomainName, SubdomainID>(subdomain_name);
293
294 return id;
295}
const SubdomainID INVALID_BLOCK_ID
Definition MooseTypes.C:20

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

◆ getSubdomainIDs() [1/4]

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

◆ getSubdomainIDs() [2/4]

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

◆ getSubdomainIDs() [3/4]

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

Definition at line 246 of file MooseMeshUtils.C.

247{
248 const auto blk_ids = getSubdomainIDs(
249 mesh, std::vector<SubdomainName>(subdomain_names.begin(), subdomain_names.end()));
250 return {blk_ids.begin(), blk_ids.end()};
251}

◆ getSubdomainIDs() [4/4]

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

Definition at line 217 of file MooseMeshUtils.C.

218{
219 std::vector<subdomain_id_type> ids;
220
221 // shortcut for "ANY_BLOCK_ID"
222 if (subdomain_names.size() == 1 && subdomain_names[0] == "ANY_BLOCK_ID")
223 {
224 // since get_mesh_subdomains() requires a prepared mesh, we need to check that here
225 mooseAssert(mesh.is_prepared(),
226 "getSubdomainIDs() should only be called on a prepared mesh if ANY_BLOCK_ID is "
227 "used to query all block IDs");
228 ids.assign(mesh.get_mesh_subdomains().begin(), mesh.get_mesh_subdomains().end());
229 return ids;
230 }
231
232 // loop through subdomain names and get IDs (this preserves the order of subdomain_names)
233 ids.resize(subdomain_names.size());
234 for (auto i : index_range(subdomain_names))
235 {
236 if (subdomain_names[i] == "ANY_BLOCK_ID")
237 mooseError("getSubdomainIDs() accepts \"ANY_BLOCK_ID\" if and only if it is the only "
238 "subdomain name being queried.");
239 ids[i] = MooseMeshUtils::getSubdomainID(subdomain_names[i], mesh);
240 }
241
242 return ids;
243}
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 586 of file MooseMeshUtils.C.

587{
588 const BoundaryInfo & boundary_info = input_mesh.get_boundary_info();
589 std::set<boundary_id_type> boundary_ids = boundary_info.get_boundary_ids();
590
591 // On a distributed mesh we may have boundary IDs that only exist on
592 // other processors
593 if (!input_mesh.is_replicated())
594 input_mesh.comm().set_union(boundary_ids);
595
596 return boundary_ids.count(id) && (id != Moose::INVALID_BOUNDARY_ID);
597}

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

601{
602 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
603 const BoundaryID id = boundary_info.get_id_by_name(name);
604 return id != Moose::INVALID_BOUNDARY_ID;
605}

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

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

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

◆ hasSubdomainID()

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

Whether a particular subdomain ID exists in the mesh.

Parameters
inputmesh over which to determine subdomain IDs
subdomainID

Definition at line 565 of file MooseMeshUtils.C.

566{
567 std::set<SubdomainID> mesh_blocks;
568 input_mesh.subdomain_ids(mesh_blocks);
569
570 // On a distributed mesh we may have sideset IDs that only exist on
571 // other processors
572 if (!input_mesh.is_replicated())
573 input_mesh.comm().set_union(mesh_blocks);
574
575 return mesh_blocks.count(id) && (id != Moose::INVALID_BLOCK_ID);
576}

Referenced by MooseMeshElementConversionUtils::assignConvertedElementsSubdomainNameSuffix(), AdvancedExtruderGenerator::generate(), BlockDeletionGenerator::generate(), BreakMeshByElementGenerator::generate(), CoarsenBlockGenerator::generate(), ManifoldSubdomainGenerator::generate(), MeshExtruderGenerator::generate(), RefineBlockGenerator::generate(), StitchMeshGenerator::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 448 of file MooseMeshUtils.h.

453{
454 id_swap_pairs.resize(id_swaps.size());
455 for (const auto i : index_range(id_swaps))
456 {
457 const auto & swaps = id_swaps[i];
458 auto & swap_pairs = id_swap_pairs[i];
459
460 if (swaps.size() % 2)
461 throw MooseException("Row ",
462 row_index_shift + i + 1,
463 " of ",
464 id_name,
465 " in ",
466 class_name,
467 " does not contain an even number of entries! Num entries: ",
468 swaps.size());
469
470 swap_pairs.reserve(swaps.size() / 2);
471 for (unsigned int j = 0; j < swaps.size(); j += 2)
472 swap_pairs[swaps[j]] = swaps[j + 1];
473 }
474}

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

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

507{
508 // Assuming that overlapped Points are allowed, the Points that are overlapped with vec_pts[0] are
509 // removed before further calculation.
510 std::vector<Point> vec_pts_nonzero{vec_pts[0]};
511 for (const auto i : index_range(vec_pts))
512 if (!MooseUtils::absoluteFuzzyEqual((vec_pts[i] - vec_pts[0]).norm(), 0.0))
513 vec_pts_nonzero.push_back(vec_pts[i]);
514 // 3 or fewer points are always coplanar
515 if (vec_pts_nonzero.size() <= 3)
516 return true;
517 else
518 {
519 for (const auto i : make_range(vec_pts_nonzero.size() - 1))
520 {
521 const Point tmp_pt = (vec_pts_nonzero[i] - vec_pts_nonzero[0])
522 .cross(vec_pts_nonzero[i + 1] - vec_pts_nonzero[0]);
523 // if the three points are not collinear, use cross product as the normal vector of the plane
524 if (!MooseUtils::absoluteFuzzyEqual(tmp_pt.norm(), 0.0))
525 return isCoPlanar(vec_pts_nonzero, tmp_pt.unit());
526 }
527 }
528 // If all the points are collinear, they are also coplanar
529 return true;
530}

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

501{
502 return isCoPlanar(vec_pts, plane_nvec, vec_pts.front());
503}
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 491 of file MooseMeshUtils.C.

492{
493 for (const auto & pt : vec_pts)
494 if (!MooseUtils::absoluteFuzzyEqual((pt - fixed_pt) * plane_nvec, 0.0))
495 return false;
496 return true;
497}

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

620{
621 // a flag to indicate if the ordered_node_list has been reversed
622 bool is_flipped = false;
623 // Start from the first element, try to find a chain of nodes
624 mooseAssert(node_assm.size(), "Node list must not be empty");
625 ordered_node_list.push_back(node_assm.front().first);
626 if (midpoint_node_list.front() != DofObject::invalid_id)
627 ordered_node_list.push_back(midpoint_node_list.front());
628 ordered_node_list.push_back(node_assm.front().second);
629 ordered_elem_id_list.push_back(elem_id_list.front());
630 // Remove the element that has just been added to ordered_node_list
631 node_assm.erase(node_assm.begin());
632 midpoint_node_list.erase(midpoint_node_list.begin());
633 elem_id_list.erase(elem_id_list.begin());
634 const unsigned int node_assm_size_0 = node_assm.size();
635 for (unsigned int i = 0; i < node_assm_size_0; i++)
636 {
637 // Find nodes to expand the chain
638 dof_id_type end_node_id = ordered_node_list.back();
639 auto isMatch1 = [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair)
640 { return old_id_pair.first == end_node_id; };
641 auto isMatch2 = [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair)
642 { return old_id_pair.second == end_node_id; };
643 auto result = std::find_if(node_assm.begin(), node_assm.end(), isMatch1);
644 bool match_first;
645 if (result == node_assm.end())
646 {
647 match_first = false;
648 result = std::find_if(node_assm.begin(), node_assm.end(), isMatch2);
649 }
650 else
651 {
652 match_first = true;
653 }
654 // If found, add the node to boundary_ordered_node_list
655 if (result != node_assm.end())
656 {
657 const auto elem_index = std::distance(node_assm.begin(), result);
658 if (midpoint_node_list[elem_index] != DofObject::invalid_id)
659 ordered_node_list.push_back(midpoint_node_list[elem_index]);
660 ordered_node_list.push_back(match_first ? (*result).second : (*result).first);
661 node_assm.erase(result);
662 midpoint_node_list.erase(midpoint_node_list.begin() + elem_index);
663 ordered_elem_id_list.push_back(elem_id_list[elem_index]);
664 elem_id_list.erase(elem_id_list.begin() + elem_index);
665 }
666 // If there are still elements in node_assm and result ==
667 // node_assm.end(), this means the curve is not a loop, the
668 // ordered_node_list is flipped and try the other direction that has not
669 // been examined yet.
670 else
671 {
672 if (is_flipped)
673 // Flipped twice; this means the node list has at least two segments.
674 throw MooseException("The node list provided has more than one segments.");
675
676 // mark the first flip event.
677 is_flipped = true;
678 std::reverse(ordered_node_list.begin(), ordered_node_list.end());
679 std::reverse(midpoint_node_list.begin(), midpoint_node_list.end());
680 std::reverse(ordered_elem_id_list.begin(), ordered_elem_id_list.end());
681 // As this iteration is wasted, set the iterator backward
682 i--;
683 }
684 }
685}

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

692{
693 std::vector<dof_id_type> dummy_midpoint_node_list(node_assm.size(), DofObject::invalid_id);
695 node_assm, elem_id_list, dummy_midpoint_node_list, ordered_node_list, ordered_elem_id_list);
696}
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 309 of file MooseMeshUtils.C.

310{
311 Point centroid_pt = Point(0.0, 0.0, 0.0);
312 Real vol_tmp = 0.0;
313 for (const auto & elem : mesh.active_local_element_ptr_range())
314 {
315 Real elem_vol = elem->volume();
316 centroid_pt += (elem->true_centroid()) * elem_vol;
317 vol_tmp += elem_vol;
318 }
319 mesh.comm().sum(centroid_pt);
320 mesh.comm().sum(vol_tmp);
321 centroid_pt /= vol_tmp;
322 return centroid_pt;
323}

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

◆ nodalQuadraturePointToNodeMap()

std::vector< unsigned int > MooseMeshUtils::nodalQuadraturePointToNodeMap ( const Elem &  elem,
const std::vector< Point > &  q_points 
)

Match the points of a nodal quadrature rule (e.g.

QNodal on a side of a parent element) to the nodes of an element at the same physical locations. The quadrature ordering is not guaranteed to match the node ordering of the element, especially for higher-order faces, so the association is built geometrically so each quadrature value is attached to the node at the same physical point.

Parameters
elemthe element whose nodes are matched
q_pointsthe physical locations of the nodal quadrature points
Returns
a map from each quadrature point index to the local index of the matching node

Definition at line 1561 of file MooseMeshUtils.C.

1562{
1563 const auto n_nodes = elem.n_nodes();
1564 if (q_points.size() != n_nodes)
1565 mooseError("Nodal quadrature produced ",
1566 q_points.size(),
1567 " points for element ",
1568 elem.id(),
1569 " of type ",
1570 libMesh::Utility::enum_to_string<ElemType>(elem.type()),
1571 ", but the element has ",
1572 n_nodes,
1573 " nodes.");
1574
1575 const auto invalid_node = std::numeric_limits<unsigned int>::max();
1576 std::vector<unsigned int> qpoint_to_node(n_nodes, invalid_node);
1577 std::vector<bool> node_used(n_nodes, false);
1578
1579 const Real element_size = elem.hmax();
1580 mooseAssert(
1581 element_size > 0,
1582 "Element " << elem.id() << " of type "
1583 << libMesh::Utility::enum_to_string<ElemType>(elem.type())
1584 << " has a non-positive hmax and cannot be used for nodal quadrature point "
1585 "matching.");
1586
1587 // The nodal quadrature locations and the generated nodes are two floating-point
1588 // reconstructions of the same physical points. Scale the tolerance by element size so the
1589 // matching is insensitive to coordinate magnitude; the 100*TOLERANCE factor allows roundoff
1590 // from FE reinitialization and mesh generation while remaining far below a valid node spacing.
1591 const Real matching_tol = 100 * TOLERANCE * element_size;
1592 const Real matching_tol_sq = matching_tol * matching_tol;
1593
1594 // Each nodal quadrature point should coincide with exactly one still-unused
1595 // node. The unused-node search makes the mapping one-to-one and
1596 // avoids silently assigning two quadrature entries to the same node.
1597 for (const auto qp : make_range(q_points.size()))
1598 {
1599 unsigned int closest_node = invalid_node;
1600 Real closest_dist_sq = std::numeric_limits<Real>::max();
1601 Real second_closest_dist_sq = std::numeric_limits<Real>::max();
1602
1603 for (const auto n : make_range(n_nodes))
1604 {
1605 if (node_used[n])
1606 continue;
1607
1608 const Real dist_sq = (q_points[qp] - elem.point(n)).norm_sq();
1609 if (dist_sq < closest_dist_sq)
1610 {
1611 second_closest_dist_sq = closest_dist_sq;
1612 closest_dist_sq = dist_sq;
1613 closest_node = n;
1614 }
1615 else if (dist_sq < second_closest_dist_sq)
1616 second_closest_dist_sq = dist_sq;
1617 }
1618
1619 if (closest_node == invalid_node || closest_dist_sq > matching_tol_sq)
1620 mooseError("Could not match nodal quadrature point ",
1621 qp,
1622 " at ",
1623 q_points[qp],
1624 " to a node on element ",
1625 elem.id(),
1626 " of type ",
1627 libMesh::Utility::enum_to_string<ElemType>(elem.type()),
1628 ". The nearest unmatched node distance is ",
1629 std::sqrt(closest_dist_sq),
1630 ", which exceeds the tolerance ",
1631 matching_tol,
1632 ".");
1633
1634 if (second_closest_dist_sq <= matching_tol_sq)
1635 mooseError("Nodal quadrature point ",
1636 qp,
1637 " at ",
1638 q_points[qp],
1639 " does not map uniquely to element ",
1640 elem.id(),
1641 " of type ",
1642 libMesh::Utility::enum_to_string<ElemType>(elem.type()),
1643 ". Two unmatched nodes are within the matching tolerance ",
1644 matching_tol,
1645 ".");
1646
1647 qpoint_to_node[qp] = closest_node;
1648 node_used[closest_node] = true;
1649 }
1650
1651#ifdef DEBUG
1652 // In optimized builds the mapping above skips already matched nodes for speed. In debug builds,
1653 // audit the full candidate set to catch ambiguous geometry or accidental many-to-one matches.
1654 std::vector<unsigned int> node_to_qpoint(n_nodes, invalid_node);
1655 for (const auto qp : make_range(q_points.size()))
1656 {
1657 const auto mapped_node = qpoint_to_node[qp];
1658 mooseAssert(mapped_node != invalid_node && mapped_node < n_nodes,
1659 "Invalid node mapping for nodal quadrature point " << qp << ".");
1660 mooseAssert(node_to_qpoint[mapped_node] == invalid_node,
1661 "Node " << mapped_node << " on element " << elem.id()
1662 << " was matched to both nodal quadrature point "
1663 << node_to_qpoint[mapped_node] << " and " << qp << ".");
1664 node_to_qpoint[mapped_node] = qp;
1665
1666 // Check the qp -> node direction without excluding nodes already matched by previous qps.
1667 unsigned int candidate_count = 0;
1668 unsigned int candidate_node = invalid_node;
1669 for (const auto n : make_range(n_nodes))
1670 if ((q_points[qp] - elem.point(n)).norm_sq() <= matching_tol_sq)
1671 {
1672 ++candidate_count;
1673 candidate_node = n;
1674 }
1675
1676 mooseAssert(candidate_count == 1,
1677 "Nodal quadrature point " << qp << " on element " << elem.id() << " has "
1678 << candidate_count << " node candidates within tolerance "
1679 << matching_tol << ".");
1680 mooseAssert(candidate_node == mapped_node,
1681 "Nodal quadrature point "
1682 << qp << " on element " << elem.id() << " was matched to node " << mapped_node
1683 << ", but the full candidate search found node " << candidate_node << ".");
1684 }
1685
1686 for (const auto n : make_range(n_nodes))
1687 {
1688 mooseAssert(node_to_qpoint[n] != invalid_node,
1689 "Node " << n << " on element " << elem.id()
1690 << " was not matched to a nodal quadrature point.");
1691
1692 // Check the node -> qp direction so every node is also uniquely represented.
1693 unsigned int candidate_count = 0;
1694 unsigned int candidate_qp = invalid_node;
1695 for (const auto qp : make_range(q_points.size()))
1696 if ((q_points[qp] - elem.point(n)).norm_sq() <= matching_tol_sq)
1697 {
1698 ++candidate_count;
1699 candidate_qp = qp;
1700 }
1701
1702 mooseAssert(candidate_count == 1,
1703 "Node " << n << " on element " << elem.id() << " has " << candidate_count
1704 << " nodal quadrature point candidates within tolerance " << matching_tol
1705 << ".");
1706 mooseAssert(candidate_qp == node_to_qpoint[n],
1707 "Node " << n << " on element " << elem.id()
1708 << " was matched to nodal quadrature point " << node_to_qpoint[n]
1709 << ", but the full candidate search found point " << candidate_qp << ".");
1710 }
1711#endif
1712
1713 return qpoint_to_node;
1714}
LIBMESH_DEVICE_INLINE auto norm_sq(const T &a)
const dof_id_type n_nodes

Referenced by AutomaticMortarGeneration::computeADNodalNormals(), AutomaticMortarGeneration::computeNodalGeometry(), and AdvancedExtruderGenerator::computeNodeNormals().

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

700{
701 Node * n_temp = elem.node_ptr(nd1);
702 elem.set_node(nd1, elem.node_ptr(nd2));
703 elem.set_node(nd2, n_temp);
704}

Referenced by AdvancedExtruderGenerator::generate().