Meshing workflows#

PyFluent provides access to Fluent’s meshing workflows.

Overview#

  • Enhanced Meshing Workflows: A PyFluent API available only when using PyFluent with Ansys Fluent 2026 R1 and later. It provides clearer task organization, easier navigation, and strongly typed, well-documented arguments.

  • Legacy Meshing Workflows: The PyFluent meshing API used prior to Ansys Fluent 2026 R1 remains available. For information on how to enable and use it, see Legacy meshing interface.

Watertight geometry meshing workflow#

Use the Watertight Geometry workflow for watertight CAD geometries that require little cleanup. This is useful for clean geometries prepared in CAD tools such as Ansys SpaceClaim.

Import geometry#

import ansys.fluent.core as pyfluent
from ansys.fluent.core import examples

import_file_name = examples.download_file('mixing_elbow.pmdb', 'pyfluent/mixing_elbow')
meshing_session = pyfluent.launch_fluent(
    mode=pyfluent.FluentMode.MESHING, precision=pyfluent.Precision.DOUBLE, processor_count=2
)
watertight = meshing_session.watertight()
import_geometry = watertight.import_geometry
import_geometry.file_name.set_state(import_file_name)
import_geometry.length_unit.set_state("in")
import_geometry()

Add local sizing#

add_local_sizing = watertight.add_local_sizing_wtm
add_local_sizing.add_child_to_task()
add_local_sizing()

Generate surface mesh#

create_surface_mesh = watertight.create_surface_mesh
create_surface_mesh.cfd_surface_mesh_controls.max_size = 0.3
create_surface_mesh()

Describe geometry#

describe_geometry = watertight.describe_geometry
describe_geometry.update_child_tasks(setup_type_changed=False)
describe_geometry.setup_type = "fluid"
describe_geometry.update_child_tasks(setup_type_changed=True)
describe_geometry()

Update boundaries#

update_boundaries = watertight.update_boundaries
update_boundaries.boundary_zone_list.set_state(["wall-inlet"])
update_boundaries.boundary_label_list.set_state(["wall-inlet"])
update_boundaries.boundary_label_type_list.set_state(["wall"])
update_boundaries.old_boundary_label_list.set_state(["wall-inlet"])
update_boundaries.old_boundary_label_type_list.set_state(["velocity-inlet"])
update_boundaries()

Update regions#

watertight.update_regions()

Add boundary layers#

add_boundary_layers = watertight.add_boundary_layers
add_boundary_layers.add_child_to_task()
add_boundary_layers.control_name.set_state("smooth-transition_1")
add_boundary_layers.insert_compound_child_task()
watertight.add_boundary_layers_child_1()

Generate volume mesh#

create_volume_mesh = watertight.create_volume_mesh_wtm
create_volume_mesh.volume_fill.set_state("poly-hexcore")
create_volume_mesh.volume_fill_controls.hex_max_cell_length.set_state(0.3)
create_volume_mesh()

Switch to solution mode#

solver_session = meshing_session.switch_to_solver()

Fault-tolerant meshing workflow#

Use the Fault-tolerant meshing workflow for complex CAD geometries that need cleanup or modification, such as addressing overlaps, intersections, holes, and duplicates. The following example shows how to use the fault-tolerant workflow.

Import CAD and part management#

Note

API change. For earlier API and compatibility details, see Legacy meshing interface.

import ansys.fluent.core as pyfluent
from ansys.fluent.core import examples

import_file_name = examples.download_file(
    "exhaust_system.fmd", "pyfluent/exhaust_system"
)
meshing_session = pyfluent.launch_fluent(precision=pyfluent.Precision.DOUBLE, processor_count=2, mode=pyfluent.FluentMode.MESHING)

