Time‑Accurate XV‑15 rotor#
This notebook walks through a time‑accurate setup for the XV‑15 using Flow360. The geometry consists of an isolated rotor from the XV-15 rotorcraft with a sliding interface around it. The farfield zone is cylindrical around the rotor and the rotating zone.

1. Create Project from Volume Mesh#
Load Python libraries and Flow360 client. If you use environment variables or tokens, initialize them here so later API calls can authenticate. XV15 data files are loaded here.
Project is created from the volume mesh
[1]:
import flow360 as fl
from flow360.examples import TutorialRANSXv15
import matplotlib.pyplot as plt
TutorialRANSXv15.get_files()
project = fl.Project.from_volume_mesh(
TutorialRANSXv15.mesh_filename,
name="Tutorial Time-accurate RANS CFD on XV-15 from Python",
)
volume_mesh = project.volume_mesh
[11:12:09] INFO: VolumeMesh successfully submitted: type = Volume Mesh name = Tutorial Time-accurate RANS CFD on XV-15 from Python id = vm-897c667d-6e6a-45da-a6ad-2051ebfd4404 status = uploaded
2. Define rotating zone#
The following steps are needed to use a rotating zone:
The volume zone ‘innerRotating’ is defined with a center and axis of rotation.
The rotating model is defined with the rotating zone and the angular velocity.
[2]:
with fl.SI_unit_system:
rotation_zone = volume_mesh["innerRotating"]
rotation_zone.center = (0, 0, 0) * fl.u.m
rotation_zone.axis = (0, 0, -1)
rotation_model = fl.Rotation(
volumes=rotation_zone,
spec=fl.AngularVelocity(600 * fl.u.rpm),
)
[11:12:30] INFO: using: SI unit system for unit inference.
3. Define time and DDES settings#
To use a time accurate numerical setup with sliding interface, the time settings need to be specified as unsteady. For simulation, we will do 5 revolutions at 3 ° per time step, thus 600 physical time steps in total
[3]:
time_model = fl.Unsteady(
max_pseudo_steps=35,
steps=600,
step_size=0.5 / 600 * fl.u.s,
CFL=fl.AdaptiveCFL(),
)
4. DDES settings#
To use DDES, the turbulence model needs to be defined as such:
[4]:
ddes_model = fl.SpalartAllmaras(
absolute_tolerance=1e-8,
linear_solver=fl.LinearSolver(max_iterations=25),
hybrid_model=fl.DetachedEddySimulation(shielding_function="DDES"),
rotation_correction=True,
equation_evaluation_frequency=1,
)
5. Define SimulationParams#
The simulation parameters are defined in the python class fl.SimulationParams()
Reference geometry for the non-dimensionalisation of the coefficients are specified
Operating conditions are specified in SI units. For our case we have the following operating conditions:
Airspeed = 5 m/s
Rotation rate = 600 RPM
Speed of sound = 340.2 m/s
Density = 1.225 kg/m3
Alpha = -90 °, air coming down from above (i.e., an ascent case)
Other key considerations:
The reference velocity magnitude is arbitrarily set to the tip velocity magnitude of the blades, with an estimated M = 0.7 (238.14 m/s)
[5]:
with fl.SI_unit_system:
params = fl.SimulationParams(
reference_geometry=fl.ReferenceGeometry(
moment_center=(0, 0, 0),
moment_length=(3.81, 3.81, 3.81),
area=45.604,
),
operating_condition=fl.AerospaceCondition(
velocity_magnitude=5,
alpha=-90 * fl.u.deg,
reference_velocity_magnitude=238.14,
),
time_stepping=time_model,
models=[
fl.Fluid(
navier_stokes_solver=fl.NavierStokesSolver(
absolute_tolerance=1e-9,
linear_solver=fl.LinearSolver(max_iterations=35),
limit_velocity=True,
limit_pressure_density=True,
),
turbulence_model_solver=ddes_model,
),
fl.Freestream(surfaces=volume_mesh["farField/farField"]),
fl.Wall(surfaces=volume_mesh["innerRotating/blade"]),
rotation_model,
],
outputs=[
fl.VolumeOutput(
output_fields=[
"primitiveVars",
"T",
"Cp",
"Mach",
"qcriterion",
"VelocityRelative",
],
),
fl.SurfaceOutput(
surfaces=volume_mesh["*"],
output_fields=[
"primitiveVars",
"Cp",
"Cf",
"CfVec",
"yPlus",
"nodeForcesPerUnitArea",
],
),
],
)
INFO: using: SI unit system for unit inference.
6. Run Case#
Run the case specifying parameters and the case name.
[6]:
case = project.run_case(
params=params,
name="Tutorial Time-accurate DDES CFD on XV-15 from Python",
)
INFO: using: SI unit system for unit inference.
[11:12:32] INFO: Successfully submitted: type = Case name = Tutorial Time-accurate DDES CFD on XV-15 from Python id = case-f1ced317-b54b-42b5-9831-2c13d492f880 status = pending
7. Post Processing#
Once the simulation is finished, we will monitor the convergence of forces and residuals.
[7]:
case.wait()
results = case.results
total_forces = case.results.total_forces.as_dataframe()
total_forces.plot("physical_step", ["CL", "CD"])
non_linear = case.results.nonlinear_residuals.as_dataframe()
non_linear.plot(
"physical_step",
["0_cont", "1_momx", "2_momy", "3_momz", "4_energ", "5_nuHat"],
logy=True,
)
plt.xlim(550, 600)
plt.show()
[11:27:50] INFO: Saved to /tmp/tmpn_0xth2e/24f33ce6-7071-4e9c-8582-be1d2082445a.csv
[11:27:52] INFO: Saved to /tmp/tmpn_0xth2e/5ecb7daf-6cce-4a22-8b3a-452c4b33b6fc.csv