Skip to content

fix: improve examples and tests due to more errors raised by the new SpeosRPC server #546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 11, 2025
Merged
1 change: 1 addition & 0 deletions doc/changelog.d/546.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
improve examples and tests due to more errors raised by the new SpeosRPC server
127 changes: 77 additions & 50 deletions examples/core/opt-prop.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,82 @@
# the surface optical property (SOP) and the volume optical property (VOP).

# The property is then applied to a geometry (like bodies, faces).
#
# ## Prerequisites
#
# ### Perform imports

# +
from pathlib import Path

from ansys.speos.core import GeoRef, Project, Speos

# If using docker container
assets_data_path = Path("/app") / "assets"
# If using local server
# assets_data_path = Path().resolve().parent.parent / "tests" / "assets"
# If using a different path
# assets_data_path = Path("path/to/downloaded/example/assets")
# -
# ### Define constants
# Constants help ensure consistency and avoid repetition throughout the example.

# ## Create connection with speos rpc server
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.

# +
speos = Speos(host="localhost", port=50098)
# -
# ### Define helper functions

# ## New Project

# The only way to create an optical property is to create it from a project.
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](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")

# ### 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.

speos = Speos(host=HOSTNAME, port=GRPC_PORT)

# ### Create a new project
#
# The only way to create an optical property using the core layer, is to create it from a project.
# The ``Project`` class is instantiated by passing a ``Speos`` instance

# +
p = Project(speos=speos)
print(p)
# -
create_helper_geometries(p)

# ## Create VOP (volume optical property)

#
# Create locally.

# The mention "local: " is added when printing the optical property.

# +
op1 = p.create_optical_property(name="Material.1")
op1.set_surface_mirror(reflectance=80) # SOP : mirror
op1.set_volume_opaque() # VOP : opaque
Expand All @@ -55,23 +95,20 @@
]
)
print(op1)
# -

# ## Push it to the server.

# ## Push it to the server.
#
# Now that it is committed to the server,
# the mention "local: " is no more present when printing the optical property.

# +
op1.commit()
print(op1)
# -

# ## Another example.

#
# Setting several more characteristics.

# +
op2 = p.create_optical_property(name="Material.2")
op2.set_surface_opticalpolished() # SOP : optical polished
op2.set_volume_library(
Expand All @@ -86,41 +123,35 @@
)
op2.commit()
print(op2)
# -

# ## Create FOP (face optical property)

# ## Create FOP (face optical property)
#
# Sometimes it is needed to create property but only for surface.

#
# In this case, no call for set_volume_xxx function is needed, and we will select a face for the
# geometries.

# +
op3 = p.create_optical_property(name="Material.FOP")
op3.set_surface_mirror(reflectance=90) # SOP : mirror
# This optical property will be applied a face from TheBodyD named : "TheFaceF".
op3.set_geometries(geometries=[GeoRef.from_native_link(geopath="TheBodyD/TheFaceF")])
op3.commit()
print(op3)
# -

# ## Default values

#
# Some default values are available when applicable in every methods and class.

# +
op4 = p.create_optical_property(name="Material.3").commit()
print(op4)
# -

# ## Read
# ### Material Instance Information

#
# A mention "local: " is added if it is not yet committed to the server.

# +
print(op1)
# -

# The get methods allows you to get some properties of your feature

Expand Down Expand Up @@ -158,47 +189,43 @@
# ### Project Information
# Committed feature information will appear inside a project information.

# +
print(p)
# -

# ## Update

#
# Tipp: if you are manipulating an optical property already committed, don't forget to commit your
# changes.

#
# If you don't, you will still only watch what is committed on the server.

# +

print("op1 surface type before update: {}".format(op1.get(key="sops")[0]))
op1.set_volume_optic().set_surface_opticalpolished().commit()
print(op1)
print("op1 surface type after update: {}".format(op1.get(key="sops")[0]))
# -

# ## Reset

# ## Reset
#
# Possibility to reset local values from the one available in the server.

# +
op1.set_surface_mirror() # set surface as a mirror but no commit
op1.reset() # reset -> this will apply the server value to the local value
op1.delete() # delete (to display the local value with the below print)
print(op1)
# -

# ## Delete

# ## Delete
#
# Once the data is deleted from the server, you can still work with local data and maybe commit
# later.

# +

