Advanced Meshing Examples

After learning about some of the advanced meshing tools, it is useful to see examples of "what's possible". This chapter contains images and small snippet examples of "what's possible".

Possible Advanced Reactor Geometries

This tutorial covers the generation of mostly standard geometries, but many reactor designs involve features which were not covered previously. Using the tools covered in this section, MOOSE can generate quite complex geometries illustrated here. The key mesh generators required are listed briefly.

Molten Salt Reactor Experiment (MSRE) 2D lattice

Figure 1: Molten Salt Reactor Experiment (MSRE) 2D lattice.

KRUSTY heat-pipe cooled microreactor 2D core

Figure 2: KRUSTY heat pipe-cooled microreactor 2D core.

Modular High Temperature Gas Cooled Reactor (MHTGR)

Figure 3: MHTGR 2D mesh.

Figure 4: MHTGR 2D mesh, zoomed in.

2D Pebble Bed Reactor with Streamlines

Figure 5: 2D generic pebble bed reactor meshes for Pronghorn (left) and Griffin (right) with flow streamlines from top inlet to bottom conical outlet.

Boundary Layers and Biasing

During the mesh refinement process, it is common to require finer discretizations in one region and coarser discretizations in another region. The boundary layer and biasing features available in the Reactor Module allow the user to refine the mesh in areas of interest for the physics problem at hand.

Mesh Biasing

Mesh biasing applies non-uniform meshing subintervals within a specific region. For example, a fuel pin may generally require an axial meshing size of 5 cm, but at the very top and bottom of the active fuel zone where the power shape has a larger gradient, the user may require finer grids. This is possible using mesh biasing parameters available in AdvancedExtruderGenerator.

Figure 6: A 3D mesh generated by extruding a 2D square mesh using AdvancedExtruderGenerator with axial biasing in the top (green) and bottom (white) axial blocks.

Listing 1: Axial mesh biasing example.

[Mesh]
  [gmg]
    type = GeneratedMeshGenerator
    dim = 2
    nx = 6
    ny = 6
    nz = 0
    zmin = 0
    zmax = 0
    elem_type = QUAD4
  []

  [extrude]
    type = AdvancedExtruderGenerator
    input = gmg
    heights = '2 1 2'
    num_layers = '5 3 5'
    biases = '1.6 1.0 0.625'
    direction = '0 0 1'
    bottom_boundary = 4
    top_boundary = 5
    subdomain_swaps = '0 1;
                         0 2;
                         0 3'
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/ax_bias.i)

Similarly, the user may want to radially bias the mesh where solution gradients are known to be high, for example at the edge of a fuel pin or control rod. This is possible using mesh biasing parameters in PolygonConcentricCircleMeshGenerator as well as PeripheralRingMeshGenerator.

Figure 7: A hexagonal pin mesh generated by PolygonConcentricCircleMeshGenerator with radial biasing in both the outmost ring block (red) and background block (blue).

Listing 2: Radial mesh biasing example.

[Mesh]
  [hex_1]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '4 4 4 4 4 4'
    background_intervals = 4
    ring_radii = '2.0 4.0'
    ring_intervals = '5 5'
    ring_block_ids = '10 11 15'
    ring_block_names = 'center_tri center mid'
    background_block_ids = 20
    background_block_names = background
    polygon_size = 5.0
    preserve_volumes = on
    ring_radial_biases = '1.0 1.6'
    background_radial_bias = 0.625
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/rad_bias_pccmg.i)

Figure 8: A peripheral ring mesh with radial biasing added to a hexagonal pin mesh.

Listing 3: Peripheral ring radial mesh biasing example.

