Mesh generation#

This example demonstrates how to generate a mesh for a NACA airfoil using Fluent Meshing.

Starting from the geometry created in the previous example, the script generates a mesh using Fluent Meshing. The parameters are set to generate a mesh with a surface mesh size of 2 and 1000, and a volume mesh size of 512. It leverages the Fluent Meshing Workflow API to create the mesh.

import os

import ansys.fluent.core as pyfluent

Parameters for the script#

The following parameters are used to control the script execution. You can modify these parameters to suit your needs.

# NACA 4-digits airfoil geometry
NACA_AIRFOIL = "6412"

# Data directory
DATA_DIR = os.path.join(os.path.dirname(__file__), "outputs")

Generate the mesh#

The function generate_mesh generates a mesh for a NACA airfoil using Fluent Meshing. The function takes the following parameters:

  • naca_airfoil: NACA 4-digits airfoil number.

  • data_dir: Directory to save the mesh file.

  • ui_mode: User interface mode. The default is None.

  • container_dict: Configuration for the Fluent container. The default is None.

The function launches Fluent Meshing and initializes the workflow for watertight geometry. It imports the geometry, generates the surface mesh, describes the geometry, updates boundaries and regions, adds boundary layers, generates the volume mesh, checks the mesh, writes the mesh, and closes Fluent Meshing.

def generate_mesh(
    naca_airfoil: str,
    data_dir: str,
    ui_mode: str | None = None,
    container_dict: dict | None = None,
):
    """
    Generate a mesh for a NACA airfoil using Fluent Meshing.

    Parameters
    ----------
    naca_airfoil : str
        NACA 4-digits airfoil number.
    data_dir : str
        Directory to save the mesh file.
    ui_mode : str, optional
        User interface mode. The default is None.
    container_dict : dict, optional
        Configuration for the Fluent container. The default is None.
    """

    # Launch Fluent Meshing
    if container_dict is not None:
        meshing = pyfluent.launch_fluent(
            container_dict=container_dict,
            start_container=True,
            precision="double",
            processor_count=4,
            mode="meshing",
            ui_mode="no_gui_or_graphics",
            cwd=data_dir,
            cleanup_on_exit=False,
        )
    else:
        meshing = pyfluent.launch_fluent(
            precision="double",
            processor_count=4,
            mode="meshing",
            ui_mode=ui_mode,
            cwd=data_dir,
        )

    # Initialize workflow - Watertight Geometry
    meshing.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry")

    # Import the geometry
    geo_import = meshing.workflow.TaskObject["Import Geometry"]
    geo_import.Arguments.set_state(
        {
            "FileName": os.path.join(data_dir, f"NACA_Airfoil_{naca_airfoil}.pmdb"),
        }
    )
    geo_import.Execute()

    # Generate surface mesh
    surface_mesh_gen = meshing.workflow.TaskObject["Generate the Surface Mesh"]
    surface_mesh_gen.Arguments.set_state(
        {"CFDSurfaceMeshControls": {"MaxSize": 1000, "MinSize": 2}}
    )
    surface_mesh_gen.Execute()

    # Describe the geometry
    describe_geo = meshing.workflow.TaskObject["Describe Geometry"]
    describe_geo.UpdateChildTasks(SetupTypeChanged=False)
    describe_geo.Arguments.set_state(
        {"SetupType": "The geometry consists of only fluid regions with no voids"}
    )
    describe_geo.UpdateChildTasks(SetupTypeChanged=True)
    describe_geo.Execute()

    # Update boundaries
    meshing.workflow.TaskObject["Update Boundaries"].Execute()

    # Update regions
    meshing.workflow.TaskObject["Update Regions"].Execute()

    # Add boundary layers
    add_boundary_layer = meshing.workflow.TaskObject["Add Boundary Layers"]
    add_boundary_layer.Arguments.set_state({"NumberOfLayers": 12})
    add_boundary_layer.AddChildAndUpdate()

    # Generate volume mesh
    volume_mesh_gen = meshing.workflow.TaskObject["Generate the Volume Mesh"]
    volume_mesh_gen.Arguments.set_state(
        {
            "VolumeFill": "poly-hexcore",
            "VolumeFillControls": {"HexMaxCellLength": 512},
            "VolumeMeshPreferences": {
                "CheckSelfProximity": "yes",
                "ShowVolumeMeshPreferences": True,
            },
        }
    )
    volume_mesh_gen.Execute()

    # Check mesh
    meshing.tui.mesh.check_mesh()

    # Write mesh
    meshing.tui.file.write_mesh(os.path.join(data_dir, f"NACA_Airfoil_{naca_airfoil}.msh.h5"))

    # Close Fluent Meshing
    meshing.exit()

