https://mooseframework.inl.gov
Classes | Functions
MooseMeshElementConversionUtils Namespace Reference

Classes

struct  BCTupleKeyComp
 

Functions

void hexElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 Split a HEX8 element into six TET4 elements. More...
 
void pyramidElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 Split a PYRAMID5 element into two TET4 elements. More...
 
void prismElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 Split a PRISM6 element into three TET4 elements. More...
 
void polyhedronElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 Split a polyhedron element into n_sides TET4 elements. More...
 
void nodeRotationHEX8 (const unsigned int min_id_index, const unsigned int sec_min_pos, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
 Rotate a HEX8 element's nodes to ensure that the node with the minimum id is the first node; and the node among its three neighboring nodes with the minimum id is the second node. More...
 
std::vector< unsigned intneighborNodeIndicesHEX8 (unsigned int min_id_index)
 Calculate the indices (within the element nodes) of the three neighboring nodes of a node in a HEX8 element. More...
 
void hexNodesToTetNodesDeterminer (std::vector< const Node *> &hex_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
 For a vector of rotated nodes that can form a HEX8 element, create a vector of four-node sets that can form TET4 elements to replace the original HEX8 element. More...
 
std::vector< bool > quadFaceDiagonalDirectionsHex (const std::vector< const Node *> &hex_nodes)
 For a HEX8 element, determine the direction of the diagonal line of each face that involves the node with the minimum id of that face. More...
 
bool quadFaceDiagonalDirection (const std::vector< const Node *> &quad_nodes)
 For a QUAD4 element, determine the direction of the diagonal line that involves the node with the minimum id of that element. More...
 
std::vector< std::vector< unsigned int > > tetNodesForHex (const std::vector< bool > diagonal_directions, std::vector< std::vector< unsigned int >> &tet_face_indices)
 Creates sets of four nodes indices that can form TET4 elements to replace the original HEX8 element. More...
 
void nodeRotationPRISM6 (unsigned int min_id_index, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
 Rotate a PRISM6 element nodes to ensure that the node with the minimum id is the first node. More...
 
void prismNodesToTetNodesDeterminer (std::vector< const Node *> &prism_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
 For a rotated nodes that can form a PRISM6 element, create a series of four-node set that can form TET4 elements to replace the original PRISM6 element. More...
 
std::vector< std::vector< unsigned int > > tetNodesForPrism (const bool diagonal_direction, std::vector< std::vector< unsigned int >> &tet_face_indices)
 Creates sets of four nodes indices that can form TET4 elements to replace the original PRISM6 element. More...
 
void nodeRotationPYRAMID5 (unsigned int min_id_index, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
 Rotate a PYRAMID5 element nodes to ensure that the node with the minimum id is the first node for the bottom face. More...
 
void pyramidNodesToTetNodesDeterminer (std::vector< const Node *> &pyramid_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
 For a rotated nodes that can form a PYRAMID5 element, create a series of four-node set that can form TET4 elements to replace the original PYRAMID5 element. More...
 
void convert3DMeshToAllTet4 (MeshBase &mesh, const std::vector< std::pair< dof_id_type, bool >> &elems_to_process, std::vector< dof_id_type > &converted_elems_ids_to_track, const subdomain_id_type block_id_to_remove, const bool delete_block_to_remove)
 Convert all the elements in a 3D mesh, consisting of only linear elements, into TET4 elements. More...
 
void convert3DMeshToAllTet4 (MeshBase &mesh)
 Convert all the elements in a 3D mesh consisting of only linear elements into TET4 elements. More...
 
void elementBoundaryInfoCollector (const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
 Collect the boundary information of the given element in a mesh. More...
 
void convertElem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 Convert the element to an element with TRI3 side-elements on the user-specified sides by modifying the mesh. More...
 
void convertHex8Elem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 Convert a HEX8 element to elements with TRI3 surfaces on the given original QUAD4 side(s). More...
 
void createUnitPyramid5FromHex8 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 Create one PYRAMID5 element based on a side and the centroid of the HEX8 element. More...
 
void createUnitTet4FromHex8 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 Create two TET4 elements based on a side and the centroid of the HEX8 element. More...
 
void convertPrism6Elem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 Convert a PRISM6 element to elements with TRI3 surfaces on the given original QUAD4 side(s). More...
 
void createUnitTet4FromPrism6 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 Create one or two TET4 elements based on a side and the centroid of the PRISM6 element. More...
 
void createUnitPyramid5FromPrism6 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 Create a PYRAMID5 element opposite the sides converted to tets and the centroid of the PRISM6 element. More...
 
void convertPyramid5Elem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 Convert a PYRAMID5 element to elements with TRI3 surfaces on the original QUAD4 side. More...
 
void retainEEID (MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
 Retain the extra integer of the original element in a new element. More...
 
void transitionLayerGenerator (MeshBase &mesh, const std::vector< BoundaryName > &boundary_names, const unsigned int conversion_element_layer_number, const bool external_boundaries_checking)
 Generate a transition layer of elements with TRI3 surfaces on the given boundaries. More...
 
void assignConvertedElementsSubdomainNameSuffix (MeshBase &mesh, const std::set< subdomain_id_type > &original_subdomain_ids, const subdomain_id_type sid_shift_base, const SubdomainName &tet_suffix, const SubdomainName &pyramid_suffix)
 Assign a subdomain name suffix to the converted elements created during transition layer generation. More...
 
void hexElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 
void prismElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 
void pyramidElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 
void polyhedronElemSplitter (MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
 
void hexNodesToTetNodesDeterminer (std::vector< const Node *> &hex_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
 
std::vector< bool > quadFaceDiagonalDirectionsHex (const std::vector< const Node *> &hex_nodes)
 
bool quadFaceDiagonalDirection (const std::vector< const Node *> &quad_nodes)
 
void prismNodesToTetNodesDeterminer (std::vector< const Node *> &prism_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
 
void pyramidNodesToTetNodesDeterminer (std::vector< const Node *> &pyramid_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
 
void convert3DMeshToAllTet4 (MeshBase &mesh, const std::vector< std::pair< dof_id_type, bool >> &elems_to_process, std::vector< dof_id_type > &converted_elems_ids_to_track, const subdomain_id_type block_id_to_remove, const bool delete_block_to_remove)
 
void convert3DMeshToAllTet4 (MeshBase &mesh)
 
void elementBoundaryInfoCollector (const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
 Collect the boundary information of the given element in a mesh. More...
 
void convertElem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 
void convertHex8Elem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 
void createUnitPyramid5FromHex8 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 
void createUnitTet4FromHex8 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 
void convertPrism6Elem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 
void createUnitTet4FromPrism6 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 
void createUnitPyramid5FromPrism6 (MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
 
void convertPyramid5Elem (MeshBase &mesh, const dof_id_type &elem_id, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
 
void retainEEID (MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
 
void transitionLayerGenerator (MeshBase &mesh, const std::vector< BoundaryName > &boundary_names, const unsigned int conversion_element_layer_number, const bool external_boundaries_checking)
 
void assignConvertedElementsSubdomainNameSuffix (MeshBase &mesh, const std::set< subdomain_id_type > &original_subdomain_ids, const subdomain_id_type sid_shift_base, const SubdomainName &tet_suffix, const SubdomainName &pyramid_suffix)
 

Function Documentation

◆ assignConvertedElementsSubdomainNameSuffix() [1/2]

void MooseMeshElementConversionUtils::assignConvertedElementsSubdomainNameSuffix ( MeshBase &  mesh,
const std::set< subdomain_id_type > &  original_subdomain_ids,
const subdomain_id_type  sid_shift_base,
const SubdomainName &  tet_suffix,
const SubdomainName &  pyramid_suffix 
)

Assign a subdomain name suffix to the converted elements created during transition layer generation.

Parameters
meshThe mesh to be modified
original_subdomain_idsA set of original subdomain IDs of the mesh before conversion
sid_shift_baseThe base subdomain ID to shift the original elements because of the element type change
tet_suffixThe suffix to be added to the subdomain names of the converted TET4 elements
pyramid_suffixThe suffix to be added to the subdomain names of the converted PYRAMID5 elements

Referenced by BoundaryElementConversionGenerator::generate(), and CutMeshByLevelSetGeneratorBase::generate().

◆ assignConvertedElementsSubdomainNameSuffix() [2/2]

void MooseMeshElementConversionUtils::assignConvertedElementsSubdomainNameSuffix ( MeshBase mesh,
const std::set< subdomain_id_type > &  original_subdomain_ids,
const subdomain_id_type  sid_shift_base,
const SubdomainName &  tet_suffix,
const SubdomainName &  pyramid_suffix 
)

Definition at line 1304 of file MooseMeshElementConversionUtils.C.

1310 {
1311  // If we have an unprepared mesh, we at least need its element
1312  // caches prepared for subdomain_ids
1315 
1316  for (const auto & subdomain_id : original_subdomain_ids)
1317  {
1318  if (MooseMeshUtils::hasSubdomainID(mesh, subdomain_id + sid_shift_base))
1319  {
1320  const SubdomainName new_name =
1321  (mesh.subdomain_name(subdomain_id).empty() ? std::to_string(subdomain_id)
1322  : mesh.subdomain_name(subdomain_id)) +
1323  '_' + tet_suffix;
1324  if (MooseMeshUtils::hasSubdomainName(mesh, new_name))
1325  throw MooseException(
1326  "This suffix for converted TET4 elements results in a subdomain name, " + new_name +
1327  ", that already exists in the mesh. Please choose a different suffix.");
1328  mesh.subdomain_name(subdomain_id + sid_shift_base) = new_name;
1329  }
1330  if (MooseMeshUtils::hasSubdomainID(mesh, subdomain_id + 2 * sid_shift_base))
1331  {
1332  const SubdomainName new_name =
1333  (mesh.subdomain_name(subdomain_id).empty() ? std::to_string(subdomain_id)
1334  : mesh.subdomain_name(subdomain_id)) +
1335  '_' + pyramid_suffix;
1336  if (MooseMeshUtils::hasSubdomainName(mesh, new_name))
1337  throw MooseException(
1338  "This suffix for converted PYRAMID5 elements results in a subdomain name, " + new_name +
1339  ", that already exists in the mesh. Please choose a different suffix.");
1340  mesh.subdomain_name(subdomain_id + 2 * sid_shift_base) = new_name;
1341  }
1342  }
1343 }
MeshBase & mesh
Preparation preparation() const
bool hasSubdomainID(const MeshBase &input_mesh, const SubdomainID &id)
Whether a particular subdomain ID exists in the mesh.
std::string & subdomain_name(subdomain_id_type id)
bool hasSubdomainName(const MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain name exists in the mesh.
Provides a way for users to bail out of the current solve.

◆ convert3DMeshToAllTet4() [1/4]

void MooseMeshElementConversionUtils::convert3DMeshToAllTet4 ( MeshBase &  mesh,
const std::vector< std::pair< dof_id_type, bool >> &  elems_to_process,
std::vector< dof_id_type > &  converted_elems_ids_to_track,
const subdomain_id_type  block_id_to_remove,
const bool  delete_block_to_remove 
)

Convert all the elements in a 3D mesh, consisting of only linear elements, into TET4 elements.

Parameters
meshThe mesh to be converted
elems_to_processA vector of pairs of element ids and a bool indicating whether the element needs to be fully retained or will be further processed in the following procedures
converted_elems_ids_to_trackA vector of element ids that need to be tracked for being further processed in the following procedures
block_id_to_removeThe id of a new subdomain in the mesh containing all the elements to be removed
delete_block_to_removeA bool indicating whether the block to be removed will be deleted in this method

Referenced by ElementsToTetrahedronsConverter::generate(), CutMeshByLevelSetGeneratorBase::generate(), and transitionLayerGenerator().

◆ convert3DMeshToAllTet4() [2/4]

void MooseMeshElementConversionUtils::convert3DMeshToAllTet4 ( MeshBase &  mesh)

Convert all the elements in a 3D mesh consisting of only linear elements into TET4 elements.

Parameters
meshThe mesh to be converted

◆ convert3DMeshToAllTet4() [3/4]

void MooseMeshElementConversionUtils::convert3DMeshToAllTet4 ( MeshBase mesh,
const std::vector< std::pair< dof_id_type, bool >> &  elems_to_process,
std::vector< dof_id_type > &  converted_elems_ids_to_track,
const subdomain_id_type  block_id_to_remove,
const bool  delete_block_to_remove 
)

Definition at line 646 of file MooseMeshElementConversionUtils.C.

651 {
652  mooseAssert(mesh.is_serial(),
653  "This method only supports serial meshes. If you are calling this method with a "
654  "distributed mesh, please serialize it first.");
655  std::vector<dof_id_type> converted_elems_ids_to_retain;
656  // Build boundary information of the mesh
657  BoundaryInfo & boundary_info = mesh.get_boundary_info();
658  const auto bdry_side_list = boundary_info.build_side_list();
659  for (const auto & elem_to_process : elems_to_process)
660  {
661  switch (mesh.elem_ptr(elem_to_process.first)->type())
662  {
663  case ElemType::HEX8:
664  hexElemSplitter(mesh,
665  bdry_side_list,
666  elem_to_process.first,
667  elem_to_process.second ? converted_elems_ids_to_track
668  : converted_elems_ids_to_retain);
669  mesh.elem_ptr(elem_to_process.first)->subdomain_id() = block_id_to_remove;
670  break;
671  case ElemType::PYRAMID5:
672  pyramidElemSplitter(mesh,
673  bdry_side_list,
674  elem_to_process.first,
675  elem_to_process.second ? converted_elems_ids_to_track
676  : converted_elems_ids_to_retain);
677  mesh.elem_ptr(elem_to_process.first)->subdomain_id() = block_id_to_remove;
678  break;
679  case ElemType::PRISM6:
680  prismElemSplitter(mesh,
681  bdry_side_list,
682  elem_to_process.first,
683  elem_to_process.second ? converted_elems_ids_to_track
684  : converted_elems_ids_to_retain);
685  mesh.elem_ptr(elem_to_process.first)->subdomain_id() = block_id_to_remove;
686  break;
687  case ElemType::C0POLYHEDRON:
689  bdry_side_list,
690  elem_to_process.first,
691  elem_to_process.second ? converted_elems_ids_to_track
692  : converted_elems_ids_to_retain);
693  mesh.elem_ptr(elem_to_process.first)->subdomain_id() = block_id_to_remove;
694  break;
695  case ElemType::TET4:
696  if (elem_to_process.second)
697  converted_elems_ids_to_track.push_back(elem_to_process.first);
698  else
699  converted_elems_ids_to_retain.push_back(elem_to_process.first);
700  break;
701  default:
702  mooseError("Unexpected element type.");
703  }
704  }
705 
706  if (delete_block_to_remove)
707  {
708  for (auto elem_it = mesh.active_subdomain_elements_begin(block_id_to_remove);
709  elem_it != mesh.active_subdomain_elements_end(block_id_to_remove);
710  elem_it++)
711  mesh.delete_elem(*elem_it);
712 
713  mesh.contract();
715  }
716 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
MeshBase & mesh
void polyhedronElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
const BoundaryInfo & get_boundary_info() const
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
void prismElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
virtual bool is_serial() const
virtual void delete_elem(Elem *e)=0
void hexElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual bool contract()=0
void pyramidElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
subdomain_id_type subdomain_id() const
virtual ElemType type() const=0

◆ convert3DMeshToAllTet4() [4/4]

void MooseMeshElementConversionUtils::convert3DMeshToAllTet4 ( MeshBase mesh)

Definition at line 719 of file MooseMeshElementConversionUtils.C.

720 {
721  mooseAssert(mesh.is_serial(),
722  "This method only supports serial meshes. If you are calling this method with a "
723  "distributed mesh, please serialize it first.");
724  // Subdomain ID for new utility blocks must be new
725  std::set<subdomain_id_type> subdomain_ids_set;
726  mesh.subdomain_ids(subdomain_ids_set);
727  const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
728  const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
729  std::vector<std::pair<dof_id_type, bool>> original_elems;
730 
731  for (auto elem_it = mesh.active_elements_begin(); elem_it != mesh.active_elements_end();
732  elem_it++)
733  {
734  if ((*elem_it)->default_order() != Order::FIRST)
735  mooseError("Only first order elements are supported for cutting.");
736  original_elems.push_back(std::make_pair((*elem_it)->id(), false));
737  }
738 
739  std::vector<dof_id_type> converted_elems_ids_to_track;
740 
742  mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove, true);
743 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
MeshBase & mesh
virtual bool is_serial() const
void subdomain_ids(std::set< subdomain_id_type > &ids, const bool global=true) const

◆ convertElem() [1/2]

void MooseMeshElementConversionUtils::convertElem ( MeshBase &  mesh,
const dof_id_type elem_id,
const std::vector< unsigned int > &  side_indices,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Convert the element to an element with TRI3 side-elements on the user-specified sides by modifying the mesh.

Parameters
meshThe mesh containing the element
elem_idThe ID of the element to be converted
side_indicesThe indices of the sides to be converted
elem_side_infoThe boundary IDs associated with the sides of the element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

Referenced by CutMeshByLevelSetGeneratorBase::generate(), and transitionLayerGenerator().

◆ convertElem() [2/2]

void MooseMeshElementConversionUtils::convertElem ( MeshBase mesh,
const dof_id_type elem_id,
const std::vector< unsigned int > &  side_indices,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 763 of file MooseMeshElementConversionUtils.C.

768 {
769  const auto & elem_type = mesh.elem_ptr(elem_id)->type();
770  switch (elem_type)
771  {
772  case HEX8:
773  // HEX8 to PYRAMID5 (+2*subdomain_id_shift_base)
774  // HEX8 to TET4 (+subdomain_id_shift_base)
775  convertHex8Elem(mesh, elem_id, side_indices, elem_side_info, subdomain_id_shift_base);
776  break;
777  case PRISM6:
778  // PRISM6 to TET4 (+subdomain_id_shift_base)
779  // PRISM6 to PYRAMID5 (+2*subdomain_id_shift_base)
780  convertPrism6Elem(mesh, elem_id, side_indices, elem_side_info, subdomain_id_shift_base);
781  break;
782  case PYRAMID5:
783  // PYRAMID5 to TET4 (+subdomain_id_shift_base)
784  convertPyramid5Elem(mesh, elem_id, elem_side_info, subdomain_id_shift_base);
785  break;
786  default:
787  mooseAssert(false,
788  "The provided element type '" + std::to_string(elem_type) +
789  "' is not supported and is not supposed to be passed to this function. "
790  "Only HEX8, PRISM6 and PYRAMID5 are supported.");
791  }
792 }
HEX8
MeshBase & mesh
void convertHex8Elem(MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
void convertPyramid5Elem(MeshBase &mesh, const dof_id_type &elem_id, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
virtual const Elem * elem_ptr(const dof_id_type i) const=0
PYRAMID5
void convertPrism6Elem(MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
PRISM6
virtual ElemType type() const=0

◆ convertHex8Elem() [1/2]

void MooseMeshElementConversionUtils::convertHex8Elem ( MeshBase &  mesh,
const dof_id_type elem_id,
const std::vector< unsigned int > &  side_indices,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Convert a HEX8 element to elements with TRI3 surfaces on the given original QUAD4 side(s).

Parameters
meshThe mesh containing the element
elem_idThe ID of the HEX8 element to be converted
side_indicesThe indices of the QUAD4 sides to be converted to TRI3 sides
elem_side_infoThe boundary IDs associated with the sides of the HEX8 element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ convertHex8Elem() [2/2]

void MooseMeshElementConversionUtils::convertHex8Elem ( MeshBase mesh,
const dof_id_type elem_id,
const std::vector< unsigned int > &  side_indices,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 795 of file MooseMeshElementConversionUtils.C.

Referenced by convertElem().

800 {
801  // We add a node at the centroid of the HEX8 element
802  // With this node, the HEX8 can be converted into 6 PYRAMID5 elements
803  // For the PYRAMID5 element at the 'side_indices', they can further be converted into 2 TET4
804  // elements
805  const Point elem_cent = mesh.elem_ptr(elem_id)->true_centroid();
806  auto new_node = mesh.add_point(elem_cent);
807  for (const auto & i_side : make_range(mesh.elem_ptr(elem_id)->n_sides()))
808  {
809  if (std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
811  mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
812  else
814  mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
815  }
816 }
virtual Point true_centroid() const
void createUnitPyramid5FromHex8(MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
void createUnitTet4FromHex8(MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
MeshBase & mesh
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual unsigned int n_sides() const=0
IntRange< T > make_range(T beg, T end)

◆ convertPrism6Elem() [1/2]

void MooseMeshElementConversionUtils::convertPrism6Elem ( MeshBase &  mesh,
const dof_id_type elem_id,
const std::vector< unsigned int > &  side_indices,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Convert a PRISM6 element to elements with TRI3 surfaces on the given original QUAD4 side(s).

Parameters
meshThe mesh containing the element
elem_idThe ID of the PRISM6 element to be converted
side_indicesThe indices of the QUAD sides to be converted to TRI3 sides
elem_side_infoThe boundary IDs associated with the sides of the PRISM6 element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ convertPrism6Elem() [2/2]

void MooseMeshElementConversionUtils::convertPrism6Elem ( MeshBase mesh,
const dof_id_type elem_id,
const std::vector< unsigned int > &  side_indices,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 901 of file MooseMeshElementConversionUtils.C.

Referenced by convertElem().

906 {
907  // We add a node at the centroid of the PRISM6 element
908  // With this node, the PRISM6 can be converted into 3 PYRAMID5 elements and 2 TET4 elements
909  // For the PYRAMID5 element, it can further be converted into 2 TET3 elements
910  const Point elem_cent = mesh.elem_ptr(elem_id)->true_centroid();
911  auto new_node = mesh.add_point(elem_cent);
912  for (const auto & i_side : make_range(mesh.elem_ptr(elem_id)->n_sides()))
913  {
914  if (i_side % 4 == 0 ||
915  std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
917  mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
918  else
920  mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
921  }
922 }
virtual Point true_centroid() const
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
void createUnitPyramid5FromPrism6(MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
MeshBase & mesh
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
void createUnitTet4FromPrism6(MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual unsigned int n_sides() const=0
IntRange< T > make_range(T beg, T end)

◆ convertPyramid5Elem() [1/2]

void MooseMeshElementConversionUtils::convertPyramid5Elem ( MeshBase &  mesh,
const dof_id_type elem_id,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Convert a PYRAMID5 element to elements with TRI3 surfaces on the original QUAD4 side.

Parameters
meshThe mesh containing the element
elem_idThe ID of the PYRAMID5 element to be converted
elem_side_infoThe boundary IDs associated with the sides of the PYRAMID
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ convertPyramid5Elem() [2/2]

void MooseMeshElementConversionUtils::convertPyramid5Elem ( MeshBase mesh,
const dof_id_type elem_id,
const std::vector< std::vector< boundary_id_type >> &  elem_side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 1008 of file MooseMeshElementConversionUtils.C.

Referenced by convertElem().

1012 {
1013  // A Pyramid5 element has only one QUAD4 face, so we can convert it to 2 TET4 elements
1014  unsigned int lid_index = 0;
1015  for (const auto & i : make_range(1, 4))
1016  {
1017  if (mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(i)->id() <
1018  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(lid_index)->id())
1019  lid_index = i;
1020  }
1021  auto new_elem_0 = std::make_unique<Tet4>();
1022  new_elem_0->set_node(
1023  0,
1024  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(MathUtils::euclideanMod(2 - lid_index % 2, 4)));
1025  new_elem_0->set_node(
1026  1,
1027  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(MathUtils::euclideanMod(1 - lid_index % 2, 4)));
1028  new_elem_0->set_node(
1029  2,
1030  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(MathUtils::euclideanMod(0 - lid_index % 2, 4)));
1031  new_elem_0->set_node(3, mesh.elem_ptr(elem_id)->node_ptr(4));
1032  new_elem_0->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base;
1033  auto new_elem_ptr_0 = mesh.add_elem(std::move(new_elem_0));
1034  retainEEID(mesh, elem_id, new_elem_ptr_0);
1035 
1036  auto new_elem_1 = std::make_unique<Tet4>();
1037  new_elem_1->set_node(
1038  0,
1039  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(MathUtils::euclideanMod(3 - lid_index % 2, 4)));
1040  new_elem_1->set_node(
1041  1,
1042  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(MathUtils::euclideanMod(2 - lid_index % 2, 4)));
1043  new_elem_1->set_node(
1044  2,
1045  mesh.elem_ptr(elem_id)->side_ptr(4)->node_ptr(MathUtils::euclideanMod(0 - lid_index % 2, 4)));
1046  new_elem_1->set_node(3, mesh.elem_ptr(elem_id)->node_ptr(4));
1047  new_elem_1->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base;
1048  auto new_elem_ptr_1 = mesh.add_elem(std::move(new_elem_1));
1049  retainEEID(mesh, elem_id, new_elem_ptr_1);
1050 
1051  for (const auto & bid : elem_side_info[0])
1052  mesh.get_boundary_info().add_side(new_elem_ptr_0, 2 - lid_index % 2, bid);
1053  for (const auto & bid : elem_side_info[1])
1054  if (lid_index % 2)
1055  mesh.get_boundary_info().add_side(new_elem_ptr_1, 2, bid);
1056  else
1057  mesh.get_boundary_info().add_side(new_elem_ptr_0, 1, bid);
1058  for (const auto & bid : elem_side_info[2])
1059  mesh.get_boundary_info().add_side(new_elem_ptr_1, 2 + lid_index % 2, bid);
1060  for (const auto & bid : elem_side_info[3])
1061  if (lid_index % 2)
1062  mesh.get_boundary_info().add_side(new_elem_ptr_0, 1, bid);
1063  else
1064  mesh.get_boundary_info().add_side(new_elem_ptr_1, 3, bid);
1065  for (const auto & bid : elem_side_info[4])
1066  {
1067  mesh.get_boundary_info().add_side(new_elem_ptr_0, 0, bid);
1068  mesh.get_boundary_info().add_side(new_elem_ptr_1, 0, bid);
1069  }
1070 }
MeshBase & mesh
const BoundaryInfo & get_boundary_info() const
std::size_t euclideanMod(T1 dividend, T2 divisor)
perform modulo operator for Euclidean division that ensures a non-negative result ...
Definition: MathUtils.h:439
void retainEEID(MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
subdomain_id_type subdomain_id() const
const Node * node_ptr(const unsigned int i) const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
IntRange< T > make_range(T beg, T end)

◆ createUnitPyramid5FromHex8() [1/2]

void MooseMeshElementConversionUtils::createUnitPyramid5FromHex8 ( MeshBase &  mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node *  new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Create one PYRAMID5 element based on a side and the centroid of the HEX8 element.

Parameters
meshThe mesh containing the element
elem_idThe ID of the HEX8 element to be converted
side_indexThe index of the side to be converted
new_nodeThe new node created at the centroid of the HEX8 element
side_infoThe boundary IDs associated with the side of the HEX8 element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ createUnitPyramid5FromHex8() [2/2]

void MooseMeshElementConversionUtils::createUnitPyramid5FromHex8 ( MeshBase mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 819 of file MooseMeshElementConversionUtils.C.

Referenced by convertHex8Elem(), and createUnitPyramid5FromPrism6().

825 {
826  auto new_elem = std::make_unique<Pyramid5>();
827  new_elem->set_node(0, mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(3));
828  new_elem->set_node(1, mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(2));
829  new_elem->set_node(2, mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(1));
830  new_elem->set_node(3, mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(0));
831  new_elem->set_node(4, const_cast<Node *>(new_node));
832  new_elem->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base * 2;
833  auto new_elem_ptr = mesh.add_elem(std::move(new_elem));
834  retainEEID(mesh, elem_id, new_elem_ptr);
835  for (const auto & bid : side_info)
836  mesh.get_boundary_info().add_side(new_elem_ptr, 4, bid);
837 }
MeshBase & mesh
const BoundaryInfo & get_boundary_info() const
void retainEEID(MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
subdomain_id_type subdomain_id() const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)

◆ createUnitPyramid5FromPrism6() [1/2]

void MooseMeshElementConversionUtils::createUnitPyramid5FromPrism6 ( MeshBase &  mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node *  new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Create a PYRAMID5 element opposite the sides converted to tets and the centroid of the PRISM6 element.

Parameters
meshThe mesh containing the element
elem_idThe ID of the PRISM6 element to be converted
side_indexThe index of the side to be converted
new_nodeThe new node created at the centroid of the PRISM6 element
side_infoThe boundary IDs associated with the side of the PRISM6 element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ createUnitPyramid5FromPrism6() [2/2]

void MooseMeshElementConversionUtils::createUnitPyramid5FromPrism6 ( MeshBase mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 995 of file MooseMeshElementConversionUtils.C.

Referenced by convertPrism6Elem().

1001 {
1002  // Same as Hex8
1004  mesh, elem_id, side_index, new_node, side_info, subdomain_id_shift_base);
1005 }
void createUnitPyramid5FromHex8(MeshBase &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)

◆ createUnitTet4FromHex8() [1/2]

void MooseMeshElementConversionUtils::createUnitTet4FromHex8 ( MeshBase &  mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node *  new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Create two TET4 elements based on a side and the centroid of the HEX8 element.

Parameters
meshThe mesh containing the element
elem_idThe ID of the HEX8 element to be converted
side_indexThe index of the side to be converted
new_nodeThe new node created at the centroid of the HEX8 element
side_infoThe boundary IDs associated with the side of the HEX8 element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ createUnitTet4FromHex8() [2/2]

void MooseMeshElementConversionUtils::createUnitTet4FromHex8 ( MeshBase mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 840 of file MooseMeshElementConversionUtils.C.

Referenced by convertHex8Elem().

846 {
847  // We want to make sure that the QUAD4 is divided by the diagonal that involves the node with
848  // the lowest node id This may help maintain consistency for future applications
849  unsigned int lid_index = 0;
850  for (const auto & i : make_range(1, 4))
851  {
852  if (mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(i)->id() <
853  mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(lid_index)->id())
854  lid_index = i;
855  }
856 
857  auto new_elem_0 = std::make_unique<Tet4>();
858  new_elem_0->set_node(0,
859  mesh.elem_ptr(elem_id)
860  ->side_ptr(side_index)
861  ->node_ptr(MathUtils::euclideanMod(2 - lid_index % 2, 4)));
862  new_elem_0->set_node(1,
863  mesh.elem_ptr(elem_id)
864  ->side_ptr(side_index)
865  ->node_ptr(MathUtils::euclideanMod(1 - lid_index % 2, 4)));
866  new_elem_0->set_node(2,
867  mesh.elem_ptr(elem_id)
868  ->side_ptr(side_index)
869  ->node_ptr(MathUtils::euclideanMod(0 - lid_index % 2, 4)));
870  new_elem_0->set_node(3, const_cast<Node *>(new_node));
871  new_elem_0->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base;
872  auto new_elem_ptr_0 = mesh.add_elem(std::move(new_elem_0));
873  retainEEID(mesh, elem_id, new_elem_ptr_0);
874 
875  auto new_elem_1 = std::make_unique<Tet4>();
876  new_elem_1->set_node(0,
877  mesh.elem_ptr(elem_id)
878  ->side_ptr(side_index)
879  ->node_ptr(MathUtils::euclideanMod(3 - lid_index % 2, 4)));
880  new_elem_1->set_node(1,
881  mesh.elem_ptr(elem_id)
882  ->side_ptr(side_index)
883  ->node_ptr(MathUtils::euclideanMod(2 - lid_index % 2, 4)));
884  new_elem_1->set_node(2,
885  mesh.elem_ptr(elem_id)
886  ->side_ptr(side_index)
887  ->node_ptr(MathUtils::euclideanMod(0 - lid_index % 2, 4)));
888  new_elem_1->set_node(3, const_cast<Node *>(new_node));
889  new_elem_1->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base;
890  auto new_elem_ptr_1 = mesh.add_elem(std::move(new_elem_1));
891  retainEEID(mesh, elem_id, new_elem_ptr_1);
892 
893  for (const auto & bid : side_info)
894  {
895  mesh.get_boundary_info().add_side(new_elem_ptr_0, 0, bid);
896  mesh.get_boundary_info().add_side(new_elem_ptr_1, 0, bid);
897  }
898 }
MeshBase & mesh
const BoundaryInfo & get_boundary_info() const
std::size_t euclideanMod(T1 dividend, T2 divisor)
perform modulo operator for Euclidean division that ensures a non-negative result ...
Definition: MathUtils.h:439
void retainEEID(MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
subdomain_id_type subdomain_id() const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
IntRange< T > make_range(T beg, T end)

◆ createUnitTet4FromPrism6() [1/2]

void MooseMeshElementConversionUtils::createUnitTet4FromPrism6 ( MeshBase &  mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node *  new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Create one or two TET4 elements based on a side and the centroid of the PRISM6 element.

Parameters
meshThe mesh containing the element
elem_idThe ID of the PRISM6 element to be converted
side_indexThe index of the side to be converted
new_nodeThe new node created at the centroid of the PRISM6 element
side_infoThe boundary IDs associated with the side of the PRISM6 element
subdomain_id_shift_basethe reference id used to shift the subdomain ID for new elements

◆ createUnitTet4FromPrism6() [2/2]

void MooseMeshElementConversionUtils::createUnitTet4FromPrism6 ( MeshBase mesh,
const dof_id_type elem_id,
const unsigned int side_index,
const Node new_node,
const std::vector< boundary_id_type > &  side_info,
const SubdomainID subdomain_id_shift_base 
)

Definition at line 925 of file MooseMeshElementConversionUtils.C.

Referenced by convertPrism6Elem().

931 {
932  // For side 1 and side 4, they are already TRI3, so only one TET is created
933  // For side 0, 2, and 3, they are QUAD4, so we create 2 TETs
934  // We want to make sure that the QUAD4 is divided by the diagonal that involves
935  // the node with the lowest node id This may help maintain consistency for future applications
936  bool is_side_quad = (side_index % 4 != 0);
937  unsigned int lid_index = 0;
938  if (is_side_quad)
939  for (const auto & i : make_range(1, 4))
940  {
941  if (mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(i)->id() <
942  mesh.elem_ptr(elem_id)->side_ptr(side_index)->node_ptr(lid_index)->id())
943  lid_index = i;
944  }
945  // For a TRI3 side, lid_index is always 0, so the indices are always 2,1,0 here
946  auto new_elem_0 = std::make_unique<Tet4>();
947  new_elem_0->set_node(0,
948  mesh.elem_ptr(elem_id)
949  ->side_ptr(side_index)
950  ->node_ptr(MathUtils::euclideanMod(2 - lid_index % 2, 4)));
951  new_elem_0->set_node(1,
952  mesh.elem_ptr(elem_id)
953  ->side_ptr(side_index)
954  ->node_ptr(MathUtils::euclideanMod(1 - lid_index % 2, 4)));
955  new_elem_0->set_node(2,
956  mesh.elem_ptr(elem_id)
957  ->side_ptr(side_index)
958  ->node_ptr(MathUtils::euclideanMod(0 - lid_index % 2, 4)));
959  new_elem_0->set_node(3, const_cast<Node *>(new_node));
960  new_elem_0->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base;
961  auto new_elem_ptr_0 = mesh.add_elem(std::move(new_elem_0));
962  retainEEID(mesh, elem_id, new_elem_ptr_0);
963 
964  Elem * new_elem_ptr_1 = nullptr;
965  if (is_side_quad)
966  {
967  auto new_elem_1 = std::make_unique<Tet4>();
968  new_elem_1->set_node(0,
969  mesh.elem_ptr(elem_id)
970  ->side_ptr(side_index)
971  ->node_ptr(MathUtils::euclideanMod(3 - lid_index % 2, 4)));
972  new_elem_1->set_node(1,
973  mesh.elem_ptr(elem_id)
974  ->side_ptr(side_index)
975  ->node_ptr(MathUtils::euclideanMod(2 - lid_index % 2, 4)));
976  new_elem_1->set_node(2,
977  mesh.elem_ptr(elem_id)
978  ->side_ptr(side_index)
979  ->node_ptr(MathUtils::euclideanMod(0 - lid_index % 2, 4)));
980  new_elem_1->set_node(3, const_cast<Node *>(new_node));
981  new_elem_1->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id() + subdomain_id_shift_base;
982  new_elem_ptr_1 = mesh.add_elem(std::move(new_elem_1));
983  retainEEID(mesh, elem_id, new_elem_ptr_1);
984  }
985 
986  for (const auto & bid : side_info)
987  {
988  mesh.get_boundary_info().add_side(new_elem_ptr_0, 0, bid);
989  if (new_elem_ptr_1)
990  mesh.get_boundary_info().add_side(new_elem_ptr_1, 0, bid);
991  }
992 }
virtual Node *& set_node(const unsigned int i)
MeshBase & mesh
const BoundaryInfo & get_boundary_info() const
std::size_t euclideanMod(T1 dividend, T2 divisor)
perform modulo operator for Euclidean division that ensures a non-negative result ...
Definition: MathUtils.h:439
void retainEEID(MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
subdomain_id_type subdomain_id() const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
IntRange< T > make_range(T beg, T end)

◆ elementBoundaryInfoCollector() [1/2]

void MooseMeshElementConversionUtils::elementBoundaryInfoCollector ( const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
const unsigned short  n_elem_sides,
std::vector< std::vector< boundary_id_type >> &  elem_side_list 
)

Collect the boundary information of the given element in a mesh.

Parameters
bdry_side_listA list that contains the boundary information of the mesh
elem_idThe id of the element to be processed
n_elem_sidesThe number of sides of the element
elem_side_lista vector of vectors to record the boundary information of the element

Definition at line 746 of file MooseMeshElementConversionUtils.C.

Referenced by hexElemSplitter(), polyhedronElemSplitter(), prismElemSplitter(), pyramidElemSplitter(), and CutMeshByLevelSetGeneratorBase::tet4ElemCutter().

750 {
751  elem_side_list.resize(n_elem_sides);
752  const auto selected_bdry_side_list =
753  std::equal_range(bdry_side_list.begin(), bdry_side_list.end(), elem_id, BCTupleKeyComp{});
754  for (auto selected_bdry_side = selected_bdry_side_list.first;
755  selected_bdry_side != selected_bdry_side_list.second;
756  ++selected_bdry_side)
757  {
758  elem_side_list[std::get<1>(*selected_bdry_side)].push_back(std::get<2>(*selected_bdry_side));
759  }
760 }

◆ elementBoundaryInfoCollector() [2/2]

void MooseMeshElementConversionUtils::elementBoundaryInfoCollector ( const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
const unsigned short  n_elem_sides,
std::vector< std::vector< boundary_id_type >> &  elem_side_list 
)

Collect the boundary information of the given element in a mesh.

Parameters
bdry_side_listA list that contains the boundary information of the mesh
elem_idThe id of the element to be processed
n_elem_sidesThe number of sides of the element
elem_side_lista vector of vectors to record the boundary information of the element

Definition at line 746 of file MooseMeshElementConversionUtils.C.

Referenced by hexElemSplitter(), polyhedronElemSplitter(), prismElemSplitter(), pyramidElemSplitter(), and CutMeshByLevelSetGeneratorBase::tet4ElemCutter().

750 {
751  elem_side_list.resize(n_elem_sides);
752  const auto selected_bdry_side_list =
753  std::equal_range(bdry_side_list.begin(), bdry_side_list.end(), elem_id, BCTupleKeyComp{});
754  for (auto selected_bdry_side = selected_bdry_side_list.first;
755  selected_bdry_side != selected_bdry_side_list.second;
756  ++selected_bdry_side)
757  {
758  elem_side_list[std::get<1>(*selected_bdry_side)].push_back(std::get<2>(*selected_bdry_side));
759  }
760 }

◆ hexElemSplitter() [1/2]

void MooseMeshElementConversionUtils::hexElemSplitter ( MeshBase mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Definition at line 33 of file MooseMeshElementConversionUtils.C.

Referenced by convert3DMeshToAllTet4().

37 {
38  // Build boundary information of the mesh
39  BoundaryInfo & boundary_info = mesh.get_boundary_info();
40  // Create a list of sidesets involving the element to be split
41  std::vector<std::vector<boundary_id_type>> elem_side_list;
42  elem_side_list.resize(6);
43  elementBoundaryInfoCollector(bdry_side_list, elem_id, 6, elem_side_list);
44 
45  const unsigned int n_elem_extra_ids = mesh.n_elem_integers();
46  std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
47  // Record all the element extra integers of the original quad element
48  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
49  exist_extra_ids[j] = mesh.elem_ptr(elem_id)->get_extra_integer(j);
50 
51  std::vector<std::vector<unsigned int>> opt_option;
52  std::vector<const Node *> elem_node_list = {mesh.elem_ptr(elem_id)->node_ptr(0),
53  mesh.elem_ptr(elem_id)->node_ptr(1),
54  mesh.elem_ptr(elem_id)->node_ptr(2),
55  mesh.elem_ptr(elem_id)->node_ptr(3),
56  mesh.elem_ptr(elem_id)->node_ptr(4),
57  mesh.elem_ptr(elem_id)->node_ptr(5),
58  mesh.elem_ptr(elem_id)->node_ptr(6),
59  mesh.elem_ptr(elem_id)->node_ptr(7)};
60  std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
61 
62  std::vector<std::vector<const Node *>> optimized_node_list;
63  hexNodesToTetNodesDeterminer(elem_node_list, rotated_tet_face_indices, optimized_node_list);
64 
65  std::vector<Elem *> elems_Tet4;
66  for (const auto i : index_range(optimized_node_list))
67  {
68  auto new_elem = std::make_unique<Tet4>();
69  new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
70  new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
71  new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
72  new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
73  new_elem->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id();
74  elems_Tet4.push_back(mesh.add_elem(std::move(new_elem)));
75  converted_elems_ids.push_back(elems_Tet4.back()->id());
76 
77  for (unsigned int j = 0; j < 4; j++)
78  {
79  // A hex element has 6 faces indexed from 0 to 5
80  // a <6 value indicates that the face of the tet element corresponds to the face of the
81  // original hex; a =6 value means the face of the tet is an interior face of the hex
82  if (rotated_tet_face_indices[i][j] < 6)
83  {
84  for (const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
85  boundary_info.add_side(elems_Tet4.back(), j, side_info);
86  }
87  }
88  }
89 
90  // Retain element extra integers
91  for (unsigned int i = 0; i < 6; i++)
92  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
93  {
94  elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
95  }
96 }
unsigned int n_elem_integers() const
MeshBase & mesh
void hexNodesToTetNodesDeterminer(std::vector< const Node *> &hex_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
void elementBoundaryInfoCollector(const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
Collect the boundary information of the given element in a mesh.
const BoundaryInfo & get_boundary_info() const
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
subdomain_id_type subdomain_id() const
const Node * node_ptr(const unsigned int i) const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
auto index_range(const T &sizable)
dof_id_type get_extra_integer(const unsigned int index) const

◆ hexElemSplitter() [2/2]

void MooseMeshElementConversionUtils::hexElemSplitter ( MeshBase &  mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Split a HEX8 element into six TET4 elements.

Parameters
meshThe mesh to be modified
bdry_side_listA list that contains the boundary information of the original mesh
elem_idThe id of the element to be split
converted_elems_idsa vector to record the ids of the newly created TET4 elements

◆ hexNodesToTetNodesDeterminer() [1/2]

void MooseMeshElementConversionUtils::hexNodesToTetNodesDeterminer ( std::vector< const Node *> &  hex_nodes,
std::vector< std::vector< unsigned int >> &  rotated_tet_face_indices,
std::vector< std::vector< const Node *>> &  tet_nodes_list 
)

For a vector of rotated nodes that can form a HEX8 element, create a vector of four-node sets that can form TET4 elements to replace the original HEX8 element.

All the QUAD4 faces of the HEX8 element will be split by the diagonal line that involves the node with the minimum id of that face.

Parameters
hex_nodesA vector of pointers to the nodes that can form a HEX8 element
rotated_tet_face_indicesA vector of vectors of the original face indices of the HEX8 element corresponding to the faces of the newly created TET4 elements
tet_nodes_lista vector of vectors of pointers to the nodes that can form TET4 elements

◆ hexNodesToTetNodesDeterminer() [2/2]

void MooseMeshElementConversionUtils::hexNodesToTetNodesDeterminer ( std::vector< const Node *> &  hex_nodes,
std::vector< std::vector< unsigned int >> &  rotated_tet_face_indices,
std::vector< std::vector< const Node *>> &  tet_nodes_list 
)

Definition at line 292 of file MooseMeshElementConversionUtils.C.

Referenced by hexElemSplitter().

295 {
296  // Find the node with the minimum id
297  std::vector<dof_id_type> node_ids(8);
298  for (unsigned int i = 0; i < 8; i++)
299  node_ids[i] = hex_nodes[i]->id();
300 
301  const unsigned int min_node_id_index = std::distance(
302  std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
303  // Get the index of the three neighbor nodes of the minimum node
304  // The order is consistent with the description in nodeRotationHEX8()
305  // Then determine the index of the second minimum node
306  const auto neighbor_node_indices = neighborNodeIndicesHEX8(min_node_id_index);
307 
308  const auto neighbor_node_ids = {node_ids[neighbor_node_indices[0]],
309  node_ids[neighbor_node_indices[1]],
310  node_ids[neighbor_node_indices[2]]};
311  const unsigned int sec_min_pos =
312  std::distance(std::begin(neighbor_node_ids),
313  std::min_element(std::begin(neighbor_node_ids), std::end(neighbor_node_ids)));
314 
315  // Rotate the node and face indices based on the identified minimum and second minimum nodes
316  // After the rotation, we guarantee that the minimum node is the first node (Node 0)
317  // And the second node (Node 1) has the minium global id among the three neighbor nodes of Node 0
318  // This makes the splitting process simpler
319  std::vector<unsigned int> face_rotation;
320  std::vector<unsigned int> rotated_indices;
321  nodeRotationHEX8(min_node_id_index, sec_min_pos, face_rotation, rotated_indices);
322  std::vector<const Node *> rotated_hex_nodes;
323  for (unsigned int i = 0; i < 8; i++)
324  rotated_hex_nodes.push_back(hex_nodes[rotated_indices[i]]);
325 
326  // Find the selection of each face's cutting direction
327  const auto diagonal_directions = quadFaceDiagonalDirectionsHex(rotated_hex_nodes);
328 
329  // Based on the determined splitting directions of all the faces, determine the nodes of each
330  // resulting TET4 elements after the splitting.
331  std::vector<std::vector<unsigned int>> tet_face_indices;
332  const auto tet_nodes_set = tetNodesForHex(diagonal_directions, tet_face_indices);
333  for (const auto & tet_face_index : tet_face_indices)
334  {
335  rotated_tet_face_indices.push_back(std::vector<unsigned int>());
336  for (const auto & face_index : tet_face_index)
337  {
338  if (face_index < 6)
339  rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
340  else
341  rotated_tet_face_indices.back().push_back(6);
342  }
343  }
344 
345  for (const auto & tet_nodes : tet_nodes_set)
346  {
347  tet_nodes_list.push_back(std::vector<const Node *>());
348  for (const auto & tet_node : tet_nodes)
349  tet_nodes_list.back().push_back(rotated_hex_nodes[tet_node]);
350  }
351 }
std::vector< bool > quadFaceDiagonalDirectionsHex(const std::vector< const Node *> &hex_nodes)
void nodeRotationHEX8(const unsigned int min_id_index, const unsigned int sec_min_pos, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
Rotate a HEX8 element&#39;s nodes to ensure that the node with the minimum id is the first node; and the ...
std::vector< unsigned int > neighborNodeIndicesHEX8(unsigned int min_id_index)
Calculate the indices (within the element nodes) of the three neighboring nodes of a node in a HEX8 e...
std::vector< std::vector< unsigned int > > tetNodesForHex(const std::vector< bool > diagonal_directions, std::vector< std::vector< unsigned int >> &tet_face_indices)
Creates sets of four nodes indices that can form TET4 elements to replace the original HEX8 element...

◆ neighborNodeIndicesHEX8()

std::vector< unsigned int > MooseMeshElementConversionUtils::neighborNodeIndicesHEX8 ( unsigned int  min_id_index)

Calculate the indices (within the element nodes) of the three neighboring nodes of a node in a HEX8 element.

Parameters
min_id_indexThe index of the node with the minimum id
Returns
a vector of the three neighboring nodes

Definition at line 281 of file MooseMeshElementConversionUtils.C.

Referenced by hexNodesToTetNodesDeterminer().

282 {
283  const std::vector<std::vector<unsigned int>> preset_indices = {
284  {1, 3, 4}, {0, 2, 5}, {3, 1, 6}, {2, 0, 7}, {5, 7, 0}, {4, 6, 1}, {7, 5, 2}, {6, 4, 3}};
285  if (min_id_index > 7)
286  mooseError("The input node index is out of range.");
287  else
288  return preset_indices[min_id_index];
289 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311

◆ nodeRotationHEX8()

void MooseMeshElementConversionUtils::nodeRotationHEX8 ( const unsigned int  min_id_index,
const unsigned int  sec_min_pos,
std::vector< unsigned int > &  face_rotation,
std::vector< unsigned int > &  node_rotation 
)

Rotate a HEX8 element's nodes to ensure that the node with the minimum id is the first node; and the node among its three neighboring nodes with the minimum id is the second node.

Parameters
min_id_indexThe index of the node with the minimum id
sec_min_posThe index of the node among its three neighboring nodes with the minimum id (see comments in the function for more details about how the index is defined)
face_rotationA vector to record the rotation of the faces of the HEX8 element
node_rotationa vector of node indices that can form a HEX8 element

Definition at line 435 of file MooseMeshElementConversionUtils.C.

Referenced by hexNodesToTetNodesDeterminer().

439 {
440  // Assuming the original hex element is a cube, the vectors formed by nodes 0-1, 0-3, and 0-4 are
441  // overlapped with the x, y, and z axes, respectively. sec_min_pos = 0 means the second minimum
442  // node is in the x direction, sec_min_pos = 1 means the second minimum node is in the y
443  // direction, and sec_min_pos = 2 means the second minimum node is in the z direction.
444  const std::vector<std::vector<std::vector<unsigned int>>> preset_indices = {
445  {{0, 1, 2, 3, 4, 5, 6, 7}, {0, 3, 7, 4, 1, 2, 6, 5}, {0, 4, 5, 1, 3, 7, 6, 2}},
446  {{1, 0, 4, 5, 2, 3, 7, 6}, {1, 2, 3, 0, 5, 6, 7, 4}, {1, 5, 6, 2, 0, 4, 7, 3}},
447  {{2, 3, 0, 1, 6, 7, 4, 5}, {2, 1, 5, 6, 3, 0, 4, 7}, {2, 6, 7, 3, 1, 5, 4, 0}},
448  {{3, 2, 6, 7, 0, 1, 5, 4}, {3, 0, 1, 2, 7, 4, 5, 6}, {3, 7, 4, 0, 2, 6, 5, 1}},
449  {{4, 5, 1, 0, 7, 6, 2, 3}, {4, 7, 6, 5, 0, 3, 2, 1}, {4, 0, 3, 7, 5, 1, 2, 6}},
450  {{5, 4, 7, 6, 1, 0, 3, 2}, {5, 6, 2, 1, 4, 7, 3, 0}, {5, 1, 0, 4, 6, 2, 3, 7}},
451  {{6, 7, 3, 2, 5, 4, 0, 1}, {6, 5, 4, 7, 2, 1, 0, 3}, {6, 2, 1, 5, 7, 3, 0, 4}},
452  {{7, 6, 5, 4, 3, 2, 1, 0}, {7, 4, 0, 3, 6, 5, 1, 2}, {7, 3, 2, 6, 4, 0, 1, 5}}};
453 
454  const std::vector<std::vector<std::vector<unsigned int>>> preset_face_indices = {
455  {{0, 1, 2, 3, 4, 5}, {4, 0, 3, 5, 1, 2}, {1, 4, 5, 2, 0, 3}},
456  {{1, 0, 4, 5, 2, 3}, {0, 2, 3, 4, 1, 5}, {2, 1, 5, 3, 0, 4}},
457  {{0, 3, 4, 1, 2, 5}, {2, 0, 1, 5, 3, 4}, {3, 2, 5, 4, 0, 1}},
458  {{3, 0, 2, 5, 4, 1}, {0, 4, 1, 2, 3, 5}, {4, 3, 5, 1, 0, 2}},
459  {{1, 5, 2, 0, 4, 3}, {5, 4, 3, 2, 1, 0}, {4, 1, 0, 3, 5, 2}},
460  {{5, 1, 4, 3, 2, 0}, {2, 5, 3, 0, 1, 4}, {1, 2, 0, 4, 5, 3}},
461  {{3, 5, 4, 0, 2, 1}, {5, 2, 1, 4, 3, 0}, {2, 3, 0, 1, 5, 4}},
462  {{5, 3, 2, 1, 4, 0}, {4, 5, 1, 0, 3, 2}, {3, 4, 0, 2, 5, 1}}};
463 
464  if (min_id_index > 7 || sec_min_pos > 2)
465  mooseError("The input node index is out of range.");
466  else
467  {
468  // index: new face index; value: old face index
469  face_rotation = preset_face_indices[min_id_index][sec_min_pos];
470  node_rotation = preset_indices[min_id_index][sec_min_pos];
471  }
472 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311

◆ nodeRotationPRISM6()

void MooseMeshElementConversionUtils::nodeRotationPRISM6 ( unsigned int  min_id_index,
std::vector< unsigned int > &  face_rotation,
std::vector< unsigned int > &  node_rotation 
)

Rotate a PRISM6 element nodes to ensure that the node with the minimum id is the first node.

Parameters
min_id_indexThe index of the node, within the prism nodes, with the minimum id
face_rotationA vector to record the rotation of the faces of the PRISM6 element
node_rotationa vector of node indices that can form a PRISM6 element

Definition at line 475 of file MooseMeshElementConversionUtils.C.

Referenced by prismNodesToTetNodesDeterminer().

478 {
479  const std::vector<std::vector<unsigned int>> preset_indices = {{0, 1, 2, 3, 4, 5},
480  {1, 2, 0, 4, 5, 3},
481  {2, 0, 1, 5, 3, 4},
482  {3, 5, 4, 0, 2, 1},
483  {4, 3, 5, 1, 0, 2},
484  {5, 4, 3, 2, 1, 0}};
485 
486  const std::vector<std::vector<unsigned int>> preset_face_indices = {{0, 1, 2, 3, 4},
487  {0, 2, 3, 1, 4},
488  {0, 3, 1, 2, 4},
489  {4, 3, 2, 1, 0},
490  {4, 1, 3, 2, 0},
491  {4, 2, 1, 3, 0}};
492 
493  if (min_id_index > 5)
494  mooseError("The input node index is out of range.");
495  else
496  {
497  // index: new face index; value: old face index
498  face_rotation = preset_face_indices[min_id_index];
499  node_rotation = preset_indices[min_id_index];
500  }
501 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311

◆ nodeRotationPYRAMID5()

void MooseMeshElementConversionUtils::nodeRotationPYRAMID5 ( unsigned int  min_id_index,
std::vector< unsigned int > &  face_rotation,
std::vector< unsigned int > &  node_rotation 
)

Rotate a PYRAMID5 element nodes to ensure that the node with the minimum id is the first node for the bottom face.

Parameters
min_id_indexThe index of the node, within the pyramid nodes, with the minimum id for the bottom face
face_rotationA vector to record the rotation of the faces of the PYRAMID5 element
node_rotationa vector of node indices that can form a PYRAMID5 element

Definition at line 576 of file MooseMeshElementConversionUtils.C.

Referenced by pyramidNodesToTetNodesDeterminer().

579 {
580  const std::vector<std::vector<unsigned int>> preset_indices = {
581  {0, 1, 2, 3, 4}, {1, 2, 3, 0, 4}, {2, 3, 0, 1, 4}, {3, 0, 1, 2, 4}};
582 
583  const std::vector<std::vector<unsigned int>> preset_face_indices = {
584  {0, 1, 2, 3, 4}, {1, 2, 3, 0, 4}, {2, 3, 0, 1, 4}, {3, 0, 1, 2, 4}};
585 
586  if (min_id_index > 3)
587  mooseError("The input node index is out of range.");
588  else
589  {
590  // index: new face index; value: old face index
591  face_rotation = preset_face_indices[min_id_index];
592  node_rotation = preset_indices[min_id_index];
593  }
594 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311

◆ polyhedronElemSplitter() [1/2]

void MooseMeshElementConversionUtils::polyhedronElemSplitter ( MeshBase &  mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Split a polyhedron element into n_sides TET4 elements.

Parameters
meshThe mesh to be modified
bdry_side_listA list that contains the boundary information of the original mesh
elem_idThe id of the element to be split
converted_elems_idsa vector to record the ids of the newly created TET4 elements

◆ polyhedronElemSplitter() [2/2]

void MooseMeshElementConversionUtils::polyhedronElemSplitter ( MeshBase mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Definition at line 221 of file MooseMeshElementConversionUtils.C.

Referenced by convert3DMeshToAllTet4().

225 {
226  auto elem = mesh.elem_ptr(elem_id);
227  // Build boundary information of the mesh
228  BoundaryInfo & boundary_info = mesh.get_boundary_info();
229  // Create a list of sidesets involving the element to be split
230  std::vector<std::vector<boundary_id_type>> elem_side_list;
231  elementBoundaryInfoCollector(bdry_side_list, elem_id, elem->n_sides(), elem_side_list);
232 
233  const unsigned int n_elem_extra_ids = mesh.n_elem_integers();
234  std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
235 
236  // Record all the element extra integers of the original quad element
237  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
238  exist_extra_ids[j] = elem->get_extra_integer(j);
239 
240  // Split the polygon using its tetrahedralization
241  const auto poly = dynamic_cast<C0Polyhedron *>(elem);
242  Node * v_avg_node = nullptr;
243  // Currently the only extra node ever use to tetrahedralize
244  if (dynamic_cast<C0Polyhedron *>(elem))
245  v_avg_node =
246  mesh.add_point(elem->vertex_average(), mesh.max_node_id() + elem_id, elem->processor_id());
247 
248  std::vector<Elem *> elems_Tet4;
249  for (const auto tri_i : make_range(poly->n_subelements()))
250  {
251  const auto tri_indices = poly->subelement(tri_i);
252 
253  auto new_elem = std::make_unique<Tet4>();
254  for (const auto i : make_range(4))
255  if (tri_indices[i] >= 0)
256  new_elem->set_node(i, const_cast<Node *>(elem->node_ptr(tri_indices[i])));
257  else
258  new_elem->set_node(i, v_avg_node);
259 
260  new_elem->subdomain_id() = elem->subdomain_id();
261  elems_Tet4.push_back(mesh.add_elem(std::move(new_elem)));
262  converted_elems_ids.push_back(elems_Tet4.back()->id());
263 
264  // Get subelement to side map
265  const auto tet_face_indices = poly->subelement_sides_to_poly_sides(tri_i);
266 
267  // Add the sides of the tets to the relevant boundaries
268  for (unsigned int j = 0; j < 4; j++)
269  if (tet_face_indices[j] < int(elem->n_sides()))
270  for (const auto & side_info : elem_side_list[tet_face_indices[j]])
271  boundary_info.add_side(elems_Tet4.back(), j, side_info);
272  }
273 
274  // Retain element extra integers
275  for (const auto i : make_range(poly->n_subelements()))
276  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
277  elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
278 }
R poly(const C &c, const T x, const bool derivative=false)
Evaluate a polynomial with the coefficients c at x.
Definition: MathUtils.h:242
unsigned int n_elem_integers() const
MeshBase & mesh
void elementBoundaryInfoCollector(const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
Collect the boundary information of the given element in a mesh.
const BoundaryInfo & get_boundary_info() const
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
IntRange< T > make_range(T beg, T end)
virtual dof_id_type max_node_id() const=0

◆ prismElemSplitter() [1/2]

void MooseMeshElementConversionUtils::prismElemSplitter ( MeshBase &  mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Split a PRISM6 element into three TET4 elements.

Parameters
meshThe mesh to be modified
bdry_side_listA list that contains the boundary information of the original mesh
elem_idThe id of the element to be split
converted_elems_idsa vector to record the ids of the newly created TET4 elements

◆ prismElemSplitter() [2/2]

void MooseMeshElementConversionUtils::prismElemSplitter ( MeshBase mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Definition at line 99 of file MooseMeshElementConversionUtils.C.

Referenced by convert3DMeshToAllTet4().

103 {
104  // Build boundary information of the mesh
105  BoundaryInfo & boundary_info = mesh.get_boundary_info();
106  // Create a list of sidesets involving the element to be split
107  std::vector<std::vector<boundary_id_type>> elem_side_list;
108  elementBoundaryInfoCollector(bdry_side_list, elem_id, 5, elem_side_list);
109 
110  const unsigned int n_elem_extra_ids = mesh.n_elem_integers();
111  std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
112 
113  // Record all the element extra integers of the original quad element
114  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
115  exist_extra_ids[j] = mesh.elem_ptr(elem_id)->get_extra_integer(j);
116 
117  std::vector<const Node *> elem_node_list = {mesh.elem_ptr(elem_id)->node_ptr(0),
118  mesh.elem_ptr(elem_id)->node_ptr(1),
119  mesh.elem_ptr(elem_id)->node_ptr(2),
120  mesh.elem_ptr(elem_id)->node_ptr(3),
121  mesh.elem_ptr(elem_id)->node_ptr(4),
122  mesh.elem_ptr(elem_id)->node_ptr(5)};
123  std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
124  std::vector<std::vector<const Node *>> optimized_node_list;
125  prismNodesToTetNodesDeterminer(elem_node_list, rotated_tet_face_indices, optimized_node_list);
126 
127  std::vector<Elem *> elems_Tet4;
128  for (const auto i : index_range(optimized_node_list))
129  {
130  auto new_elem = std::make_unique<Tet4>();
131  new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
132  new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
133  new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
134  new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
135  new_elem->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id();
136  elems_Tet4.push_back(mesh.add_elem(std::move(new_elem)));
137  converted_elems_ids.push_back(elems_Tet4.back()->id());
138 
139  for (unsigned int j = 0; j < 4; j++)
140  {
141  // A prism element has 5 faces indexed from 0 to 4
142  // a <4 value indicates that the face of the tet element corresponds to the face of the
143  // original prism; a =5 value means the face of the tet is an interior face of the prism
144  if (rotated_tet_face_indices[i][j] < 5)
145  {
146  for (const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
147  boundary_info.add_side(elems_Tet4.back(), j, side_info);
148  }
149  }
150  }
151 
152  // Retain element extra integers
153  for (unsigned int i = 0; i < 3; i++)
154  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
155  {
156  elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
157  }
158 }
unsigned int n_elem_integers() const
MeshBase & mesh
void elementBoundaryInfoCollector(const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
Collect the boundary information of the given element in a mesh.
const BoundaryInfo & get_boundary_info() const
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
subdomain_id_type subdomain_id() const
const Node * node_ptr(const unsigned int i) const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
void prismNodesToTetNodesDeterminer(std::vector< const Node *> &prism_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
auto index_range(const T &sizable)
dof_id_type get_extra_integer(const unsigned int index) const

◆ prismNodesToTetNodesDeterminer() [1/2]

void MooseMeshElementConversionUtils::prismNodesToTetNodesDeterminer ( std::vector< const Node *> &  prism_nodes,
std::vector< std::vector< unsigned int >> &  rotated_tet_face_indices,
std::vector< std::vector< const Node *>> &  tet_nodes_list 
)

For a rotated nodes that can form a PRISM6 element, create a series of four-node set that can form TET4 elements to replace the original PRISM6 element.

All the QUAD4 face of the PRISM6 element will be split by the diagonal line that involves the node with the minimum id of that face.

Parameters
prism_nodesA vector of pointers to the nodes that can form a PRISM6 element
rotated_tet_face_indicesA vector of vectors of the original face indices of the PRISM6 element corresponding to the faces of the newly created TET4 elements
tet_nodes_lista vector of vectors of pointers to the nodes that can form TET4 elements

Referenced by CutMeshByLevelSetGeneratorBase::tet4ElemCutter().

◆ prismNodesToTetNodesDeterminer() [2/2]

void MooseMeshElementConversionUtils::prismNodesToTetNodesDeterminer ( std::vector< const Node *> &  prism_nodes,
std::vector< std::vector< unsigned int >> &  rotated_tet_face_indices,
std::vector< std::vector< const Node *>> &  tet_nodes_list 
)

Definition at line 504 of file MooseMeshElementConversionUtils.C.

Referenced by prismElemSplitter().

507 {
508  // Find the node with the minimum id
509  std::vector<dof_id_type> node_ids(6);
510  for (unsigned int i = 0; i < 6; i++)
511  node_ids[i] = prism_nodes[i]->id();
512 
513  const unsigned int min_node_id_index = std::distance(
514  std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
515 
516  // Rotate the node and face indices based on the identified minimum node
517  // After the rotation, we guarantee that the minimum node is the first node (Node 0)
518  // This makes the splitting process simpler
519  std::vector<unsigned int> face_rotation;
520  std::vector<unsigned int> rotated_indices;
521  nodeRotationPRISM6(min_node_id_index, face_rotation, rotated_indices);
522  std::vector<const Node *> rotated_prism_nodes;
523  for (unsigned int i = 0; i < 6; i++)
524  rotated_prism_nodes.push_back(prism_nodes[rotated_indices[i]]);
525 
526  std::vector<const Node *> key_quad_nodes = {rotated_prism_nodes[1],
527  rotated_prism_nodes[2],
528  rotated_prism_nodes[5],
529  rotated_prism_nodes[4]};
530 
531  // Find the selection of each face's cutting direction
532  const bool diagonal_direction = quadFaceDiagonalDirection(key_quad_nodes);
533 
534  // Based on the determined splitting directions of all the faces, determine the nodes of each
535  // resulting TET4 elements after the splitting.
536  std::vector<std::vector<unsigned int>> tet_face_indices;
537  const auto tet_nodes_set = tetNodesForPrism(diagonal_direction, tet_face_indices);
538  for (const auto & tet_face_index : tet_face_indices)
539  {
540  rotated_tet_face_indices.push_back(std::vector<unsigned int>());
541  for (const auto & face_index : tet_face_index)
542  {
543  if (face_index < 5)
544  rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
545  else
546  rotated_tet_face_indices.back().push_back(5);
547  }
548  }
549 
550  for (const auto & tet_nodes : tet_nodes_set)
551  {
552  tet_nodes_list.push_back(std::vector<const Node *>());
553  for (const auto & tet_node : tet_nodes)
554  tet_nodes_list.back().push_back(rotated_prism_nodes[tet_node]);
555  }
556 }
bool quadFaceDiagonalDirection(const std::vector< const Node *> &quad_nodes)
std::vector< std::vector< unsigned int > > tetNodesForPrism(const bool diagonal_direction, std::vector< std::vector< unsigned int >> &tet_face_indices)
Creates sets of four nodes indices that can form TET4 elements to replace the original PRISM6 element...
void nodeRotationPRISM6(unsigned int min_id_index, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
Rotate a PRISM6 element nodes to ensure that the node with the minimum id is the first node...

◆ pyramidElemSplitter() [1/2]

void MooseMeshElementConversionUtils::pyramidElemSplitter ( MeshBase &  mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Split a PYRAMID5 element into two TET4 elements.

Parameters
meshThe mesh to be modified
bdry_side_listA list that contains the boundary information of the original mesh
elem_idThe id of the element to be split
converted_elems_idsa vector to record the ids of the newly created TET4 elements

◆ pyramidElemSplitter() [2/2]

void MooseMeshElementConversionUtils::pyramidElemSplitter ( MeshBase mesh,
const std::vector< libMesh::BoundaryInfo::BCTuple > &  bdry_side_list,
const dof_id_type  elem_id,
std::vector< dof_id_type > &  converted_elems_ids 
)

Definition at line 161 of file MooseMeshElementConversionUtils.C.

Referenced by convert3DMeshToAllTet4().

165 {
166  // Build boundary information of the mesh
167  BoundaryInfo & boundary_info = mesh.get_boundary_info();
168  // Create a list of sidesets involving the element to be split
169  std::vector<std::vector<boundary_id_type>> elem_side_list;
170  elementBoundaryInfoCollector(bdry_side_list, elem_id, 5, elem_side_list);
171 
172  const unsigned int n_elem_extra_ids = mesh.n_elem_integers();
173  std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
174  // Record all the element extra integers of the original quad element
175  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
176  exist_extra_ids[j] = mesh.elem_ptr(elem_id)->get_extra_integer(j);
177 
178  std::vector<const Node *> elem_node_list = {mesh.elem_ptr(elem_id)->node_ptr(0),
179  mesh.elem_ptr(elem_id)->node_ptr(1),
180  mesh.elem_ptr(elem_id)->node_ptr(2),
181  mesh.elem_ptr(elem_id)->node_ptr(3),
182  mesh.elem_ptr(elem_id)->node_ptr(4)};
183  std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
184  std::vector<std::vector<const Node *>> optimized_node_list;
185  pyramidNodesToTetNodesDeterminer(elem_node_list, rotated_tet_face_indices, optimized_node_list);
186 
187  std::vector<Elem *> elems_Tet4;
188  for (const auto i : index_range(optimized_node_list))
189  {
190  auto new_elem = std::make_unique<Tet4>();
191  new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
192  new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
193  new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
194  new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
195  new_elem->subdomain_id() = mesh.elem_ptr(elem_id)->subdomain_id();
196  elems_Tet4.push_back(mesh.add_elem(std::move(new_elem)));
197  converted_elems_ids.push_back(elems_Tet4.back()->id());
198 
199  for (unsigned int j = 0; j < 4; j++)
200  {
201  // A pyramid element has 5 faces indexed from 0 to 4
202  // a <4 value indicates that the face of the tet element corresponds to the face of the
203  // original pyramid; a =5 value means the face of the tet is an interior face of the pyramid
204  if (rotated_tet_face_indices[i][j] < 5)
205  {
206  for (const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
207  boundary_info.add_side(elems_Tet4.back(), j, side_info);
208  }
209  }
210  }
211 
212  // Retain element extra integers
213  for (unsigned int i = 0; i < 2; i++)
214  for (unsigned int j = 0; j < n_elem_extra_ids; j++)
215  {
216  elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
217  }
218 }
unsigned int n_elem_integers() const
MeshBase & mesh
void elementBoundaryInfoCollector(const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
Collect the boundary information of the given element in a mesh.
const BoundaryInfo & get_boundary_info() const
virtual Elem * add_elem(Elem *e)=0
virtual const Elem * elem_ptr(const dof_id_type i) const=0
subdomain_id_type subdomain_id() const
const Node * node_ptr(const unsigned int i) const
void pyramidNodesToTetNodesDeterminer(std::vector< const Node *> &pyramid_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
auto index_range(const T &sizable)
dof_id_type get_extra_integer(const unsigned int index) const

◆ pyramidNodesToTetNodesDeterminer() [1/2]

void MooseMeshElementConversionUtils::pyramidNodesToTetNodesDeterminer ( std::vector< const Node *> &  pyramid_nodes,
std::vector< std::vector< unsigned int >> &  rotated_tet_face_indices,
std::vector< std::vector< const Node *>> &  tet_nodes_list 
)

For a rotated nodes that can form a PYRAMID5 element, create a series of four-node set that can form TET4 elements to replace the original PYRAMID5 element.

The QUAD4 face of the PYRAMID5 element will be split by the diagonal line that involves the node with the minimum id of that face.

Parameters
pyramid_nodesA vector of pointers to the nodes that can form a PYRAMID5 element
rotated_tet_face_indicesA vector of vectors of the original face indices of the PYRAMID5 element corresponding to the faces of the newly created TET4 elements
tet_nodes_lista vector of vectors of pointers to the nodes that can form TET4 elements

Referenced by CutMeshByLevelSetGeneratorBase::tet4ElemCutter().

◆ pyramidNodesToTetNodesDeterminer() [2/2]

void MooseMeshElementConversionUtils::pyramidNodesToTetNodesDeterminer ( std::vector< const Node *> &  pyramid_nodes,
std::vector< std::vector< unsigned int >> &  rotated_tet_face_indices,
std::vector< std::vector< const Node *>> &  tet_nodes_list 
)

Definition at line 597 of file MooseMeshElementConversionUtils.C.

Referenced by pyramidElemSplitter().

600 {
601  // Find the node with the minimum id, ignoring the top node
602  std::vector<dof_id_type> node_ids(4);
603  for (unsigned int i = 0; i < 4; i++)
604  node_ids[i] = pyramid_nodes[i]->id();
605 
606  const unsigned int min_node_id_index = std::distance(
607  std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
608 
609  // Rotate the node and face indices based on the identified minimum nodes
610  // After the rotation, we guarantee that the minimum node is the first node (Node 0)
611  // This makes the splitting process simpler
612  std::vector<unsigned int> face_rotation;
613  std::vector<unsigned int> rotated_indices;
614  nodeRotationPYRAMID5(min_node_id_index, face_rotation, rotated_indices);
615  std::vector<const Node *> rotated_pyramid_nodes;
616  for (unsigned int i = 0; i < 5; i++)
617  rotated_pyramid_nodes.push_back(pyramid_nodes[rotated_indices[i]]);
618 
619  // There is only one quad face in a pyramid element, so the splitting selection is binary
620  const std::vector<std::vector<unsigned int>> tet_nodes_set = {{0, 1, 2, 4}, {0, 2, 3, 4}};
621  const std::vector<std::vector<unsigned int>> tet_face_indices = {{4, 0, 1, 5}, {4, 5, 2, 3}};
622 
623  // Based on the determined splitting direction, determine the nodes of each resulting TET4
624  // elements after the splitting.
625  for (const auto & tet_face_index : tet_face_indices)
626  {
627  rotated_tet_face_indices.push_back(std::vector<unsigned int>());
628  for (const auto & face_index : tet_face_index)
629  {
630  if (face_index < 5)
631  rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
632  else
633  rotated_tet_face_indices.back().push_back(5);
634  }
635  }
636 
637  for (const auto & tet_nodes : tet_nodes_set)
638  {
639  tet_nodes_list.push_back(std::vector<const Node *>());
640  for (const auto & tet_node : tet_nodes)
641  tet_nodes_list.back().push_back(rotated_pyramid_nodes[tet_node]);
642  }
643 }
void nodeRotationPYRAMID5(unsigned int min_id_index, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
Rotate a PYRAMID5 element nodes to ensure that the node with the minimum id is the first node for the...

◆ quadFaceDiagonalDirection() [1/2]

bool MooseMeshElementConversionUtils::quadFaceDiagonalDirection ( const std::vector< const Node *> &  quad_nodes)

For a QUAD4 element, determine the direction of the diagonal line that involves the node with the minimum id of that element.

Parameters
quad_nodesA vector of pointers to the nodes that can form a QUAD4 element
Returns
a boolean value indicating the direction of the diagonal line

◆ quadFaceDiagonalDirection() [2/2]

bool MooseMeshElementConversionUtils::quadFaceDiagonalDirection ( const std::vector< const Node *> &  quad_nodes)

Definition at line 372 of file MooseMeshElementConversionUtils.C.

Referenced by prismNodesToTetNodesDeterminer(), and quadFaceDiagonalDirectionsHex().

373 {
374  const std::vector<dof_id_type> node_ids = {
375  quad_nodes[0]->id(), quad_nodes[1]->id(), quad_nodes[2]->id(), quad_nodes[3]->id()};
376  const unsigned int min_id_index = std::distance(
377  std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
378  if (min_id_index == 0 || min_id_index == 2)
379  return true;
380  else
381  return false;
382 }

◆ quadFaceDiagonalDirectionsHex() [1/2]

std::vector<bool> MooseMeshElementConversionUtils::quadFaceDiagonalDirectionsHex ( const std::vector< const Node *> &  hex_nodes)

For a HEX8 element, determine the direction of the diagonal line of each face that involves the node with the minimum id of that face.

Parameters
hex_nodesA vector of pointers to the nodes that can form a HEX8 element
Returns
a vector of boolean values indicating the direction of the diagonal line of each face

◆ quadFaceDiagonalDirectionsHex() [2/2]

std::vector<bool> MooseMeshElementConversionUtils::quadFaceDiagonalDirectionsHex ( const std::vector< const Node *> &  hex_nodes)

Definition at line 354 of file MooseMeshElementConversionUtils.C.

Referenced by hexNodesToTetNodesDeterminer().

355 {
356  // Bottom/Top; Front/Back; Right/Left
357  const std::vector<std::vector<unsigned int>> face_indices = {
358  {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 5, 4}, {2, 3, 7, 6}, {1, 2, 6, 5}, {3, 0, 4, 7}};
359  std::vector<bool> diagonal_directions;
360  for (const auto & face_index : face_indices)
361  {
362  std::vector<const Node *> quad_nodes = {hex_nodes[face_index[0]],
363  hex_nodes[face_index[1]],
364  hex_nodes[face_index[2]],
365  hex_nodes[face_index[3]]};
366  diagonal_directions.push_back(quadFaceDiagonalDirection(quad_nodes));
367  }
368  return diagonal_directions;
369 }
bool quadFaceDiagonalDirection(const std::vector< const Node *> &quad_nodes)

◆ retainEEID() [1/2]

void MooseMeshElementConversionUtils::retainEEID ( MeshBase &  mesh,
const dof_id_type elem_id,
Elem *  new_elem_ptr 
)

Retain the extra integer of the original element in a new element.

Parameters
meshThe mesh containing the element
elem_idThe ID of the original element
new_elem_ptrThe pointer to the new element that will retain the extra integer

◆ retainEEID() [2/2]

void MooseMeshElementConversionUtils::retainEEID ( MeshBase mesh,
const dof_id_type elem_id,
Elem new_elem_ptr 
)

Definition at line 1073 of file MooseMeshElementConversionUtils.C.

Referenced by convertPyramid5Elem(), createUnitPyramid5FromHex8(), createUnitTet4FromHex8(), and createUnitTet4FromPrism6().

1074 {
1075  const unsigned int n_eeid = mesh.n_elem_integers();
1076  for (const auto & i : make_range(n_eeid))
1077  new_elem_ptr->set_extra_integer(i, mesh.elem_ptr(elem_id)->get_extra_integer(i));
1078 }
unsigned int n_elem_integers() const
MeshBase & mesh
virtual const Elem * elem_ptr(const dof_id_type i) const=0
IntRange< T > make_range(T beg, T end)
void set_extra_integer(const unsigned int index, const dof_id_type value)
dof_id_type get_extra_integer(const unsigned int index) const

◆ tetNodesForHex()

std::vector< std::vector< unsigned int > > MooseMeshElementConversionUtils::tetNodesForHex ( const std::vector< bool >  diagonal_directions,
std::vector< std::vector< unsigned int >> &  tet_face_indices 
)

Creates sets of four nodes indices that can form TET4 elements to replace the original HEX8 element.

Parameters
diagonal_directionsA vector of boolean values indicating the direction of the diagonal line of each face; true means the diagonal line is connecting node 0 and node 2, false means the diagonal line is connecting node 1 and node 3 of that quad face
tet_face_indicesA vector of vectors of the original face indices of the HEX8 element corresponding to the faces of the newly created TET4 elements
Returns
a vector of vectors of node indices that can form TET4 elements

Definition at line 385 of file MooseMeshElementConversionUtils.C.

Referenced by hexNodesToTetNodesDeterminer().

387 {
388  const std::vector<std::vector<bool>> possible_inputs = {{true, true, true, true, true, false},
389  {true, true, true, true, false, false},
390  {true, true, true, false, true, false},
391  {true, false, true, true, true, false},
392  {true, false, true, true, false, false},
393  {true, false, true, false, true, false},
394  {true, false, true, false, false, false}};
395 
396  const unsigned int input_index = std::distance(
397  std::begin(possible_inputs),
398  std::find(std::begin(possible_inputs), std::end(possible_inputs), diagonal_directions));
399 
400  switch (input_index)
401  {
402  case 0:
403  tet_face_indices = {
404  {0, 6, 2, 6}, {1, 6, 2, 6}, {1, 6, 5, 6}, {0, 6, 3, 4}, {6, 6, 3, 6}, {6, 4, 5, 6}};
405  return {{0, 1, 2, 6}, {0, 5, 1, 6}, {0, 4, 5, 6}, {0, 2, 3, 7}, {0, 6, 2, 7}, {0, 4, 6, 7}};
406  case 1:
407  tet_face_indices = {
408  {0, 1, 2, 6}, {6, 6, 2, 6}, {6, 6, 5, 1}, {0, 6, 3, 4}, {6, 6, 3, 6}, {6, 4, 5, 6}};
409  return {{0, 1, 2, 5}, {0, 2, 6, 5}, {0, 6, 4, 5}, {0, 2, 3, 7}, {0, 6, 2, 7}, {0, 4, 6, 7}};
410  case 2:
411  tet_face_indices = {
412  {0, 6, 2, 6}, {1, 6, 2, 6}, {1, 6, 5, 6}, {4, 6, 5, 6}, {4, 6, 3, 6}, {0, 6, 3, 6}};
413  return {{0, 1, 2, 6}, {0, 5, 1, 6}, {0, 4, 5, 6}, {0, 7, 4, 6}, {0, 3, 7, 6}, {0, 2, 3, 6}};
414  case 3:
415  tet_face_indices = {
416  {4, 6, 5, 1}, {6, 6, 5, 6}, {6, 1, 2, 6}, {4, 0, 3, 6}, {6, 6, 3, 6}, {6, 6, 2, 0}};
417  return {{0, 7, 4, 5}, {0, 6, 7, 5}, {0, 1, 6, 5}, {0, 3, 7, 2}, {0, 7, 6, 2}, {0, 6, 1, 2}};
418  case 4:
419  tet_face_indices = {{0, 1, 2, 6}, {0, 6, 3, 4}, {5, 4, 6, 1}, {5, 6, 3, 2}, {6, 6, 6, 6}};
420  return {{0, 1, 2, 5}, {0, 2, 3, 7}, {4, 7, 5, 0}, {5, 7, 6, 2}, {0, 2, 7, 5}};
421  case 5:
422  tet_face_indices = {
423  {4, 6, 5, 1}, {6, 6, 5, 6}, {6, 1, 2, 6}, {2, 6, 6, 0}, {3, 6, 6, 0}, {3, 6, 6, 4}};
424  return {{0, 7, 4, 5}, {0, 6, 7, 5}, {0, 1, 6, 5}, {1, 6, 2, 0}, {2, 6, 3, 0}, {3, 6, 7, 0}};
425  case 6:
426  tet_face_indices = {
427  {1, 4, 5, 6}, {6, 6, 5, 6}, {6, 6, 3, 4}, {1, 6, 2, 0}, {6, 6, 2, 6}, {6, 0, 3, 6}};
428  return {{0, 4, 5, 7}, {0, 5, 6, 7}, {0, 6, 3, 7}, {0, 5, 1, 2}, {0, 6, 5, 2}, {0, 3, 6, 2}};
429  default:
430  mooseError("Unexpected input.");
431  }
432 }
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311

◆ tetNodesForPrism()

std::vector< std::vector< unsigned int > > MooseMeshElementConversionUtils::tetNodesForPrism ( const bool  diagonal_direction,
std::vector< std::vector< unsigned int >> &  tet_face_indices 
)

Creates sets of four nodes indices that can form TET4 elements to replace the original PRISM6 element.

Parameters
diagonal_directionA boolean value indicating the direction of the diagonal line of Face 2
tet_face_indicesA vector of vectors of the original face indices of the PRISM6 element corresponding to the faces of the newly created TET4 elements
Returns
a vector of vectors of node indices that can form TET4 elements

Definition at line 559 of file MooseMeshElementConversionUtils.C.

Referenced by prismNodesToTetNodesDeterminer().

561 {
562 
563  if (diagonal_direction)
564  {
565  tet_face_indices = {{4, 3, 5, 1}, {2, 1, 5, 5}, {2, 5, 3, 0}};
566  return {{3, 5, 4, 0}, {1, 4, 5, 0}, {1, 5, 2, 0}};
567  }
568  else
569  {
570  tet_face_indices = {{4, 3, 5, 1}, {2, 1, 5, 0}, {2, 5, 5, 3}};
571  return {{3, 5, 4, 0}, {1, 4, 2, 0}, {2, 4, 5, 0}};
572  }
573 }

◆ transitionLayerGenerator() [1/2]

void MooseMeshElementConversionUtils::transitionLayerGenerator ( MeshBase &  mesh,
const std::vector< BoundaryName > &  boundary_names,
const unsigned int  conversion_element_layer_number,
const bool  external_boundaries_checking 
)

Generate a transition layer of elements with TRI3 surfaces on the given boundaries.

Parameters
meshThe mesh to be modified
boundary_namesA vector of boundary names on which the transition layer will be generated
conversion_element_layer_numberThe number of element layers to be converted on the given boundaries.
external_boundaries_checkingWhether to check if the provided boundaries are external boundaries

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

◆ transitionLayerGenerator() [2/2]

void MooseMeshElementConversionUtils::transitionLayerGenerator ( MeshBase mesh,
const std::vector< BoundaryName > &  boundary_names,
const unsigned int  conversion_element_layer_number,
const bool  external_boundaries_checking 
)

Definition at line 1081 of file MooseMeshElementConversionUtils.C.

1085 {
1086  mooseAssert(mesh.is_serial(),
1087  "This method only supports serial meshes. If you are calling this method with a "
1088  "distributed mesh, please serialize it first.");
1089  // The base subdomain ID to shift the original elements because of the element type change
1090  const auto sid_shift_base = MooseMeshUtils::getNextFreeSubdomainID(mesh);
1091  // The maximum subdomain ID that would be involved is sid_shift_base * 3, we would like to make
1092  // sure it would not overflow
1093  if (sid_shift_base * 3 > std::numeric_limits<subdomain_id_type>::max())
1094  throw MooseException("subdomain id overflow");
1095 
1096  // It would be convenient to have a single boundary id instead of a vector.
1097  const auto uniform_tmp_bid = MooseMeshUtils::getNextFreeBoundaryID(mesh);
1098 
1099  // Check the boundaries and merge them
1100  std::vector<boundary_id_type> boundary_ids;
1101  for (const auto & sideset : boundary_names)
1102  {
1104  throw MooseException("The provided boundary '", sideset, "' was not found within the mesh");
1105  boundary_ids.push_back(MooseMeshUtils::getBoundaryID(sideset, mesh));
1106  MooseMeshUtils::changeBoundaryId(mesh, boundary_ids.back(), uniform_tmp_bid, false);
1107  }
1108 
1109  auto & sideset_map = mesh.get_boundary_info().get_sideset_map();
1110  auto side_list = mesh.get_boundary_info().build_side_list();
1111 
1112  std::vector<std::pair<dof_id_type, std::vector<unsigned int>>> elems_list;
1113  std::vector<std::set<dof_id_type>> layered_elems_list;
1114  layered_elems_list.push_back(std::set<dof_id_type>());
1115  // Need to collect the list of elements that need to be converted
1116  if (!mesh.is_prepared())
1117  mesh.find_neighbors();
1118  for (const auto & side_info : side_list)
1119  {
1120  if (std::get<2>(side_info) == uniform_tmp_bid)
1121  {
1122  // Check if the involved side is TRI3 or QUAD4
1123  // We do not limit the element type in the input mesh
1124  // As long as the involved boundaries only consist of TRI3 and QUAD4 sides,
1125  // this generator will work
1126  // As the side element of a quadratic element is still a linear element in libMesh,
1127  // we need to check the element's default_side_order() first
1128  if (mesh.elem_ptr(std::get<0>(side_info))->default_side_order() != 1)
1129  throw MooseException(
1130  "The provided boundary set contains non-linear side elements, which is not supported.");
1131  const auto side_type =
1132  mesh.elem_ptr(std::get<0>(side_info))->side_ptr(std::get<1>(side_info))->type();
1133  layered_elems_list.back().emplace(std::get<0>(side_info));
1134  // If we enforce external boundary, then a non-null neighbor leads to an error
1135  // Otherwise, we need to convert both sides, that means the neighbor information also needs to
1136  // be added
1137  const auto neighbor_ptr =
1138  mesh.elem_ptr(std::get<0>(side_info))->neighbor_ptr(std::get<1>(side_info));
1139  if (neighbor_ptr)
1140  {
1141  if (external_boundaries_checking)
1142  throw MooseException(
1143  "The provided boundary contains non-external sides, which is required when "
1144  "external_boundaries_checking is enabled.");
1145  else
1146  layered_elems_list.back().emplace(neighbor_ptr->id());
1147  }
1148 
1149  if (conversion_element_layer_number == 1)
1150  {
1151  if (side_type == TRI3)
1152  continue; // Already TRI3, no need to convert
1153  else if (side_type == QUAD4)
1154  {
1155  auto pit = std::find_if(elems_list.begin(),
1156  elems_list.end(),
1157  [elem_id = std::get<0>(side_info)](const auto & p)
1158  { return p.first == elem_id; });
1159  if (elems_list.size() && pit != elems_list.end())
1160  {
1161  pit->second.push_back(std::get<1>(side_info));
1162  }
1163  else
1164  elems_list.push_back(std::make_pair(
1165  std::get<0>(side_info), std::vector<unsigned int>({std::get<1>(side_info)})));
1166  if (neighbor_ptr)
1167  {
1168  auto sit = std::find_if(elems_list.begin(),
1169  elems_list.end(),
1170  [elem_id = neighbor_ptr->id()](const auto & p)
1171  { return p.first == elem_id; });
1172  if (elems_list.size() && sit != elems_list.end())
1173  {
1174  sit->second.push_back(
1175  neighbor_ptr->which_neighbor_am_i(mesh.elem_ptr(std::get<0>(side_info))));
1176  }
1177  else
1178  {
1179  elems_list.push_back(std::make_pair(
1180  neighbor_ptr->id(),
1181  std::vector<unsigned int>(
1182  {neighbor_ptr->which_neighbor_am_i(mesh.elem_ptr(std::get<0>(side_info)))})));
1183  }
1184  }
1185  }
1186  else if (side_type == C0POLYGON)
1187  throw MooseException("The provided boundary set contains C0POLYGON side elements, which "
1188  "is not supported.");
1189  else
1190  mooseAssert(false,
1191  "Impossible scenario: a linear non-polygon side element that is neither TRI3 "
1192  "nor QUAD4.");
1193  }
1194  }
1195  }
1196 
1197  if (conversion_element_layer_number > 1)
1198  {
1199  std::set<dof_id_type> total_elems_set(layered_elems_list.back());
1200 
1201  while (layered_elems_list.back().size() &&
1202  layered_elems_list.size() < conversion_element_layer_number)
1203  {
1204  layered_elems_list.push_back(std::set<dof_id_type>());
1205  for (const auto & elem_id : *(layered_elems_list.end() - 2))
1206  {
1207  for (const auto & i_side : make_range(mesh.elem_ptr(elem_id)->n_sides()))
1208  {
1209  if (mesh.elem_ptr(elem_id)->neighbor_ptr(i_side) != nullptr)
1210  {
1211  const auto & neighbor_id = mesh.elem_ptr(elem_id)->neighbor_ptr(i_side)->id();
1212  if (total_elems_set.find(neighbor_id) == total_elems_set.end())
1213  {
1214  layered_elems_list.back().emplace(neighbor_id);
1215  total_elems_set.emplace(neighbor_id);
1216  }
1217  }
1218  }
1219  }
1220  }
1221  }
1222 
1223  // Remove the last empty layer
1224  if (layered_elems_list.back().empty())
1225  layered_elems_list.pop_back();
1226 
1227  if (conversion_element_layer_number > layered_elems_list.size())
1228  throw MooseException("There is fewer layers of elements in the input mesh than the requested "
1229  "number of layers to convert.");
1230 
1231  std::vector<std::pair<dof_id_type, bool>> original_elems;
1232  // construct a list of the element to convert to tet4
1233  // Convert at most n_layer_conversion layers of elements
1234  const unsigned int n_layer_conversion = layered_elems_list.size() - 1;
1235  for (unsigned int i = 0; i < n_layer_conversion; ++i)
1236  for (const auto & elem_id : layered_elems_list[i])
1237  {
1238  // As these elements will become TET4 elements, we need to shift the subdomain ID
1239  // But we do not need to convert original TET4 elements
1240  if (mesh.elem_ptr(elem_id)->type() != TET4)
1241  {
1242  original_elems.push_back(std::make_pair(elem_id, false));
1243  mesh.elem_ptr(elem_id)->subdomain_id() += sid_shift_base;
1244  }
1245  }
1246 
1247  const subdomain_id_type block_id_to_remove = sid_shift_base * 3;
1248 
1249  std::vector<dof_id_type> converted_elems_ids_to_track;
1251  mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove, false);
1252 
1253  // Now we need to convert the elements on the transition layer
1254  // First, we need to identify that the sides that are on the interface with previous layer (all
1255  // TET layers)
1256  if (n_layer_conversion)
1257  {
1258  for (const auto & elem_id : layered_elems_list[n_layer_conversion])
1259  {
1260  for (const auto & i_side : make_range(mesh.elem_ptr(elem_id)->n_sides()))
1261  {
1262  if (mesh.elem_ptr(elem_id)->neighbor_ptr(i_side) != nullptr &&
1263  layered_elems_list[n_layer_conversion - 1].count(
1264  mesh.elem_ptr(elem_id)->neighbor_ptr(i_side)->id()))
1265  {
1266  if (elems_list.size() && elems_list.back().first == elem_id)
1267  elems_list.back().second.push_back(i_side);
1268  else
1269  elems_list.push_back(std::make_pair(elem_id, std::vector<unsigned int>({i_side})));
1270  }
1271  }
1272  }
1273  }
1274 
1275  // Now convert the elements
1276  for (const auto & elem_info : elems_list)
1277  {
1278  // Find the involved sidesets of the element so that we can retain them
1279  std::vector<std::vector<boundary_id_type>> elem_side_info(
1280  mesh.elem_ptr(elem_info.first)->n_sides());
1281  auto side_range = sideset_map.equal_range(mesh.elem_ptr(elem_info.first));
1282  for (auto i = side_range.first; i != side_range.second; ++i)
1283  elem_side_info[i->second.first].push_back(i->second.second);
1284 
1286  mesh, elem_info.first, elem_info.second, elem_side_info, sid_shift_base);
1287  }
1288 
1289  // delete the original elements that were converted
1290  for (const auto & elem_info : elems_list)
1291  mesh.elem_ptr(elem_info.first)->subdomain_id() = block_id_to_remove;
1292  for (auto elem_it = mesh.active_subdomain_elements_begin(block_id_to_remove);
1293  elem_it != mesh.active_subdomain_elements_end(block_id_to_remove);
1294  elem_it++)
1295  mesh.delete_elem(*elem_it);
1296  // delete temporary boundary id
1297  mesh.get_boundary_info().remove_id(uniform_tmp_bid);
1298 
1299  mesh.contract();
1301 }
void remove_id(boundary_id_type id, bool global=false)
bool is_prepared() const
virtual Order default_side_order() const
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the mesh.
std::set< std::string > sideset
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true, const bool assert_valid=true)=0
MeshBase & mesh
const BoundaryInfo & get_boundary_info() const
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
auto max(const L &left, const R &right)
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
virtual bool is_serial() const
void convert3DMeshToAllTet4(MeshBase &mesh, const std::vector< std::pair< dof_id_type, bool >> &elems_to_process, std::vector< dof_id_type > &converted_elems_ids_to_track, const subdomain_id_type block_id_to_remove, const bool delete_block_to_remove)
Convert all the elements in a 3D mesh, consisting of only linear elements, into TET4 elements...
virtual void delete_elem(Elem *e)=0
dof_id_type id() const
TET4
const std::multimap< const Elem *, std::pair< unsigned short int, boundary_id_type > > & get_sideset_map() const
virtual const Elem * elem_ptr(const dof_id_type i) const=0
void convertElem(MeshBase &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
Convert the element to an element with TRI3 side-elements on the user-specified sides by modifying th...
virtual unsigned int n_sides() const=0
const Elem * neighbor_ptr(unsigned int i) const
Provides a way for users to bail out of the current solve.
virtual bool contract()=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
subdomain_id_type subdomain_id() const
IntRange< T > make_range(T beg, T end)
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.
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
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...
virtual ElemType type() const=0
void unset_is_prepared()