[Mesh]
  [hex_1]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '4 4 4 4 4 4'
    background_intervals = 2
    ring_radii = '4.0'
    ring_intervals = '2'
    ring_block_ids = '10 15'
    ring_block_names = 'center_tri center'
    background_block_ids = 20
    background_block_names = background
    polygon_size = 5.0
    preserve_volumes = on
    background_radial_bias = 0.625
  []
  [peripheral_ring]
    type = PeripheralRingMeshGenerator
    input = hex_1
    peripheral_ring_block_id = 200
    peripheral_layer_num = 5
    input_mesh_external_boundary = 10000
    peripheral_ring_radius = 8
    peripheral_radial_bias = 0.625
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/rad_bias_prmg.i)

Mesh Boundary Layers

Boundary layers are commonly needed in thermal-hydraulic applications, where the thickness of the mesh near a wall must be a certain size, uniformly, regardless of the width of the meshed region. Boundary layers are possible using PolygonConcentricCircleMeshGenerator and PeripheralRingMeshGenerator.

Figure 9: A hexagonal pin mesh generated by PolygonConcentricCircleMeshGenerator with boundary layers created in both the outmost ring block (outer boundary layer, red) and background block (inner boundary layer, blue).

Listing 4: PolygonConcentricCircleMeshGenerator boundary layer example.

[Mesh]
  [hex_1]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '4 4 4 4 4 4'
    background_intervals = 2
    ring_radii = '2.0 4.0'
    ring_intervals = '2 2'
    ring_block_ids = '10 11 15'
    ring_block_names = 'center_tri center mid'
    background_block_ids = 20
    background_block_names = background
    polygon_size = 5.0
    preserve_volumes = on
    ## Background boundary layer setting
    background_inner_boundary_layer_bias = 1.6
    background_inner_boundary_layer_intervals = 3
    background_inner_boundary_layer_width = 0.4
    ## Ring boundary layer setting
    ring_outer_boundary_layer_biases = '1.0 0.625'
    ring_outer_boundary_layer_intervals = '0 3'
    ring_outer_boundary_layer_widths = '0.0 0.5'
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/bdry_layer_pccmg.i)

Stitching Assemblies with Different Pin Numbers

Typical reactor cores are comprised of many different assembly types, each with different numbers of pins. When the pins are explicitly meshed, the number of nodes on the assembly boundary is determined by a combination of the number pins as well as the pin azimuthal discretization. It is difficult to find a reasonably low azimuthal discretization for each assembly such that all assemblies have the same number of nodes on their boundaries.

The best approach for this situation is to use PatternedHexPeripheralModifier to strip the outermost layer off each assembly and replace it with a transition layer with a set number of nodes on the outermost boundary. Doing this to each assembly will ensure that all assemblies have the same number of boundary nodes and can be easily stitched. An example follows.

Figure 10: PatternedHexPeripheralModifier is used to adjust the boundary node count on each assembly to be consistent with each other and therefore stitchable.

Listing 5: Assemblies with different pin numbers example.

