Automated Meshing#

Overview#

Flow360 offers automated meshing, from a CAD geometry to a surface mesh and finally to a volume mesh. The supported CAD formats are CSM and EGADS. The output volume meshes are in CGNS format.

Geometry#

The Engineering Sketch Pad (ESP) is a solid-modeling, feature-based, web-enabled system for building parametric geometry. Readers can download the pre-built ESP so there is no need to compile the source code. The CSM file contains all operations for constructing the geometry. The tutorials for preparing the CSM files can be found on ESP’s official website. Here is an example CSM file:

sphere 0 -1 0 0.5
attribute groupName $sphere

box -0.5 0.5 -0.5 1 1 1
attribute groupName $box

select face 6
attribute faceName $top

This example contains two solid bodies: a sphere and a box. The sphere is centered at (0,-1,0) and the radius is 0.5. The corner of the box is located at (-0.5,0.5,0.5) and the dimensions of the box along the x,y,z directions are [1,1,1].

Note

For external flow, multiple solid bodies are allowed. For internal flow, only one solid body representing the fluid/air is allowed.

../../_images/sphereAndBox.svg

Fig. 8 Box and sphere in ESP.#

As shown in Fig. 8, faces with different groupName will be “grouped” as different boundary conditions when exporting the CGNS file. The face with faceName will get extra refinement when generating the surface mesh.

Surface Meshing#

The surface mesher takes the geometry file and a surfaceMesh.json as inputs to generate a surface mesh. The surfaceMesh.json controls the surface mesh resolution. Full description of surfaceMesh.json can be found at JSON surface mesher. Here is an example surfaceMesh.json:

{
    "maxEdgeLength": 0.05, 
    "curvatureResolutionAngle": 15,
    "growthRate": 1.2, 
    "faces": {
        "top": {
            "maxEdgeLength": 0.01
        }
    }
}

As shown in the above JSON file, the baseline maxEdgeLength is 0.05. An extra refinement is applied to the top face of the box with maxEdgeLength = 0.01.

The surface mesh can be created by submitting the geometry file and surfaceMesh.json via the PythonAPI:

import flow360client
surfaceMeshId = flow360client.NewSurfaceMeshFromGeometry("path/to/geometry.csm", "surfaceMesh.json", surfaceMeshName="my_surface_mesh")
Inputs
  • geometry.csm file

  • surfaceMesh.json (or a Python dictionary)

Outputs
  • surface mesh on cluster

  • return the surfaceMeshId

../../_images/surfaceMesh.png

Fig. 9 Auto-generated surface mesh. An extra refinement is applied to the top face of the box.#

Volume Meshing#

The volume mesher takes a surfaceMeshId and a volumeMesh.json to generate a volume mesh. The volumeMesh.json determines the volume mesh resolution. It contains the firstLayerThickness and growthRate of 3D anisotropic layers, the size/location/resolution of refinement zones and etc.

Full description of volumeMesh.json can be found at JSON volume mesher. Below is an example volumeMesh.json:

{
    "volume": {
        "firstLayerThickness": 1e-3,
        "growthRate": 1.2
    },
    "refinement": [
        {
            "size": [6, 4, 2],
            "center": [1, 0, -1],
            "axisOfRotation": [0, 1, 0],
            "angleOfRotation": 45,
            "spacing": 0.1
        }
    ]
}

In the above JSON file, there is a 6x4x2 volume mesh refinement zone centered at (1,0,-1). This refinement box will be rotated by 45 degrees around the y-axis. The mesh size within this refinement zone is limited to 0.1.

Note

  1. By default, all faces from ESP are treated as noSlipWall and prism layers will be grown off these faces. For internal flow, the user can specify which faces are not noSlipWall and turn off the prism layers.

  2. By default, The farfield shape will be automatically determined by the volume mesher. The user can prescribe the farfield shape if needed.

    • auto: The mesher will Sphere or semi-sphere will be generated based on the bounding box of the geometry

      • Full sphere if min{Y} < 0 and max{Y} > 0

      • +Y semi sphere if min{Y} = 0 and max{Y} > 0

      • -Y semi sphere if min{Y} <> 0 and max{Y} = 0

    • quasi-3d: Thin disk will be generated for quasi 3D cases. Both sides of the farfield disk will be treated as “symmetric plane”.

    • user-defined: The farfield shape is provided by the user in ESP

