Use PyCFX sessions#

PyCFX provides three types of session objects:

  • PreProcessing: Connects to CFX-Pre to set up simulations.

  • Solver: Controls the CFX-Solver.

  • PostProcessing: Connects to CFD-Post to postprocess simulation results.

For an overview of these session objects, see the User guide.

Each PyCFX session object exposes a hierarchy of Python settings objects that provide access to the underlying CFX setup and tools. For example, both the PreProcessing and PostProcessing session objects have a child setup object, which contains the CFX setup in a hierarchy that corresponds to the CFX Command Language (CCL) structure of CFX-Pre or CFD-Post, respectively. They also have a child file object, which provides actions that broadly correspond to the functions accessible from the CFX-Pre or CFD-Post File menus.

Each settings object that is a child of the setup object represents a CCL object or parameter, or a related function. For example, pypre.setup.flow['Flow Analysis 1'].analysis_type.option represents the following CCL parameter:

FLOW: Flow Analysis 1
  ANALYSIS TYPE:
    Option = Steady State
  END
END

When Python settings objects are created, their names are derived from the related CCL object types and parameter names by converting to lowercase and replacing spaces with underscores. Named object names (such as Flow Analysis 1) and parameter values (such as Steady State) remain unchanged from CCL.

All settings objects share a uniform interface with methods like get_state(), set_state(), and is_active(). Additional methods such as allowed_values(), min(), and max() are available for relevant objects.

All of the following examples assume that you have initialized a PreProcessing session object named pypre with a suitable case (for example, the Static mixer example).

>>> import ansys.cfx.core as pycfx
>>> pypre = pycfx.PreProcessing.from_install()
>>> pypre.file.open_case(file_name = <case_name>)

# Retrieve the parameter value
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option()
'Steady State'

# Find out the allowed values
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option.allowed_values()
['Steady State', 'Transient', 'Transient Blade Row']

# Set the Analysis Type option
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option = "Transient"

# get_state() can also be used to get the parameter value
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option.get_state()
'Transient'

# Invalid values cannot be set
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option.set_state("Invalid Value")
Traceback (most recent call last):
  ...
RuntimeError: Parameter value 'Option' for object '/FLOW:Flow Analysis 1/ANALYSIS TYPE' is not allowed.

Some items in the settings object hierarchy are methods that you call to request a particular action in PyCFX:

>>> pypre.file.save_picture(file_name = "Image.png")

Settings object types#

A settings object can be one of the primitive types such as: Integer, Real, String, and Boolean. A settings object can also be one of the two types of container objects: Group and NamedObject.

  • The Group type is a static container with predefined child objects that you can access as attributes, for example, pypre.setup.flow['Flow Analysis 1'].analysis_type or pypre.setup.flow['Flow Analysis 1']. The names of the child objects of a group can be accessed via <Group>.child_names. Within the PyCFX session setup object, Group objects correspond directly to CCL objects.

  • The NamedObject type is a container holding dynamically created named Group objects. For a given NamedObject container, each contained Group object is of the same specific CCL type. A given named Group object can be accessed using the index operator. For example, pypre.setup.flow['Flow Analysis 1'] yields a flow object with the name Flow Analysis 1, assuming it exists. The current list of named Group object children can be accessed using the <NamedObject>.get_object_names() method. Note that these NamedObject containers do not correspond to any CCL object but represent an intermediate layer. However, their contained named Group objects do correspond to CCL objects.

Object state#

You can access the state of any object by “calling” it. This returns the state of the children as a dictionary for Group and NamedObject types.

>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option()
'Transient'
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.get_state() == {
...   'option': 'Transient',
...   'external_solver_coupling': {'option': 'None'},
...   'time_duration': {'option': 'Total Time', 'total_time': '-- Undefined --'},
...   'initial_time': {'option': 'Automatic with Value', 'time': '0 [s]'},
...   'time_steps': {'option': 'Timesteps', 'timesteps': '-- Undefined --'}}
True

To modify the state of any object, you can assign the corresponding attribute in its parent object. This assignment can be done at any level. For Group and NamedObject types, the state value is a dictionary.

>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option = "Transient"

You can also access the state of an object with the get_state() method and modify it with the set_state() method.

Real, RealTriplet, and RealList settings objects incorporate units alongside values. If the object has units (not dimensionless), you must set its value as a string including the unit. Setting the value as a float is not supported. For example:

>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.time_duration.total_time = "2.0 [s]"

You can print the current state in a simple text format with the print_state() method. For example:

>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.print_state()

option : Transient
external_solver_coupling :
  option : None
time_duration :
  option : Total Time
  total_time : 2.0 [s]
initial_time :
  option : Automatic with Value
  time : 0 [s]
time_steps :
  option : Timesteps
  timesteps : -- Undefined --

Expressions, expert parameters, and user data#

In CFX, expressions are CCL parameters:

LIBRARY:
  CEL:
    EXPRESSIONS:
      MyPressure = 2 * OpeningPressure
      OpeningPressure = 101325 [Pa]
    END
  END
END

However, in PyCFX, each expression is a Group object within the expressions container. Expression values must be set with the definition attribute. Examples of creating and using expressions follow.

>>> pypre.setup.library.cel.expressions.create("MyPressure")
<ansys.cfx.core... object at 0x...>
>>> pypre.setup.library.cel.expressions['MyPressure'].definition = "2 * OpeningPressure"
>>> pypre.setup.library.cel.expressions['OpeningPressure'] = {"definition": "101325 [Pa]"}
>>> pypre.setup.library.cel.expressions.get_state()
{'MyPressure': {'definition': '2 * OpeningPressure'}, 'OpeningPressure': {'definition': '101325 [Pa]'}}
>>> print(pypre.setup.library.cel.expressions.list_properties())
LIBRARY:
  CEL:
    EXPRESSIONS:
      MyPressure = 2 * OpeningPressure
      OpeningPressure = 101325 [Pa]
    END
  END
END

Other commands relating to expressions can be found by using the dir() function on the expressions container.

Similar behavior exists for other objects that have parameters that can be given a user-defined name, for example, the EXPERT PARAMETERS and USER CCL objects in CFX-Pre.

Commands#

Commands are methods of settings objects that you use to modify the state of the session, for example, the open_case() method of the pypre.file object. The get_active_command_names() method of a settings object provides the names of the object’s currently available commands.

If keyword arguments are needed, you can use commands to pass them. To access a list of valid arguments, use the argument_names attribute. If you do not specify an argument, its default value is used. Arguments are also settings objects and can be of either the primitive or container type.

Queries#

Queries are methods of settings objects that you use to query the state of the session, for example, the get_physics_messages() method of many of the PreProcessing settings objects. The query_names attribute of a settings object provides the names of the object’s currently available queries.

If keyword arguments are needed, you can use queries to pass them. To access a list of valid arguments, use the argument_names attribute. If you do not specify an argument, its default value is used. Arguments are also settings objects and can be of either the primitive or container type.

Additional metadata#

Settings object methods are provided to access some additional attributes (metadata). There are a number of explicit methods and two generic methods: get_attr() and get_attrs().

The following example shows how to use the two generic methods get_attr() and get_attrs() to get the list of allowed values for a particular Option parameter in PyCFX. Additionally, the example uses the explicit method for this attribute: allowed_values(). All string and string list objects have an allowed_values() method, which returns a list of allowed string values if such a constraint currently applies for that object. Otherwise, it returns None.

>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option.get_attr('allowed-values')
['Steady State', 'Transient', 'Transient Blade Row']
>>>
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option.get_attrs(['allowed-values'])
{'allowed-values': ['Steady State', 'Transient', 'Transient Blade Row']}
>>>
>>> pypre.setup.flow['Flow Analysis 1'].analysis_type.option.allowed_values()
['Steady State', 'Transient', 'Transient Blade Row']

The following table contains attribute names, corresponding methods to access the attribute, whether the method can return None, applicable object types, and returned data types:

Attribute name

Method

Can return None

Type applicability

Metadata type

is-active?

is_active

No

All

bool

is-read-only?

is_read_only

No

All

bool

default-value

default

Yes

All primitives

Type of primitive

allowed-values

allowed_values

Yes

str, str list

str list

min

min

Yes

int, float

int or float

max

max

Yes

int, float

int or float

Using the get_attr() method requires knowledge of attribute names, their applicability, and the ability to interpret the raw values of the attribute. You can avoid all these requirements by using the explicitly named methods. Note that the attribute values are dynamic, which means values can change based on the session state. A None value signifies that no value is currently designated for this attribute.

Active objects, commands, and queries#

Objects, commands, and queries can be active or inactive based on the session state. The is_active() method returns True if an object, command, or query is currently active.

For the PreProcessing session, objects become active or inactive depending on their physical availability. So, a turbulence model setting on a boundary is inactive if the domain does not include a turbulence model.