[Mesh]
  [hex_1]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '2 2 2 2 2 2'
    background_intervals = 1
    ring_radii = 4.0
    ring_intervals = 1
    ring_block_ids = '10'
    ring_block_names = 'center_1'
    background_block_ids = 20
    background_block_names = background_1
    polygon_size = 5.0
    preserve_volumes = on
    quad_center_elements = true
  []
  [pattern_1]
    type = PatternedHexMeshGenerator
    inputs = 'hex_1'
    pattern = '0 0;
              0 0 0;
               0 0'
    background_intervals = 1
    hexagon_size = 17
    #duct_sizes = '15 15.5'
    #duct_intervals = '1 2'
  []
  [pmg_1]
    type = PatternedHexPeripheralModifier
    input = pattern_1
    input_mesh_external_boundary = 10000
    new_num_sector = ${new_num_sector}
    num_layers = ${num_layer}
  []
  [hex_2]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '2 2 2 2 2 2'
    background_intervals = 1
    ring_radii = 2.5
    ring_intervals = 1
    ring_block_ids = '30'
    ring_block_names = 'center_2'
    background_block_ids = 40
    background_block_names = background_2
    polygon_size = 3.0
    preserve_volumes = on
    quad_center_elements = true
  []
  [pattern_2]
    type = PatternedHexMeshGenerator
    inputs = 'hex_2'
    pattern = '0 0 0;
              0 0 0 0;
             0 0 0 0 0;
              0 0 0 0;
               0 0 0'
    background_intervals = 1
    hexagon_size = 17
    #duct_sizes = '15 15.5'
    #duct_intervals = '1 2'
  []
  [pmg_2]
    type = PatternedHexPeripheralModifier
    input = pattern_2
    input_mesh_external_boundary = 10000
    new_num_sector = ${new_num_sector}
    num_layers = ${num_layer}
  []
  [hex_3]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '2 2 2 2 2 2'
    background_intervals = 1
    ring_radii = 1.5
    ring_intervals = 1
    ring_block_ids = '50'
    ring_block_names = 'center_3'
    background_block_ids = 60
    background_block_names = background_3
    polygon_size = 2.3
    preserve_volumes = on
    quad_center_elements = true
  []
  [pattern_3]
    type = PatternedHexMeshGenerator
    inputs = 'hex_3'
    pattern = '0 0 0 0;
              0 0 0 0 0;
             0 0 0 0 0 0;
            0 0 0 0 0 0 0;
             0 0 0 0 0 0;
              0 0 0 0 0;
               0 0 0 0'
    background_intervals = 1
    hexagon_size = 17
    #duct_sizes = '15 15.5'
    #duct_intervals = '1 2'
  []
  [pmg_3]
    type = PatternedHexPeripheralModifier
    input = pattern_3
    input_mesh_external_boundary = 10000
    new_num_sector = ${new_num_sector}
    num_layers = ${num_layer}
  []
  [hex_4]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '2 2 2 2 2 2'
    background_intervals = 1
    ring_radii = 1.4
    ring_intervals = 1
    ring_block_ids = '70'
    ring_block_names = 'center_4'
    background_block_ids = 80
    background_block_names = background_4
    polygon_size = 1.8
    preserve_volumes = on
    quad_center_elements = true
  []
  [pattern_4]
    type = PatternedHexMeshGenerator
    inputs = 'hex_4'
    pattern = '0 0 0 0 0;
              0 0 0 0 0 0;
             0 0 0 0 0 0 0;
            0 0 0 0 0 0 0 0;
           0 0 0 0 0 0 0 0 0;
            0 0 0 0 0 0 0 0;
             0 0 0 0 0 0 0;
              0 0 0 0 0 0;
               0 0 0 0 0'
    background_intervals = 1
    hexagon_size = 17
    #duct_sizes = '15 15.5'
    #duct_intervals = '1 2'
  []
  [pmg_4]
    type = PatternedHexPeripheralModifier
    input = pattern_4
    input_mesh_external_boundary = 10000
    new_num_sector = ${new_num_sector}
    num_layers = ${num_layer}
  []
  [pattern_sum]
    type = PatternedHexMeshGenerator
    inputs = 'pmg_1 pmg_2 pmg_3 pmg_4'
    pattern = '2 3;
              1 0 1;
               3 2'
    pattern_boundary = none
    generate_core_metadata = true
  []
[]
(modules/reactor/test/tests/meshgenerators/patterned_hex_peripheral_modifier/patterned.i)

Oversized Pin

Some assemblies contain an oversized pin which intrudes on neighboring unit pin cells. Here, we describe one possible approach to mesh this situation.

First, define the regular small fuel pins and place them into the assembly as a full lattice. Next, delete the dummy unit pin cells, making sure to assign the newly created hole boundary a specific boundary name.

Separately, the oversized pin should be defined as its own object, remembering to remove the background region which is created by default in PolygonConcentricCircleMeshGenerator. This mesh will serve as the "hole" for XYDelaunayGenerator.

