How to use scene and job#

This tutorial demonstrates how to create a scene, and fill it from a speos file. Then this demonstrates how to create a job from the scene, and run it.

Prerequisites#

Perform imports#

[1]:
from pathlib import Path
import time

from ansys.speos.core import launcher
from ansys.speos.core.kernel.job import ProtoJob
from ansys.speos.core.speos import Speos

# ### Define constants
# Constants help ensure consistency and avoid repetition throughout the example.

HOSTNAME = "localhost"
GRPC_PORT = 50098  # Be sure the Speos GRPC Server has been started on this port.
USE_DOCKER = True  # Set to False if you're running this example locally as a Notebook.

# ### Load assets
# The assets used to run this example are available in the
# [PySpeos repository](https://github.com/ansys/pyspeos/) on GitHub.
#
# > **Note:** Make sure you
# > have downloaded simulation assets and set ``assets_data_path``
# > to point to the assets folder.

if USE_DOCKER:  # Running on the remote server.
    assets_data_path = Path("/app") / "assets"
else:
    assets_data_path = Path("/path/to/your/download/assets/directory")


# ### Start/Connect to Speos RPC Server
# This Python client connects to a server where the Speos engine
# is running as a service. In this example, the server and
# client are the same machine. The launch_local_speos_rpc_method can
# be used to start a local instance of the service.

if USE_DOCKER:
    speos = Speos(host=HOSTNAME, port=GRPC_PORT)
else:
    speos = launcher.launch_local_speos_rpc_server(port=GRPC_PORT)

# ## Scene

# Create an empty scene
[2]:
my_scene = speos.client.scenes().create()

Load a file to fill the scene

[3]:
speos_file = str(
    assets_data_path / "LG_50M_Colorimetric_short.sv5" / "LG_50M_Colorimetric_short.sv5"
)
my_scene.load_file(file_uri=speos_file)

Print scene data model

Here it is possible to see that the scene contains two surface sources, one irradiance sensor.

[4]:
print(my_scene)
ansys.api.speos.scene.v2.Scene
{
    "name": "LG_50M_Colorimetric_short",
    "description": "From /app/assets/LG_50M_Colorimetric_short.sv5/LG_50M_Colorimetric_short.sv5",
    "part_guid": "cf7fa3fe-b8cc-4373-9aa7-526ce68ac6a6",
    "sources": [
        {
            "name": "Dom Source 2 (0) in SOURCE2",
            "source_guid": "1f4741f4-f6f6-4a29-bf34-92e666883009",
            "surface_properties": {
                "exitance_constant_properties": {
                    "geo_paths": [
                        {
                            "geo_path": "Solid Body in SOURCE2:2920204960/Face in SOURCE2:222",
                            "reverse_normal": false
                        }
                    ]
                }
            },
            "description": "",
            "metadata": {}
        },
        {
            "name": "Surface Source (0) in SOURCE1",
            "source_guid": "6c056a1f-43a8-459d-972d-072ad946922a",
            "surface_properties": {
                "exitance_constant_properties": {
                    "geo_paths": [
                        {
                            "geo_path": "Solid Body in SOURCE1:2494956811/Face in SOURCE1:187",
                            "reverse_normal": false
                        }
                    ]
                }
            },
            "description": "",
            "metadata": {}
        }
    ],
    "sensors": [
        {
            "name": "Dom Irradiance Sensor (0)",
            "sensor_guid": "93c27153-bb72-47e3-8d12-4f920b8bf430",
            "result_file_name": "ASSEMBLY1.DS (0).Dom Irradiance Sensor (0)",
            "irradiance_properties": {
                "axis_system": [
                    -42.0,
                    2.0,
                    5.0,
                    0.0,
                    1.0,
                    0.0,
                    0.0,
                    0.0,
                    -1.0,
                    -1.0,
                    0.0,
                    0.0
                ],
                "layer_type_source": {},
                "integration_direction": [
                    1.0,
                    -0.0,
                    -0.0
                ],
                "ray_file_type": "RayFileNone"
            },
            "description": "",
            "metadata": {}
        }
    ],
    "simulations": [
        {
            "name": "ASSEMBLY1.DS (0)",
            "simulation_guid": "9f406ee8-972a-46a8-af36-ef9dd5c5c10a",
            "sensor_paths": [
                "Dom Irradiance Sensor (0)"
            ],
            "source_paths": [
                "Dom Source 2 (0) in SOURCE2",
                "Surface Source (0) in SOURCE1"
            ],
            "description": "",
            "metadata": {}
        }
    ],
    "materials": [
        {
            "name": "Material.1",
            "sop_guids": [
                "9582a5e1-7331-46da-bb49-305e49539d07"
            ],
            "geometries": {
                "geo_paths": [
                    "Solid Body in GUIDE:1379760262/Face in GUIDE:169"
                ]
            },
            "description": "",
            "metadata": {}
        },
        {
            "name": "Material.2",
            "vop_guid": "9fba243e-6fa1-412c-9f34-4879e550a0a9",
            "sop_guids": [
                "adc9325f-5f28-4fa1-a4ed-c977056db95a"
            ],
            "geometries": {
                "geo_paths": [
                    "Solid Body in GUIDE:1379760262"
                ]
            },
            "description": "",
            "metadata": {}
        },
        {
            "name": "Material.3",
            "vop_guid": "38eacb23-6522-4f95-bbd5-180edacb93e9",
            "sop_guids": [
                "9582a5e1-7331-46da-bb49-305e49539d07"
            ],
            "geometries": {
                "geo_paths": [
                    "Solid Body in SOURCE2:2920204960",
                    "Solid Body in SOURCE1:2494956811"
                ]
            },
            "description": "",
            "metadata": {}
        },
        {
            "name": "Material.4",
            "vop_guid": "a0906340-adf2-4e9e-9f26-d02f3d3abddc",
            "description": "",
            "metadata": {},
            "sop_guids": []
        }
    ],
    "metadata": {},
    "scenes": []
}