Executing the mesh generation#

The previous function is called to generate the mesh for the NACA airfoil. The mesh is saved in the outputs directory. Depending on the environment, the script will run in a container or locally.

Depending on the environment, the script will run in a container or locally.

if os.getenv("PYANSYS_WORKFLOWS_CI") == "true":
    container_dict = {
        "fluent_image": f"{os.environ['FLUENT_DOCKER_IMAGE']}:{os.environ['FLUENT_IMAGE_TAG']}",
        "host_mount_path": DATA_DIR,
        "license_server": os.environ["ANSYSLMD_LICENSE_FILE"],
        "timeout": 300,
    }
    # https://fluent.docs.pyansys.com/version/stable/api/general/launcher/fluent_container.html
    generate_mesh(NACA_AIRFOIL, "/mnt/pyfluent", container_dict=container_dict)
else:
    generate_mesh(NACA_AIRFOIL, DATA_DIR)
pyfluent.general WARNING: Using 'mount_source = /home/runner/work/pyansys-workflows/pyansys-workflows/geometry-mesh-fluent/outputs' for 'configure_container_dict()' instead of 'host_mount_path = /home/runner/work/pyansys-workflows/pyansys-workflows/geometry-mesh-fluent/outputs'.
pyfluent.launcher WARNING: Starting Fluent container mounted to /home/runner/work/pyansys-workflows/pyansys-workflows/geometry-mesh-fluent/outputs, with this path available as /mnt/pyfluent for the Fluent session running inside the container.

Warning: PMDB file will not be saved as the same is being imported.

Importing one geom object per program-controlled and one zone per body ...
Initializing ANSYS component system ...
running Ansys.Meshing.FieldMesher.exe ...
creating FMComponent instance ...
querying IFieldMesher interface ...
AnsysFieldMesher build date: May 13 2024 15:08:00

argv[0] = /ansys_inc/v242/aisol/CommonFiles/linx64/ansys.meshing.fieldmesher.exe
argv[1] = -B
argv[2] = /ansys_inc/v242/commonfiles/CPython/3_10/linx64/Release/python/../Ansys/TGrid/CADReaders.py
argv[3] = -a
argv[4] = /mnt/pyfluent/FM_6c600132d6c8_152/options1729997306.661543152.xml
argv[5] = -a
argv[6] = /mnt/pyfluent/FM_6c600132d6c8_152/options1729997306.661543152.xml
    /ansys_inc/v242/aisol/CommonFiles/linx64/ansys.meshing.fieldmesher.exe started by root on 6c600132d6c8 linx64 on Sun Oct 27 02:48:27 2024
    using Python 3.10.12 (main, Mar 26 2024, 02:17:48) [GCC 8.2.0]

    using Ansys.Meshing.FieldMesher build May 13 2024 15:04:53

    running ANSYS TGrid CADToTGridConverter ...
    setting up parameters ...
    setting up parameters done.
    running conversion ...
    converting 1 file(s) from Workbench to FLTG using output path '/mnt/pyfluent/FM_6c600132d6c8_152/out1729997306.661543152.tgf'
    converting file 'NACA_Airfoil_6412.pmdb' (1 of 1) from Workbench to FLTG using output path '/mnt/pyfluent/FM_6c600132d6c8_152'
    importing data ...
    importing meshing model from PartMgr from file '/mnt/pyfluent/NACA_Airfoil_6412.pmdb' ...
    setting enclosure and symmetry processing to False
    setting transfer named selections to True
    setting named selection prefixes to ''
    setting mixed import resolution type to 'SolidAndSurface'
    setting target application to 'FluentMeshing'
    initializing part manager from file ...
    processing assembly 'C:\Users\ContainerAdministrator\AppData\Local\Temp\b2de0f9b-42e0-4a84-8530-ef6288521286.scdocx' with ID 1 and reference key '<?xml version="1.0" encoding="utf-16"?>
    <IdTable xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Table>
        <Entry>
          <Text>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:2" /&gt;</Text>
          <ExplodedBodyText>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:22" /&gt;</ExplodedBodyText>
          <Id>10000</Id>
          <IsExploded>true</IsExploded>
        </Entry>
        <Entry>
          <Text>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:2" /&gt;</Text>
          <ExplodedBodyText>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:4813" /&gt;</ExplodedBodyText>
          <Id>10001</Id>
          <IsExploded>true</IsExploded>
        </Entry>
      </Table>
    </IdTable>'
    length unit = [m]
    processing part 'b2de0f9b-42e0-4a84-8530-ef6288521286' with ID 3
    processing part 'b2de0f9b-42e0-4a84-8530-ef6288521286' with ID 5
    processing named selection 'Outlet Fluid'
    processing named selection 'Inlet Fluid'
    processing named selection 'Surrounding Faces'
    processing named selection 'Airfoil Faces'
    processing data ...
    removing named collections of entities ...
    removing named collections of entities stopped, no named collections selected.
    analyzing feature edges ...
    detecting feature edges, feature angle = 40 [deg] ...
        Data information
            Meshing model
                Attributes:
                    'LengthUnit': '[mm]'
                Entity summary:
                    Collection: 4
                    Component : 3
                    Body      : 2
                    Shell     : 2
                    Face      : 405
                    Loop      : 405
                    Edge      : 1207
                    Vertex    : 806
                    Surface   : 405
                    Curve     : 1207
                Tessellation summary:
                    Face facets  : 1604
                    Edge segments: 1207
                Bounding box:
                    (-4500, -1000, -2000) x (5500, 1000, 3000)
                Assembly component hierarchy:
                    'C:\Users\ContainerAdministrator\AppData\Local\Temp\b2de0f9b-42e0-4a84-8530-ef6288521286.scdocx'
                      'b2de0f9b-42e0-4a84-8530-ef6288521286'
                      'b2de0f9b-42e0-4a84-8530-ef6288521286'
                NamedCollections:
                    'Outlet Fluid'
                    'Inlet Fluid'
                    'Surrounding Faces'
                    'Airfoil Faces'


    exporting FLTG data to file '/mnt/pyfluent/FM_6c600132d6c8_152/out1729997306.661543152.tgf' ...
    writing face-based mesh file '/mnt/pyfluent/FM_6c600132d6c8_152/out1729997306.661543152.tgf' ...
    ======== Exported Data ========
    Entity summary:
        Object       : 2
        Object region: 6
        Zone         : 10

    running conversion done.
    running ANSYS TGrid CADToTGridConverter done.
    ran ANSYS TGrid CADToTGridConverter in 0.181 [s]

