How to create a component#
This tutorial demonstrates how to create a component feature.
Component feature includes: lightbox import.
Prerequisites#
Perform imports#
[1]:
import json
from pathlib import Path
[2]:
from ansys.speos.core import OptProp, Project, Speos, launcher
from ansys.speos.core.component import LightBox, LightBoxFileInstance
from ansys.speos.core.kernel.client import (
default_docker_channel,
)
from ansys.speos.core.simulation import SimulationDirect
from ansys.speos.core.source import SourceSurface
Define constants#
The constants help ensure consistency and avoid repetition throughout the example.
[3]:
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.
FILES = "CameraInputFiles"
Define helper functions#
These helpers keep LightBox output concise for documentation. Detailed nested content is truncated because it is not the focus of this example.
[4]:
def _truncate_json_value(value, *, max_depth=3, max_list_items=8, max_dict_items=12, _depth=0):
"""Truncate nested JSON-like data for readable output.
Parameters
----------
value : Any
Input value to truncate.
max_depth : int, default: 3
Maximum nesting depth to keep.
max_list_items : int, default: 8
Maximum number of items kept per list.
max_dict_items : int, default: 12
Maximum number of keys kept per dictionary.
_depth : int, default: 0
Current recursion depth. This parameter is for internal use.
Returns
-------
Any
Truncated representation of the input value.
"""
if _depth >= max_depth:
if isinstance(value, dict):
return {"...": f"{len(value)} keys hidden"}
if isinstance(value, list):
return [f"... {len(value)} items hidden"]
return value
if isinstance(value, dict):
items = list(value.items())
out = {
key: _truncate_json_value(
sub_value,
max_depth=max_depth,
max_list_items=max_list_items,
max_dict_items=max_dict_items,
_depth=_depth + 1,
)
for key, sub_value in items[:max_dict_items]
}
hidden = len(items) - max_dict_items
if hidden > 0:
out["..."] = f"{hidden} more keys"
return out
if isinstance(value, list):
out = [
_truncate_json_value(
item,
max_depth=max_depth,
max_list_items=max_list_items,
max_dict_items=max_dict_items,
_depth=_depth + 1,
)
for item in value[:max_list_items]
]
hidden = len(value) - max_list_items
if hidden > 0:
out.append(f"... {hidden} more items")
return out
return value
def print_lightbox_compact(lightbox, *, max_depth=3, max_list_items=8):
"""Print a compact LightBox representation.
Parameters
----------
lightbox : ansys.speos.core.component.LightBox
LightBox feature to print.
max_depth : int, default: 3
Maximum nesting depth kept in the printed JSON payload.
max_list_items : int, default: 8
Maximum number of items shown per list in the printed payload.
Returns
-------
None
This function prints formatted output and returns nothing.
Notes
-----
The optional ``"local: "`` prefix from ``str(lightbox)`` is preserved.
"""
out_str = str(lightbox)
prefix = ""
payload = out_str
if out_str.startswith("local: "):
prefix = "local: "
payload = out_str[len(prefix) :]
try:
payload_dict = json.loads(payload)
except json.JSONDecodeError:
# Fallback to default string output if it is not valid JSON.
print(out_str)
return
compact_payload = _truncate_json_value(
payload_dict,
max_depth=max_depth,
max_list_items=max_list_items,
)
print(prefix + json.dumps(compact_payload, indent=4))
Model Setup#
Load assets#
The assets used to run this example are available in the PySpeos repository on GitHub.
Note: Make sure you have downloaded the simulation assets and set
assets_data_pathto point to the assets’ folder.
[5]:
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")
Connect to the 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.
[6]:
if USE_DOCKER:
speos = Speos(channel=default_docker_channel())
else:
speos = launcher.launch_local_speos_rpc_server(port=GRPC_PORT)
/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.")
Create a new project#
The only way to create a lightbox import, is to create it from a project.
[7]:
p = Project(speos=speos)
print(p)
{
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sub_scene_anchor_axis_system": [],
"sources": [],
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
Create#
Create locally
The mention “local: “ is added when printing the lightbox
[8]:
lightbox = p.create_lightbox(
name="Light Box Import.1",
lightbox=LightBoxFileInstance(
file=assets_data_path / "lightbox" / "Light Box Export.2.SPEOSLightBox", password=""
),
)
print_lightbox_compact(lightbox)
local: {
"name": "Light Box Import.1",
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
"... 4 more items"
],
"display_name": "",
"description": "",
"metadata": {},
"scene_guid": "",
"trajectory_file_uri": ""
}
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1231: UserWarning: The pySpeos feature : FaceStub.read_batch needs a Speos Version of 2025 R2 SP0 or higher.
f_data_list = face_db.read_batch(refs=f_links)
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1338: UserWarning: The pySpeos feature : SourceSurface needs a Speos Version of 2025 R2 SP0 or higher.
src_feat = SourceSurface(
Push it to the server.#
Now that it is committed to the server, the mention “local: “ is no more present when printing the lightbox.
[9]:
lightbox.commit()
print_lightbox_compact(lightbox)
{
"name": "Light Box Import.1",
"metadata": {
"UniqueId": "788e3104-331a-43e1-9a53-a2bcc60b29de"
},
"scene_guid": "daaf2f33-ef81-485b-a817-94ba3fd01dfa",
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
"... 4 more items"
],
"display_name": "",
"description": "",
"trajectory_file_uri": "",
"scene": {
"name": "Light Box Export.2",
"description": "From Speos Light Box: /app/assets/lightbox/Light Box Export.2.SPEOSLightBox",
"part_guid": "a960dac2-7d99-453a-ab75-9a76b26154c8",
"sources": [
{
"...": "7 keys hidden"
}
],
"materials": [
{
"...": "8 keys hidden"
}
],
"metadata": {},
"sub_scene_anchor_axis_system": [],
"sensors": [],
"simulations": [],
"scenes": [],
"part": {
"name": "RootPart",
"body_guids": [
"... 1 items hidden"
],
"description": "",
"metadata": {
"...": "0 keys hidden"
},
"parts": [
"... 0 items hidden"
],
"bodys": [
"... 1 items hidden"
]
}
}
}
Read#
Lightbox Instance#
Properties methods provided are used to retrieve or modify the information of lightbox.
[10]:
print(lightbox.name)
print(lightbox.axis_system)
print(lightbox.source_paths)
lightbox.axis_system = [100, 50, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]
print_lightbox_compact(lightbox)
Light Box Import.1
[0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
['Light Box Import.1/Surface.2:1']
{
"name": "Light Box Import.1",
"metadata": {
"UniqueId": "788e3104-331a-43e1-9a53-a2bcc60b29de"
},
"scene_guid": "daaf2f33-ef81-485b-a817-94ba3fd01dfa",
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
"... 4 more items"
],
"display_name": "",
"description": "",
"trajectory_file_uri": "",
"scene": {
"name": "Light Box Export.2",
"description": "From Speos Light Box: /app/assets/lightbox/Light Box Export.2.SPEOSLightBox",
"part_guid": "a960dac2-7d99-453a-ab75-9a76b26154c8",
"sources": [
{
"...": "7 keys hidden"
}
],
"materials": [
{
"...": "8 keys hidden"
}
],
"metadata": {},
"sub_scene_anchor_axis_system": [],
"sensors": [],
"simulations": [],
"scenes": [],
"part": {
"name": "RootPart",
"body_guids": [
"... 1 items hidden"
],
"description": "",
"metadata": {
"...": "0 keys hidden"
},
"parts": [
"... 0 items hidden"
],
"bodys": [
"... 1 items hidden"
]
}
}
}
Commit the modification to the server
[11]:
lightbox.commit()
print_lightbox_compact(lightbox)
{
"name": "Light Box Import.1",
"metadata": {
"UniqueId": "788e3104-331a-43e1-9a53-a2bcc60b29de"
},
"scene_guid": "daaf2f33-ef81-485b-a817-94ba3fd01dfa",
"axis_system": [
100.0,
50.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
"... 4 more items"
],
"display_name": "",
"description": "",
"trajectory_file_uri": "",
"scene": {
"name": "Light Box Export.2",
"description": "From Speos Light Box: /app/assets/lightbox/Light Box Export.2.SPEOSLightBox",
"part_guid": "a960dac2-7d99-453a-ab75-9a76b26154c8",
"sources": [
{
"...": "7 keys hidden"
}
],
"materials": [
{
"...": "8 keys hidden"
}
],
"metadata": {},
"sub_scene_anchor_axis_system": [],
"sensors": [],
"simulations": [],
"scenes": [],
"part": {
"name": "RootPart",
"body_guids": [
"... 1 items hidden"
],
"description": "",
"metadata": {
"...": "0 keys hidden"
},
"parts": [
"... 0 items hidden"
],
"bodys": [
"... 1 items hidden"
]
}
}
}
Source and Bodies instance inside Lightbox#
Find method is provided to select the features, e.g. sources, bodies inside lightbox.
Example source in lightbox:
[12]:
lightbox_source = lightbox.find(name=".*", name_regex=True, feature_type=SourceSurface)[0]
print(lightbox_source)
{
"name": "Surface.2:1",
"metadata": {
"UniqueId": "05a37ca1-7d45-451b-8192-1c5215581407"
},
"source_guid": "867ae885-b43d-4b5a-9bb7-bbe002dfac88",
"display_name": "",
"description": "",
"source": {
"name": "Surface.2:1",
"surface": {
"radiant_flux": {
"radiant_value": 41.275308514008174
},
"intensity_guid": "e18bd306-ea0c-476a-b1b3-784a5188d779",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Surface_source2:1796887610/face.1:3037138295",
"reverse_normal": false
}
]
},
"spectrum_guid": "e787fc1f-3429-4695-9f9d-369b4f45a0c8",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"blackbody": {
"temperature": 2856.0
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
Example material property in lightbox:
[13]:
lightbox_material = lightbox.find(name=".*", name_regex=True, feature_type=OptProp)[0]
print(lightbox_material)
{
"name": "Material.2",
"metadata": {
"UniqueId": "db82142d-64c5-495a-9802-6cc13d0f8ec0"
},
"geometries": {
"geo_paths": [
"Surface_source2:1796887610/face.1:3037138295"
]
},
"sop_guid": "c708cda8-c3f3-4d55-8365-5109b0f497f8",
"display_name": "",
"description": "",
"sop_guids": [],
"sop": {
"mirror": {
"reflectance": 100.0
},
"name": "",
"description": "",
"metadata": {}
},
"sops": [
{
"mirror": {
"reflectance": 100.0
},
"name": "",
"description": "",
"metadata": {}
}
]
}
Modify lightbox features#
feature instance modify method#
The Lightbox contains features that can be modified via feature commit.
[14]:
lightbox_source = lightbox.find(name=".*", name_regex=True, feature_type=SourceSurface)[0]
print(lightbox_source)
lightbox_source.flux.value = 30
lightbox_source.commit()
print(lightbox_source)
{
"name": "Surface.2:1",
"metadata": {
"UniqueId": "05a37ca1-7d45-451b-8192-1c5215581407"
},
"source_guid": "867ae885-b43d-4b5a-9bb7-bbe002dfac88",
"display_name": "",
"description": "",
"source": {
"name": "Surface.2:1",
"surface": {
"radiant_flux": {
"radiant_value": 41.275308514008174
},
"intensity_guid": "e18bd306-ea0c-476a-b1b3-784a5188d779",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Surface_source2:1796887610/face.1:3037138295",
"reverse_normal": false
}
]
},
"spectrum_guid": "e787fc1f-3429-4695-9f9d-369b4f45a0c8",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"blackbody": {
"temperature": 2856.0
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
{
"name": "Surface.2:1",
"metadata": {
"UniqueId": "05a37ca1-7d45-451b-8192-1c5215581407"
},
"source_guid": "867ae885-b43d-4b5a-9bb7-bbe002dfac88",
"display_name": "",
"description": "",
"source": {
"name": "Surface.2:1",
"surface": {
"radiant_flux": {
"radiant_value": 30.0
},
"intensity_guid": "e18bd306-ea0c-476a-b1b3-784a5188d779",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Surface_source2:1796887610/face.1:3037138295",
"reverse_normal": false
}
]
},
"spectrum_guid": "e787fc1f-3429-4695-9f9d-369b4f45a0c8",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"blackbody": {
"temperature": 2856.0
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
lightbox instance as global modify method#
The Lightbox contains features that can be modified via lightbox commit.
[15]:
lightbox_material = lightbox.find(name=".*", name_regex=True, feature_type=OptProp)[0]
print(lightbox_material)
lightbox_material.sop_mirror.reflectance = 85
print(lightbox_source)
lightbox_source.intensity.set_cos().total_angle = 20
lightbox.commit()
print(lightbox_material)
print(lightbox_source)
{
"name": "Material.2",
"metadata": {
"UniqueId": "db82142d-64c5-495a-9802-6cc13d0f8ec0"
},
"geometries": {
"geo_paths": [
"Surface_source2:1796887610/face.1:3037138295"
]
},
"sop_guid": "c708cda8-c3f3-4d55-8365-5109b0f497f8",
"display_name": "",
"description": "",
"sop_guids": [],
"sop": {
"mirror": {
"reflectance": 100.0
},
"name": "",
"description": "",
"metadata": {}
},
"sops": [
{
"mirror": {
"reflectance": 100.0
},
"name": "",
"description": "",
"metadata": {}
}
]
}
{
"name": "Surface.2:1",
"metadata": {
"UniqueId": "05a37ca1-7d45-451b-8192-1c5215581407"
},
"source_guid": "867ae885-b43d-4b5a-9bb7-bbe002dfac88",
"display_name": "",
"description": "",
"source": {
"name": "Surface.2:1",
"surface": {
"radiant_flux": {
"radiant_value": 30.0
},
"intensity_guid": "e18bd306-ea0c-476a-b1b3-784a5188d779",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Surface_source2:1796887610/face.1:3037138295",
"reverse_normal": false
}
]
},
"spectrum_guid": "e787fc1f-3429-4695-9f9d-369b4f45a0c8",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"blackbody": {
"temperature": 2856.0
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
{
"name": "Material.2",
"metadata": {
"UniqueId": "db82142d-64c5-495a-9802-6cc13d0f8ec0"
},
"geometries": {
"geo_paths": [
"Surface_source2:1796887610/face.1:3037138295"
]
},
"sop_guid": "c708cda8-c3f3-4d55-8365-5109b0f497f8",
"display_name": "",
"description": "",
"sop_guids": [],
"sop": {
"mirror": {
"reflectance": 85.0
},
"name": "",
"description": "",
"metadata": {}
},
"sops": [
{
"mirror": {
"reflectance": 85.0
},
"name": "",
"description": "",
"metadata": {}
}
]
}
{
"name": "Surface.2:1",
"metadata": {
"UniqueId": "05a37ca1-7d45-451b-8192-1c5215581407"
},
"source_guid": "867ae885-b43d-4b5a-9bb7-bbe002dfac88",
"display_name": "",
"description": "",
"source": {
"name": "Surface.2:1",
"surface": {
"radiant_flux": {
"radiant_value": 30.0
},
"intensity_guid": "e18bd306-ea0c-476a-b1b3-784a5188d779",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Surface_source2:1796887610/face.1:3037138295",
"reverse_normal": false
}
]
},
"spectrum_guid": "e787fc1f-3429-4695-9f9d-369b4f45a0c8",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 20.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"blackbody": {
"temperature": 2856.0
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
[16]:
# ## Delete
lightbox_source.delete()
[16]:
<ansys.speos.core.source.SourceSurface at 0x7f1209bfe900>
Lightbox sources in simulation#
The project contains two lightbox features. source_paths are in format of lightbox_name/source_name.
[17]:
p2 = Project(
speos=speos,
path=assets_data_path / "lightbox" / "Direct.1.speos",
)
lightboxes = p2.find(name=".*", name_regex=True, feature_type=LightBox)
lightbox_1 = lightboxes[0]
lightbox_2 = lightboxes[1]
print(lightbox_1.source_paths)
print(lightbox_2.source_paths)
['3/Surface.1:258']
['Light Box Import.2/Surface.2:1', 'Light Box Import.2/Ray-file.1:12']
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1324: UserWarning: The pySpeos feature : SourceRayFile needs a Speos Version of 2025 R2 SP0 or higher.
src_feat = SourceRayFile(
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1440: UserWarning: The pySpeos feature : SimulationDirect needs a Speos Version of 2025 R2 SP0 or higher.
sim_feat = SimulationDirect(
Adding lightbox sources in simulation#
User can add all the sources from lightbox using source_paths method Alternatively, user can choose to add selected features
[18]:
sim = p2.find(name=".*", name_regex=True, feature_type=SimulationDirect)[0]
sim.source_paths = lightbox_2.source_paths
sim.commit()
lightbox_source = lightbox_2.find(name=".*", name_regex=True, feature_type=SourceSurface)[0]
sim.source_paths = [lightbox_source]
sim.commit()
[18]:
<ansys.speos.core.simulation.SimulationDirect at 0x7f12086d06e0>
Black Lightbox#
The Black Lightbox is a lightbox which does not show any features’ information. All sources, geometries, materials information cannot be viewed and cannot be edited.
[19]:
lightbox2 = p.create_lightbox(
name="Light Box Import.2",
lightbox=LightBoxFileInstance(
file=assets_data_path / "lightbox" / "BlackLightBox.SPEOSLightBox", password=""
),
)
print_lightbox_compact(lightbox2)
print(lightbox2.name)
print(lightbox2.source_paths)
local: {
"name": "Light Box Import.2",
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
"... 4 more items"
],
"display_name": "",
"description": "",
"metadata": {},
"scene_guid": "",
"trajectory_file_uri": ""
}
Light Box Import.2
[]
Add a black lightbox to simulation needs to add lightbox to the source paths.
[20]:
lightbox_3 = p2.create_lightbox(
name="Black Light Box Import",
lightbox=LightBoxFileInstance(
file=assets_data_path / "lightbox" / "BlackLightBox.SPEOSLightBox", password=""
),
)
lightbox_3.commit()
sim.source_paths = [lightbox_3.name]
sim.commit()
[20]:
<ansys.speos.core.simulation.SimulationDirect at 0x7f12086d06e0>