Space Shuttle launch stack: GeometryAI surface meshing¶

This notebook rebuilds the benchmark's GeometryAI surface mesh of the Space Shuttle launch stack: the orbiter, the external tank and both solid rocket boosters, imported from a single STEP assembly. It keeps the 180° rotation applied to the assembly and the surface controls that tighten the geometric accuracy at the thin trailing edges of the elevons and the OMS pods, and around the main engines. Volume meshing and the downstream health case are available in the linked Flow360 project, but are intentionally outside this notebook.

Requirements¶

Install and configure the Flow360 Python API using the installation and setup guide. This notebook targets the latest client with the public benchmark-asset helper:

pip install "flow360>=25.10.4"

Run the cells from top to bottom in one kernel.

Imports and public input geometry¶

The public snapshot contains the source STEP assembly without exposing the benchmark account's private project. The geometry is imported in feet with the v2 CAD importer, as in the benchmark, so the body ids used below refer to the same parts.

In [ ]:
import flow360 as fl
from flow360.examples import download_benchmark_assets
In [ ]:
solver_version = "release-25.12"

root_asset_files = download_benchmark_assets("Space_Shuttle", "root_assets")
geometry_files = [
    file for file in root_asset_files
    if "/results/" not in file and "/logs/" not in file
    and file.lower().endswith((".csm", ".egads", ".stp", ".step", ".iges", ".igs", ".stl"))
]
project = fl.Project.from_geometry(
    geometry_files,
    name="Space Shuttle: surface meshing",
    solver_version=solver_version,
    length_unit="ft",
    cad_importer_version="v2",
)

Geometry preparation and meshing settings¶

The assembly is rotated 180° about the vertical axis before meshing. The complete benchmark meshing configuration is retained: the automated farfield, the trailing-edge refinement on the elevons and on the OMS pods' engine nozzles, aft closeout panels and RCS thruster housings, and the engine refinement box, which is defined in the rotated frame. Physics and solver settings are omitted.

In [ ]:
trailing_edge_bodies = [
    "body00207",  # elevon
    "body00224",  # elevon
    "body00142",  # OMS pod aft closeout panel
    "body00179",  # OMS pod aft closeout panel
    "body00172",  # aft RCS thruster housing
    "body00161",  # fill panel under the RCS housing
    "body00198",  # OMS engine nozzle
    "body00173",  # aft RCS thruster housing
    "body00178",  # fill panel under the RCS housing
    "body00199",  # OMS engine nozzle
    "body00181",  # fill panel under the RCS housing
    "body00180",  # fill panel under the RCS housing
    "body00159",  # fill panel under the RCS housing
    "body00158",  # fill panel under the RCS housing
]

with fl.SI_unit_system, fl.create_draft(
    new_run_from=project.geometry,
    face_grouping="groupByBodyId",
    edge_grouping="edgeId",
) as draft:
    z_rotation = draft.coordinate_systems.add(
        coordinate_system=fl.CoordinateSystem(
            name="Z Rotation",
            axis_of_rotation=(0, 0, 1),
            angle_of_rotation=180 * fl.u.deg,
        )
    )
    draft.coordinate_systems.assign(
        entities=list(draft.body_groups),
        coordinate_system=z_rotation,
    )

    farfield = fl.AutomatedFarfield()
    trailing_edges = [draft.surfaces[name] for name in trailing_edge_bodies]
    engine_box = fl.Box.from_principal_axes(
        name="Engine Refinement Global",
        center=(160, -0.5, 16.5) * fl.u.ft,
        size=(60, 100, 80) * fl.u.ft,
        axes=[(1, 0, 0), (0, 1, 0)],
    )
    params = fl.SimulationParams(
        meshing=fl.MeshingParams(
            defaults=fl.MeshingDefaults(
                surface_max_edge_length=3 * fl.u.ft,
                curvature_resolution_angle=4 * fl.u.deg,
                geometry_accuracy=0.25 * fl.u.ft,
                min_passage_size=4 * fl.u.ft,
                target_surface_node_count=1.75e6,
                remove_hidden_geometry=True,
                preserve_thin_geometry=True,
                boundary_layer_first_layer_thickness=0.01 * fl.u.mm,
            ),
            volume_zones=[farfield],
            refinements=[
                fl.GeometryRefinement(
                    name="TE",
                    faces=trailing_edges,
                    geometry_accuracy=0.025 * fl.u.ft,
                ),
                fl.GeometryRefinement(
                    name="Engines",
                    entities=[engine_box],
                    geometry_accuracy=0.05 * fl.u.ft,
                ),
            ],
        ),
    )

    params = fl.SimulationParams.model_validate(params.model_dump(mode="python"))
    surface_mesh = project.generate_surface_mesh(
        params=params,
        name=f"Space_Shuttle_surface_mesh_{solver_version}",
        solver_version=solver_version,
        use_geometry_AI=True,
    )

Wait for the surface mesh¶

The wait keeps the notebook attached until the generated surface mesh reaches a terminal state.

In [ ]:
surface_mesh.wait()
surface_mesh

Named inspection viewpoints¶

These camera settings reproduce the benchmark's inspection angles over the full stack, the engines and maneuvering pods, the orbiter-to-tank attachments, the tail and the front of a solid rocket booster. They help review the mesh but do not affect mesh generation. matrix is the camera model-view transform used by the benchmark renderer, and vertScale is the height of the orthographic view.

