Skip to content

Commit

Permalink
Merge pull request #26581 from miaoyinb/3dcut
Browse files Browse the repository at this point in the history
3D Cutting Capability Implementation
  • Loading branch information
GiudGiud authored Feb 7, 2024
2 parents bb2a44c + 5e454d6 commit 822dc5a
Show file tree
Hide file tree
Showing 28 changed files with 1,998 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# CutMeshByPlaneGenerator

!syntax description /Mesh/CutMeshByPlaneGenerator

## Overview

The `CutMeshByPlaneGenerator` is basically the 3D version of [`XYMeshLineCutter`](/XYMeshLineCutter.md). It is used to slice a 3D input mesh along a given plane, and discard the portion of the mesh on one side of the plane. The input mesh, given by [!param](/Mesh/CutMeshByPlaneGenerator/input), must be 3D and contain only first-order elements. The cutting plane is specified by [!param](/Mesh/CutMeshByPlaneGenerator/plane_normal) and [!param](/Mesh/CutMeshByPlaneGenerator/plane_point), which are two `libMesh::Point` type data that represent the normal vector of the cutting plane and a point on the cutting plane, respectively. This mesh generator removes the part of the mesh located on the side of the plane in the direction of the normal vector. The mesh is then smoothed to ensure a straight cut instead of a "zigzag" cut along element boundaries as generated by [`PlaneDeletionGenerator`](/PlaneDeletionGenerator.md).

## Methods

`CutMeshByPlaneGenerator` first converts all elements of the input mesh into `TET4` elements. Next, the `TET4` elements sliced by the cutting plane are further split into `TET4` elements.

### Splitting of Non-TET4 Elements

The splitting of non-TET4 elements was performed using the same algorithm as described in [`ElementsToTetrahedronsConverter`](/ElementsToTetrahedronsConverter.md). Note that only those elements that will be fully or partially retained after the cutting are split.

### Cutting of TET4 Elements along Plane

Once all the elements of the input mesh have been converted into TET elements, the cutting method only needs to be applied to TET elements. First, all the elements that are cut by the given cutting plane are identified. For the TET elements involved, their relationship with the cutting plane can be categorized into one of the six cases shown in [tet_cut]. For each of these six cases, new nodes are created at the intersection points between the cutting plane and the edges of the TET element. Then the red part of the original TET element is removed and new TET element(s) are created as shown in [tet_cut]. The cross-sections created by this cutting procedure are assigned a new boundary ID as defined by [!param](/Mesh/CutMeshByPlaneGenerator/cut_face_id)

!media framework/meshgenerators/tet_cut.png
style=display: block;margin-left:auto;margin-right:auto;width:75%;
id=tet_cut
caption=The six possible cases when slicing a TET element. The cutting plane intersection with the element is shown as blue faces. The red part of the original TET element is removed after cutting, while the blue part of the original TET element is kept and split into multiple TET elements if necessary.

## Example Syntax

!listing test/tests/meshgenerators/cut_mesh_by_plane_generator/simple_cut.i block=Mesh/cut

!syntax parameters /Mesh/CutMeshByPlaneGenerator

!syntax inputs /Mesh/CutMeshByPlaneGenerator

!syntax children /Mesh/CutMeshByPlaneGenerator

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ElementsToTetrahedronsConverter

!syntax description /Mesh/ElementsToTetrahedronsConverter

## Overview

The `ElementsToTetrahedronsConverter` converts a 3D mesh that consists of first-order elements (e.g., TET4, PYRAMID5, PRISM6, and HEX8) into a mesh that only contains TET4 elements.

## Methods

All original mesh elements which are not TET4 type are converted into TET4 elements through splitting by this mesh generator. To be specific, each HEX8 element is split into six TET4 elements; each PRISM6 element is split into three TET4 elements; and each PYRAMID5 element is split into two TET4 elements. Details on the splitting approach follow.

!media framework/meshgenerators/hex_split.png
style=display: block;margin-left:auto;margin-right:auto;width:32%;float:left;
id=hex_split
caption=An example of splitting of a HEX8 element into six TET4 elements.

!media framework/meshgenerators/prism_split.png
style=display: block;margin-left:auto;margin-right:auto;width:32%;float:left;
id=prism_split
caption=An example of splitting of a PRISM6 element into three TET4 elements.

!media framework/meshgenerators/pyramid_split.png
style=display: block;margin-left:auto;margin-right:auto;width:36%;float:left;
id=pyramid_split
caption=An example of splitting of a PYRAMID5 element into two TET4 elements.

After this conversion, all the elements become TET4 elements. In that case, all the subdomain IDs and names can be preserved.

### Splitting of HEX8 Elements

There are multiple ways to split one HEX8 element into multiple TET4 elements, resulting in either five or six TET4 elements (or even more if additional nodes can be added). A splitting method that does not require adding nodes needs to split each of the six quadrilateral faces of a HEX8 element into two triangles, which can be done in two different ways for each face. As these quadrilateral faces could be shared with neighboring HEX8 or other types of elements, the splitting of the quadrilateral faces on neighboring elements must be performed consistently. To achieve a consistent splitting approach, which will be discussed later in this documentation page, a HEX8 element needs to be split into six TET4 elements. An example of this splitting is illustrated in [hex_split]. Note that the splitting approach shown in [hex_split] is not unique and will be discussed later.

### Splitting of PRISM6 Elements

A PRISM6 element can be split into three TET4 elements. An example of this splitting is illustrated in [prism_split]. Note that the splitting approach shown in [prism_split] is not unique and will be discussed later. Namely, the three quadrilateral faces of a PRISM6 element need to be split consistently with the neighboring elements.