op2.delete()
print(op2)
# -

# +
# Clean up all Optical properties

op1.delete()
op3.delete()
op4.delete()
# -
8 changes: 5 additions & 3 deletions examples/core/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ansys.speos.core import Project, Speos
from ansys.speos.core.sensor import SensorIrradiance
from ansys.speos.core.simulation import SimulationDirect
from ansys.speos.core.source import SourceSurface
from ansys.speos.core.source import SourceLuminaire, SourceSurface

# If using docker container
assets_data_path = Path("/app") / "assets"
Expand Down Expand Up @@ -45,7 +45,8 @@
# create feature - e.g. source

# +
source1 = p.create_source(name="Source.1", feature_type=SourceSurface)
source1 = p.create_source(name="Source.1", feature_type=SourceLuminaire)
source1.set_intensity_file_uri(uri=str(assets_data_path / "IES_C_DETECTOR.ies"))
source1.commit()
# -

Expand Down Expand Up @@ -99,7 +100,7 @@
# Here a wrong type is given: no source is called Sensor.1 in the project

# +
features = p.find(name="Sensor.1", feature_type=SourceSurface)
features = p.find(name="Sensor.1", feature_type=SourceLuminaire)
print(features)
# -

Expand Down Expand Up @@ -177,6 +178,7 @@

# +
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]
Expand Down
2 changes: 1 addition & 1 deletion examples/core/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
# -

# +
sensor3.set_type_colorimetric()
sensor3.set_type_radiometric()
sensor3.set_layer_type_polarization()
sensor3.commit()
print(sensor3)
Expand Down
27 changes: 26 additions & 1 deletion examples/core/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@
USE_DOCKER = True # Set to False if you're running this example locally as a Notebook.
IES = "IES_C_DETECTOR.ies"

# ### Define helper functions


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
Expand Down Expand Up @@ -168,11 +192,12 @@
# ### Surface source

# +
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("TheBodyB/TheFaceG"), True),
(GeoRef.from_native_link("TheBodyC/TheFaceF"), True),
]
)
source4.commit()
Expand Down
4 changes: 3 additions & 1 deletion src/ansys/speos/core/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ def _fill_features(self):
op_feature._fill(mat_inst=mat_inst)

for src_inst in scene_data.sources:
src_feat = None
if src_inst.HasField("rayfile_properties"):
src_feat = SourceRayFile(
project=self,
Expand All @@ -768,7 +769,8 @@ def _fill_features(self):
source_instance=src_inst,
default_values=False,
)
self._features.append(src_feat)
if src_feat is not None:
self._features.append(src_feat)

for ssr_inst in scene_data.sensors:
if ssr_inst.HasField("irradiance_properties"):
Expand Down
1 change: 1 addition & 0 deletions src/ansys/speos/core/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,7 @@ def __init__(

if default_values:
# Default values
self._exitance_variable.SetInParent()
self.set_axis_plane()

def set_xmp_file_uri(self, uri: str) -> SourceSurface.ExitanceVariable:
Expand Down
26 changes: 26 additions & 0 deletions tests/core/test_opt_prop.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ def test_reset_optical_property(speos: Speos):
"""Test reset of optical property."""
p = Project(speos=speos)

root_part = p.create_root_part()
body_b = root_part.create_body(name="TheBodyB")
body_b.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])
root_part.commit()

# Create + commit
op1 = (
p.create_optical_property(name="Material.1")
Expand Down Expand Up @@ -185,6 +192,13 @@ def test_delete_optical_property(speos: Speos):
"""Test delete of optical property."""
p = Project(speos=speos)

root_part = p.create_root_part()
body_b = root_part.create_body(name="TheBodyB")
body_b.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])
root_part.commit()

# Create + commit
op1 = (
p.create_optical_property(name="Material.1")
Expand Down Expand Up @@ -216,6 +230,18 @@ def test_delete_optical_property(speos: Speos):
def test_get_optical_property(speos: Speos, capsys):
"""Test get of an optical property."""
p = Project(speos=speos)

root_part = p.create_root_part()
body_a = root_part.create_body(name="TheBodyA")
body_a.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])
body_b = root_part.create_body(name="TheBodyB")
body_b.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])
root_part.commit()

op1 = (
p.create_optical_property(name="Material.1")
.set_volume_opaque()
Expand Down
Loading