Finally, XYDelaunayGenerator is used to mesh the regions between the assembly (with deleted dummies) and the oversized pin. This is done by giving XYDelaunayGenerator the assembly mesh and the oversized pin mesh and specifying via input parameters that the region between the assembly mesh and the oversized pin mesh should be triangulated. The oversized pin mesh is placed into the geometry at this time as well.

Figure 11: An assembly mesh with an oversized pin in the center. The mesh is generated by modifying the output of PatternedHexMeshGenerator by replacing the central region with a mesh generated by XYDelaunayGenerator.

Listing 6: Oversized pin example.

[Mesh]
  [pin_regular]
    type = AdvancedConcentricCircleGenerator
    num_sectors = 12
    ring_radii = '1 2'
    ring_intervals = '2 2'
    ring_block_ids = '10 15 20'
    ring_block_names = 'inner_tri inner outer'
    external_boundary_id = 100
    external_boundary_name = 'ext'
    create_outward_interface_boundaries = false
  []
  [pin_oversize]
    type = AdvancedConcentricCircleGenerator
    num_sectors = 12
    ring_radii = '2 3'
    ring_intervals = '2 2'
    ring_block_ids = '30 35 40'
    ring_block_names = 'inner_os_tri inner_os outer_os'
    external_boundary_id = 100
    external_boundary_name = 'ext'
    create_outward_interface_boundaries = false
  []
  [fpg]
    type = FlexiblePatternGenerator
    inputs = 'pin_regular pin_oversize'
    boundary_type = HEXAGON
    boundary_sectors = 10
    boundary_size = '${fparse 22.0*sqrt(3.0)}'
    hex_patterns = '0 0 0 0;
                   0 1 0 1 0;
                  0 0 0 0 0 0;
                 0 0 0 1 0 0 0;
                  0 0 0 0 0 0;
                   0 1 0 1 0;
                    0 0 0 0'
    hex_pitches = '5.5'
    hex_origins = '0.0 0.0 0.0'
    use_auto_area_func = true
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/oversize.i)

Filling Between Curves using "FillBetweenSidesetsGenerator"

The MSRE 2D lattice case pictured in tutorial04-adv_ex_fbsg was constructed using the FillBetweenSidesetsGenerator to connect "quarter" circular pins, as shown in tutorial04-adv_ex_fbsg. First, ConcentricCircleMeshGenerator (a predecessor of PolygonConcentricCircleMeshGenerator which has a different set of input options and works only for square pin cells) was used to create two quarter pins. Each quarter pin mesh initially contains two duplicate "quarter pin" shaped blocks, and then one of the duplicate blocks is deleted in order to be able to label the sideset on the curved boundary as curve_1 and curve_2 in the two pins, respectively. This is the simplest possible procedure with the current Mesh system in MOOSE, but could be improved in the future. These two pins were translated in space to move them apart from each other, and then FillBetweenSidesetsGenerator was used to mesh the area between curve_1 and curve_2.

Figure 12: An example of using FillBetweenSidesetsGenerator to connect quarter circular-shapedsquare meshes.

Listing 7: FillBetweenSidesetsGenerator example.

[Mesh]
  [connect_two_circles]
    type = FillBetweenSidesetsGenerator
    input_mesh_1 = 'Corner_bottom_left_2'
    input_mesh_2 = 'Corner_top_right_3'
    boundary_1 = 'curve_1'
    boundary_2 = 'curve_2'
    num_layers = 8
    keep_inputs = true
    use_quad_elements = true
    block_id = 200
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/quarter_circle_connect.i)

Triangulation of Odd-Shaped Regions Using "ParsedCurveGenerator" and "XYDelaunayGenerator"

This example demonstrates how to place a control drum object in an arbitrary position in a core that may overlap subdomain boundaries.

First, the center assembly is created using regular pins and procedures.

Figure 13: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, patterned pins.

Listing 8: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, patterned pins.

