NekMeshGenerator

Converts MOOSE meshes to element types needed for Nek (Quad8 or Hex20), while optionally preserving curved edges (which were faceted) in the original mesh.

Description

This mesh generator is used to convert:

  • A HEX27 mesh into a HEX20 mesh, or

  • A QUAD9 mesh into a QUAD8 mesh

These two element types (HEX20, QUAD8) are compatible with NekRS's exo2nek utility that generates a NekRS mesh (the custom .re2 format). This page is written for the HEX27 to HEX20 conversion, but the QUAD9 to QUAD8 conversion features are identical, just executed in 2-D. This mesh generator will:

  • Take a HEX27 mesh and convert it into an equivalent HEX20 mesh

  • Optionally move nodes to be conformal with a cylinder. You can also optionally move nodes at polygon corners to a cylindrical radius of curvature. This allows NekRS to exactly represent curved corners of meshes that represent regular polygons, such as for curving the corners of a mesh representing a six-sided duct. Set geometry_type = cylinder for either of these.

  • Optionally move nodes to be conformal with a sphere surface.

NekRS uses a high-order spectral element solution, which will exactly represent circular surfaces (e.g. circles, cylinders, spheres) its GLL points (as long as the HEX20 elements have their mid-side nodes one the curve, which is what this mesh generator does for you).

commentnote:"Have a HEX8 mesh instead of a HEX27 mesh?