Reading "/mnt/pyfluent/FM_6c600132d6c8_152/out1729997306.661543152.tgf"...

nodes: 1612
edges: 812
faces: 1604
cells: 0
generating pointers...done.
extracting boundary entities...
 1612 boundary nodes.
 1604 boundary faces.
 4 boundary face zones.
done.
analyzing boundary connectivity...done.


---------------- Import of NACA_Airfoil_6412, consisting of 2 parts/objects, complete.

Writing "/mnt/pyfluent/FM_6c600132d6c8_152/TaskObject3.msh.h5" ...
writing 1 node zones
writing 6 edge zones
writing 4 face zones
writing node curvature data...
done.
---------------- The Global Max size was adjusted to 1000

Importing one mesh object per program-controlled and one zone per body ...
Initializing ANSYS component system ...
running Ansys.Meshing.FieldMesher.exe ...
creating FMComponent instance ...
querying IFieldMesher interface ...
AnsysFieldMesher build date: May 13 2024 15:08:00

argv[0] = /ansys_inc/v242/aisol/CommonFiles/linx64/ansys.meshing.fieldmesher.exe
argv[1] = -B
argv[2] = /ansys_inc/v242/commonfiles/CPython/3_10/linx64/Release/python/../Ansys/TGrid/CADReaders.py
argv[3] = -a
argv[4] = /mnt/pyfluent/FM_6c600132d6c8_152/options1729997309.493558152.xml
argv[5] = -a
argv[6] = /mnt/pyfluent/FM_6c600132d6c8_152/options1729997309.493558152.xml
    /ansys_inc/v242/aisol/CommonFiles/linx64/ansys.meshing.fieldmesher.exe started by root on 6c600132d6c8 linx64 on Sun Oct 27 02:48:29 2024
    using Python 3.10.12 (main, Mar 26 2024, 02:17:48) [GCC 8.2.0]

    using Ansys.Meshing.FieldMesher build May 13 2024 15:04:53

    running ANSYS TGrid CADToTGridConverter ...
    setting up parameters ...
    setting up parameters done.
    running conversion ...
    converting 1 file(s) from Workbench to FLTG using output path '/mnt/pyfluent/FM_6c600132d6c8_152/out1729997309.493558152.tgf'
    converting file 'NACA_Airfoil_6412.pmdb' (1 of 1) from Workbench to FLTG using output path '/mnt/pyfluent/FM_6c600132d6c8_152'
    importing data ...
    importing meshing model from PartMgr from file '/mnt/pyfluent/NACA_Airfoil_6412.pmdb' ...
    setting enclosure and symmetry processing to False
    setting transfer named selections to True
    setting named selection prefixes to ''
    setting mixed import resolution type to 'SolidAndSurface'
    setting target application to 'FluentMeshing'
    initializing part manager from file ...
    processing assembly 'C:\Users\ContainerAdministrator\AppData\Local\Temp\b2de0f9b-42e0-4a84-8530-ef6288521286.scdocx' with ID 1 and reference key '<?xml version="1.0" encoding="utf-16"?>
    <IdTable xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Table>
        <Entry>
          <Text>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:2" /&gt;</Text>
          <ExplodedBodyText>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:22" /&gt;</ExplodedBodyText>
          <Id>10000</Id>
          <IsExploded>true</IsExploded>
        </Entry>
        <Entry>
          <Text>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:2" /&gt;</Text>
          <ExplodedBodyText>&lt;SnippetV1 sctype="SpaceClaim.BasicMoniker`1[[SpaceClaim.IEvaluation, Core]], Core" refId="4098eb18-e9d4-425d-bbf4-f6c3490d7250:4813" /&gt;</ExplodedBodyText>
          <Id>10001</Id>
          <IsExploded>true</IsExploded>
        </Entry>
      </Table>
    </IdTable>'
    length unit = [m]
    processing part 'b2de0f9b-42e0-4a84-8530-ef6288521286' with ID 3
    processing part 'b2de0f9b-42e0-4a84-8530-ef6288521286' with ID 5
    processing named selection 'Outlet Fluid'
    processing named selection 'Inlet Fluid'
    processing named selection 'Surrounding Faces'
    processing named selection 'Airfoil Faces'
    processing data ...
    saving size function background grid to file '/mnt/pyfluent/FM_6c600132d6c8_152/NACA_Airfoil_6412.sf' ...
    writing size function background grid file '/mnt/pyfluent/FM_6c600132d6c8_152/NACA_Airfoil_6412.sf' ...
    Vertices already exist
    initializing size function background grid done in 1.39 [s]
    tessellating 405 faces done in 2.09 [s]
    removing named collections of entities ...
    removing named collections of entities stopped, no named collections selected.
    analyzing feature edges ...
    detecting feature edges, feature angle = 40 [deg] ...
        Data information
            Meshing model
                Attributes:
                    'LengthUnit': '[mm]'
                Entity summary:
                    Collection: 4
                    Component : 3
                    Body      : 2
                    Shell     : 2
                    Face      : 405
                    Loop      : 405
                    Edge      : 1207
                    Vertex    : 806
                    Surface   : 405
                    Curve     : 1207
                Tessellation summary:
                    Face facets  : 223338
                    Edge segments: 97124
                Bounding box:
                    (-4500, -1000, -2000) x (5500, 1000, 3000)
                Assembly component hierarchy:
                    'C:\Users\ContainerAdministrator\AppData\Local\Temp\b2de0f9b-42e0-4a84-8530-ef6288521286.scdocx'
                      'b2de0f9b-42e0-4a84-8530-ef6288521286'
                      'b2de0f9b-42e0-4a84-8530-ef6288521286'
                NamedCollections:
                    'Outlet Fluid'
                    'Inlet Fluid'
                    'Surrounding Faces'
                    'Airfoil Faces'


    exporting FLTG data to file '/mnt/pyfluent/FM_6c600132d6c8_152/out1729997309.493558152.tgf' ...
    writing face-based mesh file '/mnt/pyfluent/FM_6c600132d6c8_152/out1729997309.493558152.tgf' ...
    ======== Exported Data ========
    Entity summary:
        Object       : 2
        Object region: 6
        Zone         : 10

    running conversion done.
    running ANSYS TGrid CADToTGridConverter done.
    ran ANSYS TGrid CADToTGridConverter in 4.126 [s]

