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 Rotation model

  • Setup 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.

Cube Mesh

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 flow360 and the example geometry (Cube). The Cube example 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 the length_unit (meters in this case).

  • Group faces for snappy: Call geo.group_faces_for_snappy() to organize geometry faces by body names. This creates a snappy_bodies dictionary 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.SurfaceMeshingParams

  • Volume 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.

  • center and axis: 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) and axis=(1, 0, 0) indicate rotation about the x-axis through the origin.

  • Convert to zone: Wrap the SeedpointVolume in a CustomZones object to make it available for meshing and physics models.

Surface meshing configuration:

  • ``SurfaceMeshingDefaults``: Global surface meshing parameters:

    • min_spacing and max_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 spacing parameter (100 mm in this example) controls the mesh size along edges, while distances (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 fluid volume 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 the SeedpointVolume (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 Rotation model is added to the models list in SimulationParams (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:

  1. ``meshing``: Reference to the ModularMeshingWorkflow defined in Section 2.

  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.

  3. ``time_stepping``: Steady() indicates a steady-state simulation. For unsteady SRF cases, use Unsteady() with appropriate time step settings.

  4. ``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 in operating_condition.

    • ``rotating_farfield``: The rotation model defined in Section 3. This makes the entire fluid domain rotate.

  5. ``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 SimulationParams object 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:

  1. The case is submitted and queued for execution.

  2. Flow360 performs surface meshing using snappyHexMesh.

  3. Volume meshing is performed using the new volume mesher.

  4. The CFD solver runs the simulation.

  5. 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. Flowfield