fault_tolerant = meshing_session.fault_tolerant()
fault_tolerant.parts.input_file_changed(
 file_path=import_file_name, ignore_solid_names=False, part_per_body=False
)
fault_tolerant.parts_files.file_manager.load_files()
fault_tolerant.parts.node["Meshing Model"].copy(
    paths=[
        "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/main,1",
        "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/flow-pipe,1",
        "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/outpipe3,1",
        "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/object2,1",
        "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/object1,1",
    ]
)
fault_tolerant.parts.object_setting["DefaultObjectSetting"].one_zone_per.set_state("part")

fault_tolerant.import_cad_and_part_management.context.set_state(0)
fault_tolerant.import_cad_and_part_management.create_object_per.set_state("Custom")
fault_tolerant.import_cad_and_part_management.fmd_file_name.set_state(import_file_name)
fault_tolerant.import_cad_and_part_management.file_loaded.set_state("yes")
fault_tolerant.import_cad_and_part_management.object_setting.set_state("DefaultObjectSetting")
fault_tolerant.import_cad_and_part_management()

Describe geometry and flow#

describe_geometry = fault_tolerant.describe_geometry_and_flow
describe_geometry.add_enclosure.set_state("No")
describe_geometry.close_caps.set_state("Yes")
geom_options = describe_geometry.describe_geometry_and_flow_options
geom_options.advanced_options.set_state(True)
geom_options.extract_edge_features.set_state("Yes")
describe_geometry.flow_type.set_state("Internal flow through the object")
describe_geometry.update_child_tasks(setup_type_changed=False)
describe_geometry()

Enclose fluid regions (capping)#

fault_tolerant.capping.create_patch_preferences.show_in_gui.set_state(False)

enclose_fluid_regions = fault_tolerant.capping
enclose_fluid_regions.patch_name.set_state("inlet-1")
enclose_fluid_regions.selection_type.set_state("zone")
enclose_fluid_regions.zone_selection_list.set_state(["inlet.1"])
enclose_fluid_regions.insert_compound_child_task()
fault_tolerant.capping_child_1()

enclose_fluid_regions.patch_name.set_state("inlet-2")
enclose_fluid_regions.selection_type.set_state("zone")
enclose_fluid_regions.zone_selection_list.set_state(["inlet.2"])
enclose_fluid_regions.insert_compound_child_task()
fault_tolerant.capping_child_2()

enclose_fluid_regions.patch_name.set_state("inlet-3")
enclose_fluid_regions.selection_type.set_state("zone")
enclose_fluid_regions.zone_selection_list.set_state(["inlet"])
enclose_fluid_regions.insert_compound_child_task()
fault_tolerant.capping_child_3()

enclose_fluid_regions.patch_name.set_state("outlet-1")
enclose_fluid_regions.selection_type.set_state("zone")
enclose_fluid_regions.zone_selection_list.set_state(["outlet"])
enclose_fluid_regions.zone_type.set_state("pressure-outlet")
enclose_fluid_regions.insert_compound_child_task()
fault_tolerant.capping_child_4()

Extract edge features#

edge_features = fault_tolerant.extract_edge_features
edge_features.extract_edges_name.set_state("edge-group-1")
edge_features.extract_method_type.set_state("Intersection Loops")
edge_features.object_selection_list.set_state(["flow_pipe", "main"])
edge_features.insert_compound_child_task()
fault_tolerant.extract_edge_features_child_1()

Identify regions#

identify_regions = fault_tolerant.identify_regions
identify_regions.show_coordinates = True
identify_regions.material_points_name.set_state("fluid-region-1")
identify_regions.selection_type.set_state("zone")
identify_regions.x.set_state(377.322045740589)
identify_regions.y.set_state(-176.800676988458)
identify_regions.z.set_state(-37.0764628583475)
identify_regions.zone_selection_list.set_state(["main.1"])
identify_regions.insert_compound_child_task()
fault_tolerant.identify_regions_child_1()