The volume mesh can be created by submitting the surfaceMeshId and volumeMesh.json using the PythonAPI:

volumeMeshId = flow360client.NewMeshFromSurface(surfaceMeshId, "volumeMesh.json", meshName="my_volume_mesh")
Inputs
  • surfaceMeshId

  • volumeMesh.json (or a Python dictionary)

Outputs
  • volume mesh on cluster (in CGNS format)

  • Flow360Mesh.json on cluster

  • return the volumeMeshId

../../_images/volumeMesh3DView.svg

Fig. 10 Left: WebUI showing the refinement zone. Right: auto-generated volume mesh.#

../../_images/volumeMeshSlices.svg

Fig. 11 Auto-generated volume mesh. Left: sliced at y=1. Right: sliced at y=-1.#

JSON surface mesher#

Option

Default

Description

maxEdgeLength

REQUIRED

[float] Global maximum edge length for surface cells. This value will be overwritten by the local maxEdgeLength in the faces subsection

curvatureResolutionAngle

REQUIRED

[float] Global maximum angular deviation in degrees. This value will restrict:
(1) The angle between a cell’s normal and its underlying surface normal
(2) The angle between a line segment’s normal and its underlying curve normal

growthRate

REQUIRED

[float] Growth rate of the anisotropic layers grown from the edges

edges

{}

[dict] Extra treatment for edges with attribute edgeName

faces

{}

[dict] Extra refinement for faces with attribute faceName

edges#

Subsection edges is a dictionary, the keys in this dictionary should correspond to the edgeName attribute in the CSM file. If users want to apply special treatment to a particular edge, they need to add the edgeName attribute for that edge in ESP. They can then specify the desired type of treatment in this subsection.

Option

Default

Description

type

REQUIRED

[string] aniso or projectAnisoSpacing
(1) aniso: grow anisotropic layers orthogonal to the edge, see Fig. 12
(2) projectAnisoSpacing: project the anisotropic spacing from neighboring faces to the edge, see Fig. 13

method

REQUIRED for aniso

[string] angle, height or aspectRatio
(1) angle: curvature resolution in degrees
(2) height: first layer height of the anisotropic layers
(3) aspectRatio: maximum aspect ratio of the anisotropic cells

value

REQUIRED for aniso

[float] Input value for the corresponding method

Example:

"edges": {
    "leadingEdge":  {
        "type": "aniso",
        "method": "angle",
        "value": 1
    },
    "trailingEdge":  {
        "type": "aniso",
        "method": "height",
        "value": 1e-3
    },
    "hubCircle": {
        "type": "aniso",
        "method": "height",
        "value": 0.1
    },
    "hubSplitEdge": {
        "type": "projectAnisoSpacing"
    }
}
../../_images/surfaceMesh_firstLayerThickness.png

Fig. 12 Surface mesh on a wing. Anisotropic layers are growing from leading and trailing edges.#

../../_images/projectAnisoSpacing.png

Fig. 13 Surface mesh on a hub. Anisotropic layers are growing from hubCircle (green). The anisotropic spacing on the neighboring patches is “projected” to hubSplitEdge (red) and updates the nodes distribution along hubSplitEdge.#

faces#

Subsection faces is a dictionary where the keys should match the faceName attribute in the CSM file. By default, the global maxEdgeLength will be applied to all faces. If users want extra refinement on a specific face, they need to add the faceName attribute to that face in ESP and specify the target local maxEdgeLength in this subsection.

Option

Default

Description

maxEdgeLength

REQUIRED

[float] Local maximum edge length. This value overwrites the global maxEdgeLength.

Example:

"faces": {
    "rightWing": {
        "maxEdgeLength": 0.05
    },
    "fuselage": {
        "maxEdgeLength": 0.05
    }
}

JSON volume mesher#

Option

Default

Description

refinementFactor

1

[float] If refinementFactor=r is provided all spacings in refinement regions and first layer thickness will be adjusted to generate r-times finer mesh. For example, if refinementFactor=2, all spacings will be divided by \(2^{1/3}\approx 1.26\) , so the resulting mesh will have approximately 2 times more nodes

farfield->type

auto

[string] auto, quasi-3d or user-defined
(1) auto automatically detect if the geometry is a full/+Y half/-Y half airplane and create the farfield accordingly
(2) quasi-3d creates two slip walls at the min/max Y locations
(3) user-defined farfield geometry provided by the user in ESP

