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_path to 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#

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": {}
    }
}

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>