LCOV - code coverage report
Current view: top level - include/utils - MooseMeshUtils.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31761 (28487c) with base 701993 Lines: 35 41 85.4 %
Date: 2025-11-11 13:51:07 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : #include "libmesh/replicated_mesh.h"
      13             : #include "libmesh/boundary_info.h"
      14             : 
      15             : #include "MooseUtils.h"
      16             : #include "MooseTypes.h"
      17             : #include "FaceInfo.h"
      18             : #include "MeshGenerator.h"
      19             : 
      20             : namespace MooseMeshUtils
      21             : {
      22             : 
      23             : // Used to temporarily store information about which lower-dimensional
      24             : // sides to add and what subdomain id to use for the added sides.
      25             : struct ElemSidePair
      26             : {
      27       24507 :   ElemSidePair(Elem * elem_in, unsigned short int side_in) : elem(elem_in), side(side_in) {}
      28             : 
      29             :   Elem * elem;
      30             :   unsigned short int side;
      31             : };
      32             : 
      33             : /**
      34             :  * Merges the boundary IDs of boundaries that have the same names
      35             :  * but different IDs.
      36             :  * @param mesh The input mesh whose boundaries we will modify
      37             :  */
      38             : void mergeBoundaryIDsWithSameName(MeshBase & mesh);
      39             : 
      40             : /**
      41             :  * Changes the old boundary ID to a new ID in the mesh
      42             :  *
      43             :  * @param mesh the mesh
      44             :  * @param old_id the old boundary id
      45             :  * @param new_id the new boundary id
      46             :  * @param delete_prev whether to delete the previous boundary id from the mesh
      47             :  */
      48             : void changeBoundaryId(MeshBase & mesh,
      49             :                       const libMesh::boundary_id_type old_id,
      50             :                       const libMesh::boundary_id_type new_id,
      51             :                       bool delete_prev);
      52             : 
      53             : /**
      54             :  * Changes the old subdomain ID to a new ID in the mesh
      55             :  *
      56             :  * @param mesh the mesh
      57             :  * @param old_id the old subdomain id
      58             :  * @param new_id the new subdomain id
      59             :  */
      60             : void
      61             : changeSubdomainId(MeshBase & mesh, const subdomain_id_type old_id, const subdomain_id_type new_id);
      62             : 
      63             : /**
      64             :  * Gets the boundary IDs with their names.
      65             :  *
      66             :  * The ordering of the returned boundary ID vector matches the vector of the boundary
      67             :  * names in \p boundary_name.
      68             :  * When a boundary name is not available in the mesh, if \p generate_unknown is true
      69             :  * a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id
      70             :  * will be returned.
      71             :  */
      72             : std::vector<BoundaryID> getBoundaryIDs(const libMesh::MeshBase & mesh,
      73             :                                        const std::vector<BoundaryName> & boundary_name,
      74             :                                        bool generate_unknown,
      75             :                                        const std::set<BoundaryID> & mesh_boundary_ids);
      76             : 
      77             : /**
      78             :  * Gets the boundary IDs with their names.
      79             :  *
      80             :  * The ordering of the returned boundary ID vector matches the vector of the boundary
      81             :  * names in \p boundary_name.
      82             :  * When a boundary name is not available in the mesh, if \p generate_unknown is true
      83             :  * a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id
      84             :  * will be returned.
      85             :  */
      86             : std::vector<BoundaryID> getBoundaryIDs(const libMesh::MeshBase & mesh,
      87             :                                        const std::vector<BoundaryName> & boundary_name,
      88             :                                        bool generate_unknown);
      89             : 
      90             : /**
      91             :  * Gets the boundary IDs into a set with their names.
      92             :  *
      93             :  * Because libMesh allows the same boundary to have multiple different boundary names,
      94             :  * the size of the returned boundary ID set may be smaller than the size of the bounndary
      95             :  * name vector.
      96             :  * When a boundary name is not available in the mesh, if \p generate_unknown is true
      97             :  * a non-existant boundary ID will be returned, otherwise a BoundaryInfo::invalid_id
      98             :  * will be returned.
      99             :  */
     100             : std::set<BoundaryID> getBoundaryIDSet(const libMesh::MeshBase & mesh,
     101             :                                       const std::vector<BoundaryName> & boundary_name,
     102             :                                       bool generate_unknown);
     103             : 
     104             : /**
     105             :  * Gets the boundary ID associated with the given BoundaryName.
     106             :  *
     107             :  * This is needed because the BoundaryName can be either an ID or a name.
     108             :  * If it is a name, the mesh is queried for the ID associated with said name.
     109             :  */
     110             : BoundaryID getBoundaryID(const BoundaryName & boundary_name, const MeshBase & mesh);
     111             : 
     112             : /**
     113             :  * Gets the subdomain ID associated with the given SubdomainName.
     114             :  *
     115             :  * This is needed because the SubdomainName can be either an ID or a name.
     116             :  * If it is a name, the mesh is queried for the ID associated with said name.
     117             :  */
     118             : SubdomainID getSubdomainID(const SubdomainName & subdomain_name, const MeshBase & mesh);
     119             : 
     120             : /**
     121             :  * Get the associated subdomainIDs for the subdomain names that are passed in.
     122             :  *
     123             :  * @param mesh The mesh
     124             :  * @param subdomain_name The names of the subdomains
     125             :  * @return The subdomain ids from the passed subdomain names.
     126             :  */
     127             : std::vector<subdomain_id_type> getSubdomainIDs(const libMesh::MeshBase & mesh,
     128             :                                                const std::vector<SubdomainName> & subdomain_name);
     129             : std::set<subdomain_id_type> getSubdomainIDs(const libMesh::MeshBase & mesh,
     130             :                                             const std::set<SubdomainName> & subdomain_name);
     131             : 
     132             : /**
     133             :  * Calculates the centroid of a MeshBase.
     134             :  * @param mesh input mesh whose centroid needs to be calculated
     135             :  * @return a Point data containing the mesh centroid
     136             :  */
     137             : Point meshCentroidCalculator(const MeshBase & mesh);
     138             : 
     139             : /**
     140             :  * compute a coordinate transformation factor
     141             :  * @param point The libMesh \p Point in space where we are evaluating the factor
     142             :  * @param factor The output of this function. Would be 1 for cartesian coordinate systems, 2*pi*r
     143             :  * for cylindrical coordinate systems, and 4*pi*r^2 for spherical coordinate systems
     144             :  * @param coord_type The coordinate system type, e.g. cartesian (COORD_XYZ), cylindrical (COORD_RZ),
     145             :  * or spherical (COORD_RSPHERICAL)
     146             :  * @param rz_radial_coord The index at which to index \p point for the radial coordinate when in a
     147             :  * cylindrical coordinate system
     148             :  */
     149             : template <typename P, typename C>
     150             : void
     151  2166986565 : coordTransformFactor(const P & point,
     152             :                      C & factor,
     153             :                      const Moose::CoordinateSystemType coord_type,
     154             :                      const unsigned int rz_radial_coord = libMesh::invalid_uint)
     155             : {
     156  2166986565 :   switch (coord_type)
     157             :   {
     158  2163890761 :     case Moose::COORD_XYZ:
     159  2163890761 :       factor = 1.0;
     160  2163890761 :       break;
     161     3057538 :     case Moose::COORD_RZ:
     162             :     {
     163             :       mooseAssert(rz_radial_coord != libMesh::invalid_uint,
     164             :                   "Must pass in a valid rz radial coordinate");
     165     3057538 :       factor = 2 * M_PI * point(rz_radial_coord);
     166     3057538 :       break;
     167             :     }
     168       38266 :     case Moose::COORD_RSPHERICAL:
     169       38266 :       factor = 4 * M_PI * point(0) * point(0);
     170       38266 :       break;
     171           0 :     default:
     172           0 :       mooseError("Unknown coordinate system");
     173             :   }
     174  2166986565 : }
     175             : 
     176             : /**
     177             :  * Computes the distance to a general axis
     178             :  *
     179             :  * @param[in] point  Point for which to compute distance from axis
     180             :  * @param[in] origin  Axis starting point
     181             :  * @param[in] direction  Axis direction
     182             :  */
     183             : template <typename P, typename C>
     184             : C
     185     1212256 : computeDistanceToAxis(const P & point, const Point & origin, const RealVectorValue & direction)
     186             : {
     187     1212256 :   return (point - origin).cross(direction).norm();
     188             : }
     189             : 
     190             : /**
     191             :  * Computes a coordinate transformation factor for a general axisymmetric axis
     192             :  *
     193             :  * @param[in] point  The libMesh \p Point in space where we are evaluating the factor
     194             :  * @param[in] axis  The pair of values defining the general axisymmetric axis.
     195             :  *                  Respectively, the values are the axis starting point and direction.
     196             :  * @param[out] factor  The coordinate transformation factor
     197             :  */
     198             : template <typename P, typename C>
     199             : void
     200     1212256 : coordTransformFactorRZGeneral(const P & point,
     201             :                               const std::pair<Point, RealVectorValue> & axis,
     202             :                               C & factor)
     203             : {
     204     1212256 :   factor = 2 * M_PI * computeDistanceToAxis<P, C>(point, axis.first, axis.second);
     205     1212256 : }
     206             : 
     207             : inline void
     208             : computeFiniteVolumeCoords(FaceInfo & fi,
     209             :                           const Moose::CoordinateSystemType coord_type,
     210             :                           const unsigned int rz_radial_coord = libMesh::invalid_uint)
     211             : {
     212             :   coordTransformFactor(fi.faceCentroid(), fi.faceCoord(), coord_type, rz_radial_coord);
     213             : }
     214             : 
     215             : /**
     216             :  * Crate a new set of element-wise IDs by finding unique combinations of existing extra ID values
     217             :  *
     218             :  * This function finds the unique combinations by recursively calling itself for extra ID inputs. In
     219             :  * the recursive calling, the new unique combinations is determined by combining the extra ID value
     220             :  * of current level and the unique combination determined in the previous level in recursion. In the
     221             :  * lowest level of recursion, the base combination is set by the unique ID values of the
     222             :  * corresponding extra ID.
     223             :  *
     224             :  * @param mesh input mesh
     225             :  * @param block_ids block ids
     226             :  * @param extra_ids extra ids
     227             :  * @return map of element id to new extra id
     228             :  **/
     229             : std::unordered_map<dof_id_type, dof_id_type>
     230             : getExtraIDUniqueCombinationMap(const MeshBase & mesh,
     231             :                                const std::set<SubdomainID> & block_ids,
     232             :                                std::vector<ExtraElementIDName> extra_ids);
     233             : 
     234             : /**
     235             :  * Decides whether all the Points of a vector of Points are in a plane that is defined by a normal
     236             :  * vector and an inplane Point
     237             :  * @param vec_pts vector of points to be examined
     238             :  * @param plane_nvec normal vector of the plane
     239             :  * @param fixed_pt a Point in the plane
     240             :  * @return whether all the Points are in the given plane
     241             :  */
     242             : bool isCoPlanar(const std::vector<Point> vec_pts, const Point plane_nvec, const Point fixed_pt);
     243             : 
     244             : /**
     245             :  * Decides whether all the Points of a vector of Points are in a plane with a given normal vector
     246             :  * @param vec_pts vector of points to be examined
     247             :  * @param plane_nvec normal vector of the plane
     248             :  * @return whether all the Points are in the same plane with the given normal vector
     249             :  */
     250             : bool isCoPlanar(const std::vector<Point> vec_pts, const Point plane_nvec);
     251             : 
     252             : /**
     253             :  * Decides whether all the Points of a vector of Points are coplanar
     254             :  * @param vec_pts vector of points to be examined
     255             :  * @return whether all the Points are in a same plane
     256             :  */
     257             : bool isCoPlanar(const std::vector<Point> vec_pts);
     258             : 
     259             : /**
     260             :  * Checks input mesh and returns max(block ID) + 1, which represents
     261             :  * a block ID that is not currently in use in the mesh
     262             :  * @param input mesh over which to compute the next free block id
     263             :  */
     264             : SubdomainID getNextFreeSubdomainID(MeshBase & input_mesh);
     265             : 
     266             : /**
     267             :  * Checks input mesh and returns the largest boundary ID in the mesh plus one, which is
     268             :  * a boundary ID in the mesh that is not currently in use
     269             :  * @param input mesh over which to compute the next free boundary ID
     270             :  */
     271             : 
     272             : BoundaryID getNextFreeBoundaryID(MeshBase & input_mesh);
     273             : /**
     274             :  * Whether a particular subdomain ID exists in the mesh
     275             :  * @param input mesh over which to determine subdomain IDs
     276             :  * @param subdomain ID
     277             :  */
     278             : bool hasSubdomainID(const MeshBase & input_mesh, const SubdomainID & id);
     279             : 
     280             : /**
     281             :  * Whether a particular subdomain name exists in the mesh
     282             :  * @param input mesh over which to determine subdomain names
     283             :  * @param subdomain name
     284             :  */
     285             : bool hasSubdomainName(const MeshBase & input_mesh, const SubdomainName & name);
     286             : 
     287             : /**
     288             :  * Whether a particular boundary ID exists in the mesh
     289             :  * @param input mesh over which to determine boundary IDs
     290             :  * @param boundary ID
     291             :  */
     292             : bool hasBoundaryID(const MeshBase & input_mesh, const BoundaryID id);
     293             : 
     294             : /**
     295             :  * Whether a particular boundary name exists in the mesh
     296             :  * @param input mesh over which to determine boundary names
     297             :  * @param boundary name
     298             :  */
     299             : bool hasBoundaryName(const MeshBase & input_mesh, const BoundaryName & name);
     300             : 
     301             : /**
     302             :  * Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes
     303             :  * based on connectivity
     304             :  * @param node_assm vector of pairs of node ids that represent the sides
     305             :  * @param elem_id_list vector of element ids that represent the elements that contain the sides
     306             :  * @param midpoint_node_list vector of node ids that represent the midpoints of the sides for
     307             :  * quadratic sides
     308             :  * @param ordered_node_list vector of node ids that represent the ordered nodes
     309             :  * @param ordered_elem_id_list vector of element corresponding to the ordered nodes
     310             :  * */
     311             : void makeOrderedNodeList(std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
     312             :                          std::vector<dof_id_type> & elem_id_list,
     313             :                          std::vector<dof_id_type> & midpoint_node_list,
     314             :                          std::vector<dof_id_type> & ordered_node_list,
     315             :                          std::vector<dof_id_type> & ordered_elem_id_list);
     316             : 
     317             : /**
     318             :  * Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes
     319             :  * based on connectivity
     320             :  * @param node_assm vector of pairs of node ids that represent the sides
     321             :  * @param elem_id_list vector of element ids that represent the elements that contain the sides
     322             :  * @param ordered_node_list vector of node ids that represent the ordered nodes
     323             :  * @param ordered_elem_id_list vector of element corresponding to the ordered nodes
     324             :  * */
     325             : void makeOrderedNodeList(std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
     326             :                          std::vector<dof_id_type> & elem_id_list,
     327             :                          std::vector<dof_id_type> & ordered_node_list,
     328             :                          std::vector<dof_id_type> & ordered_elem_id_list);
     329             : 
     330             : /**
     331             :  * Converts a given name (BoundaryName or SubdomainName) that is known to only contain digits into a
     332             :  * corresponding ID (BoundaryID or SubdomainID) and performs bounds checking to ensure that overflow
     333             :  * doesn't happen.
     334             :  * @param name Name that is to be converted into an ID.
     335             :  * @return ID type corresponding to the type of name.
     336             :  */
     337             : template <typename T, typename Q>
     338             : Q
     339      534202 : getIDFromName(const T & name)
     340             : {
     341      534202 :   if (!MooseUtils::isDigits(name))
     342           0 :     mooseError(
     343             :         "'name' ", name, " should only contain digits that can be converted to a numerical type.");
     344      534202 :   long long id = std::stoll(name);
     345      534202 :   Q id_Q = Q(id);
     346      534202 :   if (id < std::numeric_limits<Q>::min() || id > std::numeric_limits<Q>::max())
     347           4 :     mooseError(MooseUtils::prettyCppType<T>(&name),
     348             :                " ",
     349             :                name,
     350             :                " is not within the numeric limits of the expected ID type ",
     351             :                MooseUtils::prettyCppType<Q>(&id_Q),
     352             :                ".");
     353             : 
     354      534198 :   return id_Q;
     355             : }
     356             : 
     357             : /**
     358             :  * Swap two nodes within an element
     359             :  * @param elem element whose nodes need to be swapped
     360             :  * @param nd1 index of the first node to be swapped
     361             :  * @param nd2 index of the second node to be swapped
     362             :  */
     363             : void swapNodesInElem(Elem & elem, const unsigned int nd1, const unsigned int nd2);
     364             : 
     365             : /**
     366             :  * Reprocess the swap related input parameters to make pairs out of them to ease further processing
     367             :  * @param class_name name of the mesh generator class used for exception messages
     368             :  * @param id_name name of the parameter to be swapped used for exception messages
     369             :  * @param id_swaps vector of vectors of the ids to be swapped
     370             :  * @param id_swap_pairs vector of maps of the swapped pairs
     371             :  * @param row_index_shift shift to be applied to the row index in the exception messages (useful
     372             :  * when this method is utilized to process a fraction of a long vector)
     373             :  */
     374             : template <typename T>
     375             : void
     376         508 : idSwapParametersProcessor(const std::string & class_name,
     377             :                           const std::string & id_name,
     378             :                           const std::vector<std::vector<T>> & id_swaps,
     379             :                           std::vector<std::unordered_map<T, T>> & id_swap_pairs,
     380             :                           const unsigned int row_index_shift = 0)
     381             : {
     382         508 :   id_swap_pairs.resize(id_swaps.size());
     383         970 :   for (const auto i : index_range(id_swaps))
     384             :   {
     385         462 :     const auto & swaps = id_swaps[i];
     386         462 :     auto & swap_pairs = id_swap_pairs[i];
     387             : 
     388         462 :     if (swaps.size() % 2)
     389           0 :       throw MooseException("Row ",
     390           0 :                            row_index_shift + i + 1,
     391             :                            " of ",
     392             :                            id_name,
     393             :                            " in ",
     394             :                            class_name,
     395             :                            " does not contain an even number of entries! Num entries: ",
     396           0 :                            swaps.size());
     397             : 
     398         462 :     swap_pairs.reserve(swaps.size() / 2);
     399        1255 :     for (unsigned int j = 0; j < swaps.size(); j += 2)
     400         793 :       swap_pairs[swaps[j]] = swaps[j + 1];
     401             :   }
     402         508 : }
     403             : 
     404             : /**
     405             :  * Reprocess the elem_integers_swaps into maps so they are easier to use
     406             :  * @param class_name name of the mesh generator class used for exception messages
     407             :  * @param num_sections number of sections in the mesh
     408             :  * @param num_integers number of extra element integers in the mesh
     409             :  * @param elem_integers_swaps vector of vectors of vectors of extra element ids to be swapped
     410             :  * @param elem_integers_swap_pairs vector of maps of the swapped pairs
     411             :  */
     412             : void extraElemIntegerSwapParametersProcessor(
     413             :     const std::string & class_name,
     414             :     const unsigned int num_sections,
     415             :     const unsigned int num_integers,
     416             :     const std::vector<std::vector<std::vector<dof_id_type>>> & elem_integers_swaps,
     417             :     std::vector<std::unordered_map<dof_id_type, dof_id_type>> & elem_integers_swap_pairs);
     418             : 
     419             : /**
     420             :  * Build a lower-dimensional mesh from a boundary of an input mesh
     421             :  * Note: The lower-dimensional mesh will only have one subdomain and one boundary.
     422             :  *       Error will be thrown if the mesh does not have the boundary.
     423             :  *       This function works only with replicated mesh, for similar functionality with
     424             :  *       distributed meshes, please refer to LowerDBlockFromSidesetGenerator generator.
     425             :  * @param input_mesh  The input mesh
     426             :  * @param boundary_id The boundary id
     427             :  */
     428             : std::unique_ptr<ReplicatedMesh> buildBoundaryMesh(const ReplicatedMesh & input_mesh,
     429             :                                                   const boundary_id_type boundary_id);
     430             : 
     431             : /**
     432             :  * Create a new subdomain by generating new side elements from a list of sidesets in a given mesh.
     433             :  * @param mesh The mesh to work on
     434             :  * @param boundary_names The names of the sidesets to be used to create the new subdomain
     435             :  * @param new_subdomain_id The ID of the new subdomain to be created based on the sidesets
     436             :  * @param new_subdomain_name The name of the new subdomain to be created based on the sidesets
     437             :  * @param type_name The type of the mesh generator that is calling this method, used for error
     438             :  *                  messages and debugging purposes.
     439             :  */
     440             : void createSubdomainFromSidesets(std::unique_ptr<MeshBase> & mesh,
     441             :                                  std::vector<BoundaryName> boundary_names,
     442             :                                  const SubdomainID new_subdomain_id,
     443             :                                  const SubdomainName new_subdomain_name,
     444             :                                  const std::string type_name);
     445             : 
     446             : /**
     447             :  * Convert a list of blocks in a given mesh to a standalone new mesh.
     448             :  * @param source_mesh The source mesh from which the blocks will be converted
     449             :  * @param target_mesh The target mesh to which the blocks will be converted
     450             :  * @param target_blocks The names of the blocks to be converted to the target mesh
     451             :  */
     452             : void convertBlockToMesh(std::unique_ptr<MeshBase> & source_mesh,
     453             :                         std::unique_ptr<MeshBase> & target_mesh,
     454             :                         const std::vector<SubdomainName> & target_blocks);
     455             : 
     456             : /**
     457             :  * Helper function for copying one mesh into another
     458             :  * @param mg The mesh generator calling this function
     459             :  * @param destination The mesh to copy into
     460             :  * @param source The mesh to copy from
     461             :  * @param avoid_merging_subdomains If true, subdomain IDs in the source mesh will
     462             :  * be offset to avoid merging with subdomain IDs in the destination mesh
     463             :  * @param avoid_merging_boundaries If true, boundary IDs in the source mesh will
     464             :  * be offset to avoid merging with boundary IDs in the destination mesh
     465             :  * @param communicator The communicator for parallel operations
     466             :  */
     467             : void copyIntoMesh(MeshGenerator & mg,
     468             :                   UnstructuredMesh & destination,
     469             :                   const UnstructuredMesh & source,
     470             :                   const bool avoid_merging_subdomains,
     471             :                   const bool avoid_merging_boundaries,
     472             :                   const Parallel::Communicator & communicator);
     473             : }

Generated by: LCOV version 1.14