The get_active_child_names() method returns a list of active children, including both CCL objects and parameters:

>>> pypre.setup.flow['Flow Analysis 1'].domain['Default Domain'].get_active_child_names()
['location', 'domain_type', 'coord_frame', 'number_of_passages_in_360', 'number_of_passages_in_component', 'fluid_definition', 'domain_models', 'fluid_models', 'boundary', 'initialisation', 'solver_control']

The get_active_command_names() or get_active_query_names method returns the list of active commands or queries:

>>> pypre.file.get_active_command_names()
['close_case', 'export_ccl', 'import_mesh', 'new_case', 'open_case', 'save_case', 'save_picture', 'write_solver_input_file']
>>>
>>> pypre.setup.get_active_query_names()
['get_physics_messages']

PreProcessing session details#

The PreProcessing session object has some unique behaviors that are designed to make it easy to set up complex CFD simulations.

Physics messages#

A complex simulation setup can be difficult to set up correctly because many parameters and objects are interdependent and any change could require other updates. At any time, you can check whether your setup is physically valid by calling the get_physics_messages() method of any PreProcessing settings object that is a child of the setup object. For example, to check the entire setup: pypre.setup.get_physics_messages(). Or, to check a specific domain: pypre.setup.flow['Flow Analysis 1'].domain['Default Domain'].get_physics_messages(). The messages returned can be filtered by severity level (All, Beta, Information, Warning, and Error).

Physics updates#

In a PreProcessing session, changing one value (for example, Boundary Type) can require large numbers of dependent objects and parameters to be updated. For the PreProcessing session to be usable, the session incorporates physics updates, which update the necessary dependent objects when any parameter value or other change is made.

For example, a case with Turbulence Model set to k-Epsilon must have a Wall Function set to Scalable as this is the only valid Wall Function for the k-Epsilon model. If you later set Turbulence Model to Shear Stress Transport, the Wall Function must be updated to Automatic as this is the only allowed Wall Function option for the Shear Stress Transport model. The physics updates in the PreProcessing session automatically makes this change.

If you are familiar with the CFX-Pre user interface, then the easiest way to understand the physics updates is to imagine opening the editor for the object that you want to change and making the same parameter or object change. For example, if you open the Domain editor for a case with Turbulence Model set to k-Epsilon, then the Wall Function must be set to Scalable. If you then change Turbulence Model to Shear Stress Transport, you can see that the Wall Function option, further down the panel, automatically updates to Automatic.

Physics updates are limited to the top-level objects. For example, changing a parameter in a domain does not update a boundary condition object, only other dependent objects within the domain. Top-level objects are those that have their own editors in CFX-Pre, such as for the Domain, Boundary, Initial Conditions, and Execution Control.

>>> pypre.setup.flow['Flow Analysis 1'].domain['Default Domain'].fluid_models.print_state()

heat_transfer_model :
  option : Thermal Energy
turbulence_model :
  option : k epsilon
turbulent_wall_functions :
  option : Scalable
thermal_radiation_model :
  option : None
combustion_model :
  option : None

>>> pypre.setup.flow['Flow Analysis 1'].domain['Default Domain'].fluid_models.turbulence_model.option = "SST"
>>> pypre.setup.flow['Flow Analysis 1'].domain['Default Domain'].fluid_models.print_state()

heat_transfer_model :
  option : Thermal Energy
turbulence_model :
  option : SST
turbulent_wall_functions :
  option : Automatic
thermal_radiation_model :
  option : None
combustion_model :
  option : None

The turbulent_wall_functions option was automatically updated from Scalable to Automatic by the physics update.

Note

For CFX versions up to and including 2026 R1, if a state is supplied as a dictionary, the physics updates are not applied and the state is applied as-is. The PreProcessing session may be left in an invalid physical state following such an update. You should check for any physics warnings or errors.

Optional objects and parameters#

The CCL structure in the PreProcessing session is more complex than those of the other session types. Some parameters and objects are optional, and their existence (or lack thereof) affects the setup.

To add an optional parameter, simply set its value to the desired value. To remove an optional parameter, set the value to None. For example, this code adds and then removes the Coord Frame parameter in a boundary object:

>>> in1 = pypre.setup.flow["Flow Analysis 1"].domain["Default Domain"].boundary["in1"]
>>> in1.print_state()

boundary_type : INLET
location : in1
boundary_conditions :
  ...
>>> in1.coord_frame = "Coord 0"  # Add the optional Coord Frame parameter
>>> in1.print_state()