[Mesh]
  [hex_1]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '2 2 2 2 2 2'
    background_intervals = 2
    ring_radii = 4.0
    ring_intervals = 2
    ring_block_ids = '10 15'
    ring_block_names = 'pin_tri pin_quad'
    background_block_ids = 20
    background_block_names = pin_background
    polygon_size = 5.0
    preserve_volumes = on
  []

  [pattern]
    type = PatternedHexMeshGenerator
    inputs = 'hex_1'
    hexagon_size = 25
    background_block_id = 30
    background_block_name = assembly_background
    pattern = '0 0 0;
                0 0 0 0;
               0 0 0 0 0;
                0 0 0 0;
                 0 0 0'
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/pcg_xyd.i)

Next, two circular peripheral regions are added using PeripheralTriangleMeshGenerator (yellow, purple zones).

Figure 14: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, patterned pins with rings.

Listing 9: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, patterned pins with rings.

[Mesh]
  [tmg1]
    type = PeripheralTriangleMeshGenerator
    input = pattern
    peripheral_ring_radius = 35
    peripheral_ring_num_segments = 50
    peripheral_ring_block_name = peripheral_1
    desired_area = 8
  []

  [tmg2]
    type = PeripheralTriangleMeshGenerator
    input = tmg1
    peripheral_ring_radius = 38
    peripheral_ring_num_segments = 80
    peripheral_ring_block_name = peripheral_2
    desired_area = 6
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/pcg_xyd.i)

Next, the complex boundary shape which is the outer edge of the light blue zone is defined using ParsedCurveGenerator and analytic piecewise functions. The interior of this boundary is then filled in, including the center assembly, using XYDelaunayGenerator.

Figure 15: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, patterned pins with irregular peripheral region.

Listing 10: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, patterned pins with irregular peripheral region.

[Mesh]
  [pcg1]
    type = ParsedCurveGenerator
    x_formula = 't1:=t;
                     t2:=t-1;
                     t3:=t-2;
                     t4:=t-3;
                     x1:=r*cos(t1*(th1-th0)+th0);
                     x2_0:=r*cos(th1);
                     x2_1:=x2_0-Lx;
                     x2:=x2_0+(x2_1-x2_0)*t2;
                     rs:=abs(r*sin(th1));
                     rth0:=1.5*pi;
                     rth1:=0.5*pi;
                     x3:=x2_1+rs*cos(rth0+(rth1-rth0)*t3);
                     x4_1:=r*cos(th1);
                     x4_0:=x4_1-Lx;
                     x4:=x4_0+(x4_1-x4_0)*t4;
                     if(t<1,x1,if(t<2,x2,if(t<3,x3,x4)))'
    y_formula = 't1:=t;
                     t2:=t-1;
                     t3:=t-2;
                     t4:=t-3;
                     y1:=r*sin(t1*(th1-th0)+th0);
                     y2:=r*sin(th1);
                     rs:=abs(r*sin(th1));
                     rth0:=1.5*pi;
                     rth1:=0.5*pi;
                     y3:=rs*sin(rth0+(rth1-rth0)*t3);
                     y4:=r*sin(th0);
                     if(t<1,y1,if(t<2,y2,if(t<3,y3,y4)))'
    section_bounding_t_values = '0 1 2 3 4'
    constant_names = 'pi           r    th0               th1                    Lx'
    constant_expressions = '${fparse pi} 100.0 ${fparse pi/9.0} ${fparse pi/9.0*17.0} 10.0'
    nums_segments = '50 3 15 3'
    is_closed_loop = true
  []

  [xydg1]
    type = XYDelaunayGenerator
    boundary = 'pcg1'
    holes = 'tmg2'
    add_nodes_per_boundary_segment = 0
    refine_boundary = false
    desired_area = 30
    output_subdomain_name = xy_layer_1
    stitch_holes = 'true'
    refine_holes = 'false'
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/pcg_xyd.i)

