ElementsToSimplicesConverter
Splits all non-simplex elements in a mesh into simplices.
An input mesh, as specified in the "input" parameter, will be modified to replace each non-simplex mesh element with a set of simplices connecting the same nodes. Each quad is split into 2 triangles, each pyramid into 2 tetrahedra, each prism into 3 tets, and each cube into 6 tets.
The input mesh must be "flat", not hierarchically refined.
The algorithm in 2D splits quads along their shortest interior diagonal, to try to improve element quality.
Currently the algorithm in 3D uses node ids to decide on splitting directions in a consistent way across face neighbors; this may change in the future.
In 3D, the geometry of any non-planar quadrilateral faces of cubes and/or prisms will not be exactly preserved, due to the change from bilinear or biquadratic mapping on quadrilaterals to linear or quadratic mapping on the triangles that replace them.
input
C++ Type:MeshGeneratorName
Controllable:No
Description:Input mesh to convert to all-simplex mesh
(test/tests/meshgenerators/elements_to_simplices_converter/simple_convert.i)
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 3
nx = 1
ny = 2
nz = 2
[]
[block_1]
type = ParsedSubdomainMeshGenerator
input = gmg
combinatorial_geometry = 'z>0.5'
block_id = 1
[]
[convert]
type = ElementsToSimplicesConverter
input = block_1
[]
# Simplices conversion currently depends on element id numbering
allow_renumbering = false
[]
(test/tests/meshgenerators/manifold_subdomain/cone.i)
expected = '2975'
!include check.i
[Mesh]
[disk]
type = ConcentricCircleMeshGenerator
num_sectors = 6
radii = '0.9'
rings = '10'
has_outer_square = false
preserve_volumes = false
[]
[cone]
type = ParsedNodeTransformGenerator
input = disk
z_function = '0.9 - sqrt(x * x + y * y)'
[]
[surface_quads]
type = StitchMeshGenerator
inputs = 'cone disk'
stitch_boundaries_pairs = 'outer outer'
clear_stitched_boundary_ids = true
[]
[background]
type = GeneratedMeshGenerator
dim = 3
nx = 25
ny = 25
nz = 25
xmin = -1
xmax = 1
ymin = -1
ymax = 1
zmax = 1
[]
[surface]
type = ElementsToSimplicesConverter
input = surface_quads
[]
[tag]
type = ManifoldSubdomainGenerator
input = background
manifold = surface
block_id = 1
[]
[remove]
type = BlockDeletionGenerator
input = tag
block = '0'
[]
[]
(test/tests/meshgenerators/tri_to_quad_converter/all_quad_ids.i)
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 4
ny = 2
xmax = 2
ymax = 1
[]
[tri]
type = ElementsToSimplicesConverter
input = gmg
[]
[blk_right]
type = SubdomainBoundingBoxGenerator
input = tri
block_id = 2
block_name = right_block
bottom_left = '0 0 0'
top_right = '2 1 0'
[]
[blk_left]
type = SubdomainBoundingBoxGenerator
input = blk_right
block_id = 1
block_name = left_block
bottom_left = '0 0 0'
top_right = '1.25 1 0'
[]
[iface]
type = SideSetsBetweenSubdomainsGenerator
input = blk_left
primary_block = left_block
paired_block = right_block
new_boundary = block_interface
[]
[diag_ss]
type = ParsedGenerateSideset
input = iface
combinatorial_geometry = 'x > 1.7 & x < 1.8 & y > 0.2 & y < 0.3'
included_subdomains = right_block
normal = '1 0 0'
normal_tol = 0.4
new_sideset_name = interior_diagonal
[]
[origin_ns]
type = ExtraNodesetGenerator
input = diag_ss
new_boundary = origin_node
coord = '0 0 0'
[]
[eeid]
type = ParsedExtraElementIDGenerator
input = origin_ns
expression = '1 + floor(4 * x) + 10 * floor(4 * y)'
extra_elem_integer_name = tri_id
[]
[to_quad]
type = TriToQuadConverter
input = eeid
algorithm = RECOMBINE
all_quad = true
[]
# Both the triangulation and the recombination depend on element id numbering
allow_renumbering = false
[]
(test/tests/meshgenerators/tri_to_quad_converter/subdivision_all_quad.i)
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 4
ny = 4
[]
[tri]
type = ElementsToSimplicesConverter
input = gmg
[]
[to_quad]
type = TriToQuadConverter
input = tri
algorithm = SUBDIVISION
[]
# The subdivision of each triangle depends on element id numbering
allow_renumbering = false
[]
(modules/xfem/test/tests/solid_mechanics_basic/double_cantilever_crack.i)
# 3D Double Cantiler beam example.
# Figure 9 in: Belytschko and Black (1999)
# https://doi.org/10.1002/(SICI)1097-0207(19990620)45:5<601::AID-NME598>3.0.CO;2-S
# to reproduce literature results the mesh must be refined, in addition to using smaller fracture domain integral radii and smaller crack growth increments
# search comments for "to reproduce literature use"
L = 11.8
H = 3.94
W = 4
poissons = 0.3
youngs = 3e7
a = 3.94
da = 0.3
dtheta = 5.71 # 1.43, 2.86, 5.71
[GlobalParams]
displacements = 'disp_x disp_y disp_z'
volumetric_locking_correction = true
[]
[XFEM]
geometric_cut_userobjects = 'cut_mesh'
qrule = volfrac
output_cut_plane = true
[]
[Mesh]
[cut_profile]
type = PolyLineMeshGenerator
loop = false
points = '-0.01 0 -2.01
${a} 0 -2.01
${fparse a+da*cos(dtheta*pi/180)} ${fparse da*sin(dtheta*pi/180)} -2.01'
[]
[cut_surfaace]
type = AdvancedExtruderGenerator
input = cut_profile
direction = '0 0 1'
heights = '4.02'
num_layers = '3'
biases = '1'
[]
[tri]
type = ElementsToSimplicesConverter
input = cut_surfaace
save_with_name = cut_mesh
[]
[gen]
type = GeneratedMeshGenerator
dim = 3
nx = 30 # to reproduce literature use 240
ny = 11 # to reproduce literature use 81
nz = 4 # to reproduce literature use 10
xmin = 0
xmax = ${L}
ymin = '-${fparse H/2}'
ymax = '${fparse H/2}'
zmin = '-${fparse W/2}'
zmax = '${fparse W/2}'
elem_type = HEX8
[]
[bottom_left_elem]
type = ParsedGenerateSideset
input = gen
combinatorial_geometry = 'x < 0.21'
normal = '0 -1 0'
include_only_external_sides=true
new_sideset_name = bottom_left_elem
[]
[top_left_elem]
type = ParsedGenerateSideset
input = bottom_left_elem
combinatorial_geometry = 'x < 0.21'
normal = '0 1 0'
include_only_external_sides=true
new_sideset_name = top_left_elem
[]
final_generator = 'top_left_elem'
[]
[Functions]
[growth_func_v]
type = ParsedFunction
expression = 0.21 # to reproduce literature use 0.0125
[]
[]
[UserObjects]
[cut_mesh]
type = CrackMeshCut3DUserObject
mesh_generator_name = 'cut_mesh'
growth_dir_method = MAX_HOOP_STRESS
size_control = 1
n_step_growth = 1
growth_rate = growth_func_v
[]
[]
[DomainIntegral]
integrals = 'Jintegral InteractionIntegralKI InteractionIntegralKII'
displacements = 'disp_x disp_y disp_z'
crack_front_points_provider = cut_mesh
crack_direction_method = CurvedCrackFront
radius_inner = 0.42 # to reproduce literature use 0.1
radius_outer = 1.0 # to reproduce literature use 0.3
poissons_ratio = ${poissons}
youngs_modulus = ${youngs}
incremental = false
[]
[Physics/SolidMechanics/QuasiStatic]
[all]
strain = SMALL
incremental = false
generate_output = 'stress_xx stress_yy stress_zz vonmises_stress max_principal_stress'
add_variables = true
[]
[]
[BCs]
[right_x]
type = DirichletBC
boundary = 'right'
variable = disp_x
value = 0
[]
[right_y]
type = DirichletBC
boundary = 'right'
variable = disp_y
value = 0
[]
[right_z]
type = DirichletBC
boundary = 'right'
variable = disp_z
value = 0
[]
[planar_z]
type = DirichletBC
boundary = 'front back'
variable = disp_z
value = 0
[]
[bottom_left_elem_y]
type = NeumannBC
boundary = 'bottom_left_elem'
variable = disp_y
value = -1000
[]
[top_left_elem_y]
type = NeumannBC
boundary = 'top_left_elem'
variable = disp_y
value = 1000
[]
[]
[Materials]
[elasticity_tensor]
type = ComputeIsotropicElasticityTensor
youngs_modulus = ${youngs}
poissons_ratio = ${poissons}
[]
[stress]
type = ComputeLinearElasticStress
[]
[]
[Executioner]
type = Transient
solve_type = 'NEWTON'
petsc_options_iname = '-pc_type -pc_hypre_type -ksp_gmres_restart'
petsc_options_value = 'hypre boomeramg 31'
# petsc_options_iname = '-pc_type -pc_factor_mat_solver_package -pc_factor_shift_type -pc_factor_shift_amount'
# petsc_options_value = ' lu superlu_dist NONZERO 1e-20'
line_search = 'none'
nl_abs_tol = 1e-7
dt = 1.0
end_time = 8 # to reproduce literature use 100
max_xfem_update = 1
[]
[Outputs]
csv = true
execute_on=final
[]
(test/tests/meshgenerators/mesh_repair_generator/nonconvex_polygon.i)
dx = 2
[Mesh]
[hex_one_nonconvex_dent]
type = ElementGenerator
nodal_positions = "0 -0.8 0
-1 -1 0
-1 1 0
0 2 0
1 1 0
1 -1 0"
element_connectivity = '0 1 2 3 4 5'
elem_type = "C0POLYGON"
[]
[hex_two_nonconvex_dents]
type = ElementGenerator
input = hex_one_nonconvex_dent
nodal_positions = "${fparse 2*dx + 0} -0.8 0
${fparse 2*dx + -1} -1 0
${fparse 2*dx + 0.01} 1 0
${fparse 2*dx + 0} 2 0
${fparse 2*dx + 1} 1 0
${fparse 2*dx + 1} -1 0"
element_connectivity = '0 1 2 3 4 5'
elem_type = "C0POLYGON"
[]
# looks like a 3-branch star
[hex_three_nonconvex_dents]
type = ElementGenerator
input = hex_two_nonconvex_dents
nodal_positions = "${fparse 2*dx + 0} -1 0
${fparse 2*dx + -2} -1.5 0
${fparse 2*dx - 0.01} 1 0
${fparse 2*dx + 0} 2 0
${fparse 2*dx + 0.01} 1 0
${fparse 2*dx + 2} -1.5 0"
element_connectivity = '0 1 2 3 4 5'
elem_type = "C0POLYGON"
[]
[hex_two_nodes_in_a_single_nonconvex_dent]
type = ElementGenerator
input = hex_three_nonconvex_dents
nodal_positions = "${fparse 2*dx + 0} -2 0
${fparse 2*dx + 0.01} -1 0
${fparse 2*dx + 0.01} 1 0
${fparse 2*dx + 0} 2 0
${fparse 2*dx + 1} 1 0
${fparse 2*dx + 1} -1 0"
element_connectivity = '0 1 2 3 4 5'
elem_type = "C0POLYGON"
[]
[check]
type = MeshDiagnosticsGenerator
input = hex_two_nodes_in_a_single_nonconvex_dent
check_polygons = INFO
[]
[repair]
type = MeshRepairGenerator
input = 'check'
split_nonconvex_polygons = true
[]
[check_after_repair]
type = MeshDiagnosticsGenerator
input = repair
check_polygons = ERROR
[]
[convert]
type = ElementsToSimplicesConverter
input = 'check_after_repair'
[]
[]
(test/tests/meshgenerators/tri_to_quad_converter/recombine_ids.i)
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 4
ny = 2
xmax = 2
ymax = 1
[]
[tri]
type = ElementsToSimplicesConverter
input = gmg
[]
[blk_right]
type = SubdomainBoundingBoxGenerator
input = tri
block_id = 2
block_name = right_block
bottom_left = '0 0 0'
top_right = '2 1 0'
[]
[blk_left]
type = SubdomainBoundingBoxGenerator
input = blk_right
block_id = 1
block_name = left_block
bottom_left = '0 0 0'
top_right = '1.25 1 0'
[]
[iface]
type = SideSetsBetweenSubdomainsGenerator
input = blk_left
primary_block = left_block
paired_block = right_block
new_boundary = block_interface
[]
[diag_ss]
type = ParsedGenerateSideset
input = iface
combinatorial_geometry = 'x > 1.7 & x < 1.8 & y > 0.2 & y < 0.3'
included_subdomains = right_block
normal = '1 0 0'
normal_tol = 0.4
new_sideset_name = interior_diagonal
[]
[origin_ns]
type = ExtraNodesetGenerator
input = diag_ss
new_boundary = origin_node
coord = '0 0 0'
[]
[eeid]
type = ParsedExtraElementIDGenerator
input = origin_ns
expression = '1 + floor(4 * x) + 10 * floor(4 * y)'
extra_elem_integer_name = tri_id
[]
[to_quad]
type = TriToQuadConverter
input = eeid
algorithm = RECOMBINE
tri_subdomain_name_suffix = leftover
[]
# Both the triangulation and the recombination depend on element id numbering
allow_renumbering = false
[]
(test/tests/meshgenerators/elements_to_simplices_converter/hex_prism_convert.i)
[Mesh]
[accg]
type = FileMeshGenerator
file = 'hex_prism_2d.e'
[]
[extrude]
type = AdvancedExtruderGenerator
input = accg
heights = '0.4 0.8 1.2'
num_layers = '1 2 3'
direction = '0 0 1'
bottom_boundary = '200'
top_boundary = '300'
subdomain_swaps = '10 11 15 16;
10 12 15 17;
10 13 15 18'
[]
[convert]
type = ElementsToSimplicesConverter
input = extrude
[]
# Simplices conversion currently depends on element id numbering
allow_renumbering = false
[]