identify_regions.show_coordinates = True
identify_regions.material_points_name.set_state("void-region-1")
identify_regions.new_region_type.set_state("void")
identify_regions.selection_type = "object"
identify_regions.object_selection_list.set_state(["inlet-1", "inlet-2", "inlet-3", "main"])
identify_regions.x.set_state(374.722045740589)
identify_regions.y.set_state(-278.9775145640143)
identify_regions.z.set_state(-161.1700719416913)
identify_regions.insert_compound_child_task()
fault_tolerant.identify_regions_child_2()

Define leakage threshold#

leakage_threshold = fault_tolerant.define_leakage_threshold
leakage_threshold.add_child = "yes"
leakage_threshold.flip_direction = True
leakage_threshold.leakage_name = "leakage-1"
leakage_threshold.plane_direction = "X"
leakage_threshold.region_selection_single = "void-region-1"
leakage_threshold.insert_compound_child_task()
fault_tolerant.define_leakage_threshold_child_1()

Update regions settings#

update_region = fault_tolerant.update_region_settings
update_region.all_region_filter_categories.set_state(["2"] * 5 + ["1"] * 2)
update_region.all_region_leakage_size_list.set_state(["none"] * 6 + ["6.4"])
update_region.all_region_linked_construction_surface_list.set_state(["n/a"] * 6 + ["no"])
update_region.all_region_mesh_method_list.set_state(["none"] * 6 + ["wrap"])
update_region.all_region_name_list.set_state([
            "main",
            "flow_pipe",
            "outpipe3",
            "object2",
            "object1",
            "void-region-1",
            "fluid-region-1",
        ])
update_region.all_region_overset_componen_list.set_state(["no"] * 7)
update_region.all_region_source_list.set_state(["object"] * 5 + ["mpt"] * 2)
update_region.all_region_type_list.set_state(["void"] * 6 + ["fluid"])
update_region.all_region_volume_fill_list.set_state(["none"] * 6 + ["tet"])
update_region.filter_category.set_state("Identified Regions")
update_region.all_region_leakage_size_list.set_state([""])
update_region.all_region_mesh_method_list.set_state(["wrap"])
update_region.all_region_name_list.set_state(["fluid-region-1"])
update_region.all_region_overset_componen_list.set_state(["no"])
update_region.all_region_type_list.set_state(["fluid"])
update_region.all_region_volume_fill_list.set_state(["hexcore"])
update_region.all_region_leakage_size_list.set_state([""])
update_region.all_region_mesh_method_list.set_state(["wrap"])
update_region.all_region_name_list.set_state(["fluid-region-1"])
update_region.all_region_overset_componen_list.set_state(["no"])
update_region.all_region_type_list.set_state(["fluid"])
update_region.all_region_volume_fill_list.set_state(["tet"])
update_region()

Choose mesh control options#

mesh_control = fault_tolerant.setup_size_controls
mesh_control.local_settings_name = "default-curvature"
mesh_control.local_size_control_parameters.sizing_type = "curvature"
mesh_control.object_selection_list = [
    "inlet-1",
    "inlet-2",
    "inlet-3",
]
mesh_control.add_child_and_update(defer_update=False)
mesh_control.local_settings_name = "default-proximity"
mesh_control.local_size_control_parameters.sizing_type = "proximity"
mesh_control.object_selection_list = [
    "inlet-1",
    "inlet-2",
    "inlet-3",
]
mesh_control.add_child_and_update(defer_update=False)
fault_tolerant.choose_mesh_control_options()

Generate surface mesh#

fault_tolerant.generate_surface_mesh()

Update boundaries#

fault_tolerant.update_boundaries()

Add boundary layers#

add_boundary_layer = fault_tolerant.add_boundary_layers
add_boundary_layer.control_name.set_state("aspect-ratio_1")
add_boundary_layer.insert_compound_child_task()
fault_tolerant.add_boundary_layers_child_1()

Generate volume mesh#

create_volume_mesh = fault_tolerant.create_volume_mesh_ftm
create_volume_mesh.all_region_name_list.set_state([
            "main",
            "flow_pipe",
            "outpipe3",
            "object2",
            "object1",
            "void-region-1",
            "fluid-region-1",
        ])