Reading "/mnt/pyfluent/FM_6c600132d6c8_152/out1729997309.493558152.tgf"...

nodes: 113549
edges: 1882
faces: 223338
cells: 0
appending mesh...
done.
generating pointers...done.
extracting boundary entities...
 115161 boundary nodes.
 224942 boundary faces.
 8 boundary face zones.
done.

Reading "/mnt/pyfluent/FM_6c600132d6c8_152/NACA_Airfoil_6412.sf"...

ANSYS(R) TGLib(TM) 3D, revision 24.1.0
 Read 277427 vertices
0 faces marked.

    computing regions...
Warning: Region is named after face zone label "airfoil-faces" based on alphabetical order of face zone labels (airfoil-faces b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil).
done

---------------- 1 disconnected regions have been detected


------------------------------------------ --------------------- -------------------- ---------------- ----------
                                      name skewed-cells (> 0.80)    averaged-skewness maximum-skewness face count
------------------------------------------ --------------------- -------------------- ---------------- ----------

b2de0f9b-42e0-4a84-8530-ef6288521286-fluid                     0           0.14027446       0.79997719     221222
                       dead0-airfoil-faces                     0           0.14104044       0.79997719     219676
------------------------------------------ --------------------- -------------------- ---------------- ----------
                                      name skewed-cells (> 0.80)    averaged-skewness maximum-skewness face count