Job#

Create a job for the first simulation. When loaded from a speos file, there is always only one simulation in the scene.

[5]:
# First create the protobuf message
job_message = ProtoJob(name="my_job")
job_message.scene_guid = my_scene.key  # The job needs a scene guid
job_message.simulation_path = (
    my_scene.get().simulations[0].name
)  # And needs to know which simulation in the scene is involved.
job_message.job_type = ProtoJob.Type.CPU  # Choose type of job, can also be GPU.
job_message.direct_mc_simulation_properties.automatic_save_frequency = 1800
job_message.direct_mc_simulation_properties.stop_condition_rays_number = (
    200000  # Stop condition, here 200000 rays will be sent.
)

# Create the JobLink
job_link = speos.client.jobs().create(message=job_message)

Start the job

[6]:
job_link.start()

Verify state of the job

[7]:
job_link.get_state()
[7]:
state: RUNNING

Wait that the job is finished

[8]:
job_state_res = job_link.get_state()
while (
    job_state_res.state != ProtoJob.State.FINISHED
    and job_state_res.state != ProtoJob.State.STOPPED
    and job_state_res.state != ProtoJob.State.IN_ERROR
):
    time.sleep(2)

    job_state_res = job_link.get_state()

Retrieve results of the job

Two results are generated : the result of irradiance sensor: “ASSEMBLY1.DS (0).Dom Irradiance Sensor (0).xmp” and the simulation report in html

[9]:
results = job_link.get_results().results
print(results)
[upload_response {
  info {
    uri: "14190f1d-a8fa-432b-99c3-ebd41a7333d8"
    file_name: "ASSEMBLY1.DS (0).Dom Irradiance Sensor (0).xmp"
    file_size: 1434549
  }
  upload_duration {
    nanos: 1966117
  }
}
, upload_response {
  info {
    uri: "33fdfe7c-1d1c-41bb-8633-c90ccb135932"
    file_name: "ASSEMBLY1.DS (0).html"
    file_size: 504182
  }
  upload_duration {
    nanos: 794747
  }
}
]

Once no more needed: delete the job

[10]:
job_link.delete()

When loading a speos file into a scene, this creates many objects (source templates, sensor templates, vop template, sop templates). Then at the end of the example, we just clean all databases

[11]:
for item in (
    speos.client.scenes().list()
    + speos.client.simulation_templates().list()
    + speos.client.sensor_templates().list()
    + speos.client.source_templates().list()
    + speos.client.intensity_templates().list()
    + speos.client.spectrums().list()
    + speos.client.vop_templates().list()
    + speos.client.sop_templates().list()
    + speos.client.parts().list()
    + speos.client.bodies().list()
    + speos.client.faces().list()
):
    item.delete()
[12]:
speos.close()
[12]:
True