The control drum object is defined including the absorber arc using PolygonConcentricCircleMeshGenerator and AzimuthalBlockSplitGenerator, then the background region of the control drum is deleted to leave only the circular part. This mesh is then translated into the desired position of the final mesh using TransformGenerator. The small red pin is defined similarly (not requiring AzimuthalBlockSplitGenerator).

Figure 16: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, three holes for XYDelaunayGenerator.

Listing 11: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, three holes for XYDelaunayGenerator.

[Mesh]
  [cd]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '6 6 6 6 6 6'
    background_intervals = 2
    ring_radii = '27 30 32'
    ring_intervals = '2 2 2'
    ring_block_ids = '110 115 120 125'
    ring_block_names = 'cd_1_tri cd_1_quad cd_2 cd_3'
    background_block_ids = 130
    background_block_names = cd_background
    polygon_size = 40
    preserve_volumes = on
  []

  [cd_azi_define]
    type = AzimuthalBlockSplitGenerator
    input = cd
    start_angle = 300
    angle_range = 120
    old_blocks = '120'
    new_block_ids = '121'
    new_block_names = 'absorber'
    preserve_volumes = true
  []

  [cd_bd]
    type = BlockDeletionGenerator
    input = cd_azi_define
    block = cd_background
  []

  [cd_translate]
    type = TransformGenerator
    input = cd_bd
    transform = translate
    vector_value = '${fparse 100.0*cos(pi/9.0)-10.0} 0 0'
  []

  [outer_pin]
    type = PolygonConcentricCircleMeshGenerator
    num_sides = 6
    num_sectors_per_side = '2 2 2 2 2 2'
    background_intervals = 2
    ring_radii = '10 12'
    ring_intervals = '2 2'
    ring_block_ids = '210 215 220'
    ring_block_names = 'op_1_tri op_1_quad op_2'
    background_block_ids = 230
    background_block_names = op_background
    polygon_size = 15
    preserve_volumes = on
  []

  [op_bd]
    type = BlockDeletionGenerator
    input = outer_pin
    block = op_background
  []

  [op_translate]
    type = TransformGenerator
    input = op_bd
    transform = translate
    vector_value = '${fparse 120/sqrt(2)} ${fparse 120/sqrt(2)} 0'
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/pcg_xyd.i)

The outer boundary of the dark blue zone is then generated using ParsedCurveGenerator and analytical functions. XYDelaunayGenerator is again used to fill the dark blue regions, keeping the light blue region and assembly, control drum, and small pin.

Figure 17: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, second XYDelaunayGenerator.

Listing 12: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, second XYDelaunayGenerator.

[Mesh]
  [pcg2]
    type = ParsedCurveGenerator
    x_formula = 'r*cos(t)'
    y_formula = 'r*sin(t)'
    section_bounding_t_values = '0 ${fparse 2*pi}'
    constant_names = 'pi           r'
    constant_expressions = '${fparse pi} 140.0'
    nums_segments = '100'
    is_closed_loop = true
  []

  [xydg2]
    type = XYDelaunayGenerator
    boundary = 'pcg2'
    holes = 'xydg1 cd_translate op_translate'
    add_nodes_per_boundary_segment = 0
    refine_boundary = false
    desired_area = 30
    output_subdomain_name = xy_layer_2
    stitch_holes = 'true true true'
    refine_holes = 'false false false'
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/pcg_xyd.i)

Finally, a circular peripheral region is added at the end using PeripheralTriangleMeshGenerator (yellow).

Figure 18: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, complete.

Listing 13: An example of using XYDelaunayGenerator with curve meshes generated by ParsedCurveGenerator, complete.

[Mesh]
  [tmg3]
    type = PeripheralTriangleMeshGenerator
    input = xydg2
    peripheral_ring_radius = 150
    peripheral_ring_num_segments = 100
    peripheral_ring_block_name = peripheral_3
    desired_area = 20
  []
[]
(tutorials/tutorial04_meshing/app/test/tests/adv_examples/pcg_xyd.i)