Note
Go to the end to download the full example code.
Modeling External Compressible Flow#
The purpose of this tutorial is to compute the turbulent flow past a transonic wing at a nonzero angle of attack using the k-w SST turbulence model.
This example uses the guided workflow for watertight geometry meshing because it is appropriate for geometries that can have no imperfections, such as gaps and leakages.
Workflow tasks
The Modeling External Compressible Flow Using the Meshing Workflow guides you through these tasks:
Creation of capsule mesh using Watertight Geometry workflow.
Model compressible flow (using the ideal gas law for density).
Set boundary conditions for external aerodynamics.
Use the k-w SST turbulence model.
Calculate a solution using the pressure-based coupled solver with global time step selected for the pseudo time method.
Check the near-wall mesh resolution by plotting the distribution of .
Problem description
The problem considers the flow around a wing at an angle of attack a=3.06° and a free stream Mach number of 0.8395 (M=0.8395). The flow is transonic, and has a shock near the mid-chord (x/c≃0.20) on the upper (suction) side. The wing has a mean aerodynamic chord length of 0.64607 m, a span of 1.1963 m, an aspect ratio of 3.8, and a taper ratio of 0.562.
Example Setup#
Before you can use the meshing workflow, you must set up the example and initialize this workflow.
Perform required imports#
Perform required imports, which includes downloading and importing the geometry files.
import ansys.fluent.core as pyfluent
from ansys.fluent.core import examples
wing_spaceclaim_file, wing_intermediary_file = [
examples.download_file(CAD_file, "pyfluent/external_compressible")
for CAD_file in ["wing.scdoc", "wing.pmdb"]
]
Launch Fluent#
Launch Fluent as a service in meshing mode with double precision running on four processors and print Fluent version.
meshing = pyfluent.launch_fluent(
precision="double",
processor_count=4,
mode="meshing",
)
print(meshing.get_fluent_version())
Fluent version 2025 R1
Initialize workflow#
Initialize the watertight geometry meshing workflow.
meshing.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry")
Watertight geometry meshing workflow#
The fault-tolerant meshing workflow guides you through the several tasks that follow.
Import CAD and set length units#
Import the CAD geometry and set the length units to inches.
geo_import = meshing.workflow.TaskObject["Import Geometry"]
geo_import.Arguments.set_state(
{
"FileName": wing_intermediary_file,
}
)
meshing.upload(wing_intermediary_file)
geo_import.Execute()
/home/ansys/actions-runner/_work/pyfluent/pyfluent/src/ansys/fluent/core/session.py:360: PyFluentUserWarning: You have directly called the upload() method of the session. Please be advised that for the current version of Fluent, many API methods automatically handle file uploads and downloads internally. You may not need to explicitly call upload() in most cases. However, there are exceptions, particularly in PMFileManagement, where complex file interactions require explicit use of upload() method for relevant files.
warnings.warn(self._file_transfer_api_warning("upload()"), PyFluentUserWarning)
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 ...
writing cad import logs to "/mnt/pyfluent/cadImport1732718345.608516.log"
Reading "/mnt/pyfluent/FM_2c4a6ca1e415_152/out1732718345.604977152.tgf"...
nodes: 1603
edges: 267
faces: 2649
cells: 0
generating pointers...done.
extracting boundary entities...
1603 boundary nodes.
2649 boundary faces.
6 boundary face zones.
done.
analyzing boundary connectivity...done.
---------------- Import of wing, consisting of 2 parts/objects, complete.
---------------- Import complete in 0.07 minutes.
Add local sizing#
Add local sizing controls to the faceted geometry.
local_sizing = meshing.workflow.TaskObject["Add Local Sizing"]
local_sizing.Arguments.set_state(
{
"AddChild": "yes",
"BOIControlName": "wing-facesize",
"BOIFaceLabelList": ["wing_bottom", "wing_top"],
"BOISize": 10,
}
)
local_sizing.AddChildAndUpdate()
local_sizing.Arguments.set_state(
{
"AddChild": "yes",
"BOIControlName": "wing-ege-facesize",
"BOIFaceLabelList": ["wing_edge"],
"BOISize": 2,
}
)
local_sizing.AddChildAndUpdate()
local_sizing.Arguments.set_state(
{
"AddChild": "yes",
"BOIControlName": "boi_1",
"BOIExecution": "Body Of Influence",
"BOIFaceLabelList": ["wing-boi"],
"BOISize": 5,
}
)
local_sizing.AddChildAndUpdate()
---------------- A local size of 10 was added to wing-facesize
---------------- The Global Min size was adjusted to 2
---------------- A local size of 2 was added to wing-ege-facesize
---------------- A Body of Influence with a target size of 5 was added to: wing-boi
Generate surface mesh#
Generate the surface mash.
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()
Writing "/mnt/pyfluent/FM_2c4a6ca1e415_152/TaskObject3.msh.h5" ...
writing 1 node zones
writing 10 edge zones
writing 6 face zones
writing node curvature data
done. processing size functions/scoped sizing to create Size Field...
Writing "/mnt/pyfluent/FM_2c4a6ca1e415_152/wing.sf"...
Done.
Importing one mesh object per program-controlled and one zone per body ...
writing cad import logs to "/mnt/pyfluent/cadImport1732718353.956592.log"
Reading "/mnt/pyfluent/FM_2c4a6ca1e415_152/out1732718353.95456152.tgf"...
nodes: 77317
edges: 4045
faces: 146550
cells: 0
appending mesh...
done.
generating pointers...done.
extracting boundary entities...
78920 boundary nodes.
149199 boundary faces.
12 boundary face zones.
done.
Reading "/mnt/pyfluent/FM_2c4a6ca1e415_152//wing.sf"...
Read 379882 vertices
Warning: Deleting empty objects (wing-boi)
removed 54012 faces.
0 faces marked.
computing regions...done
Deleting import_curvature_0
Deleting import_proximity_0
processing size functions/scoped sizing to create Size Field...
Writing "/mnt/pyfluent/FM_2c4a6ca1e415_152/wing.sf"...
Done.
remeshing...
------------------------- --------------------- -------------------- ---------------- ----------
name skewed-cells (> 0.80) averaged-skewness maximum-skewness face count
------------------------- --------------------- -------------------- ---------------- ----------
fluid 0 0.02760156 0.65385375 79804
------------------------- --------------------- -------------------- ---------------- ----------
name skewed-cells (> 0.80) averaged-skewness maximum-skewness face count
------------------------- --------------------- -------------------- ---------------- ----------
wing-fluid 0 0.02760156 0.65385375 79804
---------------- After Surface mesh, the model consists of 1 fluid/solid regions and 0 voids.
---------------- Surface Meshing of wing complete in 0.67 minutes, with a maximum skewness of 0.65.
Describe geometry#
Describe geometry and define the fluid region.
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()
---------------- Symmetry zone type was automatically assigned to zones containing the string '*symmetry*'.
---------------- Pressure-far-field zone type was automatically assigned to zones containing the string '*far*field*'.
---------------- Describe Geometry task complete in 0.01 minutes.
Update boundaries#
Update the boundaries.
meshing.workflow.TaskObject["Update Boundaries"].Execute()
---------------- Boundary Conditions Updated
Update regions#
Update the regions.
meshing.workflow.TaskObject["Update Regions"].Execute()
---------------- Regions Updated
Add boundary layers#
Add boundary layers, which consist of setting properties for the boundary layer mesh.
add_boundary_layer = meshing.workflow.TaskObject["Add Boundary Layers"]
add_boundary_layer.Arguments.set_state({"NumberOfLayers": 12})
add_boundary_layer.AddChildAndUpdate()
Created Scoped Prism: smooth-transition_1
---------------- Inflation control added to wing-fluid
Generate volume mesh#
Generate the volume mesh, which consists of setting properties for the 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()
Writing "/mnt/pyfluent/FM_2c4a6ca1e415_152/TaskObject11.msh.h5" ...
writing 3 node zones
writing 23 edge zones
writing 11 face zones
writing node curvature data
done. processing size functions/scoped sizing to create Size Field...
Writing "/mnt/pyfluent/FM_2c4a6ca1e415_152/wing.sf"...
Done.
updating regions...
done.
checking object "wing-fluid"...
skipping validating regions of mesh object "wing-fluid"...done.
auto meshing object wing-fluid...
processing scoped prisms...
starting orientation...
done.
setting prism growth...done.
done.
Identifying Topology...
The octree hexcore cells will be refined using the computed Size Field.
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
------------------------- -------- ---------------------- ---------------- ----------
fluid 670 0 0.060909445 1009880
name id cells (quality < 0.05) minimum quality cell count
------------------------- -------- ---------------------- ---------------- ----------
Overall Summary none 0 0.060909445 1009880
Total Number of Cell Zones : 1
[Quality Measure : Orthogonal Quality]
---------------- Volume mesh creation completed in : 0.72 minutes
---------------- 1009880 cells were created in : 0.74 minutes
---------------- The mesh has a minimum Orthogonal Quality of: 0.06
---------------- The volume meshing of wing-fluid is complete.
Check mesh in meshing mode#
Check the mesh in meshing mode.
meshing.tui.mesh.check_mesh()
Domain extents.
x-coordinate: min = -2.503520e+04, max = 2.614408e+04.
y-coordinate: min = -9.623149e-08, max = 2.503895e+04.
z-coordinate: min = -2.503942e+04, max = 2.503943e+04.
Volume statistics.
minimum volume: 6.592227e-04.
maximum volume: 6.084455e+08.
total volume: 4.214431e+13.
Face area statistics.
minimum face area: 3.731184e-06.
maximum face area: 1.203898e+06.
average face area: 6.134290e+04.
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.
Save mesh file#
Save the mesh file (wing.msh.h5
).
meshing.meshing.File.WriteMesh(FileName="wing.msh.h5")
Done.Writing "wing.msh.h5" ...
writing 3 node zones
writing 13 edge zones
writing 6 face zones
writing 1 cell zones
writing boundary layer flags
writing node curvature data
done.Copying the required intermediate mesh files into wing_workflow_files
Done.
Solve and postprocess#
Once you have completed the watertight geometry meshing workflow, you can solve and postprcess the results.
Switch to solution mode#
Switch to solution mode. Now that a high-quality mesh has been generated using Fluent in meshing mode, you can switch to solver mode to complete the setup of the simulation.
solver = meshing.switch_to_solver()
Preparing...
Check mesh in solver mode#
Check the mesh in solver mode. The mesh check lists the minimum and maximum x, y, and z values from the mesh in the default SI units of meters. It also reports a number of other mesh features that are checked. Any errors in the mesh are reported.
solver.mesh.check()
unused zone boundary-node-21 removed
Transferring mesh
creating threads... done
transferring nodes... done
transferring cells... done
transferring faces... done
post mesh transfer operations... done
done
Building...
mesh
auto partitioning mesh by Metis (fast),
distributing mesh
parts....,
faces....,
nodes....,
cells....,
bandwidth reduction using Reverse Cuthill-McKee: 249313/10326 = 24.1442
materials,
interface,
domains,
zones,
interior--fluid
fluid_symmetry
pressure_farfield
wing_edge
wing_bottom
wing_top
fluid
surfaces,
parallel,
Done.
Mesh is now scaled to meters.
Warning: Pressure far-field boundary condition can only be used with ideal gas law.
Please change either the boundary condition type or enable ideal gas law.
Solver cannot proceed until this is fixed.
Warning: Pressure far-field boundary condition can only be used with ideal gas law.
Please change either the boundary condition type or enable ideal gas law.
Solver cannot proceed until this is fixed.
Domain Extents:
x-coordinate: min (m) = -2.502407e+01, max (m) = 2.614408e+01
y-coordinate: min (m) = -9.623149e-11, max (m) = 2.503569e+01
z-coordinate: min (m) = -2.503942e+01, max (m) = 2.503943e+01
Volume statistics:
minimum volume (m3): 6.592227e-13
maximum volume (m3): 6.084455e-01
total volume (m3): 4.214431e+04
Face area statistics:
minimum face area (m2): 3.731184e-12
maximum face area (m2): 1.203898e+00
Checking mesh.....................................
Done.
Note: Settings to improve the robustness of pathline and
particle tracking have been automatically enabled.
Define model#
Set the k-w sst turbulence model.
# model : k-omega
# k-omega model : sst
viscous = solver.setup.models.viscous
viscous.model = "k-omega"
viscous.k_omega_model = "sst"
Define materials#
Modify the default material air
to account for compressibility and variations of the thermophysical properties with temperature.
# 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
Note: Enabling energy equation as required by material density method.
Boundary Conditions#
Set the boundary conditions for pressure_farfield
.
# gauge pressure : 0 [Pa]
# mach number : 0.8395
# temperature : 255.56 [K]
# x-component of flow direction : 0.998574
# z-component of flow direction : 0.053382
# turbulent intensity : 5 [%]
# turbulent viscosity ratio : 10
pressure_farfield = solver.setup.boundary_conditions.pressure_far_field[
"pressure_farfield"
]
pressure_farfield.momentum.gauge_pressure = 0
pressure_farfield.momentum.mach_number = 0.8395
pressure_farfield.thermal.temperature = 255.56
pressure_farfield.momentum.flow_direction[0] = 0.998574
pressure_farfield.momentum.flow_direction[2] = 0.053382
pressure_farfield.turbulence.turbulent_intensity = 0.05
pressure_farfield.turbulence.turbulent_viscosity_ratio = 10
Operating Conditions#
Set the operating conditions.
# operating pressure : 80600 [Pa]
solver.setup.general.operating_conditions.operating_pressure = 80600
Initialize flow field#
Initialize the flow field using hybrid initialization.
solver.solution.initialization.hybrid_initialize()
Initialize using the hybrid initialization method.
Checking case topology...
-This case has a single farfield bc
-Case will be initialized with constant pressure
iter scalar-0
1 1.000000e+00
2 3.386578e-04
3 6.850164e-05
4 1.218787e-05
5 3.071446e-06
6 5.898514e-07
7 1.483115e-07
8 2.794801e-08
9 6.803494e-09
10 1.664232e-09
Hybrid initialization is done.
Save case file#
Save the case file external_compressible1.cas.h5
.
solver.file.write(file_name="external_compressible.cas.h5", file_type="case")
Fast-loading "/ansys_inc/v251/fluent/fluent25.1.0/addons/afd/lib/hdfio.bin"
Done.
Writing to 2c4a6ca1e415:"/mnt/pyfluent/external_compressible.cas.h5" in NODE0 mode and compression level 1 ...
Grouping cells for Laplace smoothing ...
1009880 cells, 1 zone ...
3995325 faces, 6 zones ...
2083869 nodes, 1 zone ...
Done.
Writing boundary layer flags ...
Done.
Done.
Solve for 25 iterations#
Solve for 25 iterations (100 iterations is recommended, however for this example 25 is sufficient).
solver.solution.run_calculation.iterate(iter_count=25)
/home/ansys/actions-runner/_work/pyfluent/pyfluent/src/ansys/fluent/core/session_solver.py:309: DeprecatedSettingWarning: 'solution' is deprecated. Use 'settings.solution' instead.
warnings.warn(
iter continuity x-velocity y-velocity z-velocity energy k omega time/iter
1 1.0000e+00 4.0335e-07 3.8304e-07 8.1691e-07 9.2470e-07 9.9600e-01 4.9891e-01 0:04:32 24
2 1.0000e+00 3.6220e-07 3.4687e-07 6.1131e-07 8.7077e-07 9.9341e-01 4.9823e-01 0:04:14 23
3 1.0000e+00 3.4447e-07 3.6960e-07 5.3973e-07 7.8462e-07 9.8817e-01 4.9711e-01 0:03:59 22
4 1.0000e+00 3.2099e-07 3.9396e-07 5.1410e-07 7.0951e-07 9.7278e-01 4.9524e-01 0:03:41 21
5 1.0000e+00 3.0103e-07 4.0980e-07 5.0372e-07 6.4156e-07 9.3756e-01 4.9201e-01 0:03:24 20
6 1.0300e+00 2.8211e-07 4.1698e-07 4.9810e-07 5.8548e-07 8.4358e-01 4.8629e-01 0:03:09 19
7 1.0394e+00 2.6739e-07 4.1449e-07 4.9097e-07 5.3676e-07 5.7303e-01 4.7582e-01 0:02:55 18
8 1.0287e+00 2.5715e-07 4.0228e-07 4.7789e-07 4.9543e-07 2.9234e-01 4.5621e-01 0:02:43 17
9 1.0054e+00 2.5130e-07 3.8204e-07 4.5921e-07 4.6678e-07 1.3994e-01 4.1971e-01 0:02:31 16
10 9.7975e-01 2.4922e-07 3.5754e-07 4.3792e-07 4.5132e-07 6.6768e-02 3.5659e-01 0:02:21 15
11 9.4738e-01 2.4727e-07 3.3153e-07 4.1589e-07 4.4118e-07 3.3488e-02 2.6515e-01 0:02:11 14
iter continuity x-velocity y-velocity z-velocity energy k omega time/iter
12 9.1232e-01 2.4502e-07 3.0477e-07 3.9250e-07 4.3095e-07 1.8692e-02 1.6522e-01 0:02:02 13
13 8.7797e-01 2.4520e-07 2.7883e-07 3.6764e-07 4.1918e-07 1.2388e-02 8.7038e-02 0:01:53 12
14 8.4088e-01 2.4418e-07 2.5205e-07 3.4001e-07 3.9899e-07 9.4535e-03 4.1059e-02 0:01:41 11
15 8.0849e-01 2.4216e-07 2.2390e-07 3.0915e-07 3.8400e-07 7.5559e-03 1.8468e-02 0:01:30 10
16 7.7903e-01 2.4321e-07 1.9900e-07 2.8224e-07 3.7615e-07 6.1619e-03 8.2983e-03 0:01:19 9
17 7.5550e-01 2.4337e-07 1.7697e-07 2.5946e-07 3.6938e-07 5.1356e-03 3.8478e-03 0:01:10 8
18 7.3927e-01 2.4495e-07 1.5946e-07 2.4136e-07 3.7141e-07 4.3687e-03 1.8890e-03 0:01:02 7
19 7.3206e-01 2.4647e-07 1.4752e-07 2.2830e-07 3.7416e-07 3.7692e-03 1.0003e-03 0:00:53 6
20 7.2046e-01 2.4232e-07 1.3824e-07 2.1719e-07 3.7258e-07 3.2978e-03 5.7585e-04 0:00:44 5
21 7.0008e-01 2.3746e-07 1.3005e-07 2.0521e-07 3.5842e-07 2.9065e-03 3.5926e-04 0:00:36 4
22 6.7301e-01 2.2634e-07 1.2162e-07 1.9204e-07 3.4148e-07 2.5834e-03 2.4031e-04 0:00:27 3
iter continuity x-velocity y-velocity z-velocity energy k omega time/iter
23 6.3985e-01 2.1337e-07 1.1347e-07 1.7679e-07 3.2566e-07 2.2946e-03 1.7007e-04 0:00:18 2
24 5.9642e-01 2.0386e-07 1.0741e-07 1.6071e-07 3.1560e-07 2.0317e-03 1.2572e-04 0:00:09 1
25 5.5051e-01 1.9653e-07 1.0128e-07 1.4510e-07 3.0266e-07 1.7956e-03 9.6212e-05 0:00:00 0
Write final case file and data#
Write the final case file and the data.
solver.file.write(file_name="external_compressible1.cas.h5", file_type="case")
/home/ansys/actions-runner/_work/pyfluent/pyfluent/src/ansys/fluent/core/session_solver.py:309: DeprecatedSettingWarning: 'file' is deprecated. Use 'settings.file' instead.
warnings.warn(
Writing to 2c4a6ca1e415:"/mnt/pyfluent/external_compressible1.cas.h5" in NODE0 mode and compression level 1 ...
Grouping cells for Laplace smoothing ...
1009880 cells, 1 zone ...
3995325 faces, 6 zones ...
2083869 nodes, 1 zone ...
Done.
Writing boundary layer flags ...
Done.
Done.
Close Fluent#
Close Fluent.
solver.exit()
Total running time of the script: (7 minutes 11.863 seconds)