create_volume_mesh.all_region_size_list.set_state(["11.33375"] * 7)
create_volume_mesh.all_region_volume_fill_list.set_state(["none"] * 6 + ["tet"])
create_volume_mesh()

Switch to solution mode#

solver_session = meshing_session.switch_to_solver()

2D meshing workflow#

Use the 2D meshing workflow to mesh specific two-dimensional geometries. The example below demonstrates the workflow.

Import geometry#

import ansys.fluent.core as pyfluent
from ansys.fluent.core import examples

import_file_name = examples.download_file('NACA0012.fmd', 'pyfluent/airfoils')
meshing_session = pyfluent.launch_fluent(
    mode=pyfluent.FluentMode.MESHING, precision=pyfluent.Precision.DOUBLE, processor_count=2
)
two_dim_mesh = meshing_session.two_dimensional_meshing()

load_cad = two_dim_mesh.load_cad_geometry
load_cad.file_name = import_file_name
load_cad.length_unit = "mm"
load_cad.refaceting.refacet = False
load_cad()

Set regions and boundaries#

update_boundaries = two_dim_mesh.update_boundaries
update_boundaries.selection_type = "zone"
update_boundaries()

Define global sizing#

global_sizing = two_dim_mesh.define_global_sizing
global_sizing.curvature_normal_angle = 20
global_sizing.max_size = 2000.0
global_sizing.min_size = 5.0
global_sizing.size_functions = "Curvature"
global_sizing()

Adding BOI#

add_local_sizing = two_dim_mesh.add_local_sizing_wtm
add_local_sizing.add_child = "yes"
add_local_sizing.boi_control_name = "boi_1"
add_local_sizing.boi_execution = "Body Of Influence"
add_local_sizing.boi_face_label_list = ["boi"]
add_local_sizing.boi_size = 50.0
add_local_sizing.boi_zoneor_label = "label"
add_local_sizing.draw_size_control = True
add_local_sizing.add_child_and_update(defer_update=False)

Set edge sizing#

add_local_sizing.add_child = "yes"
add_local_sizing.boi_control_name = "edgesize_1"
add_local_sizing.boi_execution = "Edge Size"
add_local_sizing.boi_size = 5.0
add_local_sizing.boi_zoneor_label = "label"
add_local_sizing.draw_size_control = True
add_local_sizing.edge_label_list = ["airfoil-te"]
add_local_sizing.add_child_and_update(defer_update=False)

Set curvature sizing#

add_local_sizing.add_child = "yes"
add_local_sizing.boi_control_name = "curvature_1"
add_local_sizing.boi_curvature_normal_angle = 10
add_local_sizing.boi_execution = "Curvature"
add_local_sizing.boi_max_size = 2
add_local_sizing.boi_min_size = 1.5
add_local_sizing.boi_scope_to = "edges"
add_local_sizing.boi_zoneor_label = "label"
add_local_sizing.draw_size_control = True
add_local_sizing.edge_label_list = ["airfoil"]
add_local_sizing.add_child_and_update(defer_update=False)

Add boundary layer#

add_boundary_layers = two_dim_mesh.add_2d_boundary_layers
add_boundary_layers.add_child = "yes"
add_boundary_layers.control_name = "aspect-ratio_1"
add_boundary_layers.number_of_layers = 4
add_boundary_layers.offset_method_type = "aspect-ratio"
add_boundary_layers.add_child_and_update(defer_update=False)

Generate surface mesh#

# NOTE: Setting `show_advanced_options = True` is required to configure advanced preferences.
# This dependency may be removed in a future release as the API evolves.
generate_surface_mesh = two_dim_mesh.generate_initial_surface_mesh
mesh_preferences = two_dim_mesh.generate_initial_surface_mesh.surface_2d_preferences
mesh_preferences.show_advanced_options = True
mesh_preferences.merge_edge_zones_based_on_labels = "no"
mesh_preferences.merge_face_zones_based_on_labels = "no"
generate_surface_mesh()