------------------------------------------ --------------------- -------------------- ---------------- ----------

b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil                     0           0.14027446       0.79997719     221222

---------------- After Surface mesh, the model consists of 1 fluid/solid regions and 1 voids.

---------------- Surface Meshing of NACA_Airfoil_6412 complete in  0.14 minutes, with a maximum skewness of  0.80.


---------------- Velocity-inlet zone type was automatically assigned to zones containing the string '*inlet*'.

---------------- Pressure-outlet zone type was automatically assigned to zones containing the string '*outlet*'.

---------------- Describe Geometry task complete in  0.00 minutes.

---------------- Boundary Conditions Updated

---------------- Regions Updated

Created Scoped Prism: smooth-transition_1

---------------- Inflation control added to b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil
Writing "/mnt/pyfluent/FM_6c600132d6c8_152/TaskObject11.msh.h5" ...
writing 2 node zones
writing 12 edge zones
writing 8 face zones
writing node curvature data...
done.
    updating regions...
    done.
checking object "b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil"...
    skipping validating regions of mesh object "b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil"...done.
auto meshing object b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil...

processing scoped prisms...
    starting orientation...
done.
    setting prism growth...done.
done.
Identifying Topology...

The octree hexcore cells will be refined using local surface mesh sizes and body of influence (boi) size controls, if there are any defined.
Generating Prisms...

Generating initial mesh...

Refining mesh...

Create polyhedra ...

delete virtual and dead zones.

Merging zones...

Cleaning up dead entities...


Merging Domains...
done.

                     name       id cells (quality < 0.05)  minimum quality cell count
------------------------- -------- ---------------------- ---------------- ----------
b2de0f9b-42e0-4a84-8530-ef6288521286-fluid      118                      0      0.076512581    2197021
                    fluid      113                      0      0.088740511    1874429

                     name       id cells (quality < 0.05)  minimum quality cell count
------------------------- -------- ---------------------- ---------------- ----------
          Overall Summary     none                      0      0.076512581    4071450

Total Number of Cell Zones : 2

[Quality Measure : Orthogonal Quality]

---------------- Volume mesh creation completed in :  4.62 minutes

---------------- 4071450 cells were created in :  4.74 minutes

---------------- The mesh has a minimum Orthogonal Quality of:  0.08

---------------- The volume meshing of b2de0f9b-42e0-4a84-8530-ef6288521286-airfoil is complete.


Domain extents.
  x-coordinate: min = -4.500000e+03, max = 5.500000e+03.
  y-coordinate: min = -1.000000e+03, max = 1.000000e+03.
  z-coordinate: min = -2.000000e+03, max = 3.000000e+03.
Volume statistics.
  minimum volume: 8.468777e-04.
  maximum volume: 1.422774e+08.
    total volume: 1.000000e+11.
Face area statistics.
   minimum face area: 2.280691e-03.
   maximum face area: 6.993715e+05.
   average face area: 1.386184e+02.
Checking number of nodes per edge.
Checking number of nodes per face.
Checking number of nodes per cell.
Checking number of faces/neighbors per cell.
Checking cell faces/neighbors.
Checking isolated cells.
Checking face handedness.
Checking periodic face pairs.
Checking face children.
Checking face zone boundary conditions.
Checking for invalid node coordinates.
Checking poly cells.
Checking zones.
Checking neighborhood.
Checking modified centroid.
Checking non-positive or too small area.
Checking face zones thread type.

Total running time of the script: (5 minutes 20.424 seconds)