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.

ROTOR

Note: The settings in this example are by no means a validation setup; they are crafted to showcase the capabilities of Flow360 and we have intentionally reduced node count and example FC cost. For rigorous validation, modify the settings as needed.

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
../../../_images/python_api_example_library_notebooks_time_accurate_XV_15_14_2.png
../../../_images/python_api_example_library_notebooks_time_accurate_XV_15_14_3.png