Fluids simulation#

This example demonstrates how to solve the flow around a NACA airfoil using Fluent.

Starting from the mesh created in the previous example, the script solves the flow around a NACA airfoil using Fluent. The parameters are set to solve the flow with a Mach number of 0.3, a temperature of 255.56 K, an angle of attack of 3.06 degrees, and a pressure of 80600 Pa. Overall, these are the conditions for a compressible flow.

import os

import ansys.fluent.core as pyfluent
import numpy as np

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")

# Simulation parameters
SIM_MACH = 0.3  # 0.8395 # Mach number
SIM_TEMPERATURE = 255.56  # In Kelvin
SIM_AOA = 3.06  # in degrees
SIM_PRESSURE = 80600  # in Pa

Solve the flow around the airfoil#

The function solve_airfoil_flow solves the flow around a NACA airfoil using Fluent. The function takes the following parameters:

  • naca_airfoil: NACA 4-digits airfoil number.

  • sim_mach: Mach number.

  • sim_temperature: Temperature in Kelvin.

  • sim_aoa: Angle of attack in degrees.

  • sim_pressure: Pressure in Pascal.

  • data_dir: Directory to save the mesh file.

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

  • iter_count: Number of iterations to solve. The default is 25.

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

The function switches to the Fluent solver and loads the mesh. It defines the model, material, boundary conditions, operating conditions, initializes the flow field, saves the case file, solves for the requested iterations, and exits Fluent.

def solve_airfoil_flow(
    naca_airfoil: str,
    sim_mach: float,
    sim_temperature: float,
    sim_aoa: float,
    sim_pressure: float,
    data_dir: str,
    container_dict: dict | None = None,
    iter_count: int = 25,
    ui_mode: str | None = None,
):
    """
    Solve the flow around a NACA airfoil using Fluent.

    Parameters
    ----------
    naca_airfoil : str
        NACA 4-digits airfoil number.
    sim_mach : float
        Mach number.
    sim_temperature : float
        Temperature in Kelvin.
    sim_aoa : float
        Angle of attack in degrees.
    sim_pressure : float
        Pressure in Pascal.
    data_dir : str
        Directory to save the mesh file.
    container_dict : dict, optional
        Configuration for the Fluent container. The default is None.
    iter_count : int, optional
        Number of iterations to solve. The default is ``25``.
    ui_mode : str, optional
        User interface mode. The default is None.
    """

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

    # Load mesh
    solver.file.read_mesh(file_name=f"{data_dir}/NACA_Airfoil_{naca_airfoil}.msh.h5")

    # Verify the mesh
    solver.mesh.check()

    # Define the model
    # model : k-omega
    # k-omega model : sst
    viscous = solver.setup.models.viscous
    viscous.model = "k-omega"
    viscous.k_omega_model = "sst"

    # Define material
    #
    # density : ideal-gas
    # viscosity : sutherland
    # viscosity method : three-coefficient-method
    # reference viscosity : 1.716e-05 [kg/(m s)]
    # reference temperature : 273.11 [K]
    # effective temperature : 110.56 [K]
    air = solver.setup.materials.fluid["air"]
    air.density.option = "ideal-gas"
    air.viscosity.option = "sutherland"
    air.viscosity.sutherland.option = "three-coefficient-method"
    air.viscosity.sutherland.reference_viscosity = 1.716e-05
    air.viscosity.sutherland.reference_temperature = 273.11
    air.viscosity.sutherland.effective_temperature = 110.56

    # Define Boundary conditions
    #
    # gauge pressure : 0 [Pa]
    # turbulent intensity : 5 [%]solve
    # turbulent viscosity ratio : 10
    #
    solver.setup.boundary_conditions.set_zone_type(
        zone_list=["inlet-fluid"], new_type="pressure-far-field"
    )

    inlet_fluid = solver.setup.boundary_conditions.pressure_far_field["inlet-fluid"]
    aoa = np.deg2rad(sim_aoa)
    if solver.get_fluent_version() < pyfluent.FluentVersion.v242:
        inlet_fluid.gauge_pressure = 0
        inlet_fluid.m = sim_mach
        inlet_fluid.t = sim_temperature
        inlet_fluid.flow_direction[0] = np.cos(aoa)
        inlet_fluid.flow_direction[1] = np.sin(aoa)
        inlet_fluid.turbulent_intensity = 0.05
        inlet_fluid.turbulent_viscosity_ratio_real = 10

    else:
        inlet_fluid.momentum.gauge_pressure = 0
        inlet_fluid.momentum.mach_number = sim_mach
        inlet_fluid.thermal.temperature = sim_temperature
        inlet_fluid.momentum.flow_direction[0] = np.cos(aoa)
        inlet_fluid.momentum.flow_direction[1] = np.sin(aoa)
        inlet_fluid.turbulence.turbulent_intensity = 0.05
        inlet_fluid.turbulence.turbulent_viscosity_ratio = 10

    # Define operating conditions
    #
    solver.setup.general.operating_conditions.operating_pressure = sim_pressure

    # Initialize flow field
    solver.solution.initialization.hybrid_initialize()

    # Save case file
    solver.file.write(
        file_name=f"{data_dir}/NACA_Airfoil_{naca_airfoil}_initialization.cas.h5",
        file_type="case",
    )

    # Solve for requested iterations
    solver.solution.run_calculation.iterate(iter_count=iter_count)
    solver.file.write(
        file_name=f"{data_dir}/NACA_Airfoil_{naca_airfoil}_resolved.cas.h5",
        file_type="case",
    )
    # Write data file as well
    solver.file.write(
        file_name=f"{data_dir}/NACA_Airfoil_{naca_airfoil}_resolved.dat.h5",
        file_type="data",
    )

    # Exit Fluent
    solver.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
    # Solve the flow around the airfoil
    solve_airfoil_flow(
        NACA_AIRFOIL,
        SIM_MACH,
        SIM_TEMPERATURE,
        SIM_AOA,
        SIM_PRESSURE,
        "/mnt/pyfluent",
        container_dict=container_dict,
    )
else:
    # Solve the flow around the airfoil
    solve_airfoil_flow(NACA_AIRFOIL, SIM_MACH, SIM_TEMPERATURE, SIM_AOA, SIM_PRESSURE, 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.
Fast-loading "/ansys_inc/v242/fluent/fluent24.2.0/addons/afd/lib/hdfio.bin"
Done.

Reading from 08124a23adc1:"/mnt/pyfluent/NACA_Airfoil_6412.msh.h5" in NODE0 mode ...
  Reading mesh ...
     4071450 cells,     2 cell zones ...
        1874429 mixed cells,  zone id: 113
        2197021 mixed cells,  zone id: 118
    17742510 faces,     6 face zones ...
            821 polygonal wall faces,  zone id: 24
         111648 polygonal wall faces,  zone id: 21
            254 polygonal velocity-inlet faces,  zone id: 23
            254 polygonal pressure-outlet faces,  zone id: 22
        9515305 mixed interior faces,  zone id: 120
        8114228 mixed interior faces,  zone id: 115
    10080893 nodes,     4 node zones ...

Building...
     mesh
        distributing mesh
                parts....,
                faces....,
                nodes....,
                cells....,
        bandwidth reduction using Reverse Cuthill-McKee: 998809/33416 = 29.8901
  Reading boundary layer flags ...
  Done.

     materials,
     interface,
     domains,
     zones,
        airfoil-faces-shadow
        Skipping thread 15 of domain 1 (not referenced by grid).
        Skipping thread 16 of domain 1 (not referenced by grid).
        Skipping thread 17 of domain 1 (not referenced by grid).
        Skipping thread 18 of domain 1 (not referenced by grid).
        Skipping thread 19 of domain 1 (not referenced by grid).
        Skipping thread 20 of domain 1 (not referenced by grid).
        surrounding-faces
        airfoil-faces
        inlet-fluid
        outlet-fluid
        interior--b2de0f9b-42e0-4a84-8530-ef6288521286-fluid
        interior--fluid
        fluid
        b2de0f9b-42e0-4a84-8530-ef6288521286-fluid
     parallel,
Done.
Mesh is now scaled to meters.

 Domain Extents:
   x-coordinate: min (m) = -4.500000e+00, max (m) = 5.500000e+00
   y-coordinate: min (m) = -1.000000e+00, max (m) = 1.000000e+00
   z-coordinate: min (m) = -2.000000e+00, max (m) = 3.000000e+00
 Volume statistics:
   minimum volume (m3): 8.468777e-13
   maximum volume (m3): 1.422774e-01
     total volume (m3): 1.000000e+02
 Face area statistics:
   minimum face area (m2): 2.280691e-09
   maximum face area (m2): 6.993715e-01
 Checking mesh......................................
Done.

Note: Settings to improve the robustness of pathline and
      particle tracking have been automatically enabled.


Note: Enabling energy equation as required by material density method.

Initialize using the hybrid initialization method.

Checking case topology...
-This case combines farfield, inlets and outlets
-Pressure information is available at the boundaries

        iter            scalar-0                scalar-1

        1               1.000000e+00    1.000000e+00
        2               6.645157e-05    3.378266e-07
        3               2.000818e-05    1.336523e-07
        4               1.179705e-05    1.067819e-07
        5               5.258877e-06    3.525356e-08
        6               2.720042e-06    3.793973e-08
        7               1.356182e-06    1.184089e-08
        8               1.018637e-06    1.410328e-08
        9               5.315569e-07    4.750358e-09
        10              3.906237e-07    4.863557e-09

Hybrid initialization is done.

Writing to 08124a23adc1:"/mnt/pyfluent/NACA_Airfoil_6412_initialization.cas.h5" in NODE0 mode and compression level 1 ...
Grouping cells for Laplace smoothing ...
  Done.     4071450 cells,     2 zones ...
    17854158 faces,     7 zones ...
    10189562 nodes,     1 zone  ...
  Done.

  Writing boundary layer flags ...
  Done.
Done.

  iter  continuity  x-velocity  y-velocity  z-velocity      energy           k       omega     time/iter
     1  1.0000e+00  2.7927e-04  2.7549e-04  1.4197e-04  3.8109e-05  9.7772e-01  4.9401e-01  0:15:14   24
     2  6.3285e-01  2.3948e-04  4.6531e-04  9.3791e-05  3.6542e-05  9.5841e-01  4.9022e-01  0:14:25   23
     3  6.7535e-01  2.3960e-04  3.1404e-04  7.3400e-05  3.7161e-05  9.0243e-01  4.8386e-01  0:13:43   22
     4  6.7792e-01  2.1568e-04  2.1945e-04  6.6004e-05  3.5185e-05  7.2034e-01  4.7295e-01  0:13:00   21
     5  6.8850e-01  1.8595e-04  1.5467e-04  6.1813e-05  3.0405e-05  4.4829e-01  4.5389e-01  0:12:05   20
     6  6.8022e-01  1.5790e-04  1.1210e-04  5.8129e-05  2.5294e-05  2.3021e-01  4.2061e-01  0:11:10   19
     7  6.3170e-01  1.4876e-04  8.4635e-05  5.4588e-05  2.0944e-05  1.2310e-01  3.6502e-01  0:10:21   18
     8  5.6177e-01  1.4460e-04  6.6812e-05  4.9994e-05  1.8412e-05  6.4281e-02  2.8370e-01  0:09:40   17
     9  4.8102e-01  1.3857e-04  5.6132e-05  4.4578e-05  1.6471e-05  3.4783e-02  1.9139e-01  0:09:01   16
    10  4.1075e-01  1.2847e-04  4.8600e-05  3.8843e-05  1.4855e-05  2.3376e-02  1.1103e-01  0:08:23   15
    11  3.5291e-01  1.2120e-04  4.2468e-05  3.3183e-05  1.4150e-05  2.1954e-02  5.8104e-02  0:07:46   14

  iter  continuity  x-velocity  y-velocity  z-velocity      energy           k       omega     time/iter
    12  3.0537e-01  1.1489e-04  3.6212e-05  2.7712e-05  1.4446e-05  2.5487e-02  2.9454e-02  0:07:10   13
    13  2.6472e-01  1.0914e-04  3.0598e-05  2.2723e-05  1.5033e-05  2.8451e-02  1.5329e-02  0:06:32   12
    14  2.3196e-01  1.0154e-04  2.5552e-05  1.8410e-05  1.4791e-05  2.9939e-02  8.5765e-03  0:05:55   11
    15  2.0799e-01  9.3274e-05  2.1878e-05  1.5124e-05  1.3863e-05  2.9777e-02  5.3140e-03  0:05:20   10
    16  1.8926e-01  8.8168e-05  1.9071e-05  1.2838e-05  1.3013e-05  2.8299e-02  3.6617e-03  0:04:46    9
    17  1.7518e-01  8.5202e-05  1.6849e-05  1.1388e-05  1.2371e-05  2.6638e-02  2.7829e-03  0:04:12    8
    18  1.6629e-01  8.3267e-05  1.5262e-05  1.0466e-05  1.1768e-05  2.4917e-02  2.2321e-03  0:03:39    7
    19  1.6003e-01  8.0477e-05  1.4380e-05  9.9830e-06  1.0869e-05  2.2951e-02  1.8476e-03  0:03:07    6
    20  1.5333e-01  7.5748e-05  1.3817e-05  9.7537e-06  9.7003e-06  2.0532e-02  1.5957e-03  0:02:35    5
    21  1.4599e-01  6.9516e-05  1.3180e-05  9.6127e-06  8.4613e-06  1.7574e-02  1.4175e-03  0:02:03    4
    22  1.3645e-01  6.2743e-05  1.2259e-05  9.2616e-06  7.3881e-06  1.4974e-02  1.2744e-03  0:01:32    3

  iter  continuity  x-velocity  y-velocity  z-velocity      energy           k       omega     time/iter
    23  1.2500e-01  5.6063e-05  1.1127e-05  8.5603e-06  6.5064e-06  1.2900e-02  1.1525e-03  0:01:01    2
    24  1.1365e-01  5.0070e-05  9.7635e-06  7.5534e-06  5.7811e-06  1.1134e-02  1.0436e-03  0:00:31    1
    25  1.0336e-01  4.4514e-05  8.4698e-06  6.4937e-06  5.1570e-06  9.6102e-03  9.4639e-04  0:00:00    0

Writing to 08124a23adc1:"/mnt/pyfluent/NACA_Airfoil_6412_resolved.cas.h5" in NODE0 mode and compression level 1 ...
Grouping cells for Laplace smoothing ...
     4071450 cells,     2 zones ...
    17854158 faces,     7 zones ...
    10189562 nodes,     1 zone  ...
  Done.

  Writing boundary layer flags ...
  Done.
Done.

Writing to 08124a23adc1:"/mnt/pyfluent/NACA_Airfoil_6412_resolved.dat.h5" in NODE0 mode and compression level 1 ...
  Writing results.
Done.

Total running time of the script: (17 minutes 59.460 seconds)