SRF with Cube#
This notebook demonstrates how to set up a Single Rotating Frame (SRF) simulation with a mesh of a simple cube using snappyHexMesh in Flow360.
Key features demonstrated:
Integration of snappyHexMesh for surface meshing with Flow360’s new volume mesher
Definition of rotating zones using the
RotationmodelSetup of boundary conditions for SRF simulations
Use of the modular meshing workflow with custom zones
This example uses a simple cube geometry to focus on the SRF setup workflow, making it easy to understand the key concepts before applying them to more complex geometries. Therefore, remember this is not a validation case.

1. Create Project from geometry#
The first step is to initialize the Flow360 client and create a project from the geometry file.
Key steps:
Load libraries: Import
flow360and the example geometry (Cube). TheCubeexample provides a pre-configured geometry file for demonstration purposes.Create project: Use
fl.Project.from_geometry()to create a project from the CAD file. Specify thelength_unit(meters in this case).Group faces for snappy: Call
geo.group_faces_for_snappy()to organize geometry faces by body names. This creates asnappy_bodiesdictionary that allows you to reference specific bodies (like"cube"and"farfield") when defining boundary conditions and meshing refinements.
Note: The group_faces_for_snappy() method is essential when using snappyHexMesh integration, as it enables body-based surface selection for meshing and boundary condition assignment.
[1]:
import flow360 as fl
from flow360.examples import Cube
Cube.get_files()
project = fl.Project.from_geometry(
Cube.geometry, name="SRF Cube", length_unit="m"
)
geo = project.geometry
geo.group_faces_for_snappy()
[15:06:00] INFO: Geometry successfully submitted: type = Geometry name = SRF Cube id = geo-85658a73-8dd5-4a94-a00d-be3382fc6bff status = uploaded project id = prj-fb7aece0-8595-4475-9ebf-0680094ee432
INFO: Waiting for geometry to be processed.
[15:06:28] INFO: Regrouping face entities under `faceId` tag (previous `groupByBodyId`).
2. Meshing Parameters#
The meshing configuration uses Flow360’s modular meshing workflow, which allows you to independently choose surface and volume meshers. This example combines:
Surface meshing: snappyHexMesh integration via
snappy.SurfaceMeshingParamsVolume meshing: Flow360’s new volume mesher via
VolumeMeshingParams
Defining the fluid zone:
The fluid domain must be explicitly defined using a SeedpointVolume:
point_in_mesh: A coordinate point that lies inside the fluid region (e.g.,(10, 0, 0)). This seed point helps the mesher identify which volume is the fluid domain.centerandaxis: Define the center and rotation axis for the volume. These are critical for SRF simulations, as they specify the rotation reference frame. Here,center=(0, 0, 0)andaxis=(1, 0, 0)indicate rotation about the x-axis through the origin.Convert to zone: Wrap the
SeedpointVolumein aCustomZonesobject to make it available for meshing and physics models.
Surface meshing configuration:
``SurfaceMeshingDefaults``: Global surface meshing parameters:
min_spacingandmax_spacing: Control the surface mesh resolution (500 mm in this example)gap_resolution: Minimum feature size to capture (1 mm)
``BodyRefinement``: Apply specific refinements to the cube body to ensure adequate mesh resolution on the geometry of interest.
``SurfaceEdgeRefinement``: Refine the mesh along surface edges to capture sharp features and geometric discontinuities. If this refinement is not used, the edges are not guaranteed to be kept by snappyHexMesh. The
spacingparameter (100 mm in this example) controls the mesh size along edges, whiledistances(2 mm) defines the distance from the edge where this refinement is applied.
Volume meshing configuration:
``VolumeMeshingDefaults``: Set boundary layer parameters:
boundary_layer_first_layer_thickness: Thickness of the first boundary layer cell (0.1 mm), which affects near-wall resolution and is important for accurate wall-bounded flow predictions.
Volume meshing refinements:
``PassiveSpacing``: Preserve the surface mesh spacing on specified faces. Applied to the farfield surfaces with
type='unchanged', this prevents the volume mesher from modifying the mesh spacing on the farfield boundaries, maintaining the resolution determined by the surface mesher.``UniformRefinement``: Apply uniform mesh spacing within a defined region. Here, a box region (center at (0.5, 0, 0) with size 3×2×2 m) is refined to 50 mm spacing to ensure adequate resolution around the cube geometry in the near-field region.
Important: When using the new volume mesher, you must set use_beta_mesher=True when running the case (see Section 5).
[2]:
with fl.SI_unit_system:
fluid = fl.SeedpointVolume(name="fluid", point_in_mesh=(10.1435, 0, 0), center=(0, 0, 0), axis=(1, 0, 0))
fluid_zone = fl.CustomZones(name="fluid", entities=[fluid])
meshing_params = fl.ModularMeshingWorkflow(
surface_meshing=fl.snappy.SurfaceMeshingParams(
defaults=fl.snappy.SurfaceMeshingDefaults(
min_spacing=0.5 * fl.u.m, max_spacing=2 * fl.u.m, gap_resolution=1 * fl.u.mm
),
refinements=[
fl.snappy.BodyRefinement(
min_spacing=50 * fl.u.mm, max_spacing=100 * fl.u.mm,
bodies=geo.snappy_bodies["cube"]
),
fl.snappy.SurfaceEdgeRefinement(
spacing=[50* fl.u.mm],
distances=[2*fl.u.mm],
entities=geo.snappy_bodies["cube"]
)
]
),
volume_meshing=fl.VolumeMeshingParams(
defaults=fl.VolumeMeshingDefaults(boundary_layer_first_layer_thickness=1 * fl.u.mm),
refinements=[
fl.PassiveSpacing(
faces=geo.snappy_bodies["farfield"]["*"],
type='unchanged'
),
fl.UniformRefinement(
entities=fl.Box(name="box", center=(0.5,0,0), size=(3,2,2)),
spacing=50*fl.u.mm
)
]
),
zones=[fluid_zone],
)
INFO: using: SI unit system for unit inference.
3. Create Rotating Model#
In an SRF simulation, the entire computational domain rotates as a rigid body. The Rotation model defines which volumes rotate and at what angular velocity.
Key parameters:
``name``: A descriptive name for the rotation model (e.g.,
"rotating_farfield")``volumes``: List of volumes that rotate. Here, we use the
fluidvolume defined earlier, which means the entire fluid domain rotates.``spec``: The rotation specification.
AngularVelocity(10 * fl.u.rpm)sets the domain to rotate at 10 revolutions per minute about the axis defined in theSeedpointVolume(x-axis through the origin).
Important considerations:
The rotation axis and center must match those defined in the
SeedpointVolume(Section 2) for consistency.In SRF simulations, boundary conditions are applied in the rotating frame. For example, a freestream velocity is specified relative to the rotating domain.
The
Rotationmodel is added to themodelslist inSimulationParams(Section 4), not as a boundary condition.
[3]:
with fl.SI_unit_system:
rotating_farfield = fl.Rotation(
name="rotating_fluid",
volumes=[fluid],
spec=fl.AngularVelocity(50 * fl.u.rpm)
)
INFO: using: SI unit system for unit inference.
4. Create SimulationParams#
The SimulationParams class consolidates all simulation settings: meshing, physics, boundary conditions, and solver options.
Configuration components:
``meshing``: Reference to the
ModularMeshingWorkflowdefined in Section 2.``operating_condition``: Defines the flow conditions:
AerospaceCondition(velocity_magnitude=10 * fl.u.m / fl.u.s): Sets a freestream velocity of 10 m/s. In SRF simulations, this velocity is relative to the rotating frame.
``time_stepping``:
Steady()indicates a steady-state simulation. For unsteady SRF cases, useUnsteady()with appropriate time step settings.``models``: List of physics models and boundary conditions:
``Wall``: Applied to cube surfaces using
geo.snappy_bodies["cube"]["*"]. The"*"wildcard selects all faces belonging to the “cube” body. No-slip boundary conditions are applied by default.``Freestream``: Applied to farfield surfaces using
geo.snappy_bodies["farfield"]["*"]. This sets the farfield boundary condition with the velocity specified inoperating_condition.``rotating_farfield``: The rotation model defined in Section 3. This makes the entire fluid domain rotate.
``reference_geometry``:
ReferenceGeometry()enables calculation of reference quantities (forces, moments) for the cube geometry.
Note: The order of models in the list doesn’t matter, but all relevant models must be included.
[4]:
with fl.SI_unit_system:
params = fl.SimulationParams(
meshing=meshing_params, # Previously defined meshing parameters
operating_condition=fl.AerospaceCondition(velocity_magnitude=10 * fl.u.m / fl.u.s),
time_stepping=fl.Steady(),
models=[
fl.Wall(
surfaces=[geo.snappy_bodies["cube"]["*"]]
),
fl.Freestream(
surfaces=[geo.snappy_bodies["farfield"]["*"]]
),
rotating_farfield,
],
reference_geometry=fl.ReferenceGeometry(),
outputs=[
fl.SurfaceOutput(
surfaces=[geo.snappy_bodies["cube"]["*"]],
output_fields=['CfVec','Cf','yPlus','Cp']
)
]
)
INFO: using: SI unit system for unit inference.
5. Run Case#
Submit the case to Flow360’s cloud platform using project.run_case().
Key parameters:
``params``: The
SimulationParamsobject containing all simulation configuration.``name``: A descriptive name for the case (visible in the Flow360 web interface).
``solver_version``: Must match the version used when creating the project to ensure compatibility.
``use_beta_mesher=True``: Required when using
VolumeMeshingParams(the new volume mesher). This flag tells Flow360 to use the beta meshing pipeline instead of the default mesher.
What happens next:
The case is submitted and queued for execution.
Flow360 performs surface meshing using snappyHexMesh.
Volume meshing is performed using the new volume mesher.
The CFD solver runs the simulation.
Results are available for download and visualization.
[ ]:
case = project.run_case(params=params, name="SRF cube from Python", use_beta_mesher=True)
WARNING: The spacing of 50 mm specified in BodyRefinement will be cast to the first lower refinement in the octree series (31.25 mm).
WARNING: The spacing of 100 mm specified in BodyRefinement will be cast to the first lower refinement in the octree series (62.5 mm).
WARNING: The spacing of 50 mm specified in SurfaceEdgeRefinement will be cast to the first lower refinement in the octree series (31.25 mm).
WARNING: The spacing of 50 mm specified in BodyRefinement will be cast to the first lower refinement in the octree series (31.25 mm).
WARNING: The spacing of 100 mm specified in BodyRefinement will be cast to the first lower refinement in the octree series (62.5 mm).
WARNING: The spacing of 50 mm specified in SurfaceEdgeRefinement will be cast to the first lower refinement in the octree series (31.25 mm).
[15:06:29] INFO: Selecting beta/in-house mesher for possible meshing tasks.
[15:06:30] INFO: Successfully submitted: type = Case name = SRF cube from Python id = case-b5614958-c49f-4a03-b5a5-35f47d84bf74 status = pending project id = prj-fb7aece0-8595-4475-9ebf-0680094ee432
Image showing the friction lines on the front face of the cube, notice there is a swirl component. 