volume

REQUIRED

[dict] Global parameters for the volume mesher

faces

{}

[dict] Special treatments for faces with attribute faceName

refinement

[]

[list(dict)] Description of refinement zones

rotorDisks

[]

[list(dict)] Description of rotor disks

slidingInterfaces

[]

[list(dict)] Description of sliding interfaces

volume#

Option

Default

Description

firstLayerThickness

REQUIRED

[float] First layer thickness for volumetric anisotropic layers

growthRate

REQUIRED

[float] Growth rate for volume prism layers

gapTreatmentStrength

0

[float] Narrow gap treatment strength used when two surfaces are in close proximity. Use a value between 0 and 1, where 0 is no treatment and 1 is the most conservative treatment. This parameter has a global impact where the anisotropic transition into the isotropic mesh. However, the impact on regions without close proximity is negligible. See the examples below.

Gap treatment examples:

../../_images/gap.svg

Fig. 14 Different gapTreatmentStrength strength. The larger gapTreatmentStrength is, the more space is dedicated to isotropic mesh than anisotropic mesh in narrow gaps.#

faces#

Subsection faces is a dictionary where the keys should align with the faceName attribute in the CSM file. By default, all faces are treated as aniso and the global firstLayerThickness is applied. If users wish to overwrite the global firstLayerThickness for a specific face, they need to add the faceName attribute to that face in ESP and specify the local firstLayerThickness in this subsection. Additionally, users can also disable the anisotropic layers by changing the face type.

Option

Default

Description

type

REQUIRED

[string] aniso, projectAnisoSpacing or none
(1) aniso: grow anisotropic layers normal to the face
(2) projectAnisoSpacing: turn off anisotropic layers growing for this face. Project the anisotropic spacing from the neighboring volumes to this face. See figure Fig. 231
(3) none, turn off anisotropic layers growing for this face. The surface mesh will remain unaltered when populating the volume mesh.

firstLayerThickness

REQUIRED for aniso

[float] local first layer thickness, which will overwrite the global value

For more details of the usage of faces subsection in volumeMesh.json, see Automated Meshing for Internal Flow

refinement (list)#

  1. The mesh inside the refinement zone is uniformly refined

  2. The refinement zone could enclose/intersect with other objects

Option

Default

Description

type

box

[string] box or cylinder. Shape of the refinement zone

center

REQUIRED

[3-array(float)] Coordinate of geometrical center

spacing

REQUIRED

[float] Cell spacing applied in the refinement zone

size

REQUIRED

[3-array(float)] Size of the box in x, y and z directions

axisOfRotation

REQUIRED for box

[3-array(float)] Axis of rotation for the box

angleOfRotation

REQUIRED for box

[float] Angle (in degrees) of rotation for the box

radius

REQUIRED for cylinder

[float] Radius of the cylinder

length

REQUIRED for cylinder

[float] Length of the cylinder

axis

REQUIRED for cylinder

[3-array(float)] Axis of the cylinder

Example:

"refinement": [
 {
     "size": [4, 3, 2],
     "center": [2, 0, 0],
     "spacing": 0.05,
     "axisOfRotation": [ 0, 0, 1 ],
     "angleOfRotation": 45
 },
 {
     "type": "cylinder",
     "radius": 4,
     "length": 5,
     "center": [5, 0, 0],
     "spacing": 0.05,
     "axis": [1, 0, 0]
 }]

rotorDisks (list)#

  1. The mesh inside the rotor disk is semi-structured

  2. The rotor disk cannot enclose/intersect with other objects

  3. Users could create a donut-shape rotor disk and place their hub/centerbody in the middle

  4. Rotor disks are used for resolving the strong flow gradient along the axial direction for the actuator or BET disks

  5. The spacings along the axial, radial and circumferential directions can be adjusted separately

Option

Default

Description

name

index (0, 1, 2 …)

[string] Name for the rotor disk. The boundary name will become: rotorDisk-name

innerRadius

REQUIRED

[float] Inner radius of rotor disk, if greater than 0 then a "donut" is created

outerRadius

REQUIRED

[float] Outer radius of rotor disk

thickness

REQUIRED

[float] Thickness of rotor disk

axisThrust

REQUIRED

[3-array(float)] Axis of thrust of rotor disk. The disk is axisymmetric respect to axisThrust

center

REQUIRED

[3-array(float)] Position of center of the rotor disk

spacingAxial

REQUIRED

[float] Spacing along the axial direction

spacingRadial

REQUIRED

[float] Spacing along the radial direction

spacingCircumferential

REQUIRED

[float] Spacing along the circumferential direction

Example:

"rotorDisks": [
     {
         "name": "enclosed",
         "innerRadius": 0,
         "outerRadius": 0.75,
         "thickness": 0.1,
         "axisThrust": [1, 0, 0],
         "center": [0, 5.0, 0],
         "spacingAxial": 0.1,
         "spacingRadial": 0.1,
         "spacingCircumferential": 0.1
     },
     {
         "innerRadius": 0,
         "outerRadius": 0.75,
         "thickness": 0.1,
         "axisThrust": [0, 0, 1],
         "center": [0, -5, 0],
         "spacingAxial": 0.1,
         "spacingRadial": 0.1,
         "spacingCircumferential": 0.1
     }
 ],

slidingInterfaces (list)#

  1. The mesh on the sliding interface is guaranteed to be concentric

  2. The sliding interface is designed to enclose other objects, but it can’t intersect with other objects

  3. Users could create a donut-shape sliding interface and put their stationary centerbody in the middle

Option

Default

Description

name

index (0, 1, 2…)

[string] Name for the sliding interface. The boundary name will become: slidingInterface-name

innerRadius

REQUIRED

[float] Inner radius of sliding interface, if greater than 0 then "donut" shape is created

outerRadius

REQUIRED

[float] Outer radius of sliding interface

thickness

REQUIRED

[float] Thickness of sliding interface

axisOfRotation

REQUIRED

[3-array(float)] Axis of rotation of the sliding interface. The cylindrical shape is positioned such its axis is aligned with axisOfRotation.

center

REQUIRED

[float] Position of center of the sliding interface

spacingAxial

REQUIRED

[float] Spacing along the axial direction

spacingRadial

REQUIRED

[float] Spacing along the radial direction

spacingCircumferential

REQUIRED

[float] Spacing along the circumferential direction

enclosedObjects

REQUIRED

[list(string)] Objects enclosed by this sliding interface. Can be faces, other sliding interfaces or rotor disks

Example:

"slidingInterfaces": [
    {
        "name": "inner",
        "innerRadius": 0,
        "outerRadius": 0.75,
        "thickness": 0.5,
        "axisOfRotation": [0, 0, 1],
        "center": [0, 0, 0],
        "spacingAxial": 0.2,
        "spacingRadial": 0.2,
        "spacingCircumferential": 0.2,
        "enclosedObjects": ["hub", "blade1", "blade2", "blade3"]
    }, {
        "name": "mid",
        "innerRadius": 0,
        "outerRadius": 2.0,
        "thickness": 2.0,
        "axisOfRotation": [0, 1, 0],
        "center": [0, 0, 0],
        "spacingAxial": 0.2,
        "spacingRadial": 0.2,
        "spacingCircumferential": 0.2,
        "enclosedObjects": ["slidingInterface-inner"]
    }, {
        "innerRadius": 0,
        "outerRadius": 2.0,
        "thickness": 2.0,
        "axisOfRotation": [0, 1, 0],
        "center": [0, 5, 0],
        "spacingAxial": 0.2,
        "spacingRadial": 0.2,
        "spacingCircumferential": 0.2,
        "enclosedObjects": ["rotorDisk-enclosed"]
    }, {
        "innerRadius": 1.5,
        "outerRadius": 2.0,
        "thickness": 2.0,
        "axisOfRotation": [0, 1, 0],
        "center": [0, -5, 0],
        "spacingAxial": 0.2,
        "spacingRadial": 0.2,
        "spacingCircumferential": 0.2,
        "enclosedObjects": []
    }, {
        "name": "outer",
        "innerRadius": 0,
        "outerRadius": 8,
        "thickness": 6,
        "axisOfRotation": [1, 0, 0],
        "center": [0, 0, 0],
        "spacingAxial": 0.4,
        "spacingRadial": 0.4,
        "spacingCircumferential": 0.4,
        "enclosedObjects": ["slidingInterface-mid", "rotorDisk-1", "slidingInterface-2", "slidingInterface-3"]
    }
],
../../_images/slidingInterfaces.png

Fig. 15 Rotor disks and sliding interfaces generated according to the above configuration.#