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.client import (
default_docker_channel,
)
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(channel=default_docker_channel())
else:
speos = launcher.launch_local_speos_rpc_server(port=GRPC_PORT)
# ## Scene
# Create an empty scene
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/tools/common/cyberchannel.py:188: UserWarning: Starting gRPC client without TLS on localhost:50098. This is INSECURE. Consider using a secure connection.
warn(f"Starting gRPC client without TLS on {target}. This is INSECURE. Consider using a secure connection.")
[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 Speos file: /app/assets/LG_50M_Colorimetric_short.sv5/LG_50M_Colorimetric_short.sv5",
"part_guid": "cc5eae02-ec3f-4287-a76c-f0671ec6d20c",
"sources": [
{
"name": "Dom Source 2 (0) in SOURCE2",
"source_guid": "4032f1ca-06c6-4c6c-82ac-14ec9b7be5d6",
"surface_properties": {
"exitance_constant_properties": {
"geo_paths": [
{
"geo_path": "Solid Body in SOURCE2:2920204960/Face in SOURCE2:222",
"reverse_normal": false
}
]
}
},
"display_name": "",
"description": "",
"metadata": {}
},
{
"name": "Surface Source (0) in SOURCE1",
"source_guid": "de5daadc-ae1a-443b-a201-9ca88d46c550",
"surface_properties": {
"exitance_constant_properties": {
"geo_paths": [
{
"geo_path": "Solid Body in SOURCE1:2494956811/Face in SOURCE1:187",
"reverse_normal": false
}
]
}
},
"display_name": "",
"description": "",
"metadata": {}
}
],
"sensors": [
{
"name": "Dom Irradiance Sensor (0)",
"sensor_guid": "b0bf5bf5-4102-43ed-9de1-932af1056574",
"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"
},
"display_name": "",
"description": "",
"metadata": {}
}
],
"simulations": [
{
"name": "ASSEMBLY1.DS (0)",
"simulation_guid": "a0f8f423-48c1-4bc0-a964-7400fd9327d1",
"sensor_paths": [
"Dom Irradiance Sensor (0)"
],
"source_paths": [
"Dom Source 2 (0) in SOURCE2",
"Surface Source (0) in SOURCE1"
],
"geometries": {
"geo_paths": []
},
"display_name": "",
"description": "",
"metadata": {}
}
],
"materials": [
{
"name": "Material.1",
"geometries": {
"geo_paths": [
"Solid Body in GUIDE:1379760262/Face in GUIDE:169"
]
},
"sop_guid": "cdcdf098-423b-48f6-b98f-2235b8b93d0c",
"display_name": "",
"description": "",
"metadata": {},
"sop_guids": []
},
{
"name": "Material.2",
"vop_guid": "e9b039bf-ccd0-42cf-bd00-5b0682ea0421",
"geometries": {
"geo_paths": [
"Solid Body in SOURCE2:2920204960",
"Solid Body in SOURCE1:2494956811"
]
},
"sop_guid": "cdcdf098-423b-48f6-b98f-2235b8b93d0c",
"display_name": "",
"description": "",
"metadata": {},
"sop_guids": []
},
{
"name": "Material.3",
"vop_guid": "148595fa-dd98-41ab-b2e5-b1cc6940b797",
"geometries": {
"geo_paths": [
"Solid Body in GUIDE:1379760262"
]
},
"sop_guid": "8acaac08-1e00-491b-8d07-6ec6cad733a7",
"display_name": "",
"description": "",
"metadata": {},
"sop_guids": []
},
{
"name": "Material.4",
"vop_guid": "a2924793-7490-4659-9e99-7e292651523c",
"display_name": "",
"description": "",
"metadata": {},
"sop_guids": []
}
],
"metadata": {},
"sub_scene_anchor_axis_system": [],
"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: "9438dbb4-af88-471d-8e88-3f782bf52b61"
file_name: "ASSEMBLY1.DS (0).Dom Irradiance Sensor (0).xmp"
file_size: 1152232
}
}
, upload_response {
info {
uri: "31da21ab-bf00-4349-8964-5d3475e9659a"
file_name: "ASSEMBLY1.DS (0).html"
file_size: 174209
}
}
]
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