### Splitting of PYRAMID5 Elements

A PYRAMID5 element can be split into two TET4 elements. An example of this splitting is illustrated in [pyramid_split]. Note that the splitting approach shown in [pyramid_split] is not unique and will be discussed later. Namely, the one quadrilateral face of a PYRAMID5 element needs to be split consistently with the neighboring elements.

### Consistent Splitting for Neighboring Elements

As discussed above, although splitting of non-TET elements into TET4 elements is not unique, it is crucial to ensure that the splitting of the neighboring elements involves consistent splitting of the quadrilateral faces. To achieve this, the following approach is used. For each quadrilateral face, there are two ways to split it into two triangles, which correspond to the two diagonal lines of the quadrilateral face. Therefore, in order to ensure that one of the two diagonal lines is selected consistently for all the elements, the diagonal line that involves the node with the lowest global node ID among the four nodes of the quadrilateral face is selected.

## Example Syntax

!listing test/tests/meshgenerators/elements_to_tetrahedrons_convertor/simple_convert.i block=Mesh/convert

!syntax parameters /Mesh/ElementsToTetrahedronsConverter

!syntax inputs /Mesh/ElementsToTetrahedronsConverter

!syntax children /Mesh/ElementsToTetrahedronsConverter

106 changes: 106 additions & 0 deletions framework/include/meshgenerators/CutMeshByPlaneGenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once
#include "MeshGenerator.h"

/**
* This CutMeshByPlaneGenerator object is designed to trim the input mesh by removing all the
* elements on one side of a given plane with special processing on the elements crossed by the
* cutting line to ensure a smooth cross-section. The output mesh only consists of TET4 elements.
*/
class CutMeshByPlaneGenerator : public MeshGenerator
{
public:
static InputParameters validParams();

CutMeshByPlaneGenerator(const InputParameters & parameters);

std::unique_ptr<MeshBase> generate() override;

/// An enum class for style of input polygon size
enum class PointPlaneRelationIndex : short int
{
plane_normal_side = 1,
opposite_plane_normal_side = -1,
on_plane = 0
};

protected:
/// Name of the input mesh
const MeshGeneratorName _input_name;
/// A point on the cutting plane
const Point _plane_point;
/// A normal vector of the cutting plane
const Point _plane_normal;
/// The boundary id of the face generated by the cut.
boundary_id_type _cut_face_id;
/// The boundary name of the face generated by the cut.
const BoundaryName _cut_face_name;
/// Reference to input mesh pointer
std::unique_ptr<MeshBase> & _input;

/**
* Determine the relation between a point and a plane.
* @param point The point of interest to be determined
* @param plane_point A point on the plane of interest
* @param plane_normal The normal vector of the plane of interest
* @return an enum indicating the relation between the point and the plane
*/
PointPlaneRelationIndex pointPlaneRelation(const Point & point,
const Point & plane_point,
const Point & plane_normal) const;

/**
* Calculate the intersection point of a plane and a line segment defined by two points separated
* by the plane.
* @param point1 The first point of the line segment
* @param point2 The second point of the line segment
* @param plane_point A point on the plane of interest
* @param plane_normal The normal vector of the plane of interest
* @return the intersection point of the plane and the line segment
*/
Point pointPairPlaneInterception(const Point & point1,
const Point & point2,
const Point & plane_point,
const Point & plane_normal) const;

/**
* For a TET4 elements crossed by the cutting plane, keep the part of the element on the retaining
* side of the plane using a number of TET4 elements.
* @param mesh The mesh to be modified
* @param bdry_side_list A list that contains the boundary information of the original mesh
* @param elem_id The id of the element to be cut
* @param plane_point A point on the cutting plane
* @param plane_normal The normal vector of the cutting plane
* @param block_id_to_remove The subdomain id of the part of the element to be removed
* @param new_on_plane_nodes A vector to record the pointers to the newly created nodes on the
* cutting plane
*/
void tet4ElemCutter(ReplicatedMesh & mesh,
const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
const dof_id_type elem_id,
const Point & plane_point,
const Point & plane_normal,
const subdomain_id_type & block_id_to_remove,
std::vector<const Node *> & new_on_plane_nodes);

/**
* Check if a position on a plane has already been used as a node in the mesh. If so, return the
* pointer to the existing node. If not, create a new node and return the pointer to the new node.
* @param mesh The mesh to be modified
* @param new_on_plane_nodes A vector to record the pointers to the newly created nodes on the
* cutting plane
* @param new_point The position of the potential new node
* @return a pointer to the existing node or the newly created node
*/
const Node * nonDuplicateNodeCreator(ReplicatedMesh & mesh,
std::vector<const Node *> & new_on_plane_nodes,
const Point & new_point);
};
39 changes: 39 additions & 0 deletions framework/include/meshgenerators/ElementsToTetrahedronsConverter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once
#include "MeshGenerator.h"

/**
* This ElementsToTetrahedronsConverter object is designed to convert all the elements in a 3D mesh
* consisting of only linear elements into TET4 elements.
*/
class ElementsToTetrahedronsConverter : public MeshGenerator
{
public:
static InputParameters validParams();

ElementsToTetrahedronsConverter(const InputParameters & parameters);

std::unique_ptr<MeshBase> generate() override;

/// An enum class for style of input polygon size
enum class PointPlaneRelationIndex : short int
{
plane_normal_side = 1,
opposite_plane_normal_side = -1,
on_plane = 0
};

protected:
/// Name of the input mesh
const MeshGeneratorName _input_name;
/// Reference to input mesh pointer
std::unique_ptr<MeshBase> & _input;
};
Loading

0 comments on commit 822dc5a

Please sign in to comment.