How to create a source#
This tutorial demonstrates how to create a source.
There are different type of sources available: luminaire source, surface source, ray file source.
Prerequisites#
Perform imports#
[1]:
from pathlib import Path
from ansys.speos.core import GeoRef, Project, Speos, launcher
from ansys.speos.core.source import (
SourceAmbientNaturalLight,
SourceLuminaire,
SourceRayFile,
SourceSurface,
)
Define constants#
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.
IES = "IES_C_DETECTOR.ies"
Define helper functions#
[3]:
def create_helper_geometries(project: Project):
"""Create bodies and faces."""
def create_face(body):
(
body.create_face(name="TheFaceF")
.set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0])
.set_facets([0, 1, 2])
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
.commit()
)
root_part = project.create_root_part().commit()
body_b1 = root_part.create_body(name="TheBodyB").commit()
body_b2 = root_part.create_body(name="TheBodyC").commit()
body_b3 = root_part.create_body(name="TheBodyD").commit()
body_b4 = root_part.create_body(name="TheBodyE").commit()
for b in [body_b1, body_b2, body_b3, body_b4]:
create_face(b)
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_path
to point to the assets folder.
[4]:
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.
[5]:
if USE_DOCKER:
speos = Speos(host=HOSTNAME, port=GRPC_PORT)
else:
speos = launcher.launch_local_speos_rpc_server(port=GRPC_PORT)
Create a new project#
The only way to create a source using the core layer, is to create it from a project. The Project
class is instantiated by passing a Speos
instance
[6]:
p = Project(speos=speos)
print(p)
{
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sources": [],
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
Source Creation#
Create locally: The mention “local: “ is added when printing the source data and information is not yet pushed to the RPC server
[7]:
intensity_file_path = str(assets_data_path / IES)
source1 = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) # type luminaire
source1.set_intensity_file_uri(uri=intensity_file_path)
print(source1)
local: {
"name": "Luminaire.1",
"description": "",
"metadata": {},
"source_guid": "",
"source": {
"name": "Luminaire.1",
"luminaire": {
"flux_from_intensity_file": {},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "",
"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": {}
}
}
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.10/site-packages/ansys/speos/core/project.py:214: UserWarning: The pySpeos feature : SourceLuminaire needs a Speos Version of 2025 R2 SP0 or higher.
feature = SourceLuminaire(
Push it to the server.
After it is committed to the server, the mention “local: “ is no more present when printing the source.
[8]:
source1.commit()
print(source1)
{
"name": "Luminaire.1",
"metadata": {
"UniqueId": "67e2d0b0-b67d-4048-b0c6-96b746c3b8cf"
},
"source_guid": "88ce187d-a5d5-4cae-86cc-67423717dad9",
"description": "",
"source": {
"name": "Luminaire.1",
"luminaire": {
"flux_from_intensity_file": {},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "0c127a72-f40c-4899-9095-1ee096a2c448",
"spectrum": {
"name": "Luminaire.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": {}
}
}
Changing additional Source Properties
Setting several more characteristics.
[9]:
intensity_file_path = str(assets_data_path / IES)
source2 = p.create_source(name="Luminaire.2", feature_type=SourceLuminaire)
source2.set_intensity_file_uri(uri=intensity_file_path)
source2.set_flux_radiant() # select flux radiant with default value
# choose the source location [Origin, Xvector, Yvector, Zvector]
source2.set_axis_system(axis_system=[20, 50, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1])
source2.set_spectrum().set_blackbody() # choose blackbody with default value for the spectrum
source2.commit() # Push to the server
print(source2)
{
"name": "Luminaire.2",
"metadata": {
"UniqueId": "1fcd06b3-9530-4c9e-9ede-aef3282a9332"
},
"source_guid": "209a5476-1294-4436-8a55-11368d3d2833",
"description": "",
"source": {
"name": "Luminaire.2",
"luminaire": {
"radiant_flux": {
"radiant_value": 1.0
},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "8e99b0c2-b6d7-44c1-a69d-73661ce8aaf5",
"spectrum": {
"name": "Luminaire.2.Spectrum",
"blackbody": {
"temperature": 2856.0
},
"description": "",
"metadata": {}
},
"axis_system": [
20.0,
50.0,
10.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
}
}
Source Instance
As mention “local: “ is added if it is not yet committed to the server.
[10]:
print(source1)
{
"name": "Luminaire.1",
"metadata": {
"UniqueId": "67e2d0b0-b67d-4048-b0c6-96b746c3b8cf"
},
"source_guid": "88ce187d-a5d5-4cae-86cc-67423717dad9",
"description": "",
"source": {
"name": "Luminaire.1",
"luminaire": {
"flux_from_intensity_file": {},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "0c127a72-f40c-4899-9095-1ee096a2c448",
"spectrum": {
"name": "Luminaire.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": {}
}
}
Project:
Committed feature will appear inside the project information.
[11]:
print(p)
{
"sources": [
{
"name": "Luminaire.1",
"metadata": {
"UniqueId": "67e2d0b0-b67d-4048-b0c6-96b746c3b8cf"
},
"source_guid": "88ce187d-a5d5-4cae-86cc-67423717dad9",
"description": "",
"source": {
"name": "Luminaire.1",
"luminaire": {
"flux_from_intensity_file": {},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "0c127a72-f40c-4899-9095-1ee096a2c448",
"spectrum": {
"name": "Luminaire.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": {}
}
},
{
"name": "Luminaire.2",
"metadata": {
"UniqueId": "1fcd06b3-9530-4c9e-9ede-aef3282a9332"
},
"source_guid": "209a5476-1294-4436-8a55-11368d3d2833",
"description": "",
"source": {
"name": "Luminaire.2",
"luminaire": {
"radiant_flux": {
"radiant_value": 1.0
},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "8e99b0c2-b6d7-44c1-a69d-73661ce8aaf5",
"spectrum": {
"name": "Luminaire.2.Spectrum",
"blackbody": {
"temperature": 2856.0
},
"description": "",
"metadata": {}
},
"axis_system": [
20.0,
50.0,
10.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
}
}
],
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
Update:
Note: If you are manipulating a source already committed, don’t forget to commit your changes. If you don’t, you will still only watch what is committed on the server.
[12]:
source1.set_flux_radiant(value=1.2) # modify radiant flux value
source1.set_axis_system(axis_system=[17, 10, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1]) # modify axis system
source1.set_spectrum().set_halogen() # modify spectrum by choosing halogen
source1.commit() # Push changes to the server
print(source1)
{
"name": "Luminaire.1",
"metadata": {
"UniqueId": "67e2d0b0-b67d-4048-b0c6-96b746c3b8cf"
},
"source_guid": "88ce187d-a5d5-4cae-86cc-67423717dad9",
"description": "",
"source": {
"name": "Luminaire.1",
"luminaire": {
"radiant_flux": {
"radiant_value": 1.2
},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "0c127a72-f40c-4899-9095-1ee096a2c448",
"spectrum": {
"name": "Luminaire.1.Spectrum",
"predefined": {
"halogen": {}
},
"description": "",
"metadata": {}
},
"axis_system": [
17.0,
10.0,
10.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
}
}
Reset
Possibility to reset local values from the one available in the server.
[13]:
source1.set_flux_luminous() # modify to luminous flux BUT no commit
source1.reset()
# reset -> this will apply the server value to the local value the local value will be back to
# halogen
source1.delete() # delete (to display the local value with the below print)
print(source1)
local: {
"name": "Luminaire.1",
"description": "",
"metadata": {},
"source_guid": "",
"source": {
"name": "Luminaire.1",
"luminaire": {
"radiant_flux": {
"radiant_value": 1.2
},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "0c127a72-f40c-4899-9095-1ee096a2c448",
"spectrum": {
"name": "Luminaire.1.Spectrum",
"predefined": {
"halogen": {}
},
"description": "",
"metadata": {}
},
"axis_system": [
17.0,
10.0,
10.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
}
}
Delete
Once the data is deleted from the server, you can still work with local data and maybe commit later.
[14]:
source2.delete()
print(source2)
source1.delete()
print(p)
local: {
"name": "Luminaire.2",
"description": "",
"metadata": {},
"source_guid": "",
"source": {
"name": "Luminaire.2",
"luminaire": {
"radiant_flux": {
"radiant_value": 1.0
},
"intensity_file_uri": "/app/assets/IES_C_DETECTOR.ies",
"spectrum_guid": "8e99b0c2-b6d7-44c1-a69d-73661ce8aaf5",
"spectrum": {
"name": "Luminaire.2.Spectrum",
"blackbody": {
"temperature": 2856.0
},
"description": "",
"metadata": {}
},
"axis_system": [
20.0,
50.0,
10.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
}
}
{
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sources": [],
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
Other Sources Examples#
Ray-file source#
[15]:
ray_file_path = str(assets_data_path / "Rays.ray")
source3 = p.create_source(name="Ray-file.1", feature_type=SourceRayFile) # type ray file
source3.set_ray_file_uri(uri=ray_file_path)
source3.commit()
print(source3)
{
"name": "Ray-file.1",
"metadata": {
"UniqueId": "2c891e0f-2de3-4605-81bb-fecc7c798406"
},
"source_guid": "8f4aeb99-cd6f-423d-8bee-744b5aa9bf1d",
"description": "",
"source": {
"name": "Ray-file.1",
"rayfile": {
"ray_file_uri": "/app/assets/Rays.ray",
"flux_from_ray_file": {},
"spectrum_from_ray_file": {},
"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": {}
}
}
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.10/site-packages/ansys/speos/core/project.py:207: UserWarning: The pySpeos feature : SourceRayFile needs a Speos Version of 2025 R2 SP0 or higher.
feature = SourceRayFile(
[16]:
source3.set_flux_luminous()
source3.commit()
print(source3)
{
"name": "Ray-file.1",
"metadata": {
"UniqueId": "2c891e0f-2de3-4605-81bb-fecc7c798406"
},
"source_guid": "8f4aeb99-cd6f-423d-8bee-744b5aa9bf1d",
"description": "",
"source": {
"name": "Ray-file.1",
"rayfile": {
"ray_file_uri": "/app/assets/Rays.ray",
"luminous_flux": {
"luminous_value": 683.0
},
"spectrum_from_ray_file": {},
"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": {}
}
}
[17]:
source3.delete()
[17]:
<ansys.speos.core.source.SourceRayFile at 0x7f3db65fbcd0>
Surface source#
[18]:
create_helper_geometries(p)
source4 = p.create_source(name="Surface.1", feature_type=SourceSurface)
source4.set_exitance_constant(
geometries=[
(GeoRef.from_native_link("TheBodyB/TheFaceF"), False),
(GeoRef.from_native_link("TheBodyC/TheFaceF"), True),
]
)
source4.commit()
print(source4)
{
"name": "Surface.1",
"metadata": {
"UniqueId": "e88726a8-4ca0-445d-a287-1ce0cf2d4d77"
},
"source_guid": "b03b2b59-32df-4f8d-8c2b-a1465fecb20b",
"description": "",
"source": {
"name": "Surface.1",
"surface": {
"luminous_flux": {
"luminous_value": 683.0
},
"intensity_guid": "c7d21970-b4ca-484e-830f-cde03af49cdb",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "TheBodyB/TheFaceF",
"reverse_normal": false
},
{
"geo_path": "TheBodyC/TheFaceF",
"reverse_normal": true
}
]
},
"spectrum_guid": "2a3ec4d3-a041-43ca-a055-44ab25302189",
"intensity": {
"name": "Surface.1.Intensity",
"cos": {
"N": 1.0,
"total_angle": 180.0
},
"description": "",
"metadata": {}
},
"spectrum": {
"name": "Surface.1.Spectrum",
"monochromatic": {
"wavelength": 555.0
},
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
/home/runner/work/pyspeos/pyspeos/.venv/lib/python3.10/site-packages/ansys/speos/core/project.py:200: UserWarning: The pySpeos feature : SourceSurface needs a Speos Version of 2025 R2 SP0 or higher.
feature = SourceSurface(
[19]:
source4.set_flux_luminous_intensity()
source4.set_intensity().set_gaussian().set_axis_system(
axis_system=[10, 50, 20, 1, 0, 0, 0, 1, 0, 0, 0, 1]
)
source4.commit()
print(source4)
{
"name": "Surface.1",
"metadata": {
"UniqueId": "e88726a8-4ca0-445d-a287-1ce0cf2d4d77"
},
"source_guid": "b03b2b59-32df-4f8d-8c2b-a1465fecb20b",
"description": "",
"source": {
"name": "Surface.1",
"surface": {
"luminous_intensity_flux": {
"luminous_intensity_value": 5.0
},
"intensity_guid": "c7d21970-b4ca-484e-830f-cde03af49cdb",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "TheBodyB/TheFaceF",
"reverse_normal": false
},
{
"geo_path": "TheBodyC/TheFaceF",
"reverse_normal": true
}
]
},
"spectrum_guid": "2a3ec4d3-a041-43ca-a055-44ab25302189",
"intensity": {
"name": "Surface.1.Intensity",
"gaussian": {
"FWHM_angle_x": 30.0,
"FWHM_angle_y": 30.0,
"total_angle": 180.0,
"axis_system": [
10.0,
50.0,
20.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
},
"spectrum": {
"name": "Surface.1.Spectrum",
"monochromatic": {
"wavelength": 555.0
},
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
[20]:
source4.delete()
print(source4)
local: {
"name": "Surface.1",
"description": "",
"metadata": {},
"source_guid": "",
"source": {
"name": "Surface.1",
"surface": {
"luminous_intensity_flux": {
"luminous_intensity_value": 5.0
},
"intensity_guid": "c7d21970-b4ca-484e-830f-cde03af49cdb",
"exitance_constant": {
"geo_paths": [
{
"geo_path": "TheBodyB/TheFaceF",
"reverse_normal": false
},
{
"geo_path": "TheBodyC/TheFaceF",
"reverse_normal": true
}
]
},
"spectrum_guid": "2a3ec4d3-a041-43ca-a055-44ab25302189",
"intensity": {
"name": "Surface.1.Intensity",
"gaussian": {
"FWHM_angle_x": 30.0,
"FWHM_angle_y": 30.0,
"total_angle": 180.0,
"axis_system": [
10.0,
50.0,
20.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
]
},
"description": "",
"metadata": {}
},
"spectrum": {
"name": "Surface.1.Spectrum",
"monochromatic": {
"wavelength": 555.0
},
"description": "",
"metadata": {}
}
},
"description": "",
"metadata": {}
}
}
Ambient natural light source#
[21]:
source5 = p.create_source(name="NaturalLight.1", feature_type=SourceAmbientNaturalLight)
source5.turbidity = 4
source5.with_sky = True
print(source5.zenith_direction) # default zenith direction
print(source5.north_direction) # default north direction
source5.reverse_north_direction = True
print(source5)
source5.commit()
print(source5)
[0.0, 0.0, 1.0]
[0.0, 1.0, 0.0]
local: {
"name": "NaturalLight.1",
"description": "",
"metadata": {},
"source_guid": "",
"source": {
"name": "NaturalLight.1",
"ambient": {
"natural_light": {
"turbidity": 4.0,
"with_sky": true,
"north_direction": [
0.0,
1.0,
0.0
],
"reverse_north": true,
"sun_axis_system": {
"automatic_sun": {
"time_zone_uri": "CET",
"year": 2025,
"month": 6,
"day": 30,
"hour": 8,
"minute": 39,
"longitude": 0.0,
"latitude": 0.0
}
}
},
"zenith_direction": [
0.0,
0.0,
1.0
],
"reverse_zenith": false
},
"description": "",
"metadata": {}
}
}
{
"name": "NaturalLight.1",
"metadata": {
"UniqueId": "d20acbba-71f1-4a5d-8471-87a2a29358a3"
},
"source_guid": "75b3a394-80fe-45c0-a3a6-70f19da4f6c6",
"description": "",
"source": {
"name": "NaturalLight.1",
"ambient": {
"natural_light": {
"turbidity": 4.0,
"with_sky": true,
"north_direction": [
0.0,
1.0,
0.0
],
"reverse_north": true,
"sun_axis_system": {
"automatic_sun": {
"time_zone_uri": "CET",
"year": 2025,
"month": 6,
"day": 30,
"hour": 8,
"minute": 39,
"longitude": 0.0,
"latitude": 0.0
}
}
},
"zenith_direction": [
0.0,
0.0,
1.0
],
"reverse_zenith": false
},
"description": "",
"metadata": {}
}
}
[22]:
source5.set_sun_automatic().year = 2026
source5.set_sun_automatic().month = 12
source5.set_sun_automatic().day = 31
source5.set_sun_automatic().hour = 12
source5.set_sun_automatic().minute = 23
source5.set_sun_automatic().longitude = 10
source5.set_sun_automatic().latitude = 45
source5.set_sun_automatic().time_zone = "CST"
source5.commit()
print(source5)
{
"name": "NaturalLight.1",
"metadata": {
"UniqueId": "d20acbba-71f1-4a5d-8471-87a2a29358a3"
},
"source_guid": "75b3a394-80fe-45c0-a3a6-70f19da4f6c6",
"description": "",
"source": {
"name": "NaturalLight.1",
"ambient": {
"natural_light": {
"turbidity": 4.0,
"with_sky": true,
"north_direction": [
0.0,
1.0,
0.0
],
"reverse_north": true,
"sun_axis_system": {
"automatic_sun": {
"time_zone_uri": "CST",
"year": 2026,
"month": 12,
"day": 31,
"hour": 12,
"minute": 23,
"longitude": 10.0,
"latitude": 45.0
}
}
},
"zenith_direction": [
0.0,
0.0,
1.0
],
"reverse_zenith": false
},
"description": "",
"metadata": {}
}
}
[23]:
source5.delete()
[23]:
<ansys.speos.core.source.SourceAmbientNaturalLight at 0x7f3db662cb20>
When creating sources, this creates some intermediate objects (spectrums, intensity templates).
Deleting a source does not delete in cascade those objects because they could be used by some other entities from core layer.
Then at the end of the example, we just clean all databases
[24]:
for item in speos.client.intensity_templates().list() + speos.client.spectrums().list():
item.delete()
speos.close()
[24]:
True