How to create a project#
This tutorial demonstrates how to create a project.
What is a project?#
A project is a speos simulation container that includes parts, material properties, sensor, sources and simulations.
In this tutorial you will learn how to create a project from scratch or from a pre-defined .speos file.
Prerequisites#
Perform imports#
[1]:
import os
from pathlib import Path
from ansys.speos.core import Project, Speos
from ansys.speos.core.kernel.client import (
default_docker_channel,
)
from ansys.speos.core.launcher import launch_local_speos_rpc_server
from ansys.speos.core.sensor import SensorIrradiance
from ansys.speos.core.simulation import SimulationDirect
from ansys.speos.core.source import SourceLuminaire, SourceSurface
Define constants#
The constants help ensure consistency and avoid repetition throughout the example.
[2]:
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.
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 simulation assets and set
assets_data_pathto point to the assets folder.
[3]:
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.
[4]:
if USE_DOCKER:
speos = Speos(channel=default_docker_channel())
else:
speos = 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.")
New empty project#
An empty project can be created by only passing speos rpc server to the Project class.
[5]:
p = Project(speos=speos)
print(p)
{
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sub_scene_anchor_axis_system": [],
"sources": [],
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
Create features#
The Project class has a multitude of method to create Speos features. each create methedo takes the name and the Feature type as arguments and returns the created Feature #### Source
[6]:
source1 = p.create_source(name="Source.1", feature_type=SourceLuminaire)
source1.intensity_file_uri = assets_data_path / "IES_C_DETECTOR.ies"
source1.commit()
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:446: UserWarning: The pySpeos feature : SourceLuminaire needs a Speos Version of 2025 R2 SP0 or higher.
feature = SourceLuminaire(
[6]:
<ansys.speos.core.source.SourceLuminaire at 0x7f27bd8fe120>
Sensor#
[7]:
sensor1 = p.create_sensor(name="Sensor.1")
sensor1.commit()
[7]:
<ansys.speos.core.sensor.SensorIrradiance at 0x7f27b9b3c440>
Optical property#
[8]:
opt_prop1 = p.create_optical_property(name="Material.1")
opt_prop1.commit()
[8]:
<ansys.speos.core.opt_prop.OptProp at 0x7f27b9b3c830>
Read Project#
User can read the content of a project via simply printing the project
[9]:
print(p)
{
"sources": [
{
"name": "Source.1",
"metadata": {
"UniqueId": "2728ae42-fbe7-4c3a-9bd2-3bf99335ee0c"
},
"source_guid": "3c552fef-5364-4643-974d-43c2d3935912",
"display_name": "",
"description": "",
"source": {
"name": "Source.1",
"luminaire": {
"flux_from_intensity_file": {},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "7ccb7b43-a162-45a5-9a25-9d6a19db7b90",
"spectrum": {
"name": "Source.1.Spectrum",
"predefined": {
"incandescent": {}
},
"description": "",
"metadata": {}
},
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
}
}
],
"sensors": [
{
"name": "Sensor.1",
"metadata": {
"UniqueId": "328343a2-d2b9-41ef-8057-b67cb2426a7d"
},
"sensor_guid": "f5759458-7af6-4300-b880-fa74b28e4336",
"display_name": "",
"description": "",
"result_file_name": "",
"sensor": {
"irradiance_sensor_template": {
"sensor_type_photometric": {},
"illuminance_type_planar": {},
"dimensions": {
"x_start": -50.0,
"x_end": 50.0,
"x_sampling": 100,
"y_start": -50.0,
"y_end": 50.0,
"y_sampling": 100
},
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"layer_type_none": {},
"ray_file_type": "RayFileNone",
"integration_direction": []
},
"name": "Sensor.1",
"description": "",
"metadata": {}
}
}
],
"materials": [
{
"name": "Material.1",
"metadata": {
"UniqueId": "dce84fe3-6f6f-4fba-b077-21d3b94011fe"
},
"sop_guid": "6aa7f119-bd56-434a-bb5b-47f0f4593f62",
"display_name": "",
"description": "",
"sop_guids": [],
"sop": {
"name": "Material.1.SOP",
"mirror": {
"reflectance": 100.0
},
"description": "",
"metadata": {}
}
}
],
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sub_scene_anchor_axis_system": [],
"simulations": [],
"scenes": []
}
Or, user can use the find_key method to read a specific feature:
[10]:
for it in p.find_key(key="monochromatic"):
print(it)
Find a feature inside a project#
Use find method with an exact name#
If no feature is found, an empty list is returned.
[11]:
features = p.find(name="UnexistingName")
print(features)
[]
[12]:
features = p.find(name="Sensor.1")
print(features[0])
{
"name": "Sensor.1",
"metadata": {
"UniqueId": "328343a2-d2b9-41ef-8057-b67cb2426a7d"
},
"sensor_guid": "f5759458-7af6-4300-b880-fa74b28e4336",
"display_name": "",
"description": "",
"result_file_name": "",
"sensor": {
"irradiance_sensor_template": {
"sensor_type_photometric": {},
"illuminance_type_planar": {},
"dimensions": {
"x_start": -50.0,
"x_end": 50.0,
"x_sampling": 100,
"y_start": -50.0,
"y_end": 50.0,
"y_sampling": 100
},
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"layer_type_none": {},
"ray_file_type": "RayFileNone",
"integration_direction": []
},
"name": "Sensor.1",
"description": "",
"metadata": {}
}
}
Use find method with feature type#
Here a wrong type is given: no source is called Sensor.1 in the project
[13]:
features = p.find(name="Sensor.1", feature_type=SourceLuminaire)
print(features)
[]
[14]:
features = p.find(name="Sensor.1", feature_type=SensorIrradiance)
print(features[0])
{
"name": "Sensor.1",
"metadata": {
"UniqueId": "328343a2-d2b9-41ef-8057-b67cb2426a7d"
},
"sensor_guid": "f5759458-7af6-4300-b880-fa74b28e4336",
"display_name": "",
"description": "",
"result_file_name": "",
"sensor": {
"irradiance_sensor_template": {
"sensor_type_photometric": {},
"illuminance_type_planar": {},
"dimensions": {
"x_start": -50.0,
"x_end": 50.0,
"x_sampling": 100,
"y_start": -50.0,
"y_end": 50.0,
"y_sampling": 100
},
"axis_system": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"layer_type_none": {},
"ray_file_type": "RayFileNone",
"integration_direction": []
},
"name": "Sensor.1",
"description": "",
"metadata": {}
}
}
Use find method with approximation name with regex#
find a feature with name starting with Mat
[15]:
features = p.find(name="Mat.*", name_regex=True)
for feat in features:
print(str(type(feat)) + " : name=" + feat._name)
<class 'ansys.speos.core.opt_prop.OptProp'> : name=Material.1
find all features without defining any name
[16]:
features = p.find(name=".*", name_regex=True)
for feat in features:
print(str(type(feat)) + " : name=" + feat._name)
<class 'ansys.speos.core.source.SourceLuminaire'> : name=Source.1
<class 'ansys.speos.core.sensor.SensorIrradiance'> : name=Sensor.1
<class 'ansys.speos.core.opt_prop.OptProp'> : name=Material.1
Delete#
This erases the scene content in server database.
This deletes also each feature of the project
[17]:
p.delete()
print(p)
{
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sub_scene_anchor_axis_system": [],
"sources": [],
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
As the features were deleted just above -> this returns an empty vector
[18]:
print(p.find(name="Sensor.1"))
[]
Create project from pre-defined speos project#
Via passing the .speos/.sv5 file path to the Project class.
[19]:
p2 = Project(
speos=speos,
path=str(assets_data_path / "LG_50M_Colorimetric_short.sv5" / "LG_50M_Colorimetric_short.sv5"),
)
print(p2)
{
"name": "LG_50M_Colorimetric_short",
"description": "From Speos file: /app/assets/LG_50M_Colorimetric_short.sv5/LG_50M_Colorimetric_short.sv5",
"part_guid": "67afb773-e634-45a3-8d00-4260702257e3",
"sources": [
{
"name": "Dom Source 2 (0) in SOURCE2",
"metadata": {
"UniqueId": "a3b49cbe-e81f-43a3-be5a-9faf17672d9d"
},
"source_guid": "19fd644c-e438-4cec-ad8f-1af4af6ad925",
"display_name": "",
"description": "",
"source": {
"name": "Dom Source 2 (0) in SOURCE2",
"surface": {
"radiant_flux": {
"radiant_value": 6.590041607465698
},
"intensity_guid": "8723bfad-d88d-447d-98e0-f43761bdf41f",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Solid Body in SOURCE2:2920204960/Face in SOURCE2:222",
"reverse_normal": false
}
]
},
"spectrum_guid": "f8097d5e-3562-4979-af1e-a0b9f03439f4",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"library": {
"file_uri": "/app/assets/LG_50M_Colorimetric_short.sv5/Red Spectrum.spectrum"
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
},
{
"name": "Surface Source (0) in SOURCE1",
"metadata": {
"UniqueId": "36767e72-39ca-4aac-8e99-3accef4dd78d"
},
"source_guid": "bbdac79b-86d3-4cb3-bb99-f2325d8b5f11",
"display_name": "",
"description": "",
"source": {
"name": "Surface Source (0) in SOURCE1",
"surface": {
"radiant_flux": {
"radiant_value": 9.290411220389682
},
"intensity_guid": "4ff24221-9ef8-4a8f-a014-338f7f9cd35c",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "Solid Body in SOURCE1:2494956811/Face in SOURCE1:187",
"reverse_normal": false
}
]
},
"spectrum_guid": "49f06069-c65a-46c1-8f66-b23e47811c4f",
"intensity": {
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"name": "",
"description": "",
"metadata": {}
},
"spectrum": {
"library": {
"file_uri": "/app/assets/LG_50M_Colorimetric_short.sv5/Blue Spectrum.spectrum"
},
"name": "",
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
],
"sensors": [
{
"name": "Dom Irradiance Sensor (0)",
"metadata": {
"UniqueId": "8a973ff8-d711-4d9d-88bb-44929751b614"
},
"sensor_guid": "50c690ff-6524-4686-a049-1ccdf5f86ac3",
"result_file_name": "ASSEMBLY1.DS (0).Dom Irradiance Sensor (0)",
"display_name": "",
"description": "",
"sensor": {
"irradiance_sensor_template": {
"sensor_type_colorimetric": {
"wavelengths_range": {
"w_start": 400.0,
"w_end": 700.0,
"w_sampling": 25
}
},
"illuminance_type_planar": {},
"dimensions": {
"x_start": -20.0,
"x_end": 20.0,
"x_sampling": 500,
"y_start": -20.0,
"y_end": 20.0,
"y_sampling": 500
},
"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"
},
"name": "Dom Irradiance Sensor (0)",
"description": "",
"metadata": {}
}
}
],
"simulations": [
{
"name": "ASSEMBLY1.DS (0)",
"metadata": {
"UniqueId": "b2eddf1e-7629-49d5-b34e-7bc6a82b274b"
},
"simulation_guid": "c1a05472-32bf-4012-8595-9ec72c677589",
"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": "",
"simulation": {
"direct_mc_simulation_template": {
"geom_distance_tolerance": 0.05,
"max_impact": 100,
"weight": {
"minimum_energy_percentage": 0.005
},
"dispersion": true,
"colorimetric_standard": "CIE_1931",
"fast_transmission_gathering": false,
"ambient_material_uri": ""
},
"name": "ASSEMBLY1.DS (0)",
"metadata": {},
"description": "",
"scene_guid": "95bcfd1c-9776-4c1c-9684-420ee8c6a0e7",
"simulation_path": "ASSEMBLY1.DS (0)",
"job_type": "CPU"
}
}
],
"materials": [
{
"name": "Material.1",
"metadata": {
"UniqueId": "dbf8147d-7bea-441d-b1bf-dfdf4b68500f"
},
"geometries": {
"geo_paths": [
"Solid Body in GUIDE:1379760262/Face in GUIDE:169"
]
},
"sop_guid": "0978ae6b-4ccd-42e0-86f4-ec386f67af78",
"display_name": "",
"description": "",
"sop_guids": [],
"sop": {
"mirror": {
"reflectance": 100.0
},
"name": "",
"description": "",
"metadata": {}
}
},
{
"name": "Material.2",
"metadata": {
"UniqueId": "17b01e8a-2f60-4be4-a7ef-91cb520612ae"
},
"vop_guid": "86eb27b2-a33b-4b25-bfb2-6286d1f68fa1",
"geometries": {
"geo_paths": [
"Solid Body in GUIDE:1379760262"
]
},
"sop_guid": "ba1bc788-ae8c-493b-9937-7ae471bd0b30",
"display_name": "",
"description": "",
"sop_guids": [],
"vop": {
"optic": {
"index": 1.4,
"constringence": 60.0,
"absorption": 0.0
},
"name": "",
"description": "",
"metadata": {}
},
"sop": {
"optical_polished": {},
"name": "",
"description": "",
"metadata": {}
}
},
{
"name": "Material.3",
"metadata": {
"UniqueId": "0541dc72-5f52-4101-812d-1d9d0815e336"
},
"vop_guid": "0e63f9d1-f5cf-4ade-aae1-3dbde80537c1",
"geometries": {
"geo_paths": [
"Solid Body in SOURCE2:2920204960",
"Solid Body in SOURCE1:2494956811"
]
},
"sop_guid": "0978ae6b-4ccd-42e0-86f4-ec386f67af78",
"display_name": "",
"description": "",
"sop_guids": [],
"vop": {
"opaque": {},
"name": "",
"description": "",
"metadata": {}
},
"sop": {
"mirror": {
"reflectance": 100.0
},
"name": "",
"description": "",
"metadata": {}
}
},
{
"name": "Material.4",
"metadata": {
"UniqueId": "7e69634c-e967-40d5-b465-3dede51ffa19"
},
"vop_guid": "e0362c08-255b-4781-8a0e-32faeb67149b",
"display_name": "",
"description": "",
"sop_guids": [],
"vop": {
"optic": {
"index": 1.0,
"absorption": 0.0
},
"name": "",
"description": "",
"metadata": {}
}
}
],
"metadata": {},
"sub_scene_anchor_axis_system": [],
"scenes": []
}
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1169: 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:1169: 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:1169: 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:1264: UserWarning: The pySpeos feature : SourceSurface needs a Speos Version of 2025 R2 SP0 or higher.
src_feat = SourceSurface(
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1264: UserWarning: The pySpeos feature : SourceSurface needs a Speos Version of 2025 R2 SP0 or higher.
src_feat = SourceSurface(
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.14/site-packages/ansys/speos/core/project.py:1357: UserWarning: The pySpeos feature : SimulationDirect needs a Speos Version of 2025 R2 SP0 or higher.
sim_feat = SimulationDirect(
Preview the part information#
User can check the project part using preview method.
[20]:
p2.preview()
use find_key method to find specific information
[21]:
for it in p2.find_key(key="surface"):
print(it)
(".sources[.name='Dom Source 2 (0) in SOURCE2'].source.surface", {'radiant_flux': {'radiant_value': 6.590041607465698}, 'intensity_guid': '8723bfad-d88d-447d-98e0-f43761bdf41f', 'exitance_constant': {'geo_paths': [{'geo_path': 'Solid Body in SOURCE2:2920204960/Face in SOURCE2:222', 'reverse_normal': False}]}, 'spectrum_guid': 'f8097d5e-3562-4979-af1e-a0b9f03439f4', 'intensity': {'cos': {'N': 1.0, 'total_angle': 180.0}, 'name': '', 'description': '', 'metadata': {}}, 'spectrum': {'library': {'file_uri': '/app/assets/LG_50M_Colorimetric_short.sv5/Red Spectrum.spectrum'}, 'name': '', 'description': '', 'metadata': {}}})
(".sources[.name='Surface Source (0) in SOURCE1'].source.surface", {'radiant_flux': {'radiant_value': 9.290411220389682}, 'intensity_guid': '4ff24221-9ef8-4a8f-a014-338f7f9cd35c', 'exitance_constant': {'geo_paths': [{'geo_path': 'Solid Body in SOURCE1:2494956811/Face in SOURCE1:187', 'reverse_normal': False}]}, 'spectrum_guid': '49f06069-c65a-46c1-8f66-b23e47811c4f', 'intensity': {'cos': {'N': 1.0, 'total_angle': 180.0}, 'name': '', 'description': '', 'metadata': {}}, 'spectrum': {'library': {'file_uri': '/app/assets/LG_50M_Colorimetric_short.sv5/Blue Spectrum.spectrum'}, 'name': '', 'description': '', 'metadata': {}}})
Use find method to retrieve feature:
e.g. surface source
[22]:
features = p2.find(name=".*", name_regex=True, feature_type=SourceSurface)
print(features)
for feat in features:
print(str(type(feat)) + " : name=" + feat._name)
src = features[1]
[<ansys.speos.core.source.SourceSurface object at 0x7f27b9b3e270>, <ansys.speos.core.source.SourceSurface object at 0x7f27b9b6c690>]
<class 'ansys.speos.core.source.SourceSurface'> : name=Dom Source 2 (0) in SOURCE2
<class 'ansys.speos.core.source.SourceSurface'> : name=Surface Source (0) in SOURCE1
modify the surface source, e.g. surface source wavelength:
[23]:
src.spectrum.set_monochromatic().wavelength = 550
src.commit()
[23]:
<ansys.speos.core.source.SourceSurface at 0x7f27b9b6c690>
Retrieve a simulation feature:
[24]:
features = p2.find(name=".*", name_regex=True, feature_type=SimulationDirect)
sim_feat = features[0]
print(sim_feat)
{
"name": "ASSEMBLY1.DS (0)",
"metadata": {
"UniqueId": "b2eddf1e-7629-49d5-b34e-7bc6a82b274b"
},
"simulation_guid": "c1a05472-32bf-4012-8595-9ec72c677589",
"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": "",
"simulation": {
"direct_mc_simulation_template": {
"geom_distance_tolerance": 0.05,
"max_impact": 100,
"weight": {
"minimum_energy_percentage": 0.005
},
"dispersion": true,
"colorimetric_standard": "CIE_1931",
"fast_transmission_gathering": false,
"ambient_material_uri": ""
},
"name": "ASSEMBLY1.DS (0)",
"metadata": {},
"description": "",
"scene_guid": "95bcfd1c-9776-4c1c-9684-420ee8c6a0e7",
"simulation_path": "ASSEMBLY1.DS (0)",
"job_type": "CPU"
}
}
[25]:
sim_feat.compute_CPU()
[25]:
[upload_response {
info {
uri: "0a1d3ab8-5130-43f1-b9a5-224a22a1bc3b"
file_name: "ASSEMBLY1.DS (0).Dom Irradiance Sensor (0).xmp"
file_size: 1187269
}
}
, upload_response {
info {
uri: "15805e00-922f-4f02-b000-82ba4a059cfa"
file_name: "ASSEMBLY1.DS (0).html"
file_size: 205633
}
}
]
Preview simulation result (only windows)
[26]:
if os.name == "nt":
from ansys.speos.core.workflow.open_result import open_result_image
open_result_image(
simulation_feature=sim_feat,
result_name="ASSEMBLY1.DS (0).Dom Irradiance Sensor (0).xmp",
)
[27]:
speos.close()
[27]:
True