Skip to content

chore: Update examples to use modern API#4887

Draft
Gobot1234 wants to merge 10 commits into
mainfrom
jhilton/example-improvements
Draft

chore: Update examples to use modern API#4887
Gobot1234 wants to merge 10 commits into
mainfrom
jhilton/example-improvements

Conversation

@Gobot1234

@Gobot1234 Gobot1234 commented Feb 4, 2026

Copy link
Copy Markdown
Collaborator

Context

The examples are currently not following best practices as described by @seanpearsonuk now they do (I hope).

They should also type check better once all the PRs for these things are merged (units, vis and pyfluent), there are a couple of examples which locally have less that 10 issues (I copied over the typing changes from the aformentioned libraries and turned off a couple of checks that currently haven't been fixed) which is a massive improvement IMO

Mostly untested and not currently functional due to various settings API and other github side pull requests not being merged or fixed

Change Summary

  • Use the much more descriptive object oriented API with ORM style create() and get() methods that are more clear in intent
  • I've tried to get rid of TUI based examples and where not possible I've at least described what the parameters are
  • I've colocated the units next to their values
  • Removed the dictionary state assignment based APIs in favour of direct attribute access as it will leave users in a more recoverable state and is easier to type (both type hinting and on the keyboard)
  • Used tuples for vectors rather than lists to allow for better type hinting in the future checking 2D vs 3D cases
  • Used pathlib instead of os.path
  • Added calls to solver.upload(filename) after the example is downloaded if the mode is Meshing for based workflows
  • Changed all the lanuch_fluent to it's appropriate ModeClass.from_install
  • Stored the results of create() and use that to apply next variable assignments if appropriate rather than performing another lookup
  • I've tried to reduce the stringly-typedness of the API by reusing objects (where things are explicitly suffixed with name I've tried to use the name() method though. In practice though i don't like this and we should be instead passing round the full objects e.g. custom_field_function_name=omega_r.name() where omega_r is a custom_field_function. I think it makes more sense to pass a str | custom_field_function to a parameter called custom_field_function than passing the same type to custom_field_function_name which would work if you use another one of my PRs)
  • I've tried to update fields to use VariableCatalog though many are missing due to the fields not existing in VariableCatalog or VariableCatalog.fluent
  • Improved general pythonicness of code/algorithms/loops etc

Rationale

We want the examples to be the best things for customers to learn from

NB I've updated some of the examples @MohammedAnsys has PRs open for that looked like they were ready for merging
NBB I 've not switched the save locations for all these to examples_path, though that might be a good idea in the future

…functional due to various settings API and other github side pull requests not being merged or fixed

- We use the much more descriptive object oriented API with ORM style `create()` and `get()` methods that are more clear in intent
- I've tried to get rid of TUI based examples and where not possible I've at least described what the parameters are
- I've colocated the units next to their values
- Removed the dictionary state assignment based APIs in favour of direct attribute access as it will leave users in a more recoverable state and is easier to type (both type hinting and on the keyboard)
- Used tuples for vectors rather than lists to allow for better type hinting in the future checking 2D vs 3D cases
- Used pathlib instead of os.path
- Added calls to solver.upload(filename) after the example is downloaded if the mode is Meshing for based workflows
- Changed all the pyfluent.lanuch_fluent to it's appropriate pyfluent.ModeClass.from_install
- Stored the results of .create()  and use that to apply next variable assignments if appropriate rather than performing another lookup
- I've tried to reduce the stringly-typedness of the API by reusing objects (where things are explicitly suffixed with name I've tried to use the `name()` method though. In practice though i don't like this and we should be instead passing round the full objects e.g. `custom_field_function_name=omega_r.name()` where `omega_r` is a `custom_field_function`. I think it makes more sense to pass a str | custom_field_function to a parameter called `custom_field_function` than passing the same type to `custom_field_function_name` which would work if you use another one of my PRs)
- I've tried to update fields to use VariableCatalog though many are missing due to the fields not existing in VariableCatalog or VariableCatalog.fluent
- Improved general pythonicness of code/algorithms/loops etc

NB I've updated some of the examples @MohammedAnsys has PRs open for that looked like they were ready for merging
NBB I 've not switched the save locations for all these to examples_path, though that might be a good idea in the future
@github-actions github-actions Bot added documentation Documentation related (improving, adding, etc) examples Publishing PyFluent examples labels Feb 4, 2026
@Gobot1234 Gobot1234 changed the title Update examples to use modern API chore: Update examples to use modern API Feb 4, 2026
@github-actions github-actions Bot added the enhancement Improve any current implemented feature label Feb 4, 2026

@Gobot1234 Gobot1234 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will finish review later

Comment thread examples/00-fluent/battery_pack.py Outdated
Comment thread examples/00-fluent/battery_pack.py Outdated
Comment on lines +205 to +209
busbar_material = SolidMaterial.create(
solver, name="busbar_material", chemical_formula="bus"
)
busbar_material.uds_diffusivity.option = "value"
busbar_material.uds_diffusivity.value = 3.541e7 * S / m # Copper-like conductivity

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
busbar_material = SolidMaterial.create(
solver, name="busbar_material", chemical_formula="bus"
)
busbar_material.uds_diffusivity.option = "value"
busbar_material.uds_diffusivity.value = 3.541e7 * S / m # Copper-like conductivity
busbar_material = SolidMaterial.create(
solver,
name="busbar_material",
chemical_formula="bus",
uds_diffusivity=3.541e7 * S / m, # Copper-like conductivity
)

honestly would be surprised this didn't work

Comment on lines -224 to -225
# '*bar*' matches any zone containing 'bar',
# '|*tabzone*' matches any zone containing 'tabzone' → OR logic

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted because it should be explained further up what this does

Comment thread examples/00-fluent/battery_pack.py Outdated
Comment thread examples/00-fluent/battery_pack.py Outdated
regolith_reports = [
report_defs.surface.create(
name=f"regolith-layer-{i}-temp",
report_type="surface-facetavg",

@Gobot1234 Gobot1234 Feb 4, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NB check if there's enums for these cause I don't think there are, do we need to auto gen them? (#4891)

Comment on lines +61 to +63
from ansys.fluent.core.generated.solver.settings_builtin import Fluxes, Vector
from ansys.fluent.core.generated.solver.settings_builtin_261 import Materials, read_case
from ansys.fluent.core.solver import (

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import merge needed

Comment on lines +85 to +94
from ansys.fluent.core.generated.solver.settings_builtin import (
BoundaryCondition,
Mesh,
PlaneSurface,
ReportFile,
ReportPlot,
Residual,
)
from ansys.fluent.core.generated.solver.settings_builtin_261 import write_case, write_case_data
from ansys.fluent.core.solver import (

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge imports again

]
general = General(solver)
general.operating_conditions.gravity.enable = True
general.operating_conditions.gravity.components = [0.0, 0.0, -g]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be tuple

Comment on lines -294 to -297
# Residuals criteria
residuals_options = solver_session.settings.solution.monitor.residual
residuals_options.equations["continuity"].absolute_criteria = 0.0001
residuals_options.equations["continuity"].monitor = True # Enable continuity residuals

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lost comments

# =====================================================================================
session = pyfluent.launch_fluent(mode="meshing", cleanup_on_exit=True)
print(session.get_fluent_version())
meshing = pyfluent.Meshing.from_install(cleanup_on_exit=True, fluent_path=r"C:\ANSYSDev\v261\fluent\ntbin\win64\fluent.exe")

@seanpearsonuk seanpearsonuk Feb 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gobot1234

Other team members can comment here before you change anything due to the following observation.

One reason to avoid meshing = / solver = is that meshing and solver are protected global names in Fluent's Python console. Code that assigns to them would attempt (and fail) to overwrite those globals if the script were reused there, making the script unusable in that environment.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, I was thinking it'd be clearer for using pyconsole because you can just skip that step but then things work for you without having to change variable names, maybe it should be clearer though that this is optional in pyconsole using a separate section

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...unfortunate because I much prefer these names.

save_path=os.getcwd(),
save_path=Path.cwd(),
)
meshing.upload(geometry_filename)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gobot1234

Seeing upload() calls like this one is surprising given that the upload should be taken care of seamlessly due to the geometry import operation. Either the script's explicit upload is redundant or you're aware of a limitation.

@Gobot1234 Gobot1234 Feb 4, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was for PIM based environments so customers only need to change the launch method refs TFS/1365452

session.settings.setup.models.viscous.model = "k-epsilon"
session.settings.setup.models.viscous.k_epsilon_model = "realizable"
session.settings.setup.models.viscous.options.curvature_correction = True
air = FluidMaterial.get(solver, name="air")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gobot1234

As you'll already know, this change depends on another PR you have open. In that PR, we looked into adding this (preferred) style: air = FluidMaterial(solver).get(name="air"). Is that something we're still looking into?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realise that style was preferred by you for all situations I thought that was for cases where Fluid Material was repeated instantiated

Comment thread examples/00-fluent/ahmed_body_workflow.py Outdated
Comment thread examples/00-fluent/ahmed_body_workflow.py
Comment thread examples/00-fluent/ahmed_body_workflow.py
Comment on lines +293 to +298
methods.p_v_coupling.flow_scheme = "Coupled"

discretization_scheme = methods.spatial_discretization.discretization_scheme
discretization_scheme["pressure"] = "second-order"
discretization_scheme["k"] = "second-order-upwind"
discretization_scheme["epsilon"] = "second-order-upwind"

@seanpearsonuk seanpearsonuk Feb 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gobot1234 For some of these, perhaps we could add a comment, either # Alternatively, an enum is available in place of this string value or # Using a string as no enum is currently available. In the latter case, an issue could be raised. Why I'm commenting this is that, as a reader, I am not sure of the reason for using strings here, but I would take some (avoidable) time to try using enums in their place.

Comment thread examples/00-fluent/ahmed_body_workflow.py Outdated
Comment thread examples/00-fluent/ahmed_body_workflow.py Outdated
Comment thread examples/00-fluent/battery_pack.py Outdated
# Define constants
# ----------------

S = 1 / ohm # a Siemen

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
S = 1 / ohm # a Siemen
S = 1 / ohm # = 1 siemens

When surnames are used as units the name is always lowercase whereas the symbol is always uppercase. In this case, the unit is the siemens.

The library should probably expose it directly as a common unit.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found this online

“Siemens” is the singular and plural; “1 siemen” is wrong.

Comment thread examples/00-fluent/battery_pack.py Outdated
graphics.picture.x_resolution = 650 # Horizontal resolution for clear visualization
graphics.picture.y_resolution = 450 # Vertical resolution matching typical aspect ratio

all_walls = mesh.surfaces_list.allowed_values()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gobot1234

What do you think about adding all() for string types as an alias for allowed_values(), with the intention to deprecate the latter over time? This would align with the new <NamedType>.all() (albeit the semantics mismatch slightly) and eliminate a relatively verbose method name.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that yes, will update the PR soonish

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😃

Comment thread examples/00-fluent/battery_pack.py Outdated
Comment on lines +194 to +202
e_material = SolidMaterial.create(solver, name="e_material", chemical_formula="e")
e_material.thermal_conductivity = 20 * W / (m * K)
e_material.uds_diffusivity.option = "defined-per-uds"
e_material.uds_diffusivity.uds_diffusivities["uds-0"] = (
1e6 * S / m
) # Electronic conductivity
e_material.uds_diffusivity.uds_diffusivities["uds-1"] = (
1e6 * S / m
) # Ionic conductivity

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a couple of general questions about this section, i.e. as it already exists, and therefore not directed at @Gobot1234:

1. Terminology:
The quantities provided under uds_diffusivity have units of S/m (electrical conductivity) rather than any form of diffusivity (m²/s).
Is the term “diffusivity” here only a consequence of re-using the generic UDS diffusion operator internally? From a user perspective this is confusing, as the physical meaning is conductivity rather than diffusivity. The API user is not interested in Fluent's implementation details.

2. API structure:
The keys "uds-0" and "uds-1" appear to be created implicitly inside the uds_diffusivities container, with their semantics defined only by comments (electronic vs ionic conductivity).
This raises a few concerns:

  • these objects are not discoverable in the public schema/docs;
  • their meaning is position-based rather than name-based;
  • nothing prevents them being swapped accidentally.

It would obviously make sense to expose a more explicit structure with named fields such as electronic_conductivity and ionic_conductivity, so that the API reflects the physical intent rather than relying on implicit indices?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Referenced in #4892

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll see a similar sort of index based API with the multiphase stuff which I also wasn't a big fan of

@seanpearsonuk seanpearsonuk Feb 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gobot1234 It would be more defensible if the names weren't utterly meaningless. It shows you the level of thinking that goes into some of this stuff.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... as someone with just the code you wouldn't even know what a UDS was which I think is a pretty massive naming failure

Comment thread examples/00-fluent/tyler_sofrin_modes.py Outdated
Comment thread examples/00-fluent/tyler_sofrin_modes.py
@codacy-production

codacy-production Bot commented Apr 14, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copilot AI review requested due to automatic review settings May 14, 2026 16:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates many Fluent examples to demonstrate newer PyFluent object-oriented, typed, and unit-aware APIs instead of older dictionary/TUI-heavy settings patterns. It also adds a changelog entry for the example modernization.

Changes:

  • Replaces many launch_fluent() and dictionary settings calls with Solver.from_install(), Meshing.from_install(), typed settings accessors, and helper commands.
  • Adds unit-aware assignments, pathlib usage, and some visualization/reporting API rewrites.
  • Updates multiple meshing/solver workflows and example post-processing scripts.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 30 comments.

Show a summary per file
File Description
examples/00-fluent/tyler_sofrin_modes.py Modernizes solver launch, file reading, point surfaces, and reports.
examples/00-fluent/transient_compressible_nozzle_workflow.py Updates meshing/solver workflow, reports, units, and transient setup.
examples/00-fluent/steady_vortex.py Converts vortex setup, multiphase/materials, graphics, and save/run calls to typed APIs.
examples/00-fluent/species_transport.py Updates species transport setup, boundary conditions, reporting, and post-processing APIs.
examples/00-fluent/radiation_headlamp.py Converts meshing, radiation/material setup, reports, and file operations to newer APIs.
examples/00-fluent/parametric_static_mixer_1.py Updates parametric setup, named expressions, reports, and study management.
examples/00-fluent/Modeling_solidification_workflow.py Adds units and typed setup for solidification, boundaries, contours, and saves.
examples/00-fluent/modeling_cavitation.py Refactors cavitation model setup, materials, phases, reports, and contours.
examples/00-fluent/modeling_ablation.py Updates ablation setup, dynamic mesh zones, reports, and post-processing.
examples/00-fluent/mixing_tank_workflow.py Modernizes meshing workflow, solver setup, reports, and visualization.
examples/00-fluent/mixing_elbow_settings_api.py Updates material, boundary condition, graphics, and report APIs.
examples/00-fluent/lunar_lander_thermal.py Refactors radiation thermal setup, materials, reports, and transient loop APIs.
examples/00-fluent/fsi_1way_workflow.py Updates FSI setup, structural boundary conditions, contours, and file writes.
examples/00-fluent/frozen_rotor_workflow.py Adds visualization dependency and modernizes pump/volute setup and reports.
examples/00-fluent/external_compressible_flow.py Updates meshing session, solver setup, material properties, and boundary conditions.
examples/00-fluent/exhaust_system_settings_api.py Refactors fault-tolerant meshing, solver setup, pathlines, contours, and scene creation.
examples/00-fluent/Electrolysis_Modeling_workflow.py Updates electrolysis model setup, solid materials, inlet conditions, and contours.
examples/00-fluent/DOE_ML.py Modernizes DOE solver loop and revises ML data processing/modeling code.
examples/00-fluent/brake.py Converts brake thermal setup, reports, animation, and post-processing to newer APIs.
examples/00-fluent/battery_pack.py Updates battery model setup, materials, reports, vector/contour plots, and file save.
examples/00-fluent/ahmed_body_workflow.py Moves Ahmed body example toward new meshing workflow and typed solver APIs.
doc/changelog.d/4887.maintenance.md Adds changelog note for modernized examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


solver_session.settings.file.write_case(file_name="cav.cas.h5")
# Write the initial case file
write_case(file_name="cav.cas.h5")

solver_session.settings.file.write_case_data(file_name="cav.cas.h5")
# Write final case and data (file API retained)
write_case_data(file_name="cav.cas.h5")
run_calc.transient_controls.time_step_size = 1e-06 * s

solver_session.settings.file.write(file_type="case", file_name="ablation.cas.h5")
write_case(solver, file_name="ablation.cas.h5")
# ===========================================================================================================
solver_session.settings.setup.materials.database.copy_by_name(
type="fluid", name="water-liquid"
Materials(solver).database.copy_by_name(type="fluid", name="water-liquid")
Comment on lines +128 to +130
cold_velocities = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7] * m / s

hot_velocities = [0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0] * m / s
precision=pyfluent.Precision.DOUBLE,
mode="solver",
dimension=pyfluent.Dimension.TWO,
fluent_path=r"C:\ANSYSDev\v261\fluent\ntbin\win64\fluent.exe",
Comment on lines +130 to +131
discs.solid_motion.solid_motion_axis_origin = [-0.035, -0.821, 0.045] * m
discs.solid_motion.solid_motion_velocity = [0, 0, 0] * m / s

# Save steady state case
solver.settings.file.write_case_data(file_name="steady_state")
write_case_data(file_name="steady_state")

# Save transient case
solver.settings.file.write_case_data(file_name="unsteady_state")
write_case_data(file_name="unsteady_state")
# We shall use wildcards to specify all zones.

solver_session.settings.results.report.fluxes.get_heat_transfer_sensible(zones="*")
Fluxes.get_heat_transfer_sensible(zones="*")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Documentation related (improving, adding, etc) enhancement Improve any current implemented feature examples Publishing PyFluent examples

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants