Full workflow tutorial
Walks the same pipeline as Quickstart but explains each step and shows what's on disk at each stage. Uses PyFluent's downloadable mixing_elbow case so you can reproduce this exactly.
Run it:
docs/examples/full_workflow.pyis the runnable version of this tutorial.
Get the case file
from ansys.fluent.core import examples
case_file = examples.download_file("mixing_elbow.cas.h5", "pyfluent/mixing_elbow")
print(case_file)
The download is cached under ~/.cache/ansys_fluent_core/examples/.
Create a project
import cfdtwin
project = cfdtwin.Project.create("./elbow_study", name="elbow_v1")
project.set_case_file(case_file)
elbow_study/project_info.json now exists with the case-file reference.
Declare inputs and outputs
project.set_inputs({
"cold-inlet|momentum > velocity_magnitude": (0.2, 0.6),
"hot-inlet|momentum > velocity_magnitude": (0.4, 1.2),
})
project.set_outputs([
{"name": "outlet", "category": "Surface",
"field_variables": ["temperature"]},
])
Input keys are "<bc_name>|<parameter_display>". The bc names (cold-inlet,
hot-inlet) come from the Fluent case. See
Discovering BC names from Fluent if you don't know them.
Categories must be one of:
- Report Definition — scalar, e.g. an outlet temperature average
- Surface — 2D field on a named surface
- Cell Zone — 3D field across a cell zone
set_outputs writes output_parameters.json.
Generate DOE samples
Samples are written to doe_samples.json. LHS is recommended for any
serious training run because it spreads samples evenly across the input
space.
For a small grid sweep instead:
project.generate_doe(method="factorial", points_per_param=4)
# 4 ** 2 = 16 samples (two inputs, four levels each)
Run simulations
# mixing_elbow.cas.h5 is a single-precision case file. Fluent refuses to
# read a single-precision case in a double-precision session, so override.
project.connect_fluent(precision="single")
sim = project.run_simulations(iterations=100, verbose=True)
print(sim.summary())
Each DOE point is loaded into Fluent, the BCs are applied, the solver
iterates, and outputs are extracted into dataset/sim_NNNN.npz. Coordinates
for field outputs are saved once to dataset/coordinates.npz.
run_simulations() automatically skips already-complete sim IDs, so
interrupting and restarting is safe.
sim is a SimulationResult
with .successful, .failed, .failed_ids, .elapsed, .stopped_reason.
Train
This trains a POD+NN model per (location, field_variable) pair. For the
case above, that's a single 2D field model on outlet predicting
temperature.
result is a TrainingResult.
result.models is a list of ModelInfo — one per trained sub-model.
Predict
pred = project.predict("elbow_v1", {
"cold-inlet|momentum > velocity_magnitude": 0.4,
"hot-inlet|momentum > velocity_magnitude": 0.8,
})
print(pred.values.shape) # (1, n_points)
print(pred.coordinates.shape) # (n_points, 3)
Field reconstructions need coordinates to be useful (for plotting,
post-processing). cfdtwin loads them automatically from
dataset/coordinates.npz.
For batch prediction, pass a list of dicts:
sweep = [
{"cold-inlet|momentum > velocity_magnitude": 0.3,
"hot-inlet|momentum > velocity_magnitude": v}
for v in [0.5, 0.7, 0.9, 1.1]
]
pred = project.predict("elbow_v1", sweep)
print(pred.values.shape) # (4, n_points)
What's on disk after all this
elbow_study/
├── project_info.json
├── model_setup.json
├── output_parameters.json
├── doe_samples.json
├── dataset/
│ ├── coordinates.npz
│ ├── sim_0001.npz
│ ├── ...
│ └── sim_0020.npz
└── models/
└── elbow_v1/
├── outlet_temperature_nn.h5
├── outlet_temperature_nn.npz
├── outlet_temperature_pod.npz
├── outlet_temperature_metadata.json
├── outlet_temperature_loss_curve.png
└── training_summary.json