two_dim_mesh.add_2d_boundary_layers_child_1.revert()
two_dim_mesh.add_2d_boundary_layers_child_1.add_child = "yes"
two_dim_mesh.add_2d_boundary_layers_child_1.control_name = "uniform_1"
two_dim_mesh.add_2d_boundary_layers_child_1.first_layer_height = 2
two_dim_mesh.add_2d_boundary_layers_child_1.number_of_layers = 4
two_dim_mesh.add_2d_boundary_layers_child_1.offset_method_type = "uniform"
two_dim_mesh.add_2d_boundary_layers_child_1()


# NOTE: Setting `show_advanced_options = True` is required to configure advanced preferences.
# This dependency may be removed in a future release as the API evolves.
mesh_preferences.show_advanced_options = True
mesh_preferences.merge_edge_zones_based_on_labels = "no"
mesh_preferences.merge_face_zones_based_on_labels = "no"
generate_surface_mesh()

Switch to solution mode#

Switching to solver is not allowed in 2D Meshing mode.

Creating new meshing workflow#

Use create_workflow() to build a custom workflow. The example below demonstrates how to create and populate a workflow.

Create workflow#

import ansys.fluent.core as pyfluent
from ansys.fluent.core import examples

import_file_name = examples.download_file('mixing_elbow.pmdb', 'pyfluent/mixing_elbow')
meshing_session = pyfluent.launch_fluent(
    mode=pyfluent.FluentMode.MESHING, precision=pyfluent.Precision.DOUBLE, processor_count=2
)
created_workflow = meshing_session.create_workflow()

Insert first task#

created_workflow.insertable_tasks.import_geometry.insert()
created_workflow.import_geometry.file_name.set_state(import_file_name)
created_workflow.import_geometry.length_unit.set_state('in')
created_workflow.import_geometry()

Insert next task#

created_workflow.import_geometry.insertable_tasks.add_local_sizing.insert()
created_workflow.add_local_sizing_wtm()

Loading a saved meshing workflow#

Use load_workflow() to load and execute a previously saved workflow.

Load workflow#

import ansys.fluent.core as pyfluent
from ansys.fluent.core import examples

saved_workflow_path = examples.download_file(
    "sample_watertight_workflow.wft", "pyfluent/meshing_workflows"
)
meshing_session = pyfluent.launch_fluent(
    mode=pyfluent.FluentMode.MESHING, precision=pyfluent.Precision.DOUBLE, processor_count=2
)
loaded_workflow = meshing_session.load_workflow(file_path=saved_workflow_path)

Insert new task#

Tasks can be inserted into a workflow using an object-oriented approach.

import ansys.fluent.core as pyfluent

meshing_session = pyfluent.launch_fluent(
    mode=pyfluent.FluentMode.MESHING, precision=pyfluent.Precision.DOUBLE, processor_count=2
)
watertight = meshing_session.watertight()
watertight.import_geometry.insertable_tasks()
watertight.import_geometry.insertable_tasks.set_up_rotational_periodic_boundaries.insert()

Duplicate tasks#

ig = watertight.import_geometry
ig.insertable_tasks.import_boi_geometry.insert()
ig.insertable_tasks.import_boi_geometry.insert()
ig.insertable_tasks.import_boi_geometry.insert()
assert watertight.import_boi_geometry.arguments()
assert watertight.import_boi_geometry_1.arguments()
assert watertight.import_boi_geometry_2.arguments()

Note

Enhanced Meshing Workflows also supports indexed access to duplicate tasks:

>>> watertight.import_boi_geometry
task < import_boi_geometry: 0 >
>>> watertight.import_boi_geometry[0]
task < import_boi_geometry: 0 >
>>> watertight.import_boi_geometry[1]
task < import_boi_geometry: 1 >
>>> watertight.import_boi_geometry[2]
task < import_boi_geometry: 2 >

Index 0 returns the first instance; calling the task or indexing with 0 are equivalent.

After inserting the tasks above, the workflow contains:

>>> watertight.children()
[task < import_geometry: 0 >,
 task < import_boi_geometry: 2 >,
 task < import_boi_geometry: 1 >,
 task < import_boi_geometry: 0 >,
 task < add_local_sizing_wtm: 0 >,
 task < create_surface_mesh: 0 >,
 task < describe_geometry: 0 >,
 task < update_regions: 0 >,
 task < add_boundary_layers: 0 >,
 task < create_volume_mesh_wtm: 0 >]

Current meshing workflow#

Use the current_workflow property to access the active workflow.

Current workflow#

meshing_session.current_workflow

Note

current_workflow raises an attribute error if no workflow has been initialized.

Mark as updated#

Use the mark_as_updated() to explicitly mark a task as updated.

watertight.import_geometry.mark_as_updated()

Renaming tasks in workflow#

In Enhanced Meshing Workflow the display name update is decoupled from the Python attribute access:

Note

Behavior change. Display name changes do not affect attribute access. For legacy rename behavior, see Legacy meshing interface.

>>> watertight.import_geometry.rename(new_name="IG")
>>> watertight.import_geometry["IG"]
task < import_geometry: 0 >
>>> watertight.import_geometry
task < import_geometry: 0 >
>>> watertight.import_geometry[0]
task < import_geometry: 0 >

This allows non-Pythonic display names (for example, “I-G”) without affecting attribute access.

Deleting tasks from workflow#

Tasks can be deleted individually or in groups. In Enhanced Meshing Workflow, pass task objects to list_of_tasks:

Note

Behavior change. Delete-by-name (strings) is replaced by passing task objects. Calling task.delete() still works. See Legacy meshing interface for earlier usage.

watertight.delete_tasks(
     list_of_tasks=[
         watertight.create_volume_mesh_wtm,
         watertight.add_boundary_layers,
      ]
 )
watertight.update_regions.delete()

Duplicate tasks can also be deleted via indexing:

ig = watertight.import_geometry
ig.insertable_tasks.import_boi_geometry.insert()
ig.insertable_tasks.import_boi_geometry.insert()

del watertight.import_boi_geometry[1]
watertight.import_boi_geometry.delete()
del watertight.create_regions

Workflow navigation enhancements#

The refined API enables straightforward traversal of tasks within a workflow:

Note

New in Enhanced Meshing Workflow. This capability is not available in the legacy interface.

>>> watertight = meshing.watertight()

>>> task_1 = watertight.first_child()
>>> task_1.has_parent()
True
>>> task_1.parent()
<ansys.fluent.core.meshing.meshing_workflow_new.WatertightMeshingWorkflow at 0x22931166000>
>>> task_1.has_previous()
False  # As this is the first task in the workflow
>>> task_1.has_next()
True
>>> assert task_1.first_child() is None  # It is a simple task with no children
>>> assert task_1.last_child() is None

>>> task_2 = task_1.next()
>>> task_2
task < add_local_sizing_wtm: 0 >

>>> task_4 = task_2.next().next()
>>> task_4
task < describe_geometry: 0 >
>>> task_4_1 = task_4.first_child()  # It is a compound task with children
>>> task_4_1
task < capping: 0 >

>>> task_7 = watertight.last_child()
>>> task_7
task < create_volume_mesh_wtm: 0 >

>>> task_7.has_previous()
True
>>> task_6 = task_7.previous()
>>> task_6
task < add_boundary_layers: 0 >

This enables navigation without relying on Python attribute names.

Known limitations#

In Enhanced Meshing Workflow, the following operations are not supported within a single meshing session: - Switching from one meshing workflow to another. - Re-initializing a meshing workflow after it has already been initialized.

To perform either operation, start a new meshing session and initialize the required workflow.