If you have a HEX8 mesh, you can convert it to a HEX27 mesh by adding second_order = true in a separate MOOSE file that generates your mesh (which can be as simple as just reading the mesh from a file with a FileMeshGenerator, like this


[Mesh]
  [file]
    type = FileMeshGenerator
    file = mesh.e
  []

  second_order = true
[]

Just for illustration, if you named the above as mesh.i, you can then run cardinal-opt -i mesh.i --mesh-only to get a new mesh, mesh_in.e that is a HEX27 mesh. Then, you can use this mesh generator.

warningwarning

This mesh generator has very limited error checking, and will not protect you from inverted elements or other errors. Always be sure to check your mesh output for correct behavior.

Cylinder Examples

All examples in this section use geometry_type = cylinder. This example converts from a HEX27 mesh to a HEX20 mesh, while also moving the outer boundary (rmax) to a cylinder with radius of 0.25.

[Mesh]
  [tube]
    type = FileMeshGenerator
    file = tube_in.e
  []
  [to_hex20]
    type = NekMeshGenerator
    input = tube
    boundary = 'rmax'
    radius = '0.25'
    geometry_type = cylinder
  []

  parallel_type = replicated
[]
(test/tests/meshgenerators/second_order_hex_generator/convert_outer.i)

Figure 1 shows the meshes involved in this example; the original mesh (tube_in.e) is a HEX27 mesh, which gets converted to a HEX20 mesh (and we also moved one boundary to a cylinder surface). Then, the GLL quadrature points used in NekRS for a 5th order spectral element polynomial basis is shown on the right, which by having the curved HEX20 elements, moves the quadrature points to also be on the cylinder.

Figure 1: Input, output, and NekRS meshes involved in mesh conversion example

For a second example, consider the case where you have one boundary that you want to move with multiple origins. In this case, list the points in origins for each boundary, with a semicolon separating the origins to be used for each boundary.

[Mesh]
  [fluid]
    type = FileMeshGenerator
    file = fluid.exo
  []
  [to_hex20]
    type = NekMeshGenerator
    input = fluid
    boundary = '1'
    radius = '${fparse 7.646e-3 / 2.0}'
    origins = '+0.00000000 +0.00000000 +0.00000000
               +0.00000000 +0.00896570 +0.00000000
               -0.00776452 +0.00448285 +0.00000000
               -0.00776452 -0.00448285 +0.00000000
               +0.00000000 -0.00896570 +0.00000000
               +0.00776452 -0.00448285 +0.00000000
               +0.00776452 +0.00448285 +0.00000000'
    geometry_type = cylinder
  []

  parallel_type = replicated
[]
(test/tests/meshgenerators/second_order_hex_generator/multiple_origins.i)

Figure 2 shows the meshes involved in this second example; the original mesh (fluid.exo) is a HEX27 mesh, which gets converted to a HEX20 mesh where boundary 1 is moved according to the nearest origin from a set of 7 different origins. This allows you to group all the surfaces into one sideset, but move them to unique origins.

Figure 2: Input and output meshes when using multiple origins for a single sideset

When your mesh has boundary layers that are thin relative to the mesh movement needed to fit to cylinder surfaces, it is possible to obtain inverted elements. You can move the elements on the "other" side of the element face lying on the cylinder by setting the layers variable. With this parameter, if node on face 0 moves by to get onto the cylinder surface, then the same displacement is applied to that node's "pair" on the opposite face. An example of this usage is shown below, where nodes not on the boundary of interest are still moved in order to better mesh the boundary layer. Figure 3 shows the effect of setting layers (which defaults to zero) to 1.

[Mesh]
  [fluid]
    type = FileMeshGenerator
    file = fluid_with_bl.exo
  []
  [to_hex20]
    type = NekMeshGenerator
    input = fluid
    boundary = '1'
    radius = '${fparse 7.646e-3 / 2.0}'
    origins = '+0.00000000 +0.00000000 +0.00000000
               +0.00000000 +0.00896570 +0.00000000
               -0.00776452 +0.00448285 +0.00000000
               -0.00776452 -0.00448285 +0.00000000
               +0.00000000 -0.00896570 +0.00000000
               +0.00776452 -0.00448285 +0.00000000
               +0.00776452 +0.00448285 +0.00000000'
    layers = '1'
    geometry_type = cylinder
  []

  parallel_type = replicated
[]
(test/tests/meshgenerators/second_order_hex_generator/layers.i)

Figure 3: Input and output meshes when using different layers settings

You can also set the layers to be greater than 1, in which case multiple layers of boundary elements are moved. An example of this usage is shown below, where elements 3 layers deep are moved to match the cylinder surface. Figure 4 shows the effect of setting layers (which defaults to zero) to 3.

[Mesh]
  [fluid]
    type = FileMeshGenerator
    file = fluid_with_multiple_bl.exo
  []
  [to_hex20]
    type = NekMeshGenerator
    input = fluid
    boundary = '1'
    radius = '${fparse 7.646e-3 / 2.0}'
    origins = '+0.00000000 +0.00000000 +0.00000000
               +0.00000000 +0.00896570 +0.00000000
               -0.00776452 +0.00448285 +0.00000000
               -0.00776452 -0.00448285 +0.00000000
               +0.00000000 -0.00896570 +0.00000000
               +0.00776452 -0.00448285 +0.00000000
               +0.00776452 +0.00448285 +0.00000000'
    layers = '3'
    geometry_type = cylinder
  []

  parallel_type = replicated
[]
(test/tests/meshgenerators/second_order_hex_generator/three_layers.i)

Figure 4: Input and output meshes when using layers = 3

Finally, you can move the corners of your mesh to a specified radius of curvature. In the example below, the original mesh has an outer boundary that matches a regular six-sided polygon. We move the corners, as well as attached boundary layers, to have a radius of curvature.

[Mesh]
  [fluid]
    type = FileMeshGenerator
    file = with_bl.exo
  []
  [rotate]
    type = TransformGenerator
    input = fluid
    transform = rotate
    vector_value = '30.0 0.0 0.0'
  []
  [to_hex20]
    type = NekMeshGenerator
    input = rotate
    boundaries_to_rebuild = '1 2 3 4'
    geometry_type = cylinder

    curve_corners = true
    polygon_sides = 6
    polygon_size = 0.018001405522227287
    polygon_boundary = '4'
    polygon_layers = 3
    corner_radius = 0.002
  []

  parallel_type = replicated
[]
(test/tests/meshgenerators/polygon_corners/six_with_bl.i)

Figure 5: Input and output meshes when enforcing radius of curvature at polygon corners

Sphere Example

All examples in this section use geometry_type = sphere. For example, if you have a sphere of radius , you can move the nodes on the sphere surface to a new radius, say .

[Mesh]
  [sphere]
    type = FileMeshGenerator
    file = sphere_in.e
  []
  [move]
    type = NekMeshGenerator
    input = sphere
    geometry_type = sphere
    radius = 0.6
    boundary = '0'
  []

  parallel_type = replicated
[]
(test/tests/meshgenerators/sphere/convert.i)

Figure 6: Input and output meshes when enforcing sphere radius

Input Parameters

  • inputThe mesh we want to modify

    C++ Type:MeshGeneratorName

    Controllable:No

    Description:The mesh we want to modify

Required Parameters

  • axiszIf 'geometry_type = cylinder', the axis of the mesh about which to build the cylinder surface(s)

    Default:z

    C++ Type:MooseEnum

    Options:x, y, z

    Controllable:No

    Description:If 'geometry_type = cylinder', the axis of the mesh about which to build the cylinder surface(s)

  • boundaries_to_rebuildBoundary(s) to retain from the original mesh in the new mesh; if not specified, all original boundaries are kept.

    C++ Type:std::vector<BoundaryName>

    Controllable:No

    Description:Boundary(s) to retain from the original mesh in the new mesh; if not specified, all original boundaries are kept.

  • boundaryBoundary(s) to enforce the curved surface

    C++ Type:std::vector<BoundaryName>

    Controllable:No

    Description:Boundary(s) to enforce the curved surface

  • corner_radiusIf 'geometry_type = cylinder' and when curving corners, the radius of curvature of the corners

    C++ Type:double

    Controllable:No

    Description:If 'geometry_type = cylinder' and when curving corners, the radius of curvature of the corners

  • curve_cornersFalseIf 'geometry_type = cylinder', whether to move elements to respect radius of curvature of polygon corners

    Default:False

    C++ Type:bool

    Controllable:No

    Description:If 'geometry_type = cylinder', whether to move elements to respect radius of curvature of polygon corners

  • geometry_typeGeometry type to use for moving boundary nodes

    C++ Type:MooseEnum

    Options:cylinder, sphere

    Controllable:No

    Description:Geometry type to use for moving boundary nodes

  • layersNumber of layers to sweep for each boundary when forming the curved surfaces; if not specified, all values default to 0

    C++ Type:std::vector<unsigned int>

    Controllable:No

    Description:Number of layers to sweep for each boundary when forming the curved surfaces; if not specified, all values default to 0

  • originsOrigin(s) about which to form the curved surfaces; if not specified, all values default to (0, 0, 0)

    C++ Type:std::vector<std::vector<double>>

    Controllable:No

    Description:Origin(s) about which to form the curved surfaces; if not specified, all values default to (0, 0, 0)

  • origins_filesOrigin(s) about which to form the curved surfaces, with a file of points provided for each boundary. If not specified, all values default to (0, 0, 0)

    C++ Type:std::vector<std::string>

    Controllable:No

    Description:Origin(s) about which to form the curved surfaces, with a file of points provided for each boundary. If not specified, all values default to (0, 0, 0)

  • polygon_boundaryIf 'geometry_type = cylinder', boundary to enforce radius of curvature for polygon corners

    C++ Type:BoundaryName

    Controllable:No

    Description:If 'geometry_type = cylinder', boundary to enforce radius of curvature for polygon corners

  • polygon_layer_smoothingIf 'geometry_type = cylinder' and when curving corners, the multiplicative factor to apply to each boundary layer; if not specified, all values default to 1.0

    C++ Type:std::vector<double>

    Controllable:No

    Description:If 'geometry_type = cylinder' and when curving corners, the multiplicative factor to apply to each boundary layer; if not specified, all values default to 1.0

  • polygon_layers0If 'geometry_type = cylinder' and when curving corners, the number of layers to sweep for each polygon corner

    Default:0

    C++ Type:unsigned int

    Controllable:No

    Description:If 'geometry_type = cylinder' and when curving corners, the number of layers to sweep for each polygon corner

  • polygon_originsIf 'geometry_type = cylinder', origin(s) about which to curve the polygon corners; if not specified, defaults to (0, 0, 0)

    C++ Type:std::vector<std::vector<double>>

    Controllable:No

    Description:If 'geometry_type = cylinder', origin(s) about which to curve the polygon corners; if not specified, defaults to (0, 0, 0)

  • polygon_sidesIf 'geometry_type = cylinder' and when curving corners, the number of sides of the polygon to use for identifying corners

    C++ Type:unsigned int

    Controllable:No

    Description:If 'geometry_type = cylinder' and when curving corners, the number of sides of the polygon to use for identifying corners

  • polygon_sizeIf 'geometry_type = cylinder' and when curving corners, the size of the polygon (measured as distance from center to a corner) to use for identifying corners

    C++ Type:double

    Controllable:No

    Description:If 'geometry_type = cylinder' and when curving corners, the size of the polygon (measured as distance from center to a corner) to use for identifying corners

  • radiusRadius(es) of the surfaces

    C++ Type:std::vector<double>

    Controllable:No

    Description:Radius(es) of the surfaces

  • retain_original_elem_typeFalseWhether to skip the conversion from QUAD9 to QUAD8, or from HEX27 to HEX20, to get into NekRS-compatible element type. This is primarily used to just allow MOOSE's AdvancedExtruderGenerator to extrude Quad9 elements.

    Default:False

    C++ Type:bool

    Controllable:No

    Description:Whether to skip the conversion from QUAD9 to QUAD8, or from HEX27 to HEX20, to get into NekRS-compatible element type. This is primarily used to just allow MOOSE's AdvancedExtruderGenerator to extrude Quad9 elements.

  • rotation_angle0If 'geometry_type = cylinder' and when curving corners, the rotation angle (degrees) needed to apply to the original mesh to get a polygon boundary with one side horizontal

    Default:0

    C++ Type:double

    Controllable:No

    Description:If 'geometry_type = cylinder' and when curving corners, the rotation angle (degrees) needed to apply to the original mesh to get a polygon boundary with one side horizontal

Optional Parameters

  • control_tagsAdds user-defined labels for accessing object parameters via control logic.

    C++ Type:std::vector<std::string>

    Controllable:No

    Description:Adds user-defined labels for accessing object parameters via control logic.

  • enableTrueSet the enabled status of the MooseObject.

    Default:True

    C++ Type:bool

    Controllable:No

    Description:Set the enabled status of the MooseObject.

  • save_with_nameKeep the mesh from this mesh generator in memory with the name specified

    C++ Type:std::string

    Controllable:No

    Description:Keep the mesh from this mesh generator in memory with the name specified

Advanced Parameters

  • nemesisFalseWhether or not to output the mesh file in the nemesisformat (only if output = true)

    Default:False

    C++ Type:bool

    Controllable:No

    Description:Whether or not to output the mesh file in the nemesisformat (only if output = true)

  • outputFalseWhether or not to output the mesh file after generating the mesh

    Default:False

    C++ Type:bool

    Controllable:No

    Description:Whether or not to output the mesh file after generating the mesh

  • show_infoFalseWhether or not to show mesh info after generating the mesh (bounding box, element types, sidesets, nodesets, subdomains, etc)

    Default:False

    C++ Type:bool

    Controllable:No

    Description:Whether or not to show mesh info after generating the mesh (bounding box, element types, sidesets, nodesets, subdomains, etc)

Debugging Parameters

Input Files