4.1. Cloud assets#

Cloud assets refer to geometry, mesh and cases that have been uploaded to/generated in the cloud. User can use the IDs of existing cloud assets to reference them and interact with them.

Referencing existing cloud assets#

existing_cloud_project = fl.Project.from_cloud("prj-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
existing_cloud_geometry = fl.Geometry.from_cloud("geo-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
existing_cloud_volume_mesh = fl.VolumeMesh.from_cloud("vm-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
existing_cloud_case = fl.Case.from_cloud("case-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")

Accessing the entities within cloud assets#

For Geometry, VolumeMesh assets, user can access the entities within them by using the entity name. A full list of entities contained within each type of cloud asset is shown below:

Geometry

  • Grouped faces

  • Grouped edges

VolumeMesh

  • Boundaries

  • Volume zones

For example when specifying the Wall boundary condition, user can access the boundaries in the above existing_cloud_volume_mesh by:

wall = fl.Wall(
    name="Wall",
    entities=[
        existing_cloud_volume_mesh["leftWing"],
        existing_cloud_volume_mesh["rightWing"],
    ],
)

which will select both the leftWing and rightWing boundaries in the volume mesh.

Note

Before selecting entities in Geometry, user needs to specify grouping tags for faces and edges. See below for more information.

We also support naming pattern with wildcard/regular expression for selecting entities. For example, let’s say the existing_cloud_volume_mesh has the following boundaries and zones:

Boundaries:

  • leftWing

  • rightWing

  • fuselage

  • farfield

Volume zones:

  • ZoneWithWing

  • Farfield

User can achieve the same operation as above by:

wall = fl.Wall(
    name="Wall",
    entities=[
        existing_cloud_volume_mesh["*Wing"],
    ],
)

which will use wildcard to automatically match all the entities with that naming pattern. This results in the following entities being selected:

Boundaries:

  • leftWing

  • rightWing

Volume zones:

  • ZoneWithWing

However since the Wall.entities in Wall knows it only accepts surface-type entities. The ZoneWithWing will be automatically filtered out, resulting in only the leftWing and rightWing being selected. Therefore if the user wants SurfaceOutput for all the boundaries, the user can do:

wall = fl.SurfaceOutput(
    name="OutputOnAllBCs",
    entities=[
        existing_cloud_volume_mesh["*"],
    ],
    output_fields=["Cp"],
)

which will dump outputs on all the boundaries (leftWing, rightWing, fuselage, farfield).

Project#

Project serves as the container of all generated cloud assets (like the surface meshes, volume meshes and cases) that share the same root asset. It also is the interface for user to generate new cloud assets. For example forking an existing case to create a new case. An illustration of the content of project (also known as the “Project Tree”) is shown below:

         graph TD
     subgraph Project["Project"]
         Geometry["Geometry"]
         SurfaceMesh1["SurfaceMesh 1"]
         SurfaceMesh2["SurfaceMesh 2"]
         VolumeMesh1["VolumeMesh 1"]
         VolumeMesh2["VolumeMesh 2"]
         Case1["Case 1"]
         Case2["Case 2"]
         Case3["Case 3"]

         Geometry --> SurfaceMesh1
         Geometry --> SurfaceMesh2
         SurfaceMesh1 --> VolumeMesh1
         SurfaceMesh1 --> VolumeMesh2
         VolumeMesh1 --> Case1
         VolumeMesh2 --> Case2
         Case2 --> Case3
     end
    

Create a project#

Project can be created by uploading a geometry or a volume mesh which will become the root asset of the project. Currently we do not support creating project from a surface mesh file.

        graph TD
    Geometry -->|upload and creates| Project
    VolumeMesh -->|upload and creates| Project
    

To create a project from a geometry or a volume mesh with PythonAPI:

project_from_geometry = fl.Project.from_file(
    "my_geometry.csm", name="Project from geometry"
)
project_from_geometry = fl.Project.from_file(
    "my_volume_mesh.cgns", name="Project from volume mesh"
)

Creating new cloud assets from a project#

Once the project is created user can use the project and creates new cloud assets via the project. For example, if I want to run a case from “my_geometry.csm”, I can do the following:

project_from_geometry.run_case(my_params, name="my new case")

where my_params is a SimulationParams instance. This new case will be associated with the project.

The new asset will be then appended to the project tree. The node to which the new asset is appended is completely determined by the user setting. We will analyze the setting and try to browse through the project assets to see if any asset has the exact same meshing or case setting. If such asset is found the new asset will be appended to that node or the asset corresponding to that node will be returned directly and no meshing/case will be run.

For example, in the above example, let’s say VolumeMesh 2 has the same meshing setting as my_params. Then the new case will be appended to the VolumeMesh 2 and only the mesh generation will be skipped.

        graph TD
    classDef grayNode fill:#ddd,stroke:#bbb,stroke-width:2px;
    classDef grayText color:#bbb,fill-opacity:0.3;
    classDef highlightText color:#ff5436,fill-opacity:0.9;

    subgraph Project["Project"]
        Geometry["Geometry"]
        SurfaceMesh1["SurfaceMesh 1"]
        SurfaceMesh2["SurfaceMesh 2"]
        VolumeMesh1["VolumeMesh 1"]
        VolumeMesh2["VolumeMesh 2"]
        Case1["Case 1"]
        Case2["Case 2"]
        Case3["Case 3"]
        Case4["**my new case**"]

        Geometry --> SurfaceMesh1
        Geometry --> SurfaceMesh2
        SurfaceMesh1 --> VolumeMesh1
        SurfaceMesh1 --> VolumeMesh2
        VolumeMesh1 --> Case1
        VolumeMesh1 --> Case4
        VolumeMesh2 --> Case2
        Case2 --> Case3
    end

    %% These are irrelevant nodes
    class SurfaceMesh2,VolumeMesh2,Case1,Case2,Case3 grayNode;
    class SurfaceMesh2,VolumeMesh2,Case1,Case2,Case3 grayText;
    %% These are highlighted nodes
    class Case4 highlightText;
    

Another scenario is that if the user happens to have a case with the exact same setting (meshing and case) as my_params in the project, there will be no new case created and the existing case will be returned. For example if my_params is exactly the same as the one that created Case 2, then Case 2 will be returned.

        graph TD
    classDef grayNode fill:#ddd,stroke:#bbb,stroke-width:2px;
    classDef grayText color:#bbb,fill-opacity:0.3;
    classDef highlightText color:#ff5436,fill-opacity:0.9;

    subgraph Project["Project"]
        Geometry["Geometry"]
        SurfaceMesh1["SurfaceMesh 1"]
        SurfaceMesh2["SurfaceMesh 2"]
        VolumeMesh1["VolumeMesh 1"]
        VolumeMesh2["VolumeMesh 2"]
        Case1["Case 1"]
        Case2["**Case 2**"]
        Case3["Case 3"]

        Geometry --> SurfaceMesh1
        Geometry --> SurfaceMesh2
        SurfaceMesh1 --> VolumeMesh1
        SurfaceMesh1 --> VolumeMesh2
        VolumeMesh1 --> Case1
        VolumeMesh2 --> Case2
        Case2 --> Case3
    end

    %% These are irrelevant nodes
    class SurfaceMesh2,VolumeMesh1,Case1,Case3 grayNode;
    class SurfaceMesh2,VolumeMesh1,Case1,Case3 grayText;
    %% These are highlighted nodes
    class Case2 highlightText;
    

Geometry#

User can use Geometry asset to specify the grouping of faces and edges and these grouping information will be used when generating the mesh and running the case. Note that only the grouping/tagging information stored in the geometry file can be used. Currently we do not support creating new groups/tags.

For example in the quick start example, we tried to access the available groupings in the geometry:

geo.show_available_groupings(verbose_mode=True)

and we can see output:

INFO:  >> Available attribute tags for grouping **faces**:
INFO:     >> Tag 0: groupName. Grouping with this tag results in:
INFO:         >> Group 0: leftWing                                                                                                `
INFO:            IDs: ['body0001_face0001', 'body0001_face0002', 'body0001_face0003', 'body0001_face0004']
INFO:         >> Group 1: fuselage
INFO:            IDs: ['body0001_face0005', 'body0001_face0006', 'body0001_face0007', 'body0001_face0008', 'body0001_face0009', 'body0001_face0010']
INFO:         >> Group 2: rightWing
INFO:            IDs: ['body0001_face0011', 'body0001_face0012', 'body0001_face0013', 'body0001_face0014']
INFO:  >> Available attribute tags for grouping **edges**:
INFO:     >> Tag 0: edgeName. Grouping with this tag results in:
INFO:         >> Group 0: trailingEdge
INFO:            IDs: ['body0001_edge0001', 'body0001_edge0005', 'body0001_edge0026', 'body0001_edge0030']
INFO:         >> Group 1: leadingEdge
INFO:            IDs: ['body0001_edge0007', 'body0001_edge0032']
INFO:         >> Group 2: body0001_edge0002
INFO:            IDs: ['body0001_edge0002']
INFO:         >> Group 3: body0001_edge0004
INFO:            IDs: ['body0001_edge0004']
INFO:         >> Group 4: body0001_edge0006
INFO:            IDs: ['body0001_edge0006']
INFO:         >> Group 5: body0001_edge0008
INFO:            IDs: ['body0001_edge0008']
INFO:         >> Group 6: body0001_edge0009
...

Note that the above geometry file only specifies tag for some of the edges ("body0001_edge0001", "body0001_edge0005", "body0001_edge0026", "body0001_edge0030", "body0001_edge0007", "body0001_edge0032") , all the other edges does not have the tag “edgeName”. If “edgeName” is specified as the edge tag, the edges without this tag will be grouped by themselves (one edge per group). In other words when user do:

geo.group_edges_by_tag("edgeName")

The resulting grouped edges will be:

  • trailingEdge

  • leadingEdge

  • body0001_edge0002

  • body0001_edge0004

  • body0001_edge0006

For face grouping user can call:

geo.group_faces_by_tag("groupName")

User can always use “faceId” and “edgeId” to group faces and edges respectively. This results in each individual face/edge being grouped.