In [ ]:
viewpoints = {
    "Side-zoom": {"up": [0, 0.0016722214749675102, 0.9999986018366919], "zoom": 3.1634786924873923, "matrix": [[1.0000000000011027, 0, 0, -9.555232770242245], [0, 0.001672221474969558, -0.9999986018376122, -1429.6779033684263], [0, 0.9999986018377996, 0.0016722214749692447, 64.78569791991474], [0, 0, 0, 1]], "vertScale": 255.578741320602},
    "Angle-front-zoom": {"up": [0.07710336174882972, -0.04234502976778574, 0.9961234712930898], "zoom": 13.46894960674082, "matrix": [[-0.21858493218674754, 0.07710336174891451, -0.9727670322486217, -1352.7866905275307], [-0.9755090720987527, -0.042345029767832526, 0.2158447328733744, 299.1520898010305], [-0.024549494417377592, 0.9961234712941923, 0.08447101433551653, 74.89642081486673], [0, 0, 0, 1]], "vertScale": 60.02828179087044},
    "Center-Top-zoom-back": {"up": [0, -0.7071067811865475, 0.7071067811865475], "zoom": 3.41412220163885, "matrix": [[-1.0000000000011016, 0, 0, 121.80619984542336], [0, -0.7071067811873303, 0.7071067811871983, 934.4268304070168], [0, 0.7071067811873304, 0.7071067811871982, 907.8527292543665], [0, 0, 0, 1]], "vertScale": 236.81574784650826},
    "Center-Top-zoom-shuttle": {"up": [0, -0.7071067811865475, 0.7071067811865475], "zoom": 3.41412220163885, "matrix": [[-1.0000000000011016, 0, 0, 1.6072824510612378], [0, -0.7071067811873303, 0.7071067811871983, 934.895886427005], [0, 0.7071067811873304, 0.7071067811871982, 907.3836732343783], [0, 0, 0, 1]], "vertScale": 236.81574784650826},
    "nozzle-exits": {"up": [-0.16893825337561894, 0.00017308058046657912, 0.9856266212869395], "zoom": 14.251239442366726, "matrix": [[0.0017109270480443605, -0.16893825337463955, 0.9856251515038776, 1486.4947123747577], [0.9999985294432473, 0.00017308057912106096, -0.001706211127856365, -1.378195329513321], [0.0001176517557004341, 0.985626621288105, 0.1689383010692936, 255.37864024055872], [0, 0, 0, 1]], "vertScale": 56.68699647168094},
    "engines": {"up": [-0.8943711630615367, 0.005772706464872274, 0.44728838409243826], "zoom": 17.914103593760895, "matrix": [[0.009346877491467518, -0.8943711630618758, 0.4472279715832385, 764.7937774525348], [0.999939587444387, 0.005772706463509552, -0.009354000408597886, -10.979266878178187], [0.005784232422493328, 0.44728838409404553, 0.894371088593285, 1217.7431579802185], [0, 0, 0, 1]], "vertScale": 45.0963094948208},
    "engine-cluster": {"up": [-0.5218000027760644, 0.26786751972930567, 0.8099208288326516], "zoom": 12.235573795342466, "matrix": [[0.5163442307963654, -0.5218000027765932, 0.6790533060279582, 1192.3826775483453], [0.854925620245952, 0.2678675197295769, -0.4442399978873278, -669.7609660157791], [0.04990810728116128, 0.8099208288334739, 0.5844120394475176, 906.5022590613704], [0, 0, 0, 1]], "vertScale": 66.0255067313671},
    "front": {"up": [0, 0, 1], "zoom": 2.9312358629160564, "matrix": [[0, 0, -1.0000000000009202, -1239.908382083025], [-1.0000000000011016, 0, 0, 1.7830794682158968], [0, 1.0000000000011071, 0, 11.550428452421938], [0, 0, 0, 1]], "vertScale": 275.6038741907471},
    "side-big": {"up": [0, 0.0016722214749675102, 0.9999986018366919], "zoom": 2.51664796295834, "matrix": [[1.0000000000011027, 0, 0, -77.24224152415977], [0, 0.001672221474969558, -0.9999986018376122, -1429.772837129376], [0, 0.9999986018377996, 0.0016722214749692447, 8.014732089227438], [0, 0, 0, 1]], "vertScale": 321.28286929102086},
    "stack-iso": {"up": [0.40824829046386274, -0.40824829046386274, 0.8164965809277264], "zoom": 1.8550938119385816, "matrix": [[-0.7071067811873275, 0.4082482904643148, -0.5773502691901573, -901.7918639546542], [-0.7071067811873275, -0.408248290464315, 0.5773502691901572, 844.281681708506], [-5.551115123131905e-17, 0.8164965809286299, 0.577350269190157, 850.4757830552063], [0, 0, 0, 1]], "vertScale": 435.8366661659911},
    "booster": {"up": [0.10466429182880972, -0.0049058388380632725, 0.9944955096737587], "zoom": 7.318474147405612, "matrix": [[-0.10134591557983552, 0.10466429181920348, -0.989330274190908, -1421.1849893879823], [-0.9948345817862495, -0.004905838849569646, 0.10139076707656207, 200.55227199074625], [0.005758497938831135, 0.9944955096845062, 0.10462084370861278, 76.0425369871518], [0, 0, 0, 1]], "vertScale": 110.47629412028323},
}
list(viewpoints)