interface_boundary : False
boundary_type : INLET
location : in1
coord_frame : Coord 0
boundary_conditions :
  ...
>>> in1.coord_frame = None  # Remove the optional Coord Frame parameter
>>> in1.print_state()

interface_boundary : False
boundary_type : INLET
location : in1
boundary_conditions :
  ...

To add or remove an optional object, it must be explicitly enabled or disabled. For example, this code enables and then disables the Boundary Contour object for a boundary:

>>> in1 = pypre.setup.flow["Flow Analysis 1"].domain["Default Domain"].boundary["in1"]
>>> in1.print_state()

interface_boundary : False
boundary_type : INLET
location : in1
boundary_conditions :
  ...
>>> in1.boundary_contour.enabled = True # Enable the optional Boundary Contour object
>>> in1.print_state()

interface_boundary : False
boundary_type : INLET
location : in1
boundary_conditions :
  ...
boundary_contour :
  profile_variable : Normal Speed
>>> in1.boundary_contour.enabled = False # Disable the optional Boundary Contour object
>>> in1.print_state()

interface_boundary : False
boundary_type : INLET
location : in1
boundary_conditions :
  ...

Optional named objects are named objects that you can explicitly create but only with specific names. They are uncommon in the PreProcessing session. You can create these named objects in the same way as other named objects, for example, by using the create() method of the parent NamedObject container. To remove an optional named object, use the Python del keyword.

>>> pypre.setup.library.additional_variable.create('Additional Variable 1')
<ansys.cfx.core... object at 0x...>
>>> fluid_models_obj = pypre.setup.flow["Flow Analysis 1"].domain["Default Domain"].fluid_models
>>> fluid_models_obj.additional_variable["Additional Variable 1"] = {}
>>> del fluid_models_obj.additional_variable["Additional Variable 1"]

Note that if you use the set_state() method to apply the state as a dictionary, optional objects or parameters omitted from the dictionary are not removed from the PreProcessing state. You must explicitly remove them.

Solver session details#

For the initial release of PyCFX with Ansys CFX 2025 R2, the Solver object is very limited and does not implement a hierarchy of settings objects.

Solver-specific settings, such as parallel settings, precision settings, and initial conditions, must be set up as Execution Control in the PreProcessing session.

The only available settings object is solution, which provides access to a minimal set of solver controls.

>>> pysolve = pycfx.Solver.from_install(solver_input_file_name=solver_input_file_name)
>>> pysolve.solution.start_run()
...
>>> pysolve.solution.is_running()
True
>>> pysolve.solution.wait_for_run() # To wait for the solver run to complete.

Other available methods can be found in the Solver Controller module.

PostProcessing session details#

Long calculations#

Some operations in a PostProcessing session can take a significant amount of time to complete if a large or complex case is loaded. A example is the generation (calculation) of a plane or contour. For maximum efficiency, you need to avoid unnecessary recalculations such as calculating updates to an object before you have finished setting it up.

Suppose you create a plane with this code:

>>> pypost = pycfx.PostProcessing.from_install()
>>> pypost.file.load_results(file_name=<results_name>)
>>> pypost.results.plane.create("Plane 1")
<ansys.cfx.core... object at 0x...>
>>> plane1 = pypost.results.plane["Plane 1"]
>>> plane1.option = "ZX Plane"
>>> plane1.plane_type = "Slice"

The plane update calculation is performed three times: once when the plane is created, again with the default settings, and then finally when the option and plane_type are modified.

These unnecessary calculations can be reduced or avoided in two ways. One way is to suspend the plane object until it is complete:

>>> pypost.results.plane.create("Plane 2")
<ansys.cfx.core... object at 0x...>
>>> plane1 = pypost.results.plane["Plane 2"]
>>> plane1.suspend()  # Suspend update calculations for the plane
>>> plane1.option = "ZX Plane"
>>> plane1.plane_type = "Slice"
>>> plane1.unsuspend()  # The plane is recalculated when it is unsuspended

The other way to avoid unneeded calculations is to set up the plane with all the desired parameters in a single dictionary when it is created:

>>> pypost.results.plane["Plane 3"] = {
...   "option": "ZX Plane",
...   "plane_type": "Slice"
... }

Active objects, commands, and queries#

For the initial release of PyCFX with Ansys CFX 2025 R2, all objects and parameters of the PostProcessing session are always active. For example, you can set the X parameter for a plane with the option set to XY, even though the Z parameter is the only relevant parameter for this option. Parameters and objects that are not relevant are ignored by CFD-Post.